xref: /netbsd-src/sys/dev/usb/if_cdce.c (revision 8b0f9554ff8762542c4defc4f70e1eb76fb508fa)
1 /*	$NetBSD: if_cdce.c,v 1.14 2007/03/13 13:51:54 drochner 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 <sys/cdefs.h>
44 __KERNEL_RCSID(0, "$NetBSD: if_cdce.c,v 1.14 2007/03/13 13:51:54 drochner Exp $");
45 #include "bpfilter.h"
46 
47 #include <sys/param.h>
48 #include <sys/systm.h>
49 #include <sys/sockio.h>
50 #include <sys/mbuf.h>
51 #include <sys/malloc.h>
52 #include <sys/kernel.h>
53 #include <sys/socket.h>
54 #include <sys/device.h>
55 #if defined(__OpenBSD__)
56 #include <sys/proc.h>
57 #endif
58 
59 #if NRND > 0
60 #include <sys/rnd.h>
61 #endif
62 
63 #include <net/if.h>
64 #if defined(__NetBSD__)
65 #include <net/if_arp.h>
66 #endif
67 #include <net/if_dl.h>
68 #include <net/if_media.h>
69 
70 #define BPF_MTAP(ifp, m) bpf_mtap((ifp)->if_bpf, (m))
71 
72 #if NBPFILTER > 0
73 #include <net/bpf.h>
74 #endif
75 
76 #if defined(__NetBSD__)
77 #include <net/if_ether.h>
78 #ifdef INET
79 #include <netinet/in.h>
80 #include <netinet/if_inarp.h>
81 #endif
82 #endif /* defined(__NetBSD__) */
83 
84 #if defined(__OpenBSD__)
85 #ifdef INET
86 #include <netinet/in.h>
87 #include <netinet/in_systm.h>
88 #include <netinet/in_var.h>
89 #include <netinet/ip.h>
90 #include <netinet/if_ether.h>
91 #endif
92 #endif /* defined(__OpenBSD__) */
93 
94 
95 #include <dev/usb/usb.h>
96 #include <dev/usb/usbdi.h>
97 #include <dev/usb/usbdi_util.h>
98 #include <dev/usb/usbdevs.h>
99 #include <dev/usb/usbcdc.h>
100 
101 #include <dev/usb/if_cdcereg.h>
102 
103 Static int	 cdce_tx_list_init(struct cdce_softc *);
104 Static int	 cdce_rx_list_init(struct cdce_softc *);
105 Static int	 cdce_newbuf(struct cdce_softc *, struct cdce_chain *,
106 		    struct mbuf *);
107 Static int	 cdce_encap(struct cdce_softc *, struct mbuf *, int);
108 Static void	 cdce_rxeof(usbd_xfer_handle, usbd_private_handle, usbd_status);
109 Static void	 cdce_txeof(usbd_xfer_handle, usbd_private_handle, usbd_status);
110 Static void	 cdce_start(struct ifnet *);
111 Static int	 cdce_ioctl(struct ifnet *, u_long, void *);
112 Static void	 cdce_init(void *);
113 Static void	 cdce_watchdog(struct ifnet *);
114 Static void	 cdce_stop(struct cdce_softc *);
115 Static uint32_t	 cdce_crc32(const void *, size_t);
116 
117 Static const struct cdce_type cdce_devs[] = {
118   {{ USB_VENDOR_PROLIFIC, USB_PRODUCT_PROLIFIC_PL2501 }, CDCE_NO_UNION },
119   {{ USB_VENDOR_SHARP, USB_PRODUCT_SHARP_SL5500 }, CDCE_ZAURUS },
120   {{ USB_VENDOR_SHARP, USB_PRODUCT_SHARP_A300 }, CDCE_ZAURUS | CDCE_NO_UNION },
121   {{ USB_VENDOR_SHARP, USB_PRODUCT_SHARP_SL5600 }, CDCE_ZAURUS | CDCE_NO_UNION },
122   {{ USB_VENDOR_SHARP, USB_PRODUCT_SHARP_C700 }, CDCE_ZAURUS | CDCE_NO_UNION },
123   {{ USB_VENDOR_SHARP, USB_PRODUCT_SHARP_C750 }, CDCE_ZAURUS | CDCE_NO_UNION },
124 };
125 #define cdce_lookup(v, p) ((const struct cdce_type *)usb_lookup(cdce_devs, v, p))
126 
127 USB_DECLARE_DRIVER(cdce);
128 
129 USB_MATCH(cdce)
130 {
131 	USB_IFMATCH_START(cdce, uaa);
132 
133 	if (cdce_lookup(uaa->vendor, uaa->product) != NULL)
134 		return (UMATCH_VENDOR_PRODUCT);
135 
136 	if (uaa->class == UICLASS_CDC && uaa->subclass ==
137 	    UISUBCLASS_ETHERNET_NETWORKING_CONTROL_MODEL)
138 		return (UMATCH_IFACECLASS_GENERIC);
139 
140 	return (UMATCH_NONE);
141 }
142 
143 USB_ATTACH(cdce)
144 {
145 	USB_IFATTACH_START(cdce, sc, uaa);
146 	char				 *devinfop;
147 	int				 s;
148 	struct ifnet			*ifp;
149 	usbd_device_handle		 dev = uaa->device;
150 	const struct cdce_type		*t;
151 	usb_interface_descriptor_t	*id;
152 	usb_endpoint_descriptor_t	*ed;
153 	const usb_cdc_union_descriptor_t *ud;
154 	int				 data_ifcno;
155 	int				 i;
156 	u_char				 eaddr[ETHER_ADDR_LEN];
157 	const usb_cdc_ethernet_descriptor_t *ue;
158 	char				 eaddr_str[USB_MAX_ENCODED_STRING_LEN];
159 
160 	devinfop = usbd_devinfo_alloc(dev, 0);
161 	USB_ATTACH_SETUP;
162 	printf("%s: %s\n", USBDEVNAME(sc->cdce_dev), devinfop);
163 	usbd_devinfo_free(devinfop);
164 
165 	sc->cdce_udev = uaa->device;
166 	sc->cdce_ctl_iface = uaa->iface;
167 
168 	t = cdce_lookup(uaa->vendor, uaa->product);
169 	if (t)
170 		sc->cdce_flags = t->cdce_flags;
171 
172 	if (sc->cdce_flags & CDCE_NO_UNION)
173 		sc->cdce_data_iface = sc->cdce_ctl_iface;
174 	else {
175 		ud = (const usb_cdc_union_descriptor_t *)usb_find_desc(sc->cdce_udev,
176 		    UDESC_CS_INTERFACE, UDESCSUB_CDC_UNION);
177 		if (ud == NULL) {
178 			printf("%s: no union descriptor\n",
179 			    USBDEVNAME(sc->cdce_dev));
180 			USB_ATTACH_ERROR_RETURN;
181 		}
182 		data_ifcno = ud->bSlaveInterface[0];
183 
184 		for (i = 0; i < uaa->nifaces; i++) {
185 			if (uaa->ifaces[i] != NULL) {
186 				id = usbd_get_interface_descriptor(
187 				    uaa->ifaces[i]);
188 				if (id != NULL && id->bInterfaceNumber ==
189 				    data_ifcno) {
190 					sc->cdce_data_iface = uaa->ifaces[i];
191 					uaa->ifaces[i] = NULL;
192 				}
193 			}
194 		}
195 	}
196 
197 	if (sc->cdce_data_iface == NULL) {
198 		printf("%s: no data interface\n", USBDEVNAME(sc->cdce_dev));
199 		USB_ATTACH_ERROR_RETURN;
200 	}
201 
202 	/* Find endpoints. */
203 	id = usbd_get_interface_descriptor(sc->cdce_data_iface);
204 	sc->cdce_bulkin_no = sc->cdce_bulkout_no = -1;
205 	for (i = 0; i < id->bNumEndpoints; i++) {
206 		ed = usbd_interface2endpoint_descriptor(sc->cdce_data_iface, i);
207 		if (!ed) {
208 			printf("%s: could not read endpoint descriptor\n",
209 			    USBDEVNAME(sc->cdce_dev));
210 			USB_ATTACH_ERROR_RETURN;
211 		}
212 		if (UE_GET_DIR(ed->bEndpointAddress) == UE_DIR_IN &&
213 		    UE_GET_XFERTYPE(ed->bmAttributes) == UE_BULK) {
214 			sc->cdce_bulkin_no = ed->bEndpointAddress;
215 		} else if (UE_GET_DIR(ed->bEndpointAddress) == UE_DIR_OUT &&
216 		    UE_GET_XFERTYPE(ed->bmAttributes) == UE_BULK) {
217 			sc->cdce_bulkout_no = ed->bEndpointAddress;
218 		} else if (UE_GET_DIR(ed->bEndpointAddress) == UE_DIR_IN &&
219 		    UE_GET_XFERTYPE(ed->bmAttributes) == UE_INTERRUPT) {
220 			/* XXX: CDC spec defines an interrupt pipe, but it is not
221 			 * needed for simple host-to-host applications. */
222 		} else {
223 			printf("%s: unexpected endpoint\n",
224 			    USBDEVNAME(sc->cdce_dev));
225 		}
226 	}
227 
228 	if (sc->cdce_bulkin_no == -1) {
229 		printf("%s: could not find data bulk in\n",
230 		    USBDEVNAME(sc->cdce_dev));
231 		USB_ATTACH_ERROR_RETURN;
232 	}
233 	if (sc->cdce_bulkout_no == -1 ) {
234 		printf("%s: could not find data bulk out\n",
235 		    USBDEVNAME(sc->cdce_dev));
236 		USB_ATTACH_ERROR_RETURN;
237 	}
238 
239 	ue = (const usb_cdc_ethernet_descriptor_t *)usb_find_desc(dev,
240             UDESC_INTERFACE, UDESCSUB_CDC_ENF);
241 	if (!ue || usbd_get_string(dev, ue->iMacAddress, eaddr_str)) {
242 		printf("%s: faking address\n", USBDEVNAME(sc->cdce_dev));
243 		eaddr[0]= 0x2a;
244 		memcpy(&eaddr[1], &hardclock_ticks, sizeof(u_int32_t));
245 		eaddr[5] = (u_int8_t)(device_unit(&sc->cdce_dev));
246 	} else {
247 		int j;
248 
249 		memset(eaddr, 0, ETHER_ADDR_LEN);
250 		for (j = 0; j < ETHER_ADDR_LEN * 2; j++) {
251 			int c = eaddr_str[j];
252 
253 			if ('0' <= c && c <= '9')
254 				c -= '0';
255 			else
256 				c -= 'A' - 10;
257 			c &= 0xf;
258 			if (c%2 == 0)
259 				c <<= 4;
260 			eaddr[j / 2] |= c;
261 		}
262 	}
263 
264 	s = splnet();
265 
266 	printf("%s: address %s\n", USBDEVNAME(sc->cdce_dev),
267 	    ether_sprintf(eaddr));
268 
269 	ifp = GET_IFP(sc);
270 	ifp->if_softc = sc;
271 	ifp->if_flags = IFF_BROADCAST | IFF_SIMPLEX | IFF_MULTICAST;
272 	ifp->if_ioctl = cdce_ioctl;
273 	ifp->if_start = cdce_start;
274 	ifp->if_watchdog = cdce_watchdog;
275 	strncpy(ifp->if_xname, USBDEVNAME(sc->cdce_dev), IFNAMSIZ);
276 
277 	IFQ_SET_READY(&ifp->if_snd);
278 
279 	if_attach(ifp);
280 	Ether_ifattach(ifp, eaddr);
281 
282 	sc->cdce_attached = 1;
283 	splx(s);
284 
285 	usbd_add_drv_event(USB_EVENT_DRIVER_ATTACH, sc->cdce_udev,
286 	    USBDEV(sc->cdce_dev));
287 
288 	USB_ATTACH_SUCCESS_RETURN;
289 }
290 
291 USB_DETACH(cdce)
292 {
293 	USB_DETACH_START(cdce, sc);
294 	struct ifnet	*ifp = GET_IFP(sc);
295 	int		 s;
296 
297 	s = splusb();
298 
299 	if (!sc->cdce_attached) {
300 		splx(s);
301 		return (0);
302 	}
303 
304 	if (ifp->if_flags & IFF_RUNNING)
305 		cdce_stop(sc);
306 
307 	ether_ifdetach(ifp);
308 
309 	if_detach(ifp);
310 
311 	sc->cdce_attached = 0;
312 	splx(s);
313 
314 	return (0);
315 }
316 
317 Static void
318 cdce_start(struct ifnet *ifp)
319 {
320 	struct cdce_softc	*sc = ifp->if_softc;
321 	struct mbuf		*m_head = NULL;
322 
323 	if (sc->cdce_dying || (ifp->if_flags & IFF_OACTIVE))
324 		return;
325 
326 	IFQ_POLL(&ifp->if_snd, m_head);
327 	if (m_head == NULL)
328 		return;
329 
330 	if (cdce_encap(sc, m_head, 0)) {
331 		ifp->if_flags |= IFF_OACTIVE;
332 		return;
333 	}
334 
335 	IFQ_DEQUEUE(&ifp->if_snd, m_head);
336 
337 #if NBPFILTER > 0
338 	if (ifp->if_bpf)
339 		BPF_MTAP(ifp, m_head);
340 #endif
341 
342 	ifp->if_flags |= IFF_OACTIVE;
343 
344 	ifp->if_timer = 6;
345 }
346 
347 Static int
348 cdce_encap(struct cdce_softc *sc, struct mbuf *m, int idx)
349 {
350 	struct cdce_chain	*c;
351 	usbd_status		 err;
352 	int			 extra = 0;
353 
354 	c = &sc->cdce_cdata.cdce_tx_chain[idx];
355 
356 	m_copydata(m, 0, m->m_pkthdr.len, c->cdce_buf);
357 	if (sc->cdce_flags & CDCE_ZAURUS) {
358 		/* Zaurus wants a 32-bit CRC appended to every frame */
359 		u_int32_t crc;
360 
361 		crc = cdce_crc32(c->cdce_buf, m->m_pkthdr.len);
362 		bcopy(&crc, c->cdce_buf + m->m_pkthdr.len, 4);
363 		extra = 4;
364 	}
365 	c->cdce_mbuf = m;
366 
367 	usbd_setup_xfer(c->cdce_xfer, sc->cdce_bulkout_pipe, c, c->cdce_buf,
368 	    m->m_pkthdr.len + extra, USBD_NO_COPY, 10000, cdce_txeof);
369 	err = usbd_transfer(c->cdce_xfer);
370 	if (err != USBD_IN_PROGRESS) {
371 		cdce_stop(sc);
372 		return (EIO);
373 	}
374 
375 	sc->cdce_cdata.cdce_tx_cnt++;
376 
377 	return (0);
378 }
379 
380 Static void
381 cdce_stop(struct cdce_softc *sc)
382 {
383 	usbd_status	 err;
384 	struct ifnet	*ifp = GET_IFP(sc);
385 	int		 i;
386 
387 	ifp->if_timer = 0;
388 
389 	if (sc->cdce_bulkin_pipe != NULL) {
390 		err = usbd_abort_pipe(sc->cdce_bulkin_pipe);
391 		if (err)
392 			printf("%s: abort rx pipe failed: %s\n",
393 			    USBDEVNAME(sc->cdce_dev), usbd_errstr(err));
394 		err = usbd_close_pipe(sc->cdce_bulkin_pipe);
395 		if (err)
396 			printf("%s: close rx pipe failed: %s\n",
397 			    USBDEVNAME(sc->cdce_dev), usbd_errstr(err));
398 		sc->cdce_bulkin_pipe = NULL;
399 	}
400 
401 	if (sc->cdce_bulkout_pipe != NULL) {
402 		err = usbd_abort_pipe(sc->cdce_bulkout_pipe);
403 		if (err)
404 			printf("%s: abort tx pipe failed: %s\n",
405 			    USBDEVNAME(sc->cdce_dev), usbd_errstr(err));
406 		err = usbd_close_pipe(sc->cdce_bulkout_pipe);
407 		if (err)
408 			printf("%s: close tx pipe failed: %s\n",
409 			    USBDEVNAME(sc->cdce_dev), usbd_errstr(err));
410 		sc->cdce_bulkout_pipe = NULL;
411 	}
412 
413 	for (i = 0; i < CDCE_RX_LIST_CNT; i++) {
414 		if (sc->cdce_cdata.cdce_rx_chain[i].cdce_mbuf != NULL) {
415 			m_freem(sc->cdce_cdata.cdce_rx_chain[i].cdce_mbuf);
416 			sc->cdce_cdata.cdce_rx_chain[i].cdce_mbuf = NULL;
417 		}
418 		if (sc->cdce_cdata.cdce_rx_chain[i].cdce_xfer != NULL) {
419 			usbd_free_xfer(sc->cdce_cdata.cdce_rx_chain[i].cdce_xfer);
420 			sc->cdce_cdata.cdce_rx_chain[i].cdce_xfer = NULL;
421 		}
422 	}
423 
424 	for (i = 0; i < CDCE_TX_LIST_CNT; i++) {
425 		if (sc->cdce_cdata.cdce_tx_chain[i].cdce_mbuf != NULL) {
426 			m_freem(sc->cdce_cdata.cdce_tx_chain[i].cdce_mbuf);
427 			sc->cdce_cdata.cdce_tx_chain[i].cdce_mbuf = NULL;
428 		}
429 		if (sc->cdce_cdata.cdce_tx_chain[i].cdce_xfer != NULL) {
430 			usbd_free_xfer(sc->cdce_cdata.cdce_tx_chain[i].cdce_xfer);
431 			sc->cdce_cdata.cdce_tx_chain[i].cdce_xfer = NULL;
432 		}
433 	}
434 
435 	ifp->if_flags &= ~(IFF_RUNNING | IFF_OACTIVE);
436 }
437 
438 Static int
439 cdce_ioctl(struct ifnet *ifp, u_long command, void *data)
440 {
441 	struct cdce_softc	*sc = ifp->if_softc;
442 	struct ifaddr		*ifa = (struct ifaddr *)data;
443 	struct ifreq		*ifr = (struct ifreq *)data;
444 	int			 s, error = 0;
445 
446 	if (sc->cdce_dying)
447 		return (EIO);
448 
449 	s = splnet();
450 
451 	switch(command) {
452 	case SIOCSIFADDR:
453 		ifp->if_flags |= IFF_UP;
454 		cdce_init(sc);
455 		switch (ifa->ifa_addr->sa_family) {
456 #ifdef INET
457 		case AF_INET:
458 #if defined(__NetBSD__)
459 			arp_ifinit(ifp, ifa);
460 #else
461 			arp_ifinit(&sc->arpcom, ifa);
462 #endif
463 			break;
464 #endif /* INET */
465 		}
466 		break;
467 
468 	case SIOCSIFMTU:
469 		if (ifr->ifr_mtu > ETHERMTU)
470 			error = EINVAL;
471 		else
472 			ifp->if_mtu = ifr->ifr_mtu;
473 		break;
474 
475 	case SIOCSIFFLAGS:
476 		if (ifp->if_flags & IFF_UP) {
477 			if (!(ifp->if_flags & IFF_RUNNING))
478 				cdce_init(sc);
479 		} else {
480 			if (ifp->if_flags & IFF_RUNNING)
481 				cdce_stop(sc);
482 		}
483 		error = 0;
484 		break;
485 
486 	default:
487 		error = EINVAL;
488 		break;
489 	}
490 
491 	splx(s);
492 
493 	return (error);
494 }
495 
496 Static void
497 cdce_watchdog(struct ifnet *ifp)
498 {
499 	struct cdce_softc	*sc = ifp->if_softc;
500 
501 	if (sc->cdce_dying)
502 		return;
503 
504 	ifp->if_oerrors++;
505 	printf("%s: watchdog timeout\n", USBDEVNAME(sc->cdce_dev));
506 }
507 
508 Static void
509 cdce_init(void *xsc)
510 {
511 	struct cdce_softc	*sc = xsc;
512 	struct ifnet		*ifp = GET_IFP(sc);
513 	struct cdce_chain	*c;
514 	usbd_status		 err;
515 	int			 s, i;
516 
517 	if (ifp->if_flags & IFF_RUNNING)
518 		return;
519 
520 	s = splnet();
521 
522 	if (cdce_tx_list_init(sc) == ENOBUFS) {
523 		printf("%s: tx list init failed\n", USBDEVNAME(sc->cdce_dev));
524 		splx(s);
525 		return;
526 	}
527 
528 	if (cdce_rx_list_init(sc) == ENOBUFS) {
529 		printf("%s: rx list init failed\n", USBDEVNAME(sc->cdce_dev));
530 		splx(s);
531 		return;
532 	}
533 
534 	/* Maybe set multicast / broadcast here??? */
535 
536 	err = usbd_open_pipe(sc->cdce_data_iface, sc->cdce_bulkin_no,
537 	    USBD_EXCLUSIVE_USE, &sc->cdce_bulkin_pipe);
538 	if (err) {
539 		printf("%s: open rx pipe failed: %s\n", USBDEVNAME(sc->cdce_dev),
540 		    usbd_errstr(err));
541 		splx(s);
542 		return;
543 	}
544 
545 	err = usbd_open_pipe(sc->cdce_data_iface, sc->cdce_bulkout_no,
546 	    USBD_EXCLUSIVE_USE, &sc->cdce_bulkout_pipe);
547 	if (err) {
548 		printf("%s: open tx pipe failed: %s\n", USBDEVNAME(sc->cdce_dev),
549 		    usbd_errstr(err));
550 		splx(s);
551 		return;
552 	}
553 
554 	for (i = 0; i < CDCE_RX_LIST_CNT; i++) {
555 		c = &sc->cdce_cdata.cdce_rx_chain[i];
556 		usbd_setup_xfer(c->cdce_xfer, sc->cdce_bulkin_pipe, c,
557 		    c->cdce_buf, CDCE_BUFSZ, USBD_SHORT_XFER_OK | USBD_NO_COPY,
558 		    USBD_NO_TIMEOUT, cdce_rxeof);
559 		usbd_transfer(c->cdce_xfer);
560 	}
561 
562 	ifp->if_flags |= IFF_RUNNING;
563 	ifp->if_flags &= ~IFF_OACTIVE;
564 
565 	splx(s);
566 }
567 
568 Static int
569 cdce_newbuf(struct cdce_softc *sc, struct cdce_chain *c, struct mbuf *m)
570 {
571 	struct mbuf	*m_new = NULL;
572 
573 	if (m == NULL) {
574 		MGETHDR(m_new, M_DONTWAIT, MT_DATA);
575 		if (m_new == NULL) {
576 			printf("%s: no memory for rx list "
577 			    "-- packet dropped!\n", USBDEVNAME(sc->cdce_dev));
578 			return (ENOBUFS);
579 		}
580 		MCLGET(m_new, M_DONTWAIT);
581 		if (!(m_new->m_flags & M_EXT)) {
582 			printf("%s: no memory for rx list "
583 			    "-- packet dropped!\n", USBDEVNAME(sc->cdce_dev));
584 			m_freem(m_new);
585 			return (ENOBUFS);
586 		}
587 		m_new->m_len = m_new->m_pkthdr.len = MCLBYTES;
588 	} else {
589 		m_new = m;
590 		m_new->m_len = m_new->m_pkthdr.len = MCLBYTES;
591 		m_new->m_data = m_new->m_ext.ext_buf;
592 	}
593 	c->cdce_mbuf = m_new;
594 	return (0);
595 }
596 
597 Static int
598 cdce_rx_list_init(struct cdce_softc *sc)
599 {
600 	struct cdce_cdata	*cd;
601 	struct cdce_chain	*c;
602 	int			 i;
603 
604 	cd = &sc->cdce_cdata;
605 	for (i = 0; i < CDCE_RX_LIST_CNT; i++) {
606 		c = &cd->cdce_rx_chain[i];
607 		c->cdce_sc = sc;
608 		c->cdce_idx = i;
609 		if (cdce_newbuf(sc, c, NULL) == ENOBUFS)
610 			return (ENOBUFS);
611 		if (c->cdce_xfer == NULL) {
612 			c->cdce_xfer = usbd_alloc_xfer(sc->cdce_udev);
613 			if (c->cdce_xfer == NULL)
614 				return (ENOBUFS);
615 			c->cdce_buf = usbd_alloc_buffer(c->cdce_xfer, CDCE_BUFSZ);
616 			if (c->cdce_buf == NULL)
617 				return (ENOBUFS);
618 		}
619 	}
620 
621 	return (0);
622 }
623 
624 Static int
625 cdce_tx_list_init(struct cdce_softc *sc)
626 {
627 	struct cdce_cdata	*cd;
628 	struct cdce_chain	*c;
629 	int			 i;
630 
631 	cd = &sc->cdce_cdata;
632 	for (i = 0; i < CDCE_TX_LIST_CNT; i++) {
633 		c = &cd->cdce_tx_chain[i];
634 		c->cdce_sc = sc;
635 		c->cdce_idx = i;
636 		c->cdce_mbuf = NULL;
637 		if (c->cdce_xfer == NULL) {
638 			c->cdce_xfer = usbd_alloc_xfer(sc->cdce_udev);
639 			if (c->cdce_xfer == NULL)
640 				return (ENOBUFS);
641 			c->cdce_buf = usbd_alloc_buffer(c->cdce_xfer, CDCE_BUFSZ);
642 			if (c->cdce_buf == NULL)
643 				return (ENOBUFS);
644 		}
645 	}
646 
647 	return (0);
648 }
649 
650 Static void
651 cdce_rxeof(usbd_xfer_handle xfer, usbd_private_handle priv, usbd_status status)
652 {
653 	struct cdce_chain	*c = priv;
654 	struct cdce_softc	*sc = c->cdce_sc;
655 	struct ifnet		*ifp = GET_IFP(sc);
656 	struct mbuf		*m;
657 	int			 total_len = 0;
658 	int			 s;
659 
660 	if (sc->cdce_dying || !(ifp->if_flags & IFF_RUNNING))
661 		return;
662 
663 	if (status != USBD_NORMAL_COMPLETION) {
664 		if (status == USBD_NOT_STARTED || status == USBD_CANCELLED)
665 			return;
666 		if (sc->cdce_rxeof_errors == 0)
667 			printf("%s: usb error on rx: %s\n",
668 			    USBDEVNAME(sc->cdce_dev), usbd_errstr(status));
669 		if (status == USBD_STALLED)
670 			usbd_clear_endpoint_stall_async(sc->cdce_bulkin_pipe);
671 		DELAY(sc->cdce_rxeof_errors * 10000);
672 		sc->cdce_rxeof_errors++;
673 		goto done;
674 	}
675 
676 	sc->cdce_rxeof_errors = 0;
677 
678 	usbd_get_xfer_status(xfer, NULL, NULL, &total_len, NULL);
679 	if (sc->cdce_flags & CDCE_ZAURUS)
680 		total_len -= 4;	/* Strip off CRC added by Zaurus */
681 	if (total_len <= 1)
682 		goto done;
683 
684 	m = c->cdce_mbuf;
685 	memcpy(mtod(m, char *), c->cdce_buf, total_len);
686 
687 	if (total_len < sizeof(struct ether_header)) {
688 		ifp->if_ierrors++;
689 		goto done;
690 	}
691 
692 	ifp->if_ipackets++;
693 	m->m_pkthdr.len = m->m_len = total_len;
694 	m->m_pkthdr.rcvif = ifp;
695 
696 	s = splnet();
697 
698 	if (cdce_newbuf(sc, c, NULL) == ENOBUFS) {
699 		ifp->if_ierrors++;
700 		goto done1;
701 	}
702 
703 #if NBPFILTER > 0
704 	if (ifp->if_bpf)
705 		BPF_MTAP(ifp, m);
706 #endif
707 
708 	IF_INPUT(ifp, m);
709 
710 done1:
711 	splx(s);
712 
713 done:
714 	/* Setup new transfer. */
715 	usbd_setup_xfer(c->cdce_xfer, sc->cdce_bulkin_pipe, c, c->cdce_buf,
716 	    CDCE_BUFSZ, USBD_SHORT_XFER_OK | USBD_NO_COPY, USBD_NO_TIMEOUT,
717 	    cdce_rxeof);
718 	usbd_transfer(c->cdce_xfer);
719 }
720 
721 Static void
722 cdce_txeof(usbd_xfer_handle xfer, usbd_private_handle priv,
723     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 	usbd_status		 err;
729 	int			 s;
730 
731 	if (sc->cdce_dying)
732 		return;
733 
734 	s = splnet();
735 
736 	ifp->if_timer = 0;
737 	ifp->if_flags &= ~IFF_OACTIVE;
738 
739 	if (status != USBD_NORMAL_COMPLETION) {
740 		if (status == USBD_NOT_STARTED || status == USBD_CANCELLED) {
741 			splx(s);
742 			return;
743 		}
744 		ifp->if_oerrors++;
745 		printf("%s: usb error on tx: %s\n", USBDEVNAME(sc->cdce_dev),
746 		    usbd_errstr(status));
747 		if (status == USBD_STALLED)
748 			usbd_clear_endpoint_stall_async(sc->cdce_bulkout_pipe);
749 		splx(s);
750 		return;
751 	}
752 
753 	usbd_get_xfer_status(c->cdce_xfer, NULL, NULL, NULL, &err);
754 
755 	if (c->cdce_mbuf != NULL) {
756 		m_freem(c->cdce_mbuf);
757 		c->cdce_mbuf = NULL;
758 	}
759 
760 	if (err)
761 		ifp->if_oerrors++;
762 	else
763 		ifp->if_opackets++;
764 
765 	if (IFQ_IS_EMPTY(&ifp->if_snd) == 0)
766 		cdce_start(ifp);
767 
768 	splx(s);
769 }
770 
771 int
772 cdce_activate(device_ptr_t self, enum devact act)
773 {
774 	struct cdce_softc *sc = (struct cdce_softc *)self;
775 
776 	switch (act) {
777 	case DVACT_ACTIVATE:
778 		return (EOPNOTSUPP);
779 		break;
780 
781 	case DVACT_DEACTIVATE:
782 		if_deactivate(GET_IFP(sc));
783 		sc->cdce_dying = 1;
784 		break;
785 	}
786 	return (0);
787 }
788 
789 
790 /*  COPYRIGHT (C) 1986 Gary S. Brown.  You may use this program, or
791  *  code or tables extracted from it, as desired without restriction.
792  */
793 
794 static uint32_t cdce_crc32_tab[] = {
795 	0x00000000, 0x77073096, 0xee0e612c, 0x990951ba, 0x076dc419, 0x706af48f,
796 	0xe963a535, 0x9e6495a3,	0x0edb8832, 0x79dcb8a4, 0xe0d5e91e, 0x97d2d988,
797 	0x09b64c2b, 0x7eb17cbd, 0xe7b82d07, 0x90bf1d91, 0x1db71064, 0x6ab020f2,
798 	0xf3b97148, 0x84be41de,	0x1adad47d, 0x6ddde4eb, 0xf4d4b551, 0x83d385c7,
799 	0x136c9856, 0x646ba8c0, 0xfd62f97a, 0x8a65c9ec,	0x14015c4f, 0x63066cd9,
800 	0xfa0f3d63, 0x8d080df5,	0x3b6e20c8, 0x4c69105e, 0xd56041e4, 0xa2677172,
801 	0x3c03e4d1, 0x4b04d447, 0xd20d85fd, 0xa50ab56b,	0x35b5a8fa, 0x42b2986c,
802 	0xdbbbc9d6, 0xacbcf940,	0x32d86ce3, 0x45df5c75, 0xdcd60dcf, 0xabd13d59,
803 	0x26d930ac, 0x51de003a, 0xc8d75180, 0xbfd06116, 0x21b4f4b5, 0x56b3c423,
804 	0xcfba9599, 0xb8bda50f, 0x2802b89e, 0x5f058808, 0xc60cd9b2, 0xb10be924,
805 	0x2f6f7c87, 0x58684c11, 0xc1611dab, 0xb6662d3d,	0x76dc4190, 0x01db7106,
806 	0x98d220bc, 0xefd5102a, 0x71b18589, 0x06b6b51f, 0x9fbfe4a5, 0xe8b8d433,
807 	0x7807c9a2, 0x0f00f934, 0x9609a88e, 0xe10e9818, 0x7f6a0dbb, 0x086d3d2d,
808 	0x91646c97, 0xe6635c01, 0x6b6b51f4, 0x1c6c6162, 0x856530d8, 0xf262004e,
809 	0x6c0695ed, 0x1b01a57b, 0x8208f4c1, 0xf50fc457, 0x65b0d9c6, 0x12b7e950,
810 	0x8bbeb8ea, 0xfcb9887c, 0x62dd1ddf, 0x15da2d49, 0x8cd37cf3, 0xfbd44c65,
811 	0x4db26158, 0x3ab551ce, 0xa3bc0074, 0xd4bb30e2, 0x4adfa541, 0x3dd895d7,
812 	0xa4d1c46d, 0xd3d6f4fb, 0x4369e96a, 0x346ed9fc, 0xad678846, 0xda60b8d0,
813 	0x44042d73, 0x33031de5, 0xaa0a4c5f, 0xdd0d7cc9, 0x5005713c, 0x270241aa,
814 	0xbe0b1010, 0xc90c2086, 0x5768b525, 0x206f85b3, 0xb966d409, 0xce61e49f,
815 	0x5edef90e, 0x29d9c998, 0xb0d09822, 0xc7d7a8b4, 0x59b33d17, 0x2eb40d81,
816 	0xb7bd5c3b, 0xc0ba6cad, 0xedb88320, 0x9abfb3b6, 0x03b6e20c, 0x74b1d29a,
817 	0xead54739, 0x9dd277af, 0x04db2615, 0x73dc1683, 0xe3630b12, 0x94643b84,
818 	0x0d6d6a3e, 0x7a6a5aa8, 0xe40ecf0b, 0x9309ff9d, 0x0a00ae27, 0x7d079eb1,
819 	0xf00f9344, 0x8708a3d2, 0x1e01f268, 0x6906c2fe, 0xf762575d, 0x806567cb,
820 	0x196c3671, 0x6e6b06e7, 0xfed41b76, 0x89d32be0, 0x10da7a5a, 0x67dd4acc,
821 	0xf9b9df6f, 0x8ebeeff9, 0x17b7be43, 0x60b08ed5, 0xd6d6a3e8, 0xa1d1937e,
822 	0x38d8c2c4, 0x4fdff252, 0xd1bb67f1, 0xa6bc5767, 0x3fb506dd, 0x48b2364b,
823 	0xd80d2bda, 0xaf0a1b4c, 0x36034af6, 0x41047a60, 0xdf60efc3, 0xa867df55,
824 	0x316e8eef, 0x4669be79, 0xcb61b38c, 0xbc66831a, 0x256fd2a0, 0x5268e236,
825 	0xcc0c7795, 0xbb0b4703, 0x220216b9, 0x5505262f, 0xc5ba3bbe, 0xb2bd0b28,
826 	0x2bb45a92, 0x5cb36a04, 0xc2d7ffa7, 0xb5d0cf31, 0x2cd99e8b, 0x5bdeae1d,
827 	0x9b64c2b0, 0xec63f226, 0x756aa39c, 0x026d930a, 0x9c0906a9, 0xeb0e363f,
828 	0x72076785, 0x05005713, 0x95bf4a82, 0xe2b87a14, 0x7bb12bae, 0x0cb61b38,
829 	0x92d28e9b, 0xe5d5be0d, 0x7cdcefb7, 0x0bdbdf21, 0x86d3d2d4, 0xf1d4e242,
830 	0x68ddb3f8, 0x1fda836e, 0x81be16cd, 0xf6b9265b, 0x6fb077e1, 0x18b74777,
831 	0x88085ae6, 0xff0f6a70, 0x66063bca, 0x11010b5c, 0x8f659eff, 0xf862ae69,
832 	0x616bffd3, 0x166ccf45, 0xa00ae278, 0xd70dd2ee, 0x4e048354, 0x3903b3c2,
833 	0xa7672661, 0xd06016f7, 0x4969474d, 0x3e6e77db, 0xaed16a4a, 0xd9d65adc,
834 	0x40df0b66, 0x37d83bf0, 0xa9bcae53, 0xdebb9ec5, 0x47b2cf7f, 0x30b5ffe9,
835 	0xbdbdf21c, 0xcabac28a, 0x53b39330, 0x24b4a3a6, 0xbad03605, 0xcdd70693,
836 	0x54de5729, 0x23d967bf, 0xb3667a2e, 0xc4614ab8, 0x5d681b02, 0x2a6f2b94,
837 	0xb40bbe37, 0xc30c8ea1, 0x5a05df1b, 0x2d02ef8d
838 };
839 
840 Static uint32_t
841 cdce_crc32(const void *buf, size_t size)
842 {
843 	const uint8_t *p;
844 	uint32_t crc;
845 
846 	p = buf;
847 	crc = ~0U;
848 
849 	while (size--)
850 		crc = cdce_crc32_tab[(crc ^ *p++) & 0xFF] ^ (crc >> 8);
851 
852 	return (crc ^ ~0U);
853 }
854