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