xref: /openbsd-src/sys/dev/usb/if_cdce.c (revision e5de1fc6b3928d52c46c98b0c0e5fc0cbe0a9a7d)
1 /*	$OpenBSD: if_cdce.c,v 1.72 2016/10/12 21:51:11 fcambus 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  * http://www.usb.org/developers/devclass_docs/usbcdc11.pdf
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 <dev/usb/usb.h>
63 #include <dev/usb/usbdi.h>
64 #include <dev/usb/usbdi_util.h>
65 #include <dev/usb/usbdevs.h>
66 #include <dev/usb/usbcdc.h>
67 
68 #include <dev/usb/if_cdcereg.h>
69 
70 #ifdef CDCE_DEBUG
71 #define DPRINTFN(n, x)	do { if (cdcedebug > (n)) printf x; } while (0)
72 int cdcedebug = 0;
73 #else
74 #define DPRINTFN(n, x)
75 #endif
76 #define DPRINTF(x)	DPRINTFN(0, x)
77 
78 int	 cdce_tx_list_init(struct cdce_softc *);
79 int	 cdce_rx_list_init(struct cdce_softc *);
80 int	 cdce_newbuf(struct cdce_softc *, struct cdce_chain *,
81 		    struct mbuf *);
82 int	 cdce_encap(struct cdce_softc *, struct mbuf *, int);
83 void	 cdce_rxeof(struct usbd_xfer *, void *, usbd_status);
84 void	 cdce_txeof(struct usbd_xfer *, void *, usbd_status);
85 void	 cdce_start(struct ifnet *);
86 int	 cdce_ioctl(struct ifnet *, u_long, caddr_t);
87 void	 cdce_init(void *);
88 void	 cdce_watchdog(struct ifnet *);
89 void	 cdce_stop(struct cdce_softc *);
90 void	 cdce_intr(struct usbd_xfer *, void *, usbd_status);
91 static uint32_t	 cdce_crc32(const void *, size_t);
92 
93 const struct cdce_type cdce_devs[] = {
94     {{ USB_VENDOR_ACERLABS, USB_PRODUCT_ACERLABS_M5632 }, 0 },
95     {{ USB_VENDOR_PROLIFIC, USB_PRODUCT_PROLIFIC_PL2501 }, 0 },
96     {{ USB_VENDOR_SHARP, USB_PRODUCT_SHARP_SL5500 }, CDCE_CRC32 },
97     {{ USB_VENDOR_SHARP, USB_PRODUCT_SHARP_A300 }, CDCE_CRC32 },
98     {{ USB_VENDOR_SHARP, USB_PRODUCT_SHARP_SL5600 }, CDCE_CRC32 },
99     {{ USB_VENDOR_SHARP, USB_PRODUCT_SHARP_C700 }, CDCE_CRC32 },
100     {{ USB_VENDOR_SHARP, USB_PRODUCT_SHARP_C750 }, CDCE_CRC32 },
101     {{ USB_VENDOR_MOTOROLA2, USB_PRODUCT_MOTOROLA2_USBLAN }, CDCE_CRC32 },
102     {{ USB_VENDOR_MOTOROLA2, USB_PRODUCT_MOTOROLA2_USBLAN2 }, CDCE_CRC32 },
103     {{ USB_VENDOR_GMATE, USB_PRODUCT_GMATE_YP3X00 }, 0 },
104     {{ USB_VENDOR_NETCHIP, USB_PRODUCT_NETCHIP_ETHERNETGADGET }, 0 },
105     {{ USB_VENDOR_COMPAQ, USB_PRODUCT_COMPAQ_IPAQLINUX }, 0 },
106     {{ USB_VENDOR_AMBIT, USB_PRODUCT_AMBIT_NTL_250 }, CDCE_SWAPUNION },
107 };
108 #define cdce_lookup(v, p) \
109     ((const struct cdce_type *)usb_lookup(cdce_devs, v, p))
110 
111 int cdce_match(struct device *, void *, void *);
112 void cdce_attach(struct device *, struct device *, void *);
113 int cdce_detach(struct device *, int);
114 
115 struct cfdriver cdce_cd = {
116 	NULL, "cdce", DV_IFNET
117 };
118 
119 const struct cfattach cdce_ca = {
120 	sizeof(struct cdce_softc), cdce_match, cdce_attach, cdce_detach
121 };
122 
123 int
124 cdce_match(struct device *parent, void *match, void *aux)
125 {
126 	struct usb_attach_arg *uaa = aux;
127 	usb_interface_descriptor_t *id;
128 
129 	if (uaa->iface == NULL)
130 		return (UMATCH_NONE);
131 
132 	id = usbd_get_interface_descriptor(uaa->iface);
133 	if (id == NULL)
134 		return (UMATCH_NONE);
135 
136 	if (cdce_lookup(uaa->vendor, uaa->product) != NULL)
137 		return (UMATCH_VENDOR_PRODUCT);
138 
139 	if (id->bInterfaceClass == UICLASS_CDC &&
140 	    (id->bInterfaceSubClass ==
141 	    UISUBCLASS_ETHERNET_NETWORKING_CONTROL_MODEL ||
142 	    id->bInterfaceSubClass == UISUBCLASS_MOBILE_DIRECT_LINE_MODEL))
143 		return (UMATCH_IFACECLASS_GENERIC);
144 
145 	return (UMATCH_NONE);
146 }
147 
148 void
149 cdce_attach(struct device *parent, struct device *self, void *aux)
150 {
151 	struct cdce_softc		*sc = (struct cdce_softc *)self;
152 	struct usb_attach_arg		*uaa = aux;
153 	int				 s;
154 	struct ifnet			*ifp = GET_IFP(sc);
155 	struct usbd_device		*dev = uaa->device;
156 	const struct cdce_type		*t;
157 	usb_interface_descriptor_t	*id;
158 	usb_endpoint_descriptor_t	*ed;
159 	struct usb_cdc_union_descriptor	*ud;
160 	struct usb_cdc_ethernet_descriptor *ethd;
161 	usb_config_descriptor_t		*cd;
162 	const usb_descriptor_t		*desc;
163 	struct usbd_desc_iter		 iter;
164 	usb_string_descriptor_t		 eaddr_str;
165 	int				 i, j, numalts, len;
166 	int				 ctl_ifcno = -1;
167 	int				 data_ifcno = -1;
168 
169 	sc->cdce_udev = uaa->device;
170 	sc->cdce_ctl_iface = uaa->iface;
171 	id = usbd_get_interface_descriptor(sc->cdce_ctl_iface);
172 	ctl_ifcno = id->bInterfaceNumber;
173 
174 	t = cdce_lookup(uaa->vendor, uaa->product);
175 	if (t)
176 		sc->cdce_flags = t->cdce_flags;
177 
178 	/* Get the data interface no. and capabilities */
179 	ethd = NULL;
180 	usbd_desc_iter_init(dev, &iter);
181 	desc = usbd_desc_iter_next(&iter);
182 	while (desc) {
183 		if (desc->bDescriptorType != UDESC_CS_INTERFACE) {
184 			desc = usbd_desc_iter_next(&iter);
185 			continue;
186 		}
187 		switch(desc->bDescriptorSubtype) {
188 		case UDESCSUB_CDC_UNION:
189 			ud = (struct usb_cdc_union_descriptor *)desc;
190 			if ((sc->cdce_flags & CDCE_SWAPUNION) == 0 &&
191 			    ud->bMasterInterface == ctl_ifcno)
192 				data_ifcno = ud->bSlaveInterface[0];
193 			if ((sc->cdce_flags & CDCE_SWAPUNION) &&
194 			    ud->bSlaveInterface[0] == ctl_ifcno)
195 				data_ifcno = ud->bMasterInterface;
196 			break;
197 		case UDESCSUB_CDC_ENF:
198 			if (ethd) {
199 				printf("%s: ", sc->cdce_dev.dv_xname);
200 				printf("extra ethernet descriptor\n");
201 				return;
202 			}
203 			ethd = (struct usb_cdc_ethernet_descriptor *)desc;
204 			break;
205 		}
206 		desc = usbd_desc_iter_next(&iter);
207 	}
208 
209 	if (data_ifcno == -1) {
210 		DPRINTF(("cdce_attach: no union interface\n"));
211 		sc->cdce_data_iface = sc->cdce_ctl_iface;
212 	} else {
213 		DPRINTF(("cdce_attach: union interface: ctl=%d, data=%d\n",
214 		    ctl_ifcno, data_ifcno));
215 		for (i = 0; i < uaa->nifaces; i++) {
216 			if (usbd_iface_claimed(sc->cdce_udev, i))
217 				continue;
218 			id = usbd_get_interface_descriptor(uaa->ifaces[i]);
219 			if (id != NULL && id->bInterfaceNumber == data_ifcno) {
220 				sc->cdce_data_iface = uaa->ifaces[i];
221 				usbd_claim_iface(sc->cdce_udev, i);
222 			}
223 		}
224 	}
225 
226 	if (sc->cdce_data_iface == NULL) {
227 		printf("%s: no data interface\n", sc->cdce_dev.dv_xname);
228 		return;
229 	}
230 
231 	id = usbd_get_interface_descriptor(sc->cdce_ctl_iface);
232 	sc->cdce_intr_no = -1;
233 	for (i = 0; i < id->bNumEndpoints && sc->cdce_intr_no == -1; i++) {
234 		ed = usbd_interface2endpoint_descriptor(sc->cdce_ctl_iface, i);
235 		if (!ed) {
236 			printf("%s: no descriptor for interrupt endpoint %d\n",
237 			    sc->cdce_dev.dv_xname, i);
238 			return;
239 		}
240 		if (UE_GET_DIR(ed->bEndpointAddress) == UE_DIR_IN &&
241 		    UE_GET_XFERTYPE(ed->bmAttributes) == UE_INTERRUPT) {
242 			sc->cdce_intr_no = ed->bEndpointAddress;
243 			sc->cdce_intr_size = sizeof(sc->cdce_intr_buf);
244 		}
245 	}
246 
247 	id = usbd_get_interface_descriptor(sc->cdce_data_iface);
248 	cd = usbd_get_config_descriptor(sc->cdce_udev);
249 	numalts = usbd_get_no_alts(cd, id->bInterfaceNumber);
250 
251 	for (j = 0; j < numalts; j++) {
252 		if (usbd_set_interface(sc->cdce_data_iface, j)) {
253 			printf("%s: interface alternate setting %d failed\n",
254 			    sc->cdce_dev.dv_xname, j);
255 			return;
256 		}
257 		/* Find endpoints. */
258 		id = usbd_get_interface_descriptor(sc->cdce_data_iface);
259 		sc->cdce_bulkin_no = sc->cdce_bulkout_no = -1;
260 		for (i = 0; i < id->bNumEndpoints; i++) {
261 			ed = usbd_interface2endpoint_descriptor(
262 			    sc->cdce_data_iface, i);
263 			if (!ed) {
264 				printf("%s: no descriptor for bulk endpoint "
265 				    "%d\n", sc->cdce_dev.dv_xname, i);
266 				return;
267 			}
268 			if (UE_GET_DIR(ed->bEndpointAddress) == UE_DIR_IN &&
269 			    UE_GET_XFERTYPE(ed->bmAttributes) == UE_BULK) {
270 				sc->cdce_bulkin_no = ed->bEndpointAddress;
271 			} else if (
272 			    UE_GET_DIR(ed->bEndpointAddress) == UE_DIR_OUT &&
273 			    UE_GET_XFERTYPE(ed->bmAttributes) == UE_BULK) {
274 				sc->cdce_bulkout_no = ed->bEndpointAddress;
275 			}
276 #ifdef CDCE_DEBUG
277 			else if (
278 			    UE_GET_DIR(ed->bEndpointAddress) != UE_DIR_IN &&
279 			    UE_GET_XFERTYPE(ed->bmAttributes) != UE_INTERRUPT) {
280 				printf("%s: unexpected endpoint, ep=%x attr=%x"
281 				    "\n", sc->cdce_dev.dv_xname,
282 				    ed->bEndpointAddress, ed->bmAttributes);
283 			}
284 #endif
285 		}
286 		if ((sc->cdce_bulkin_no != -1) && (sc->cdce_bulkout_no != -1)) {
287 			DPRINTF(("cdce_attach: intr=0x%x, in=0x%x, out=0x%x\n",
288 			    sc->cdce_intr_no, sc->cdce_bulkin_no,
289 			    sc->cdce_bulkout_no));
290 			goto found;
291 		}
292 	}
293 
294 	if (sc->cdce_bulkin_no == -1) {
295 		printf("%s: could not find data bulk in\n",
296 		    sc->cdce_dev.dv_xname);
297 		return;
298 	}
299 	if (sc->cdce_bulkout_no == -1 ) {
300 		printf("%s: could not find data bulk out\n",
301 		    sc->cdce_dev.dv_xname);
302 		return;
303 	}
304 
305 found:
306 	s = splnet();
307 
308 	if (!ethd || usbd_get_string_desc(sc->cdce_udev, ethd->iMacAddress, 0,
309 	    &eaddr_str, &len)) {
310 		ether_fakeaddr(ifp);
311 	} else {
312 		for (i = 0; i < ETHER_ADDR_LEN * 2; i++) {
313 			int c = UGETW(eaddr_str.bString[i]);
314 
315 			if ('0' <= c && c <= '9')
316 				c -= '0';
317 			else if ('A' <= c && c <= 'F')
318 				c -= 'A' - 10;
319 			else if ('a' <= c && c <= 'f')
320 				c -= 'a' - 10;
321 			c &= 0xf;
322 			if (i % 2 == 0)
323 				c <<= 4;
324 			sc->cdce_arpcom.ac_enaddr[i / 2] |= c;
325 		}
326 	}
327 
328 	printf("%s: address %s\n", sc->cdce_dev.dv_xname,
329 	    ether_sprintf(sc->cdce_arpcom.ac_enaddr));
330 
331 	ifp->if_softc = sc;
332 	ifp->if_flags = IFF_BROADCAST | IFF_SIMPLEX | IFF_MULTICAST;
333 	ifp->if_ioctl = cdce_ioctl;
334 	ifp->if_start = cdce_start;
335 	ifp->if_watchdog = cdce_watchdog;
336 	strlcpy(ifp->if_xname, sc->cdce_dev.dv_xname, IFNAMSIZ);
337 
338 	if_attach(ifp);
339 	ether_ifattach(ifp);
340 
341 	sc->cdce_attached = 1;
342 	splx(s);
343 }
344 
345 int
346 cdce_detach(struct device *self, int flags)
347 {
348 	struct cdce_softc	*sc = (struct cdce_softc *)self;
349 	struct ifnet		*ifp = GET_IFP(sc);
350 	int			 s;
351 
352 	if (!sc->cdce_attached)
353 		return (0);
354 
355 	s = splusb();
356 
357 	if (ifp->if_flags & IFF_RUNNING)
358 		cdce_stop(sc);
359 
360 	if (ifp->if_softc != NULL) {
361 		ether_ifdetach(ifp);
362 		if_detach(ifp);
363 	}
364 
365 	sc->cdce_attached = 0;
366 	splx(s);
367 
368 	return (0);
369 }
370 
371 void
372 cdce_start(struct ifnet *ifp)
373 {
374 	struct cdce_softc	*sc = ifp->if_softc;
375 	struct mbuf		*m_head = NULL;
376 
377 	if (usbd_is_dying(sc->cdce_udev) || ifq_is_oactive(&ifp->if_snd))
378 		return;
379 
380 	m_head = ifq_deq_begin(&ifp->if_snd);
381 	if (m_head == NULL)
382 		return;
383 
384 	if (cdce_encap(sc, m_head, 0)) {
385 		ifq_deq_rollback(&ifp->if_snd, m_head);
386 		ifq_set_oactive(&ifp->if_snd);
387 		return;
388 	}
389 
390 	ifq_deq_commit(&ifp->if_snd, m_head);
391 
392 #if NBPFILTER > 0
393 	if (ifp->if_bpf)
394 		bpf_mtap(ifp->if_bpf, m_head, BPF_DIRECTION_OUT);
395 #endif
396 
397 	ifq_set_oactive(&ifp->if_snd);
398 
399 	ifp->if_timer = 6;
400 }
401 
402 int
403 cdce_encap(struct cdce_softc *sc, struct mbuf *m, int idx)
404 {
405 	struct cdce_chain	*c;
406 	usbd_status		 err;
407 	int			 extra = 0;
408 
409 	c = &sc->cdce_cdata.cdce_tx_chain[idx];
410 
411 	m_copydata(m, 0, m->m_pkthdr.len, c->cdce_buf);
412 	if (sc->cdce_flags & CDCE_CRC32) {
413 		/* Some devices want a 32-bit CRC appended to every frame */
414 		u_int32_t crc;
415 
416 		crc = cdce_crc32(c->cdce_buf, m->m_pkthdr.len);
417 		bcopy(&crc, c->cdce_buf + m->m_pkthdr.len, 4);
418 		extra = 4;
419 	}
420 	c->cdce_mbuf = m;
421 
422 	usbd_setup_xfer(c->cdce_xfer, sc->cdce_bulkout_pipe, c, c->cdce_buf,
423 	    m->m_pkthdr.len + extra, USBD_FORCE_SHORT_XFER | USBD_NO_COPY,
424 	    10000, cdce_txeof);
425 	err = usbd_transfer(c->cdce_xfer);
426 	if (err != USBD_IN_PROGRESS) {
427 		cdce_stop(sc);
428 		return (EIO);
429 	}
430 
431 	sc->cdce_cdata.cdce_tx_cnt++;
432 
433 	return (0);
434 }
435 
436 void
437 cdce_stop(struct cdce_softc *sc)
438 {
439 	usbd_status	 err;
440 	struct ifnet	*ifp = GET_IFP(sc);
441 	int		 i;
442 
443 	ifp->if_timer = 0;
444 	ifp->if_flags &= ~IFF_RUNNING;
445 	ifq_clr_oactive(&ifp->if_snd);
446 
447 	if (sc->cdce_bulkin_pipe != NULL) {
448 		usbd_abort_pipe(sc->cdce_bulkin_pipe);
449 		err = usbd_close_pipe(sc->cdce_bulkin_pipe);
450 		if (err)
451 			printf("%s: close rx pipe failed: %s\n",
452 			    sc->cdce_dev.dv_xname, usbd_errstr(err));
453 		sc->cdce_bulkin_pipe = NULL;
454 	}
455 
456 	if (sc->cdce_bulkout_pipe != NULL) {
457 		usbd_abort_pipe(sc->cdce_bulkout_pipe);
458 		err = usbd_close_pipe(sc->cdce_bulkout_pipe);
459 		if (err)
460 			printf("%s: close tx pipe failed: %s\n",
461 			    sc->cdce_dev.dv_xname, usbd_errstr(err));
462 		sc->cdce_bulkout_pipe = NULL;
463 	}
464 
465 	if (sc->cdce_intr_pipe != NULL) {
466 		usbd_abort_pipe(sc->cdce_intr_pipe);
467 		err = usbd_close_pipe(sc->cdce_intr_pipe);
468 		if (err)
469 			printf("%s: close interrupt pipe failed: %s\n",
470 			    sc->cdce_dev.dv_xname, usbd_errstr(err));
471 		sc->cdce_intr_pipe = NULL;
472 	}
473 
474 	for (i = 0; i < CDCE_RX_LIST_CNT; i++) {
475 		if (sc->cdce_cdata.cdce_rx_chain[i].cdce_mbuf != NULL) {
476 			m_freem(sc->cdce_cdata.cdce_rx_chain[i].cdce_mbuf);
477 			sc->cdce_cdata.cdce_rx_chain[i].cdce_mbuf = NULL;
478 		}
479 		if (sc->cdce_cdata.cdce_rx_chain[i].cdce_xfer != NULL) {
480 			usbd_free_xfer(sc->cdce_cdata.cdce_rx_chain[i].cdce_xfer);
481 			sc->cdce_cdata.cdce_rx_chain[i].cdce_xfer = NULL;
482 		}
483 	}
484 
485 	for (i = 0; i < CDCE_TX_LIST_CNT; i++) {
486 		if (sc->cdce_cdata.cdce_tx_chain[i].cdce_mbuf != NULL) {
487 			m_freem(sc->cdce_cdata.cdce_tx_chain[i].cdce_mbuf);
488 			sc->cdce_cdata.cdce_tx_chain[i].cdce_mbuf = NULL;
489 		}
490 		if (sc->cdce_cdata.cdce_tx_chain[i].cdce_xfer != NULL) {
491 			usbd_free_xfer(
492 			    sc->cdce_cdata.cdce_tx_chain[i].cdce_xfer);
493 			sc->cdce_cdata.cdce_tx_chain[i].cdce_xfer = NULL;
494 		}
495 	}
496 }
497 
498 int
499 cdce_ioctl(struct ifnet *ifp, u_long command, caddr_t data)
500 {
501 	struct cdce_softc	*sc = ifp->if_softc;
502 	int			 s, error = 0;
503 
504 	if (usbd_is_dying(sc->cdce_udev))
505 		return (EIO);
506 
507 	s = splnet();
508 
509 	switch(command) {
510 	case SIOCSIFADDR:
511 		ifp->if_flags |= IFF_UP;
512 		if (!(ifp->if_flags & IFF_RUNNING))
513 			cdce_init(sc);
514 		break;
515 
516 	case SIOCSIFFLAGS:
517 		if (ifp->if_flags & IFF_UP) {
518 			if (ifp->if_flags & IFF_RUNNING)
519 				error = ENETRESET;
520 			else
521 				cdce_init(sc);
522 		} else {
523 			if (ifp->if_flags & IFF_RUNNING)
524 				cdce_stop(sc);
525 		}
526 		break;
527 
528 	default:
529 		error = ether_ioctl(ifp, &sc->cdce_arpcom, command, data);
530 		break;
531 	}
532 
533 	if (error == ENETRESET)
534 		error = 0;
535 
536 	splx(s);
537 	return (error);
538 }
539 
540 void
541 cdce_watchdog(struct ifnet *ifp)
542 {
543 	struct cdce_softc	*sc = ifp->if_softc;
544 
545 	if (usbd_is_dying(sc->cdce_udev))
546 		return;
547 
548 	ifp->if_oerrors++;
549 	printf("%s: watchdog timeout\n", sc->cdce_dev.dv_xname);
550 }
551 
552 void
553 cdce_init(void *xsc)
554 {
555 	struct cdce_softc	*sc = xsc;
556 	struct ifnet		*ifp = GET_IFP(sc);
557 	struct cdce_chain	*c;
558 	usbd_status		 err;
559 	int			 s, i;
560 
561 	s = splnet();
562 
563 	if (sc->cdce_intr_no != -1 && sc->cdce_intr_pipe == NULL) {
564 		DPRINTFN(1, ("cdce_init: establish interrupt pipe\n"));
565 		err = usbd_open_pipe_intr(sc->cdce_ctl_iface, sc->cdce_intr_no,
566 		    USBD_SHORT_XFER_OK, &sc->cdce_intr_pipe, sc,
567 		    &sc->cdce_intr_buf, sc->cdce_intr_size, cdce_intr,
568 		    USBD_DEFAULT_INTERVAL);
569 		if (err) {
570 			printf("%s: open interrupt pipe failed: %s\n",
571 			    sc->cdce_dev.dv_xname, usbd_errstr(err));
572 			splx(s);
573 			return;
574 		}
575 	}
576 
577 	if (cdce_tx_list_init(sc) == ENOBUFS) {
578 		printf("%s: tx list init failed\n", sc->cdce_dev.dv_xname);
579 		splx(s);
580 		return;
581 	}
582 
583 	if (cdce_rx_list_init(sc) == ENOBUFS) {
584 		printf("%s: rx list init failed\n", sc->cdce_dev.dv_xname);
585 		splx(s);
586 		return;
587 	}
588 
589 	/* Maybe set multicast / broadcast here??? */
590 
591 	err = usbd_open_pipe(sc->cdce_data_iface, sc->cdce_bulkin_no,
592 	    USBD_EXCLUSIVE_USE, &sc->cdce_bulkin_pipe);
593 	if (err) {
594 		printf("%s: open rx pipe failed: %s\n", sc->cdce_dev.dv_xname,
595 		    usbd_errstr(err));
596 		splx(s);
597 		return;
598 	}
599 
600 	err = usbd_open_pipe(sc->cdce_data_iface, sc->cdce_bulkout_no,
601 	    USBD_EXCLUSIVE_USE, &sc->cdce_bulkout_pipe);
602 	if (err) {
603 		printf("%s: open tx pipe failed: %s\n", sc->cdce_dev.dv_xname,
604 		    usbd_errstr(err));
605 		splx(s);
606 		return;
607 	}
608 
609 	for (i = 0; i < CDCE_RX_LIST_CNT; i++) {
610 		c = &sc->cdce_cdata.cdce_rx_chain[i];
611 		usbd_setup_xfer(c->cdce_xfer, sc->cdce_bulkin_pipe, c,
612 		    c->cdce_buf, CDCE_BUFSZ, USBD_SHORT_XFER_OK | USBD_NO_COPY,
613 		    USBD_NO_TIMEOUT, cdce_rxeof);
614 		usbd_transfer(c->cdce_xfer);
615 	}
616 
617 	ifp->if_flags |= IFF_RUNNING;
618 	ifq_clr_oactive(&ifp->if_snd);
619 
620 	splx(s);
621 }
622 
623 int
624 cdce_newbuf(struct cdce_softc *sc, struct cdce_chain *c, struct mbuf *m)
625 {
626 	struct mbuf	*m_new = NULL;
627 
628 	if (m == NULL) {
629 		MGETHDR(m_new, M_DONTWAIT, MT_DATA);
630 		if (m_new == NULL) {
631 			printf("%s: no memory for rx list "
632 			    "-- packet dropped!\n", sc->cdce_dev.dv_xname);
633 			return (ENOBUFS);
634 		}
635 		MCLGET(m_new, M_DONTWAIT);
636 		if (!(m_new->m_flags & M_EXT)) {
637 			printf("%s: no memory for rx list "
638 			    "-- packet dropped!\n", sc->cdce_dev.dv_xname);
639 			m_freem(m_new);
640 			return (ENOBUFS);
641 		}
642 		m_new->m_len = m_new->m_pkthdr.len = MCLBYTES;
643 	} else {
644 		m_new = m;
645 		m_new->m_len = m_new->m_pkthdr.len = MCLBYTES;
646 		m_new->m_data = m_new->m_ext.ext_buf;
647 	}
648 
649 	m_adj(m_new, ETHER_ALIGN);
650 	c->cdce_mbuf = m_new;
651 	return (0);
652 }
653 
654 int
655 cdce_rx_list_init(struct cdce_softc *sc)
656 {
657 	struct cdce_cdata	*cd;
658 	struct cdce_chain	*c;
659 	int			 i;
660 
661 	cd = &sc->cdce_cdata;
662 	for (i = 0; i < CDCE_RX_LIST_CNT; i++) {
663 		c = &cd->cdce_rx_chain[i];
664 		c->cdce_sc = sc;
665 		c->cdce_idx = i;
666 		if (cdce_newbuf(sc, c, NULL) == ENOBUFS)
667 			return (ENOBUFS);
668 		if (c->cdce_xfer == NULL) {
669 			c->cdce_xfer = usbd_alloc_xfer(sc->cdce_udev);
670 			if (c->cdce_xfer == NULL)
671 				return (ENOBUFS);
672 			c->cdce_buf = usbd_alloc_buffer(c->cdce_xfer,
673 			    CDCE_BUFSZ);
674 			if (c->cdce_buf == NULL)
675 				return (ENOBUFS);
676 		}
677 	}
678 
679 	return (0);
680 }
681 
682 int
683 cdce_tx_list_init(struct cdce_softc *sc)
684 {
685 	struct cdce_cdata	*cd;
686 	struct cdce_chain	*c;
687 	int			 i;
688 
689 	cd = &sc->cdce_cdata;
690 	for (i = 0; i < CDCE_TX_LIST_CNT; i++) {
691 		c = &cd->cdce_tx_chain[i];
692 		c->cdce_sc = sc;
693 		c->cdce_idx = i;
694 		c->cdce_mbuf = NULL;
695 		if (c->cdce_xfer == NULL) {
696 			c->cdce_xfer = usbd_alloc_xfer(sc->cdce_udev);
697 			if (c->cdce_xfer == NULL)
698 				return (ENOBUFS);
699 			c->cdce_buf = usbd_alloc_buffer(c->cdce_xfer,
700 			    CDCE_BUFSZ);
701 			if (c->cdce_buf == NULL)
702 				return (ENOBUFS);
703 		}
704 	}
705 
706 	return (0);
707 }
708 
709 void
710 cdce_rxeof(struct usbd_xfer *xfer, void *priv, usbd_status status)
711 {
712 	struct cdce_chain	*c = priv;
713 	struct cdce_softc	*sc = c->cdce_sc;
714 	struct ifnet		*ifp = GET_IFP(sc);
715 	struct mbuf		*m;
716 	struct mbuf_list	 ml = MBUF_LIST_INITIALIZER();
717 	int			 total_len = 0;
718 	int			 s;
719 
720 	if (usbd_is_dying(sc->cdce_udev) || !(ifp->if_flags & IFF_RUNNING))
721 		return;
722 
723 	if (status != USBD_NORMAL_COMPLETION) {
724 		if (status == USBD_NOT_STARTED || status == USBD_CANCELLED)
725 			return;
726 		if (sc->cdce_rxeof_errors == 0)
727 			printf("%s: usb error on rx: %s\n",
728 			    sc->cdce_dev.dv_xname, usbd_errstr(status));
729 		if (status == USBD_STALLED)
730 			usbd_clear_endpoint_stall_async(sc->cdce_bulkin_pipe);
731 		DELAY(sc->cdce_rxeof_errors * 10000);
732 		if (sc->cdce_rxeof_errors++ > 10) {
733 			printf("%s: too many errors, disabling\n",
734 			    sc->cdce_dev.dv_xname);
735 			usbd_deactivate(sc->cdce_udev);
736 			return;
737 		}
738 		goto done;
739 	}
740 
741 	sc->cdce_rxeof_errors = 0;
742 
743 	usbd_get_xfer_status(xfer, NULL, NULL, &total_len, NULL);
744 	if (sc->cdce_flags & CDCE_CRC32)
745 		total_len -= 4;	/* Strip off added CRC */
746 	if (total_len <= 1)
747 		goto done;
748 
749 	m = c->cdce_mbuf;
750 	memcpy(mtod(m, char *), c->cdce_buf, total_len);
751 
752 	if (total_len < sizeof(struct ether_header)) {
753 		ifp->if_ierrors++;
754 		goto done;
755 	}
756 
757 	m->m_pkthdr.len = m->m_len = total_len;
758 	ml_enqueue(&ml, m);
759 
760 	if (cdce_newbuf(sc, c, NULL) == ENOBUFS) {
761 		ifp->if_ierrors++;
762 		goto done;
763 	}
764 
765 	s = splnet();
766 	if_input(ifp, &ml);
767 	splx(s);
768 
769 done:
770 	/* Setup new transfer. */
771 	usbd_setup_xfer(c->cdce_xfer, sc->cdce_bulkin_pipe, c, c->cdce_buf,
772 	    CDCE_BUFSZ, USBD_SHORT_XFER_OK | USBD_NO_COPY, USBD_NO_TIMEOUT,
773 	    cdce_rxeof);
774 	usbd_transfer(c->cdce_xfer);
775 }
776 
777 void
778 cdce_txeof(struct usbd_xfer *xfer, void *priv, usbd_status status)
779 {
780 	struct cdce_chain	*c = priv;
781 	struct cdce_softc	*sc = c->cdce_sc;
782 	struct ifnet		*ifp = GET_IFP(sc);
783 	usbd_status		 err;
784 	int			 s;
785 
786 	if (usbd_is_dying(sc->cdce_udev))
787 		return;
788 
789 	s = splnet();
790 
791 	ifp->if_timer = 0;
792 	ifq_clr_oactive(&ifp->if_snd);
793 
794 	if (status != USBD_NORMAL_COMPLETION) {
795 		if (status == USBD_NOT_STARTED || status == USBD_CANCELLED) {
796 			splx(s);
797 			return;
798 		}
799 		ifp->if_oerrors++;
800 		printf("%s: usb error on tx: %s\n", sc->cdce_dev.dv_xname,
801 		    usbd_errstr(status));
802 		if (status == USBD_STALLED)
803 			usbd_clear_endpoint_stall_async(sc->cdce_bulkout_pipe);
804 		splx(s);
805 		return;
806 	}
807 
808 	usbd_get_xfer_status(c->cdce_xfer, NULL, NULL, NULL, &err);
809 
810 	if (c->cdce_mbuf != NULL) {
811 		m_freem(c->cdce_mbuf);
812 		c->cdce_mbuf = NULL;
813 	}
814 
815 	if (err)
816 		ifp->if_oerrors++;
817 	else
818 		ifp->if_opackets++;
819 
820 	if (IFQ_IS_EMPTY(&ifp->if_snd) == 0)
821 		cdce_start(ifp);
822 
823 	splx(s);
824 }
825 
826 void
827 cdce_intr(struct usbd_xfer *xfer, void *addr, usbd_status status)
828 {
829 	struct cdce_softc	*sc = addr;
830 	struct usb_cdc_notification *buf = &sc->cdce_intr_buf;
831 	struct usb_cdc_connection_speed	*speed;
832 	u_int32_t		 count;
833 
834 	if (status == USBD_CANCELLED)
835 		return;
836 
837 	if (status != USBD_NORMAL_COMPLETION) {
838 		DPRINTFN(2, ("cdce_intr: status=%d\n", status));
839 		if (status == USBD_STALLED)
840 			usbd_clear_endpoint_stall_async(sc->cdce_intr_pipe);
841 		return;
842 	}
843 
844 	usbd_get_xfer_status(xfer, NULL, NULL, &count, NULL);
845 
846 	if (buf->bmRequestType == UCDC_NOTIFICATION) {
847 		switch (buf->bNotification) {
848 		case UCDC_N_NETWORK_CONNECTION:
849 			DPRINTFN(1, ("cdce_intr: network %s\n",
850 			    UGETW(buf->wValue) ? "connected" : "disconnected"));
851 			break;
852 		case UCDC_N_CONNECTION_SPEED_CHANGE:
853 			speed = (struct usb_cdc_connection_speed *)&buf->data;
854 			DPRINTFN(1, ("cdce_intr: up=%d, down=%d\n",
855 			    UGETDW(speed->dwUSBitRate),
856 			    UGETDW(speed->dwDSBitRate)));
857 			break;
858 		default:
859 			DPRINTF(("cdce_intr: bNotification 0x%x\n",
860 			    buf->bNotification));
861 		}
862 	}
863 #ifdef CDCE_DEBUG
864 	else {
865 		printf("cdce_intr: bmRequestType=%d ", buf->bmRequestType);
866 		printf("wValue=%d wIndex=%d wLength=%d\n", UGETW(buf->wValue),
867 		    UGETW(buf->wIndex), UGETW(buf->wLength));
868 	}
869 #endif
870 }
871 
872 
873 /*  COPYRIGHT (C) 1986 Gary S. Brown.  You may use this program, or
874  *  code or tables extracted from it, as desired without restriction.
875  */
876 
877 static uint32_t cdce_crc32_tab[] = {
878 	0x00000000, 0x77073096, 0xee0e612c, 0x990951ba, 0x076dc419, 0x706af48f,
879 	0xe963a535, 0x9e6495a3,	0x0edb8832, 0x79dcb8a4, 0xe0d5e91e, 0x97d2d988,
880 	0x09b64c2b, 0x7eb17cbd, 0xe7b82d07, 0x90bf1d91, 0x1db71064, 0x6ab020f2,
881 	0xf3b97148, 0x84be41de,	0x1adad47d, 0x6ddde4eb, 0xf4d4b551, 0x83d385c7,
882 	0x136c9856, 0x646ba8c0, 0xfd62f97a, 0x8a65c9ec,	0x14015c4f, 0x63066cd9,
883 	0xfa0f3d63, 0x8d080df5,	0x3b6e20c8, 0x4c69105e, 0xd56041e4, 0xa2677172,
884 	0x3c03e4d1, 0x4b04d447, 0xd20d85fd, 0xa50ab56b,	0x35b5a8fa, 0x42b2986c,
885 	0xdbbbc9d6, 0xacbcf940,	0x32d86ce3, 0x45df5c75, 0xdcd60dcf, 0xabd13d59,
886 	0x26d930ac, 0x51de003a, 0xc8d75180, 0xbfd06116, 0x21b4f4b5, 0x56b3c423,
887 	0xcfba9599, 0xb8bda50f, 0x2802b89e, 0x5f058808, 0xc60cd9b2, 0xb10be924,
888 	0x2f6f7c87, 0x58684c11, 0xc1611dab, 0xb6662d3d,	0x76dc4190, 0x01db7106,
889 	0x98d220bc, 0xefd5102a, 0x71b18589, 0x06b6b51f, 0x9fbfe4a5, 0xe8b8d433,
890 	0x7807c9a2, 0x0f00f934, 0x9609a88e, 0xe10e9818, 0x7f6a0dbb, 0x086d3d2d,
891 	0x91646c97, 0xe6635c01, 0x6b6b51f4, 0x1c6c6162, 0x856530d8, 0xf262004e,
892 	0x6c0695ed, 0x1b01a57b, 0x8208f4c1, 0xf50fc457, 0x65b0d9c6, 0x12b7e950,
893 	0x8bbeb8ea, 0xfcb9887c, 0x62dd1ddf, 0x15da2d49, 0x8cd37cf3, 0xfbd44c65,
894 	0x4db26158, 0x3ab551ce, 0xa3bc0074, 0xd4bb30e2, 0x4adfa541, 0x3dd895d7,
895 	0xa4d1c46d, 0xd3d6f4fb, 0x4369e96a, 0x346ed9fc, 0xad678846, 0xda60b8d0,
896 	0x44042d73, 0x33031de5, 0xaa0a4c5f, 0xdd0d7cc9, 0x5005713c, 0x270241aa,
897 	0xbe0b1010, 0xc90c2086, 0x5768b525, 0x206f85b3, 0xb966d409, 0xce61e49f,
898 	0x5edef90e, 0x29d9c998, 0xb0d09822, 0xc7d7a8b4, 0x59b33d17, 0x2eb40d81,
899 	0xb7bd5c3b, 0xc0ba6cad, 0xedb88320, 0x9abfb3b6, 0x03b6e20c, 0x74b1d29a,
900 	0xead54739, 0x9dd277af, 0x04db2615, 0x73dc1683, 0xe3630b12, 0x94643b84,
901 	0x0d6d6a3e, 0x7a6a5aa8, 0xe40ecf0b, 0x9309ff9d, 0x0a00ae27, 0x7d079eb1,
902 	0xf00f9344, 0x8708a3d2, 0x1e01f268, 0x6906c2fe, 0xf762575d, 0x806567cb,
903 	0x196c3671, 0x6e6b06e7, 0xfed41b76, 0x89d32be0, 0x10da7a5a, 0x67dd4acc,
904 	0xf9b9df6f, 0x8ebeeff9, 0x17b7be43, 0x60b08ed5, 0xd6d6a3e8, 0xa1d1937e,
905 	0x38d8c2c4, 0x4fdff252, 0xd1bb67f1, 0xa6bc5767, 0x3fb506dd, 0x48b2364b,
906 	0xd80d2bda, 0xaf0a1b4c, 0x36034af6, 0x41047a60, 0xdf60efc3, 0xa867df55,
907 	0x316e8eef, 0x4669be79, 0xcb61b38c, 0xbc66831a, 0x256fd2a0, 0x5268e236,
908 	0xcc0c7795, 0xbb0b4703, 0x220216b9, 0x5505262f, 0xc5ba3bbe, 0xb2bd0b28,
909 	0x2bb45a92, 0x5cb36a04, 0xc2d7ffa7, 0xb5d0cf31, 0x2cd99e8b, 0x5bdeae1d,
910 	0x9b64c2b0, 0xec63f226, 0x756aa39c, 0x026d930a, 0x9c0906a9, 0xeb0e363f,
911 	0x72076785, 0x05005713, 0x95bf4a82, 0xe2b87a14, 0x7bb12bae, 0x0cb61b38,
912 	0x92d28e9b, 0xe5d5be0d, 0x7cdcefb7, 0x0bdbdf21, 0x86d3d2d4, 0xf1d4e242,
913 	0x68ddb3f8, 0x1fda836e, 0x81be16cd, 0xf6b9265b, 0x6fb077e1, 0x18b74777,
914 	0x88085ae6, 0xff0f6a70, 0x66063bca, 0x11010b5c, 0x8f659eff, 0xf862ae69,
915 	0x616bffd3, 0x166ccf45, 0xa00ae278, 0xd70dd2ee, 0x4e048354, 0x3903b3c2,
916 	0xa7672661, 0xd06016f7, 0x4969474d, 0x3e6e77db, 0xaed16a4a, 0xd9d65adc,
917 	0x40df0b66, 0x37d83bf0, 0xa9bcae53, 0xdebb9ec5, 0x47b2cf7f, 0x30b5ffe9,
918 	0xbdbdf21c, 0xcabac28a, 0x53b39330, 0x24b4a3a6, 0xbad03605, 0xcdd70693,
919 	0x54de5729, 0x23d967bf, 0xb3667a2e, 0xc4614ab8, 0x5d681b02, 0x2a6f2b94,
920 	0xb40bbe37, 0xc30c8ea1, 0x5a05df1b, 0x2d02ef8d
921 };
922 
923 uint32_t
924 cdce_crc32(const void *buf, size_t size)
925 {
926 	const uint8_t *p;
927 	uint32_t crc;
928 
929 	p = buf;
930 	crc = ~0U;
931 
932 	while (size--)
933 		crc = cdce_crc32_tab[(crc ^ *p++) & 0xFF] ^ (crc >> 8);
934 
935 	return (htole32(crc) ^ ~0U);
936 }
937