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