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