xref: /openbsd-src/sys/dev/usb/if_cdce.c (revision d66d8ee2788197b4ee18d763efd35443169bcdc7)
1 /*	$OpenBSD: if_cdce.c,v 1.64 2015/04/10 08:41:43 mpi 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 	struct mbuf_list	 ml = MBUF_LIST_INITIALIZER();
730 	int			 total_len = 0;
731 	int			 s;
732 
733 	if (usbd_is_dying(sc->cdce_udev) || !(ifp->if_flags & IFF_RUNNING))
734 		return;
735 
736 	if (status != USBD_NORMAL_COMPLETION) {
737 		if (status == USBD_NOT_STARTED || status == USBD_CANCELLED)
738 			return;
739 		if (sc->cdce_rxeof_errors == 0)
740 			printf("%s: usb error on rx: %s\n",
741 			    sc->cdce_dev.dv_xname, usbd_errstr(status));
742 		if (status == USBD_STALLED)
743 			usbd_clear_endpoint_stall_async(sc->cdce_bulkin_pipe);
744 		DELAY(sc->cdce_rxeof_errors * 10000);
745 		if (sc->cdce_rxeof_errors++ > 10) {
746 			printf("%s: too many errors, disabling\n",
747 			    sc->cdce_dev.dv_xname);
748 			usbd_deactivate(sc->cdce_udev);
749 			return;
750 		}
751 		goto done;
752 	}
753 
754 	sc->cdce_rxeof_errors = 0;
755 
756 	usbd_get_xfer_status(xfer, NULL, NULL, &total_len, NULL);
757 	if (sc->cdce_flags & CDCE_ZAURUS)
758 		total_len -= 4;	/* Strip off CRC added by Zaurus */
759 	if (total_len <= 1)
760 		goto done;
761 
762 	m = c->cdce_mbuf;
763 	memcpy(mtod(m, char *), c->cdce_buf, total_len);
764 
765 	if (total_len < sizeof(struct ether_header)) {
766 		ifp->if_ierrors++;
767 		goto done;
768 	}
769 
770 	ifp->if_ipackets++;
771 	m->m_pkthdr.len = m->m_len = total_len;
772 	ml_enqueue(&ml, m);
773 
774 	if (cdce_newbuf(sc, c, NULL) == ENOBUFS) {
775 		ifp->if_ierrors++;
776 		goto done;
777 	}
778 
779 	s = splnet();
780 	if_input(ifp, &ml);
781 	splx(s);
782 
783 done:
784 	/* Setup new transfer. */
785 	usbd_setup_xfer(c->cdce_xfer, sc->cdce_bulkin_pipe, c, c->cdce_buf,
786 	    CDCE_BUFSZ, USBD_SHORT_XFER_OK | USBD_NO_COPY, USBD_NO_TIMEOUT,
787 	    cdce_rxeof);
788 	usbd_transfer(c->cdce_xfer);
789 }
790 
791 void
792 cdce_txeof(struct usbd_xfer *xfer, void *priv, usbd_status status)
793 {
794 	struct cdce_chain	*c = priv;
795 	struct cdce_softc	*sc = c->cdce_sc;
796 	struct ifnet		*ifp = GET_IFP(sc);
797 	usbd_status		 err;
798 	int			 s;
799 
800 	if (usbd_is_dying(sc->cdce_udev))
801 		return;
802 
803 	s = splnet();
804 
805 	ifp->if_timer = 0;
806 	ifp->if_flags &= ~IFF_OACTIVE;
807 
808 	if (status != USBD_NORMAL_COMPLETION) {
809 		if (status == USBD_NOT_STARTED || status == USBD_CANCELLED) {
810 			splx(s);
811 			return;
812 		}
813 		ifp->if_oerrors++;
814 		printf("%s: usb error on tx: %s\n", sc->cdce_dev.dv_xname,
815 		    usbd_errstr(status));
816 		if (status == USBD_STALLED)
817 			usbd_clear_endpoint_stall_async(sc->cdce_bulkout_pipe);
818 		splx(s);
819 		return;
820 	}
821 
822 	usbd_get_xfer_status(c->cdce_xfer, NULL, NULL, NULL, &err);
823 
824 	if (c->cdce_mbuf != NULL) {
825 		m_freem(c->cdce_mbuf);
826 		c->cdce_mbuf = NULL;
827 	}
828 
829 	if (err)
830 		ifp->if_oerrors++;
831 	else
832 		ifp->if_opackets++;
833 
834 	if (IFQ_IS_EMPTY(&ifp->if_snd) == 0)
835 		cdce_start(ifp);
836 
837 	splx(s);
838 }
839 
840 void
841 cdce_intr(struct usbd_xfer *xfer, void *addr, usbd_status status)
842 {
843 	struct cdce_softc	*sc = addr;
844 	struct usb_cdc_notification *buf = &sc->cdce_intr_buf;
845 	struct usb_cdc_connection_speed	*speed;
846 	u_int32_t		 count;
847 
848 	if (status == USBD_CANCELLED)
849 		return;
850 
851 	if (status != USBD_NORMAL_COMPLETION) {
852 		DPRINTFN(2, ("cdce_intr: status=%d\n", status));
853 		if (status == USBD_STALLED)
854 			usbd_clear_endpoint_stall_async(sc->cdce_intr_pipe);
855 		return;
856 	}
857 
858 	usbd_get_xfer_status(xfer, NULL, NULL, &count, NULL);
859 
860 	if (buf->bmRequestType == UCDC_NOTIFICATION) {
861 		switch (buf->bNotification) {
862 		case UCDC_N_NETWORK_CONNECTION:
863 			DPRINTFN(1, ("cdce_intr: network %s\n",
864 			    UGETW(buf->wValue) ? "connected" : "disconnected"));
865 			break;
866 		case UCDC_N_CONNECTION_SPEED_CHANGE:
867 			speed = (struct usb_cdc_connection_speed *)&buf->data;
868 			DPRINTFN(1, ("cdce_intr: up=%d, down=%d\n",
869 			    UGETDW(speed->dwUSBitRate),
870 			    UGETDW(speed->dwDSBitRate)));
871 			break;
872 		default:
873 			DPRINTF(("cdce_intr: bNotification 0x%x\n",
874 			    buf->bNotification));
875 		}
876 	}
877 #ifdef CDCE_DEBUG
878 	else {
879 		printf("cdce_intr: bmRequestType=%d ", buf->bmRequestType);
880 		printf("wValue=%d wIndex=%d wLength=%d\n", UGETW(buf->wValue),
881 		    UGETW(buf->wIndex), UGETW(buf->wLength));
882 	}
883 #endif
884 }
885 
886 
887 /*  COPYRIGHT (C) 1986 Gary S. Brown.  You may use this program, or
888  *  code or tables extracted from it, as desired without restriction.
889  */
890 
891 static uint32_t cdce_crc32_tab[] = {
892 	0x00000000, 0x77073096, 0xee0e612c, 0x990951ba, 0x076dc419, 0x706af48f,
893 	0xe963a535, 0x9e6495a3,	0x0edb8832, 0x79dcb8a4, 0xe0d5e91e, 0x97d2d988,
894 	0x09b64c2b, 0x7eb17cbd, 0xe7b82d07, 0x90bf1d91, 0x1db71064, 0x6ab020f2,
895 	0xf3b97148, 0x84be41de,	0x1adad47d, 0x6ddde4eb, 0xf4d4b551, 0x83d385c7,
896 	0x136c9856, 0x646ba8c0, 0xfd62f97a, 0x8a65c9ec,	0x14015c4f, 0x63066cd9,
897 	0xfa0f3d63, 0x8d080df5,	0x3b6e20c8, 0x4c69105e, 0xd56041e4, 0xa2677172,
898 	0x3c03e4d1, 0x4b04d447, 0xd20d85fd, 0xa50ab56b,	0x35b5a8fa, 0x42b2986c,
899 	0xdbbbc9d6, 0xacbcf940,	0x32d86ce3, 0x45df5c75, 0xdcd60dcf, 0xabd13d59,
900 	0x26d930ac, 0x51de003a, 0xc8d75180, 0xbfd06116, 0x21b4f4b5, 0x56b3c423,
901 	0xcfba9599, 0xb8bda50f, 0x2802b89e, 0x5f058808, 0xc60cd9b2, 0xb10be924,
902 	0x2f6f7c87, 0x58684c11, 0xc1611dab, 0xb6662d3d,	0x76dc4190, 0x01db7106,
903 	0x98d220bc, 0xefd5102a, 0x71b18589, 0x06b6b51f, 0x9fbfe4a5, 0xe8b8d433,
904 	0x7807c9a2, 0x0f00f934, 0x9609a88e, 0xe10e9818, 0x7f6a0dbb, 0x086d3d2d,
905 	0x91646c97, 0xe6635c01, 0x6b6b51f4, 0x1c6c6162, 0x856530d8, 0xf262004e,
906 	0x6c0695ed, 0x1b01a57b, 0x8208f4c1, 0xf50fc457, 0x65b0d9c6, 0x12b7e950,
907 	0x8bbeb8ea, 0xfcb9887c, 0x62dd1ddf, 0x15da2d49, 0x8cd37cf3, 0xfbd44c65,
908 	0x4db26158, 0x3ab551ce, 0xa3bc0074, 0xd4bb30e2, 0x4adfa541, 0x3dd895d7,
909 	0xa4d1c46d, 0xd3d6f4fb, 0x4369e96a, 0x346ed9fc, 0xad678846, 0xda60b8d0,
910 	0x44042d73, 0x33031de5, 0xaa0a4c5f, 0xdd0d7cc9, 0x5005713c, 0x270241aa,
911 	0xbe0b1010, 0xc90c2086, 0x5768b525, 0x206f85b3, 0xb966d409, 0xce61e49f,
912 	0x5edef90e, 0x29d9c998, 0xb0d09822, 0xc7d7a8b4, 0x59b33d17, 0x2eb40d81,
913 	0xb7bd5c3b, 0xc0ba6cad, 0xedb88320, 0x9abfb3b6, 0x03b6e20c, 0x74b1d29a,
914 	0xead54739, 0x9dd277af, 0x04db2615, 0x73dc1683, 0xe3630b12, 0x94643b84,
915 	0x0d6d6a3e, 0x7a6a5aa8, 0xe40ecf0b, 0x9309ff9d, 0x0a00ae27, 0x7d079eb1,
916 	0xf00f9344, 0x8708a3d2, 0x1e01f268, 0x6906c2fe, 0xf762575d, 0x806567cb,
917 	0x196c3671, 0x6e6b06e7, 0xfed41b76, 0x89d32be0, 0x10da7a5a, 0x67dd4acc,
918 	0xf9b9df6f, 0x8ebeeff9, 0x17b7be43, 0x60b08ed5, 0xd6d6a3e8, 0xa1d1937e,
919 	0x38d8c2c4, 0x4fdff252, 0xd1bb67f1, 0xa6bc5767, 0x3fb506dd, 0x48b2364b,
920 	0xd80d2bda, 0xaf0a1b4c, 0x36034af6, 0x41047a60, 0xdf60efc3, 0xa867df55,
921 	0x316e8eef, 0x4669be79, 0xcb61b38c, 0xbc66831a, 0x256fd2a0, 0x5268e236,
922 	0xcc0c7795, 0xbb0b4703, 0x220216b9, 0x5505262f, 0xc5ba3bbe, 0xb2bd0b28,
923 	0x2bb45a92, 0x5cb36a04, 0xc2d7ffa7, 0xb5d0cf31, 0x2cd99e8b, 0x5bdeae1d,
924 	0x9b64c2b0, 0xec63f226, 0x756aa39c, 0x026d930a, 0x9c0906a9, 0xeb0e363f,
925 	0x72076785, 0x05005713, 0x95bf4a82, 0xe2b87a14, 0x7bb12bae, 0x0cb61b38,
926 	0x92d28e9b, 0xe5d5be0d, 0x7cdcefb7, 0x0bdbdf21, 0x86d3d2d4, 0xf1d4e242,
927 	0x68ddb3f8, 0x1fda836e, 0x81be16cd, 0xf6b9265b, 0x6fb077e1, 0x18b74777,
928 	0x88085ae6, 0xff0f6a70, 0x66063bca, 0x11010b5c, 0x8f659eff, 0xf862ae69,
929 	0x616bffd3, 0x166ccf45, 0xa00ae278, 0xd70dd2ee, 0x4e048354, 0x3903b3c2,
930 	0xa7672661, 0xd06016f7, 0x4969474d, 0x3e6e77db, 0xaed16a4a, 0xd9d65adc,
931 	0x40df0b66, 0x37d83bf0, 0xa9bcae53, 0xdebb9ec5, 0x47b2cf7f, 0x30b5ffe9,
932 	0xbdbdf21c, 0xcabac28a, 0x53b39330, 0x24b4a3a6, 0xbad03605, 0xcdd70693,
933 	0x54de5729, 0x23d967bf, 0xb3667a2e, 0xc4614ab8, 0x5d681b02, 0x2a6f2b94,
934 	0xb40bbe37, 0xc30c8ea1, 0x5a05df1b, 0x2d02ef8d
935 };
936 
937 uint32_t
938 cdce_crc32(const void *buf, size_t size)
939 {
940 	const uint8_t *p;
941 	uint32_t crc;
942 
943 	p = buf;
944 	crc = ~0U;
945 
946 	while (size--)
947 		crc = cdce_crc32_tab[(crc ^ *p++) & 0xFF] ^ (crc >> 8);
948 
949 	return (htole32(crc) ^ ~0U);
950 }
951