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