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