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