xref: /openbsd-src/sys/dev/usb/if_cdce.c (revision ff0e7be1ebbcc809ea8ad2b6dafe215824da9e46)
1 /*	$OpenBSD: if_cdce.c,v 1.81 2023/04/27 08:33:59 gerhard Exp $ */
2 
3 /*
4  * Copyright (c) 1997, 1998, 1999, 2000-2003 Bill Paul <wpaul@windriver.com>
5  * Copyright (c) 2003 Craig Boston
6  * Copyright (c) 2004 Daniel Hartmeier
7  * All rights reserved.
8  *
9  * Redistribution and use in source and binary forms, with or without
10  * modification, are permitted provided that the following conditions
11  * are met:
12  * 1. Redistributions of source code must retain the above copyright
13  *    notice, this list of conditions and the following disclaimer.
14  * 2. Redistributions in binary form must reproduce the above copyright
15  *    notice, this list of conditions and the following disclaimer in the
16  *    documentation and/or other materials provided with the distribution.
17  * 3. All advertising materials mentioning features or use of this software
18  *    must display the following acknowledgement:
19  *	This product includes software developed by Bill Paul.
20  * 4. Neither the name of the author nor the names of any co-contributors
21  *    may be used to endorse or promote products derived from this software
22  *    without specific prior written permission.
23  *
24  * THIS SOFTWARE IS PROVIDED BY Bill Paul AND CONTRIBUTORS ``AS IS'' AND
25  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
26  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
27  * ARE DISCLAIMED.  IN NO EVENT SHALL Bill Paul, THE VOICES IN HIS HEAD OR
28  * THE CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
29  * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
30  * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
31  * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
32  * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
33  * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
34  * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
35  */
36 
37 /*
38  * USB Communication Device Class (Ethernet Networking Control Model)
39  * https://www.usb.org/sites/default/files/CDC1.2_WMC1.1_012011.zip
40  *
41  */
42 
43 #include <bpfilter.h>
44 
45 #include <sys/param.h>
46 #include <sys/systm.h>
47 #include <sys/sockio.h>
48 #include <sys/mbuf.h>
49 #include <sys/kernel.h>
50 #include <sys/socket.h>
51 #include <sys/device.h>
52 
53 #include <net/if.h>
54 
55 #if NBPFILTER > 0
56 #include <net/bpf.h>
57 #endif
58 
59 #include <netinet/in.h>
60 #include <netinet/if_ether.h>
61 
62 #include <machine/bus.h>
63 
64 #include <dev/usb/usb.h>
65 #include <dev/usb/usbdi.h>
66 #include <dev/usb/usbdivar.h>
67 #include <dev/usb/usbdi_util.h>
68 #include <dev/usb/usbdevs.h>
69 #include <dev/usb/usbcdc.h>
70 
71 #include <dev/usb/if_cdcereg.h>
72 
73 #ifdef CDCE_DEBUG
74 #define DPRINTFN(n, x)	do { if (cdcedebug > (n)) printf x; } while (0)
75 int cdcedebug = 0;
76 #else
77 #define DPRINTFN(n, x)
78 #endif
79 #define DPRINTF(x)	DPRINTFN(0, x)
80 
81 int	 cdce_tx_list_init(struct cdce_softc *);
82 int	 cdce_rx_list_init(struct cdce_softc *);
83 int	 cdce_newbuf(struct cdce_softc *, struct cdce_chain *,
84 		    struct mbuf *);
85 int	 cdce_encap(struct cdce_softc *, struct mbuf *, int);
86 void	 cdce_rxeof(struct usbd_xfer *, void *, usbd_status);
87 void	 cdce_txeof(struct usbd_xfer *, void *, usbd_status);
88 void	 cdce_start(struct ifnet *);
89 int	 cdce_ioctl(struct ifnet *, u_long, caddr_t);
90 void	 cdce_init(void *);
91 void	 cdce_watchdog(struct ifnet *);
92 void	 cdce_stop(struct cdce_softc *);
93 void	 cdce_intr(struct usbd_xfer *, void *, usbd_status);
94 
95 const struct cdce_type cdce_devs[] = {
96     {{ USB_VENDOR_ACERLABS, USB_PRODUCT_ACERLABS_M5632 }, 0, 0, -1 },
97     {{ USB_VENDOR_PROLIFIC, USB_PRODUCT_PROLIFIC_PL2501 }, 0, 0, -1 },
98     {{ USB_VENDOR_SHARP, USB_PRODUCT_SHARP_SL5500 }, 0, CDCE_CRC32, -1 },
99     {{ USB_VENDOR_SHARP, USB_PRODUCT_SHARP_A300 }, 0, CDCE_CRC32, -1 },
100     {{ USB_VENDOR_SHARP, USB_PRODUCT_SHARP_SL5600 }, 0, CDCE_CRC32, -1 },
101     {{ USB_VENDOR_SHARP, USB_PRODUCT_SHARP_C700 }, 0, CDCE_CRC32, -1 },
102     {{ USB_VENDOR_SHARP, USB_PRODUCT_SHARP_C750 }, 0, CDCE_CRC32, -1 },
103     {{ USB_VENDOR_MOTOROLA2, USB_PRODUCT_MOTOROLA2_USBLAN }, 0, CDCE_CRC32, -1 },
104     {{ USB_VENDOR_MOTOROLA2, USB_PRODUCT_MOTOROLA2_USBLAN2 }, 0, CDCE_CRC32, -1 },
105     {{ USB_VENDOR_GMATE, USB_PRODUCT_GMATE_YP3X00 }, 0, 0, -1 },
106     {{ USB_VENDOR_COMPAQ, USB_PRODUCT_COMPAQ_IPAQLINUX }, 0, 0, -1 },
107     {{ USB_VENDOR_AMBIT, USB_PRODUCT_AMBIT_NTL_250 }, 0, CDCE_SWAPUNION, -1 },
108     {{ USB_VENDOR_ASIX, USB_PRODUCT_ASIX_AX88179 }, 0x0200, CDCE_MATCHREV, 3 },
109 };
110 #define cdce_lookup(v, p) \
111     ((const struct cdce_type *)usb_lookup(cdce_devs, v, p))
112 
113 int cdce_match(struct device *, void *, void *);
114 void cdce_attach(struct device *, struct device *, void *);
115 int cdce_detach(struct device *, int);
116 
117 struct cfdriver cdce_cd = {
118 	NULL, "cdce", DV_IFNET
119 };
120 
121 const struct cfattach cdce_ca = {
122 	sizeof(struct cdce_softc), cdce_match, cdce_attach, cdce_detach
123 };
124 
125 int
126 cdce_match(struct device *parent, void *match, void *aux)
127 {
128 	struct usb_attach_arg *uaa = aux;
129 	usb_interface_descriptor_t *id;
130 	const struct cdce_type *type;
131 
132 	if ((type = cdce_lookup(uaa->vendor, uaa->product)) != NULL) {
133 		if (type->cdce_flags & CDCE_MATCHREV) {
134 			if (type->cdce_rev == uaa->release)
135 				return (UMATCH_VENDOR_PRODUCT_REV);
136 		} else
137 			return (UMATCH_VENDOR_PRODUCT);
138 	}
139 
140 	if (uaa->iface == NULL)
141 		return (UMATCH_NONE);
142 
143 	id = usbd_get_interface_descriptor(uaa->iface);
144 	if (id == NULL)
145 		return (UMATCH_NONE);
146 
147 	if (id->bInterfaceClass == UICLASS_CDC &&
148 	    (id->bInterfaceSubClass ==
149 	    UISUBCLASS_ETHERNET_NETWORKING_CONTROL_MODEL ||
150 	    id->bInterfaceSubClass == UISUBCLASS_MOBILE_DIRECT_LINE_MODEL))
151 		return (UMATCH_IFACECLASS_GENERIC);
152 
153 	return (UMATCH_NONE);
154 }
155 
156 void
157 cdce_attach(struct device *parent, struct device *self, void *aux)
158 {
159 	struct cdce_softc		*sc = (struct cdce_softc *)self;
160 	struct usb_attach_arg		*uaa = aux;
161 	int				 s;
162 	struct ifnet			*ifp = GET_IFP(sc);
163 	const struct cdce_type		*t;
164 	usb_interface_descriptor_t	*id;
165 	usb_endpoint_descriptor_t	*ed;
166 	struct usb_cdc_union_descriptor	*ud;
167 	struct usb_cdc_ethernet_descriptor *ethd;
168 	usb_config_descriptor_t		*cd;
169 	const usb_descriptor_t		*desc;
170 	struct usbd_desc_iter		 iter;
171 	usb_string_descriptor_t		 eaddr_str;
172 	int				 i, j, numalts, len;
173 	int				 ctl_ifcno = -1;
174 	int				 data_ifcno = -1;
175 	usbd_status			 err;
176 
177 	t = cdce_lookup(uaa->vendor, uaa->product);
178 	if (uaa->configno < 0) {
179 		if (t == NULL || t->cdce_cfgno < 0) {
180 			printf("%s: unknown configuration for vid/pid match\n",
181 			    sc->cdce_dev.dv_xname);
182 			return;
183 		}
184 		uaa->configno = t->cdce_cfgno;
185 		DPRINTF(("%s: switching to config #%d\n",
186 		    sc->cdce_dev.dv_xname));
187 		err = usbd_set_config_no(uaa->device, uaa->configno, 1);
188 		if (err) {
189 			printf("%s: failed to switch to config #%d: %s\n",
190 			    sc->cdce_dev.dv_xname, uaa->configno,
191 			    usbd_errstr(err));
192 			return;
193 		}
194 		for (i = 0; i <  uaa->device->cdesc->bNumInterfaces; i++) {
195 			if (usbd_iface_claimed(uaa->device, i))
196 				continue;
197 			id = usbd_get_interface_descriptor(
198 			    &uaa->device->ifaces[i]);
199 			if (id != NULL && id->bInterfaceClass == UICLASS_CDC &&
200 			    id->bInterfaceSubClass ==
201 			    UISUBCLASS_ETHERNET_NETWORKING_CONTROL_MODEL) {
202 				uaa->iface = &uaa->device->ifaces[i];
203 				uaa->ifaceno = uaa->iface->idesc->bInterfaceNumber;
204 				break;
205 			}
206 		}
207 	}
208 
209 	sc->cdce_udev = uaa->device;
210 	sc->cdce_ctl_iface = uaa->iface;
211 	id = usbd_get_interface_descriptor(sc->cdce_ctl_iface);
212 	ctl_ifcno = id->bInterfaceNumber;
213 
214 	if (t)
215 		sc->cdce_flags = t->cdce_flags;
216 
217 	/* Get the data interface no. and capabilities */
218 	ethd = NULL;
219 	usbd_desc_iter_init(sc->cdce_udev, &iter);
220 	desc = usbd_desc_iter_next(&iter);
221 	while (desc) {
222 		if (desc->bDescriptorType != UDESC_CS_INTERFACE) {
223 			desc = usbd_desc_iter_next(&iter);
224 			continue;
225 		}
226 		switch(desc->bDescriptorSubtype) {
227 		case UDESCSUB_CDC_UNION:
228 			ud = (struct usb_cdc_union_descriptor *)desc;
229 			if ((sc->cdce_flags & CDCE_SWAPUNION) == 0 &&
230 			    ud->bMasterInterface == ctl_ifcno)
231 				data_ifcno = ud->bSlaveInterface[0];
232 			if ((sc->cdce_flags & CDCE_SWAPUNION) &&
233 			    ud->bSlaveInterface[0] == ctl_ifcno)
234 				data_ifcno = ud->bMasterInterface;
235 			break;
236 		case UDESCSUB_CDC_ENF:
237 			if (ethd) {
238 				printf("%s: ", sc->cdce_dev.dv_xname);
239 				printf("extra ethernet descriptor\n");
240 				return;
241 			}
242 			ethd = (struct usb_cdc_ethernet_descriptor *)desc;
243 			break;
244 		}
245 		desc = usbd_desc_iter_next(&iter);
246 	}
247 
248 	if (data_ifcno == -1) {
249 		DPRINTF(("cdce_attach: no union interface\n"));
250 		sc->cdce_data_iface = sc->cdce_ctl_iface;
251 	} else {
252 		DPRINTF(("cdce_attach: union interface: ctl=%d, data=%d\n",
253 		    ctl_ifcno, data_ifcno));
254 		for (i = 0; i < uaa->device->cdesc->bNumInterfaces; i++) {
255 			if (usbd_iface_claimed(sc->cdce_udev, i))
256 				continue;
257 			id = usbd_get_interface_descriptor(
258 			    &uaa->device->ifaces[i]);
259 			if (id != NULL && id->bInterfaceNumber == data_ifcno) {
260 				sc->cdce_data_iface = &uaa->device->ifaces[i];
261 				usbd_claim_iface(sc->cdce_udev, i);
262 			}
263 		}
264 	}
265 
266 	if (sc->cdce_data_iface == NULL) {
267 		printf("%s: no data interface\n", sc->cdce_dev.dv_xname);
268 		return;
269 	}
270 
271 	id = usbd_get_interface_descriptor(sc->cdce_ctl_iface);
272 	sc->cdce_intr_no = -1;
273 	for (i = 0; i < id->bNumEndpoints && sc->cdce_intr_no == -1; i++) {
274 		ed = usbd_interface2endpoint_descriptor(sc->cdce_ctl_iface, i);
275 		if (!ed) {
276 			printf("%s: no descriptor for interrupt endpoint %d\n",
277 			    sc->cdce_dev.dv_xname, i);
278 			return;
279 		}
280 		if (UE_GET_DIR(ed->bEndpointAddress) == UE_DIR_IN &&
281 		    UE_GET_XFERTYPE(ed->bmAttributes) == UE_INTERRUPT) {
282 			sc->cdce_intr_no = ed->bEndpointAddress;
283 			sc->cdce_intr_size = sizeof(sc->cdce_intr_buf);
284 		}
285 	}
286 
287 	id = usbd_get_interface_descriptor(sc->cdce_data_iface);
288 	cd = usbd_get_config_descriptor(sc->cdce_udev);
289 	numalts = usbd_get_no_alts(cd, id->bInterfaceNumber);
290 
291 	for (j = 0; j < numalts; j++) {
292 		if (usbd_set_interface(sc->cdce_data_iface, j)) {
293 			printf("%s: interface alternate setting %d failed\n",
294 			    sc->cdce_dev.dv_xname, j);
295 			return;
296 		}
297 		/* Find endpoints. */
298 		id = usbd_get_interface_descriptor(sc->cdce_data_iface);
299 		sc->cdce_bulkin_no = sc->cdce_bulkout_no = -1;
300 		for (i = 0; i < id->bNumEndpoints; i++) {
301 			ed = usbd_interface2endpoint_descriptor(
302 			    sc->cdce_data_iface, i);
303 			if (!ed) {
304 				printf("%s: no descriptor for bulk endpoint "
305 				    "%d\n", sc->cdce_dev.dv_xname, i);
306 				return;
307 			}
308 			if (UE_GET_DIR(ed->bEndpointAddress) == UE_DIR_IN &&
309 			    UE_GET_XFERTYPE(ed->bmAttributes) == UE_BULK) {
310 				sc->cdce_bulkin_no = ed->bEndpointAddress;
311 			} else if (
312 			    UE_GET_DIR(ed->bEndpointAddress) == UE_DIR_OUT &&
313 			    UE_GET_XFERTYPE(ed->bmAttributes) == UE_BULK) {
314 				sc->cdce_bulkout_no = ed->bEndpointAddress;
315 			}
316 #ifdef CDCE_DEBUG
317 			else if (
318 			    UE_GET_DIR(ed->bEndpointAddress) != UE_DIR_IN &&
319 			    UE_GET_XFERTYPE(ed->bmAttributes) != UE_INTERRUPT) {
320 				printf("%s: unexpected endpoint, ep=%x attr=%x"
321 				    "\n", sc->cdce_dev.dv_xname,
322 				    ed->bEndpointAddress, ed->bmAttributes);
323 			}
324 #endif
325 		}
326 		if ((sc->cdce_bulkin_no != -1) && (sc->cdce_bulkout_no != -1)) {
327 			DPRINTF(("cdce_attach: intr=0x%x, in=0x%x, out=0x%x\n",
328 			    sc->cdce_intr_no, sc->cdce_bulkin_no,
329 			    sc->cdce_bulkout_no));
330 			goto found;
331 		}
332 	}
333 
334 	if (sc->cdce_bulkin_no == -1) {
335 		printf("%s: could not find data bulk in\n",
336 		    sc->cdce_dev.dv_xname);
337 		return;
338 	}
339 	if (sc->cdce_bulkout_no == -1 ) {
340 		printf("%s: could not find data bulk out\n",
341 		    sc->cdce_dev.dv_xname);
342 		return;
343 	}
344 
345 found:
346 	s = splnet();
347 
348 	if (!ethd || usbd_get_string_desc(sc->cdce_udev, ethd->iMacAddress,
349 	    sc->cdce_udev->langid, &eaddr_str, &len)) {
350 		ether_fakeaddr(ifp);
351 	} else {
352 		for (i = 0; i < ETHER_ADDR_LEN * 2; i++) {
353 			int c = UGETW(eaddr_str.bString[i]);
354 
355 			if ('0' <= c && c <= '9')
356 				c -= '0';
357 			else if ('A' <= c && c <= 'F')
358 				c -= 'A' - 10;
359 			else if ('a' <= c && c <= 'f')
360 				c -= 'a' - 10;
361 			c &= 0xf;
362 			if (i % 2 == 0)
363 				c <<= 4;
364 			sc->cdce_arpcom.ac_enaddr[i / 2] |= c;
365 		}
366 	}
367 
368 	printf("%s: address %s\n", sc->cdce_dev.dv_xname,
369 	    ether_sprintf(sc->cdce_arpcom.ac_enaddr));
370 
371 	ifp->if_softc = sc;
372 	ifp->if_flags = IFF_BROADCAST | IFF_SIMPLEX | IFF_MULTICAST;
373 	ifp->if_ioctl = cdce_ioctl;
374 	ifp->if_start = cdce_start;
375 	ifp->if_watchdog = cdce_watchdog;
376 	strlcpy(ifp->if_xname, sc->cdce_dev.dv_xname, IFNAMSIZ);
377 
378 	if_attach(ifp);
379 	ether_ifattach(ifp);
380 
381 	sc->cdce_attached = 1;
382 	splx(s);
383 }
384 
385 int
386 cdce_detach(struct device *self, int flags)
387 {
388 	struct cdce_softc	*sc = (struct cdce_softc *)self;
389 	struct ifnet		*ifp = GET_IFP(sc);
390 	int			 s;
391 
392 	if (!sc->cdce_attached)
393 		return (0);
394 
395 	s = splusb();
396 
397 	if (ifp->if_flags & IFF_RUNNING)
398 		cdce_stop(sc);
399 
400 	if (ifp->if_softc != NULL) {
401 		ether_ifdetach(ifp);
402 		if_detach(ifp);
403 	}
404 
405 	sc->cdce_attached = 0;
406 	splx(s);
407 
408 	return (0);
409 }
410 
411 void
412 cdce_start(struct ifnet *ifp)
413 {
414 	struct cdce_softc	*sc = ifp->if_softc;
415 	struct mbuf		*m_head = NULL;
416 
417 	if (usbd_is_dying(sc->cdce_udev) || ifq_is_oactive(&ifp->if_snd))
418 		return;
419 
420 	m_head = ifq_dequeue(&ifp->if_snd);
421 	if (m_head == NULL)
422 		return;
423 
424 	if (cdce_encap(sc, m_head, 0)) {
425 		m_freem(m_head);
426 		ifq_set_oactive(&ifp->if_snd);
427 		return;
428 	}
429 
430 #if NBPFILTER > 0
431 	if (ifp->if_bpf)
432 		bpf_mtap(ifp->if_bpf, m_head, BPF_DIRECTION_OUT);
433 #endif
434 
435 	ifq_set_oactive(&ifp->if_snd);
436 
437 	ifp->if_timer = 6;
438 }
439 
440 int
441 cdce_encap(struct cdce_softc *sc, struct mbuf *m, int idx)
442 {
443 	struct cdce_chain	*c;
444 	usbd_status		 err;
445 	int			 extra = 0;
446 
447 	c = &sc->cdce_cdata.cdce_tx_chain[idx];
448 
449 	m_copydata(m, 0, m->m_pkthdr.len, c->cdce_buf);
450 	if (sc->cdce_flags & CDCE_CRC32) {
451 		/* Some devices want a 32-bit CRC appended to every frame */
452 		u_int32_t crc;
453 
454 		crc = ether_crc32_le(c->cdce_buf, m->m_pkthdr.len) ^ ~0U;
455 		bcopy(&crc, c->cdce_buf + m->m_pkthdr.len, 4);
456 		extra = 4;
457 	}
458 	c->cdce_mbuf = m;
459 
460 	usbd_setup_xfer(c->cdce_xfer, sc->cdce_bulkout_pipe, c, c->cdce_buf,
461 	    m->m_pkthdr.len + extra, USBD_FORCE_SHORT_XFER | USBD_NO_COPY,
462 	    10000, cdce_txeof);
463 	err = usbd_transfer(c->cdce_xfer);
464 	if (err != USBD_IN_PROGRESS) {
465 		c->cdce_mbuf = NULL;
466 		cdce_stop(sc);
467 		return (EIO);
468 	}
469 
470 	sc->cdce_cdata.cdce_tx_cnt++;
471 
472 	return (0);
473 }
474 
475 void
476 cdce_stop(struct cdce_softc *sc)
477 {
478 	usbd_status	 err;
479 	struct ifnet	*ifp = GET_IFP(sc);
480 	int		 i;
481 
482 	ifp->if_timer = 0;
483 	ifp->if_flags &= ~IFF_RUNNING;
484 	ifq_clr_oactive(&ifp->if_snd);
485 
486 	if (sc->cdce_bulkin_pipe != NULL) {
487 		err = usbd_close_pipe(sc->cdce_bulkin_pipe);
488 		if (err)
489 			printf("%s: close rx pipe failed: %s\n",
490 			    sc->cdce_dev.dv_xname, usbd_errstr(err));
491 		sc->cdce_bulkin_pipe = NULL;
492 	}
493 
494 	if (sc->cdce_bulkout_pipe != NULL) {
495 		err = usbd_close_pipe(sc->cdce_bulkout_pipe);
496 		if (err)
497 			printf("%s: close tx pipe failed: %s\n",
498 			    sc->cdce_dev.dv_xname, usbd_errstr(err));
499 		sc->cdce_bulkout_pipe = NULL;
500 	}
501 
502 	if (sc->cdce_intr_pipe != NULL) {
503 		err = usbd_close_pipe(sc->cdce_intr_pipe);
504 		if (err)
505 			printf("%s: close interrupt pipe failed: %s\n",
506 			    sc->cdce_dev.dv_xname, usbd_errstr(err));
507 		sc->cdce_intr_pipe = NULL;
508 	}
509 
510 	for (i = 0; i < CDCE_RX_LIST_CNT; i++) {
511 		if (sc->cdce_cdata.cdce_rx_chain[i].cdce_mbuf != NULL) {
512 			m_freem(sc->cdce_cdata.cdce_rx_chain[i].cdce_mbuf);
513 			sc->cdce_cdata.cdce_rx_chain[i].cdce_mbuf = NULL;
514 		}
515 		if (sc->cdce_cdata.cdce_rx_chain[i].cdce_xfer != NULL) {
516 			usbd_free_xfer(sc->cdce_cdata.cdce_rx_chain[i].cdce_xfer);
517 			sc->cdce_cdata.cdce_rx_chain[i].cdce_xfer = NULL;
518 		}
519 	}
520 
521 	for (i = 0; i < CDCE_TX_LIST_CNT; i++) {
522 		if (sc->cdce_cdata.cdce_tx_chain[i].cdce_mbuf != NULL) {
523 			m_freem(sc->cdce_cdata.cdce_tx_chain[i].cdce_mbuf);
524 			sc->cdce_cdata.cdce_tx_chain[i].cdce_mbuf = NULL;
525 		}
526 		if (sc->cdce_cdata.cdce_tx_chain[i].cdce_xfer != NULL) {
527 			usbd_free_xfer(
528 			    sc->cdce_cdata.cdce_tx_chain[i].cdce_xfer);
529 			sc->cdce_cdata.cdce_tx_chain[i].cdce_xfer = NULL;
530 		}
531 	}
532 }
533 
534 int
535 cdce_ioctl(struct ifnet *ifp, u_long command, caddr_t data)
536 {
537 	struct cdce_softc	*sc = ifp->if_softc;
538 	int			 s, error = 0;
539 
540 	if (usbd_is_dying(sc->cdce_udev))
541 		return ENXIO;
542 
543 	s = splnet();
544 
545 	switch(command) {
546 	case SIOCSIFADDR:
547 		ifp->if_flags |= IFF_UP;
548 		if (!(ifp->if_flags & IFF_RUNNING))
549 			cdce_init(sc);
550 		break;
551 
552 	case SIOCSIFFLAGS:
553 		if (ifp->if_flags & IFF_UP) {
554 			if (ifp->if_flags & IFF_RUNNING)
555 				error = ENETRESET;
556 			else
557 				cdce_init(sc);
558 		} else {
559 			if (ifp->if_flags & IFF_RUNNING)
560 				cdce_stop(sc);
561 		}
562 		break;
563 
564 	default:
565 		error = ether_ioctl(ifp, &sc->cdce_arpcom, command, data);
566 		break;
567 	}
568 
569 	if (error == ENETRESET)
570 		error = 0;
571 
572 	splx(s);
573 	return (error);
574 }
575 
576 void
577 cdce_watchdog(struct ifnet *ifp)
578 {
579 	struct cdce_softc	*sc = ifp->if_softc;
580 
581 	if (usbd_is_dying(sc->cdce_udev))
582 		return;
583 
584 	ifp->if_oerrors++;
585 	printf("%s: watchdog timeout\n", sc->cdce_dev.dv_xname);
586 }
587 
588 void
589 cdce_init(void *xsc)
590 {
591 	struct cdce_softc	*sc = xsc;
592 	struct ifnet		*ifp = GET_IFP(sc);
593 	struct cdce_chain	*c;
594 	usbd_status		 err;
595 	int			 s, i;
596 
597 	s = splnet();
598 
599 	if (sc->cdce_intr_no != -1 && sc->cdce_intr_pipe == NULL) {
600 		DPRINTFN(1, ("cdce_init: establish interrupt pipe\n"));
601 		err = usbd_open_pipe_intr(sc->cdce_ctl_iface, sc->cdce_intr_no,
602 		    USBD_SHORT_XFER_OK, &sc->cdce_intr_pipe, sc,
603 		    &sc->cdce_intr_buf, sc->cdce_intr_size, cdce_intr,
604 		    USBD_DEFAULT_INTERVAL);
605 		if (err) {
606 			printf("%s: open interrupt pipe failed: %s\n",
607 			    sc->cdce_dev.dv_xname, usbd_errstr(err));
608 			splx(s);
609 			return;
610 		}
611 	}
612 
613 	if (cdce_tx_list_init(sc) == ENOBUFS) {
614 		printf("%s: tx list init failed\n", sc->cdce_dev.dv_xname);
615 		splx(s);
616 		return;
617 	}
618 
619 	if (cdce_rx_list_init(sc) == ENOBUFS) {
620 		printf("%s: rx list init failed\n", sc->cdce_dev.dv_xname);
621 		splx(s);
622 		return;
623 	}
624 
625 	/* Maybe set multicast / broadcast here??? */
626 
627 	err = usbd_open_pipe(sc->cdce_data_iface, sc->cdce_bulkin_no,
628 	    USBD_EXCLUSIVE_USE, &sc->cdce_bulkin_pipe);
629 	if (err) {
630 		printf("%s: open rx pipe failed: %s\n", sc->cdce_dev.dv_xname,
631 		    usbd_errstr(err));
632 		splx(s);
633 		return;
634 	}
635 
636 	err = usbd_open_pipe(sc->cdce_data_iface, sc->cdce_bulkout_no,
637 	    USBD_EXCLUSIVE_USE, &sc->cdce_bulkout_pipe);
638 	if (err) {
639 		printf("%s: open tx pipe failed: %s\n", sc->cdce_dev.dv_xname,
640 		    usbd_errstr(err));
641 		splx(s);
642 		return;
643 	}
644 
645 	for (i = 0; i < CDCE_RX_LIST_CNT; i++) {
646 		c = &sc->cdce_cdata.cdce_rx_chain[i];
647 		usbd_setup_xfer(c->cdce_xfer, sc->cdce_bulkin_pipe, c,
648 		    c->cdce_buf, CDCE_BUFSZ, USBD_SHORT_XFER_OK | USBD_NO_COPY,
649 		    USBD_NO_TIMEOUT, cdce_rxeof);
650 		usbd_transfer(c->cdce_xfer);
651 	}
652 
653 	ifp->if_flags |= IFF_RUNNING;
654 	ifq_clr_oactive(&ifp->if_snd);
655 
656 	splx(s);
657 }
658 
659 int
660 cdce_newbuf(struct cdce_softc *sc, struct cdce_chain *c, struct mbuf *m)
661 {
662 	struct mbuf	*m_new = NULL;
663 
664 	if (m == NULL) {
665 		MGETHDR(m_new, M_DONTWAIT, MT_DATA);
666 		if (m_new == NULL) {
667 			printf("%s: no memory for rx list "
668 			    "-- packet dropped!\n", sc->cdce_dev.dv_xname);
669 			return (ENOBUFS);
670 		}
671 		MCLGET(m_new, M_DONTWAIT);
672 		if (!(m_new->m_flags & M_EXT)) {
673 			printf("%s: no memory for rx list "
674 			    "-- packet dropped!\n", sc->cdce_dev.dv_xname);
675 			m_freem(m_new);
676 			return (ENOBUFS);
677 		}
678 		m_new->m_len = m_new->m_pkthdr.len = MCLBYTES;
679 	} else {
680 		m_new = m;
681 		m_new->m_len = m_new->m_pkthdr.len = MCLBYTES;
682 		m_new->m_data = m_new->m_ext.ext_buf;
683 	}
684 
685 	m_adj(m_new, ETHER_ALIGN);
686 	c->cdce_mbuf = m_new;
687 	return (0);
688 }
689 
690 int
691 cdce_rx_list_init(struct cdce_softc *sc)
692 {
693 	struct cdce_cdata	*cd;
694 	struct cdce_chain	*c;
695 	int			 i;
696 
697 	cd = &sc->cdce_cdata;
698 	for (i = 0; i < CDCE_RX_LIST_CNT; i++) {
699 		c = &cd->cdce_rx_chain[i];
700 		c->cdce_sc = sc;
701 		c->cdce_idx = i;
702 		if (cdce_newbuf(sc, c, NULL) == ENOBUFS)
703 			return (ENOBUFS);
704 		if (c->cdce_xfer == NULL) {
705 			c->cdce_xfer = usbd_alloc_xfer(sc->cdce_udev);
706 			if (c->cdce_xfer == NULL)
707 				return (ENOBUFS);
708 			c->cdce_buf = usbd_alloc_buffer(c->cdce_xfer,
709 			    CDCE_BUFSZ);
710 			if (c->cdce_buf == NULL)
711 				return (ENOBUFS);
712 		}
713 	}
714 
715 	return (0);
716 }
717 
718 int
719 cdce_tx_list_init(struct cdce_softc *sc)
720 {
721 	struct cdce_cdata	*cd;
722 	struct cdce_chain	*c;
723 	int			 i;
724 
725 	cd = &sc->cdce_cdata;
726 	for (i = 0; i < CDCE_TX_LIST_CNT; i++) {
727 		c = &cd->cdce_tx_chain[i];
728 		c->cdce_sc = sc;
729 		c->cdce_idx = i;
730 		c->cdce_mbuf = NULL;
731 		if (c->cdce_xfer == NULL) {
732 			c->cdce_xfer = usbd_alloc_xfer(sc->cdce_udev);
733 			if (c->cdce_xfer == NULL)
734 				return (ENOBUFS);
735 			c->cdce_buf = usbd_alloc_buffer(c->cdce_xfer,
736 			    CDCE_BUFSZ);
737 			if (c->cdce_buf == NULL)
738 				return (ENOBUFS);
739 		}
740 	}
741 
742 	return (0);
743 }
744 
745 void
746 cdce_rxeof(struct usbd_xfer *xfer, void *priv, usbd_status status)
747 {
748 	struct cdce_chain	*c = priv;
749 	struct cdce_softc	*sc = c->cdce_sc;
750 	struct ifnet		*ifp = GET_IFP(sc);
751 	struct mbuf		*m;
752 	struct mbuf_list	 ml = MBUF_LIST_INITIALIZER();
753 	int			 total_len = 0;
754 	int			 s;
755 
756 	if (usbd_is_dying(sc->cdce_udev) || !(ifp->if_flags & IFF_RUNNING))
757 		return;
758 
759 	if (status != USBD_NORMAL_COMPLETION) {
760 		if (status == USBD_NOT_STARTED || status == USBD_CANCELLED)
761 			return;
762 		if (sc->cdce_rxeof_errors == 0)
763 			printf("%s: usb error on rx: %s\n",
764 			    sc->cdce_dev.dv_xname, usbd_errstr(status));
765 		if (status == USBD_STALLED)
766 			usbd_clear_endpoint_stall_async(sc->cdce_bulkin_pipe);
767 		DELAY(sc->cdce_rxeof_errors * 10000);
768 		if (sc->cdce_rxeof_errors++ > 10) {
769 			printf("%s: too many errors, disabling\n",
770 			    sc->cdce_dev.dv_xname);
771 			usbd_deactivate(sc->cdce_udev);
772 			return;
773 		}
774 		goto done;
775 	}
776 
777 	sc->cdce_rxeof_errors = 0;
778 
779 	usbd_get_xfer_status(xfer, NULL, NULL, &total_len, NULL);
780 	if (sc->cdce_flags & CDCE_CRC32)
781 		total_len -= 4;	/* Strip off added CRC */
782 	if (total_len <= 1)
783 		goto done;
784 
785 	m = c->cdce_mbuf;
786 	memcpy(mtod(m, char *), c->cdce_buf, total_len);
787 
788 	if (total_len < sizeof(struct ether_header)) {
789 		ifp->if_ierrors++;
790 		goto done;
791 	}
792 
793 	m->m_pkthdr.len = m->m_len = total_len;
794 	ml_enqueue(&ml, m);
795 
796 	if (cdce_newbuf(sc, c, NULL) == ENOBUFS) {
797 		ifp->if_ierrors++;
798 		goto done;
799 	}
800 
801 	s = splnet();
802 	if_input(ifp, &ml);
803 	splx(s);
804 
805 done:
806 	/* Setup new transfer. */
807 	usbd_setup_xfer(c->cdce_xfer, sc->cdce_bulkin_pipe, c, c->cdce_buf,
808 	    CDCE_BUFSZ, USBD_SHORT_XFER_OK | USBD_NO_COPY, USBD_NO_TIMEOUT,
809 	    cdce_rxeof);
810 	usbd_transfer(c->cdce_xfer);
811 }
812 
813 void
814 cdce_txeof(struct usbd_xfer *xfer, void *priv, usbd_status status)
815 {
816 	struct cdce_chain	*c = priv;
817 	struct cdce_softc	*sc = c->cdce_sc;
818 	struct ifnet		*ifp = GET_IFP(sc);
819 	usbd_status		 err;
820 	int			 s;
821 
822 	if (usbd_is_dying(sc->cdce_udev))
823 		return;
824 
825 	s = splnet();
826 
827 	ifp->if_timer = 0;
828 	ifq_clr_oactive(&ifp->if_snd);
829 
830 	if (status != USBD_NORMAL_COMPLETION) {
831 		if (status == USBD_NOT_STARTED || status == USBD_CANCELLED) {
832 			splx(s);
833 			return;
834 		}
835 		ifp->if_oerrors++;
836 		printf("%s: usb error on tx: %s\n", sc->cdce_dev.dv_xname,
837 		    usbd_errstr(status));
838 		if (status == USBD_STALLED)
839 			usbd_clear_endpoint_stall_async(sc->cdce_bulkout_pipe);
840 		splx(s);
841 		return;
842 	}
843 
844 	usbd_get_xfer_status(c->cdce_xfer, NULL, NULL, NULL, &err);
845 
846 	if (c->cdce_mbuf != NULL) {
847 		m_freem(c->cdce_mbuf);
848 		c->cdce_mbuf = NULL;
849 	}
850 
851 	if (err)
852 		ifp->if_oerrors++;
853 
854 	if (ifq_empty(&ifp->if_snd) == 0)
855 		cdce_start(ifp);
856 
857 	splx(s);
858 }
859 
860 void
861 cdce_intr(struct usbd_xfer *xfer, void *addr, usbd_status status)
862 {
863 	struct cdce_softc	*sc = addr;
864 	struct usb_cdc_notification *buf = &sc->cdce_intr_buf;
865 	struct usb_cdc_connection_speed	*speed;
866 	u_int32_t		 count;
867 
868 	if (status == USBD_CANCELLED)
869 		return;
870 
871 	if (status != USBD_NORMAL_COMPLETION) {
872 		DPRINTFN(2, ("cdce_intr: status=%d\n", status));
873 		if (status == USBD_STALLED)
874 			usbd_clear_endpoint_stall_async(sc->cdce_intr_pipe);
875 		return;
876 	}
877 
878 	usbd_get_xfer_status(xfer, NULL, NULL, &count, NULL);
879 
880 	if (buf->bmRequestType == UCDC_NOTIFICATION) {
881 		switch (buf->bNotification) {
882 		case UCDC_N_NETWORK_CONNECTION:
883 			DPRINTFN(1, ("cdce_intr: network %s\n",
884 			    UGETW(buf->wValue) ? "connected" : "disconnected"));
885 			break;
886 		case UCDC_N_CONNECTION_SPEED_CHANGE:
887 			speed = (struct usb_cdc_connection_speed *)&buf->data;
888 			DPRINTFN(1, ("cdce_intr: up=%d, down=%d\n",
889 			    UGETDW(speed->dwUSBitRate),
890 			    UGETDW(speed->dwDSBitRate)));
891 			break;
892 		default:
893 			DPRINTF(("cdce_intr: bNotification 0x%x\n",
894 			    buf->bNotification));
895 		}
896 	}
897 #ifdef CDCE_DEBUG
898 	else {
899 		printf("cdce_intr: bmRequestType=%d ", buf->bmRequestType);
900 		printf("wValue=%d wIndex=%d wLength=%d\n", UGETW(buf->wValue),
901 		    UGETW(buf->wIndex), UGETW(buf->wLength));
902 	}
903 #endif
904 }
905