1 /* $OpenBSD: if_cdce.c,v 1.82 2024/01/04 08:41:59 kevlo 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 * https://www.usb.org/sites/default/files/CDC1.2_WMC1.1_012011.zip 40 * 41 */ 42 43 #include <bpfilter.h> 44 45 #include <sys/param.h> 46 #include <sys/systm.h> 47 #include <sys/sockio.h> 48 #include <sys/mbuf.h> 49 #include <sys/kernel.h> 50 #include <sys/socket.h> 51 #include <sys/device.h> 52 53 #include <net/if.h> 54 55 #if NBPFILTER > 0 56 #include <net/bpf.h> 57 #endif 58 59 #include <netinet/in.h> 60 #include <netinet/if_ether.h> 61 62 #include <dev/usb/usb.h> 63 #include <dev/usb/usbdi.h> 64 #include <dev/usb/usbdi_util.h> 65 #include <dev/usb/usbdevs.h> 66 #include <dev/usb/usbcdc.h> 67 68 #include <dev/usb/if_cdcereg.h> 69 70 #ifdef CDCE_DEBUG 71 #define DPRINTFN(n, x) do { if (cdcedebug > (n)) printf x; } while (0) 72 int cdcedebug = 0; 73 #else 74 #define DPRINTFN(n, x) 75 #endif 76 #define DPRINTF(x) DPRINTFN(0, x) 77 78 int cdce_tx_list_init(struct cdce_softc *); 79 int cdce_rx_list_init(struct cdce_softc *); 80 int cdce_newbuf(struct cdce_softc *, struct cdce_chain *, 81 struct mbuf *); 82 int cdce_encap(struct cdce_softc *, struct mbuf *, int); 83 void cdce_rxeof(struct usbd_xfer *, void *, usbd_status); 84 void cdce_txeof(struct usbd_xfer *, void *, usbd_status); 85 void cdce_start(struct ifnet *); 86 int cdce_ioctl(struct ifnet *, u_long, caddr_t); 87 void cdce_init(void *); 88 void cdce_watchdog(struct ifnet *); 89 void cdce_stop(struct cdce_softc *); 90 void cdce_intr(struct usbd_xfer *, void *, usbd_status); 91 92 const struct cdce_type cdce_devs[] = { 93 {{ USB_VENDOR_ACERLABS, USB_PRODUCT_ACERLABS_M5632 }, 0 }, 94 {{ USB_VENDOR_PROLIFIC, USB_PRODUCT_PROLIFIC_PL2501 }, 0 }, 95 {{ USB_VENDOR_SHARP, USB_PRODUCT_SHARP_SL5500 }, CDCE_CRC32 }, 96 {{ USB_VENDOR_SHARP, USB_PRODUCT_SHARP_A300 }, CDCE_CRC32 }, 97 {{ USB_VENDOR_SHARP, USB_PRODUCT_SHARP_SL5600 }, CDCE_CRC32 }, 98 {{ USB_VENDOR_SHARP, USB_PRODUCT_SHARP_C700 }, CDCE_CRC32 }, 99 {{ USB_VENDOR_SHARP, USB_PRODUCT_SHARP_C750 }, CDCE_CRC32 }, 100 {{ USB_VENDOR_MOTOROLA2, USB_PRODUCT_MOTOROLA2_USBLAN }, CDCE_CRC32 }, 101 {{ USB_VENDOR_MOTOROLA2, USB_PRODUCT_MOTOROLA2_USBLAN2 }, CDCE_CRC32 }, 102 {{ USB_VENDOR_GMATE, USB_PRODUCT_GMATE_YP3X00 }, 0 }, 103 {{ USB_VENDOR_COMPAQ, USB_PRODUCT_COMPAQ_IPAQLINUX }, 0 }, 104 {{ USB_VENDOR_AMBIT, USB_PRODUCT_AMBIT_NTL_250 }, CDCE_SWAPUNION }, 105 }; 106 #define cdce_lookup(v, p) \ 107 ((const struct cdce_type *)usb_lookup(cdce_devs, v, p)) 108 109 int cdce_match(struct device *, void *, void *); 110 void cdce_attach(struct device *, struct device *, void *); 111 int cdce_detach(struct device *, int); 112 113 struct cfdriver cdce_cd = { 114 NULL, "cdce", DV_IFNET 115 }; 116 117 const struct cfattach cdce_ca = { 118 sizeof(struct cdce_softc), cdce_match, cdce_attach, cdce_detach 119 }; 120 121 int 122 cdce_match(struct device *parent, void *match, void *aux) 123 { 124 struct usb_attach_arg *uaa = aux; 125 usb_interface_descriptor_t *id; 126 127 if (uaa->iface == NULL) 128 return (UMATCH_NONE); 129 130 id = usbd_get_interface_descriptor(uaa->iface); 131 if (id == NULL) 132 return (UMATCH_NONE); 133 134 if (cdce_lookup(uaa->vendor, uaa->product) != NULL) 135 return (UMATCH_VENDOR_PRODUCT); 136 137 if (id->bInterfaceClass == UICLASS_CDC && 138 (id->bInterfaceSubClass == 139 UISUBCLASS_ETHERNET_NETWORKING_CONTROL_MODEL || 140 id->bInterfaceSubClass == UISUBCLASS_MOBILE_DIRECT_LINE_MODEL)) 141 return (UMATCH_IFACECLASS_GENERIC); 142 143 return (UMATCH_NONE); 144 } 145 146 void 147 cdce_attach(struct device *parent, struct device *self, void *aux) 148 { 149 struct cdce_softc *sc = (struct cdce_softc *)self; 150 struct usb_attach_arg *uaa = aux; 151 int s; 152 struct ifnet *ifp = GET_IFP(sc); 153 struct usbd_device *dev = uaa->device; 154 const struct cdce_type *t; 155 usb_interface_descriptor_t *id; 156 usb_endpoint_descriptor_t *ed; 157 struct usb_cdc_union_descriptor *ud; 158 struct usb_cdc_ethernet_descriptor *ethd; 159 usb_config_descriptor_t *cd; 160 const usb_descriptor_t *desc; 161 struct usbd_desc_iter iter; 162 usb_string_descriptor_t eaddr_str; 163 int i, j, numalts, len; 164 int ctl_ifcno = -1; 165 int data_ifcno = -1; 166 167 sc->cdce_udev = uaa->device; 168 sc->cdce_ctl_iface = uaa->iface; 169 id = usbd_get_interface_descriptor(sc->cdce_ctl_iface); 170 ctl_ifcno = id->bInterfaceNumber; 171 172 t = cdce_lookup(uaa->vendor, uaa->product); 173 if (t) 174 sc->cdce_flags = t->cdce_flags; 175 176 /* Get the data interface no. and capabilities */ 177 ethd = NULL; 178 usbd_desc_iter_init(dev, &iter); 179 desc = usbd_desc_iter_next(&iter); 180 while (desc) { 181 if (desc->bDescriptorType != UDESC_CS_INTERFACE) { 182 desc = usbd_desc_iter_next(&iter); 183 continue; 184 } 185 switch(desc->bDescriptorSubtype) { 186 case UDESCSUB_CDC_UNION: 187 ud = (struct usb_cdc_union_descriptor *)desc; 188 if ((sc->cdce_flags & CDCE_SWAPUNION) == 0 && 189 ud->bMasterInterface == ctl_ifcno) 190 data_ifcno = ud->bSlaveInterface[0]; 191 if ((sc->cdce_flags & CDCE_SWAPUNION) && 192 ud->bSlaveInterface[0] == ctl_ifcno) 193 data_ifcno = ud->bMasterInterface; 194 break; 195 case UDESCSUB_CDC_ENF: 196 if (ethd) { 197 printf("%s: ", sc->cdce_dev.dv_xname); 198 printf("extra ethernet descriptor\n"); 199 return; 200 } 201 ethd = (struct usb_cdc_ethernet_descriptor *)desc; 202 break; 203 } 204 desc = usbd_desc_iter_next(&iter); 205 } 206 207 if (data_ifcno == -1) { 208 DPRINTF(("cdce_attach: no union interface\n")); 209 sc->cdce_data_iface = sc->cdce_ctl_iface; 210 } else { 211 DPRINTF(("cdce_attach: union interface: ctl=%d, data=%d\n", 212 ctl_ifcno, data_ifcno)); 213 for (i = 0; i < uaa->nifaces; i++) { 214 if (usbd_iface_claimed(sc->cdce_udev, i)) 215 continue; 216 id = usbd_get_interface_descriptor(uaa->ifaces[i]); 217 if (id != NULL && id->bInterfaceNumber == data_ifcno) { 218 sc->cdce_data_iface = uaa->ifaces[i]; 219 usbd_claim_iface(sc->cdce_udev, i); 220 } 221 } 222 } 223 224 if (sc->cdce_data_iface == NULL) { 225 printf("%s: no data interface\n", sc->cdce_dev.dv_xname); 226 return; 227 } 228 229 id = usbd_get_interface_descriptor(sc->cdce_ctl_iface); 230 sc->cdce_intr_no = -1; 231 for (i = 0; i < id->bNumEndpoints && sc->cdce_intr_no == -1; i++) { 232 ed = usbd_interface2endpoint_descriptor(sc->cdce_ctl_iface, i); 233 if (!ed) { 234 printf("%s: no descriptor for interrupt endpoint %d\n", 235 sc->cdce_dev.dv_xname, i); 236 return; 237 } 238 if (UE_GET_DIR(ed->bEndpointAddress) == UE_DIR_IN && 239 UE_GET_XFERTYPE(ed->bmAttributes) == UE_INTERRUPT) { 240 sc->cdce_intr_no = ed->bEndpointAddress; 241 sc->cdce_intr_size = sizeof(sc->cdce_intr_buf); 242 } 243 } 244 245 id = usbd_get_interface_descriptor(sc->cdce_data_iface); 246 cd = usbd_get_config_descriptor(sc->cdce_udev); 247 numalts = usbd_get_no_alts(cd, id->bInterfaceNumber); 248 249 for (j = 0; j < numalts; j++) { 250 if (usbd_set_interface(sc->cdce_data_iface, j)) { 251 printf("%s: interface alternate setting %d failed\n", 252 sc->cdce_dev.dv_xname, j); 253 return; 254 } 255 /* Find endpoints. */ 256 id = usbd_get_interface_descriptor(sc->cdce_data_iface); 257 sc->cdce_bulkin_no = sc->cdce_bulkout_no = -1; 258 for (i = 0; i < id->bNumEndpoints; i++) { 259 ed = usbd_interface2endpoint_descriptor( 260 sc->cdce_data_iface, i); 261 if (!ed) { 262 printf("%s: no descriptor for bulk endpoint " 263 "%d\n", sc->cdce_dev.dv_xname, i); 264 return; 265 } 266 if (UE_GET_DIR(ed->bEndpointAddress) == UE_DIR_IN && 267 UE_GET_XFERTYPE(ed->bmAttributes) == UE_BULK) { 268 sc->cdce_bulkin_no = ed->bEndpointAddress; 269 } else if ( 270 UE_GET_DIR(ed->bEndpointAddress) == UE_DIR_OUT && 271 UE_GET_XFERTYPE(ed->bmAttributes) == UE_BULK) { 272 sc->cdce_bulkout_no = ed->bEndpointAddress; 273 } 274 #ifdef CDCE_DEBUG 275 else if ( 276 UE_GET_DIR(ed->bEndpointAddress) != UE_DIR_IN && 277 UE_GET_XFERTYPE(ed->bmAttributes) != UE_INTERRUPT) { 278 printf("%s: unexpected endpoint, ep=%x attr=%x" 279 "\n", sc->cdce_dev.dv_xname, 280 ed->bEndpointAddress, ed->bmAttributes); 281 } 282 #endif 283 } 284 if ((sc->cdce_bulkin_no != -1) && (sc->cdce_bulkout_no != -1)) { 285 DPRINTF(("cdce_attach: intr=0x%x, in=0x%x, out=0x%x\n", 286 sc->cdce_intr_no, sc->cdce_bulkin_no, 287 sc->cdce_bulkout_no)); 288 goto found; 289 } 290 } 291 292 if (sc->cdce_bulkin_no == -1) { 293 printf("%s: could not find data bulk in\n", 294 sc->cdce_dev.dv_xname); 295 return; 296 } 297 if (sc->cdce_bulkout_no == -1 ) { 298 printf("%s: could not find data bulk out\n", 299 sc->cdce_dev.dv_xname); 300 return; 301 } 302 303 found: 304 s = splnet(); 305 306 if (!ethd || usbd_get_string_desc(sc->cdce_udev, ethd->iMacAddress, 0, 307 &eaddr_str, &len)) { 308 ether_fakeaddr(ifp); 309 } else { 310 for (i = 0; i < ETHER_ADDR_LEN * 2; i++) { 311 int c = UGETW(eaddr_str.bString[i]); 312 313 if ('0' <= c && c <= '9') 314 c -= '0'; 315 else if ('A' <= c && c <= 'F') 316 c -= 'A' - 10; 317 else if ('a' <= c && c <= 'f') 318 c -= 'a' - 10; 319 c &= 0xf; 320 if (i % 2 == 0) 321 c <<= 4; 322 sc->cdce_arpcom.ac_enaddr[i / 2] |= c; 323 } 324 } 325 326 printf("%s: address %s\n", sc->cdce_dev.dv_xname, 327 ether_sprintf(sc->cdce_arpcom.ac_enaddr)); 328 329 ifp->if_softc = sc; 330 ifp->if_flags = IFF_BROADCAST | IFF_SIMPLEX | IFF_MULTICAST; 331 ifp->if_ioctl = cdce_ioctl; 332 ifp->if_start = cdce_start; 333 ifp->if_watchdog = cdce_watchdog; 334 strlcpy(ifp->if_xname, sc->cdce_dev.dv_xname, IFNAMSIZ); 335 336 if_attach(ifp); 337 ether_ifattach(ifp); 338 339 sc->cdce_attached = 1; 340 splx(s); 341 } 342 343 int 344 cdce_detach(struct device *self, int flags) 345 { 346 struct cdce_softc *sc = (struct cdce_softc *)self; 347 struct ifnet *ifp = GET_IFP(sc); 348 int s; 349 350 if (!sc->cdce_attached) 351 return (0); 352 353 s = splusb(); 354 355 if (ifp->if_flags & IFF_RUNNING) 356 cdce_stop(sc); 357 358 if (ifp->if_softc != NULL) { 359 ether_ifdetach(ifp); 360 if_detach(ifp); 361 } 362 363 sc->cdce_attached = 0; 364 splx(s); 365 366 return (0); 367 } 368 369 void 370 cdce_start(struct ifnet *ifp) 371 { 372 struct cdce_softc *sc = ifp->if_softc; 373 struct mbuf *m_head = NULL; 374 375 if (usbd_is_dying(sc->cdce_udev) || ifq_is_oactive(&ifp->if_snd)) 376 return; 377 378 m_head = ifq_dequeue(&ifp->if_snd); 379 if (m_head == NULL) 380 return; 381 382 if (cdce_encap(sc, m_head, 0)) { 383 m_freem(m_head); 384 ifq_set_oactive(&ifp->if_snd); 385 return; 386 } 387 388 #if NBPFILTER > 0 389 if (ifp->if_bpf) 390 bpf_mtap(ifp->if_bpf, m_head, BPF_DIRECTION_OUT); 391 #endif 392 393 ifq_set_oactive(&ifp->if_snd); 394 395 ifp->if_timer = 6; 396 } 397 398 int 399 cdce_encap(struct cdce_softc *sc, struct mbuf *m, int idx) 400 { 401 struct cdce_chain *c; 402 usbd_status err; 403 int extra = 0; 404 405 c = &sc->cdce_cdata.cdce_tx_chain[idx]; 406 407 m_copydata(m, 0, m->m_pkthdr.len, c->cdce_buf); 408 if (sc->cdce_flags & CDCE_CRC32) { 409 /* Some devices want a 32-bit CRC appended to every frame */ 410 u_int32_t crc; 411 412 crc = ether_crc32_le(c->cdce_buf, m->m_pkthdr.len) ^ ~0U; 413 bcopy(&crc, c->cdce_buf + m->m_pkthdr.len, 4); 414 extra = 4; 415 } 416 c->cdce_mbuf = m; 417 418 usbd_setup_xfer(c->cdce_xfer, sc->cdce_bulkout_pipe, c, c->cdce_buf, 419 m->m_pkthdr.len + extra, USBD_FORCE_SHORT_XFER | USBD_NO_COPY, 420 10000, cdce_txeof); 421 err = usbd_transfer(c->cdce_xfer); 422 if (err != USBD_IN_PROGRESS) { 423 c->cdce_mbuf = NULL; 424 cdce_stop(sc); 425 return (EIO); 426 } 427 428 sc->cdce_cdata.cdce_tx_cnt++; 429 430 return (0); 431 } 432 433 void 434 cdce_stop(struct cdce_softc *sc) 435 { 436 usbd_status err; 437 struct ifnet *ifp = GET_IFP(sc); 438 int i; 439 440 ifp->if_timer = 0; 441 ifp->if_flags &= ~IFF_RUNNING; 442 ifq_clr_oactive(&ifp->if_snd); 443 444 if (sc->cdce_bulkin_pipe != NULL) { 445 err = usbd_close_pipe(sc->cdce_bulkin_pipe); 446 if (err) 447 printf("%s: close rx pipe failed: %s\n", 448 sc->cdce_dev.dv_xname, usbd_errstr(err)); 449 sc->cdce_bulkin_pipe = NULL; 450 } 451 452 if (sc->cdce_bulkout_pipe != NULL) { 453 err = usbd_close_pipe(sc->cdce_bulkout_pipe); 454 if (err) 455 printf("%s: close tx pipe failed: %s\n", 456 sc->cdce_dev.dv_xname, usbd_errstr(err)); 457 sc->cdce_bulkout_pipe = NULL; 458 } 459 460 if (sc->cdce_intr_pipe != NULL) { 461 err = usbd_close_pipe(sc->cdce_intr_pipe); 462 if (err) 463 printf("%s: close interrupt pipe failed: %s\n", 464 sc->cdce_dev.dv_xname, usbd_errstr(err)); 465 sc->cdce_intr_pipe = NULL; 466 } 467 468 for (i = 0; i < CDCE_RX_LIST_CNT; i++) { 469 if (sc->cdce_cdata.cdce_rx_chain[i].cdce_mbuf != NULL) { 470 m_freem(sc->cdce_cdata.cdce_rx_chain[i].cdce_mbuf); 471 sc->cdce_cdata.cdce_rx_chain[i].cdce_mbuf = NULL; 472 } 473 if (sc->cdce_cdata.cdce_rx_chain[i].cdce_xfer != NULL) { 474 usbd_free_xfer(sc->cdce_cdata.cdce_rx_chain[i].cdce_xfer); 475 sc->cdce_cdata.cdce_rx_chain[i].cdce_xfer = NULL; 476 } 477 } 478 479 for (i = 0; i < CDCE_TX_LIST_CNT; i++) { 480 if (sc->cdce_cdata.cdce_tx_chain[i].cdce_mbuf != NULL) { 481 m_freem(sc->cdce_cdata.cdce_tx_chain[i].cdce_mbuf); 482 sc->cdce_cdata.cdce_tx_chain[i].cdce_mbuf = NULL; 483 } 484 if (sc->cdce_cdata.cdce_tx_chain[i].cdce_xfer != NULL) { 485 usbd_free_xfer( 486 sc->cdce_cdata.cdce_tx_chain[i].cdce_xfer); 487 sc->cdce_cdata.cdce_tx_chain[i].cdce_xfer = NULL; 488 } 489 } 490 } 491 492 int 493 cdce_ioctl(struct ifnet *ifp, u_long command, caddr_t data) 494 { 495 struct cdce_softc *sc = ifp->if_softc; 496 int s, error = 0; 497 498 if (usbd_is_dying(sc->cdce_udev)) 499 return ENXIO; 500 501 s = splnet(); 502 503 switch(command) { 504 case SIOCSIFADDR: 505 ifp->if_flags |= IFF_UP; 506 if (!(ifp->if_flags & IFF_RUNNING)) 507 cdce_init(sc); 508 break; 509 510 case SIOCSIFFLAGS: 511 if (ifp->if_flags & IFF_UP) { 512 if (ifp->if_flags & IFF_RUNNING) 513 error = ENETRESET; 514 else 515 cdce_init(sc); 516 } else { 517 if (ifp->if_flags & IFF_RUNNING) 518 cdce_stop(sc); 519 } 520 break; 521 522 default: 523 error = ether_ioctl(ifp, &sc->cdce_arpcom, command, data); 524 break; 525 } 526 527 if (error == ENETRESET) 528 error = 0; 529 530 splx(s); 531 return (error); 532 } 533 534 void 535 cdce_watchdog(struct ifnet *ifp) 536 { 537 struct cdce_softc *sc = ifp->if_softc; 538 539 if (usbd_is_dying(sc->cdce_udev)) 540 return; 541 542 ifp->if_oerrors++; 543 printf("%s: watchdog timeout\n", sc->cdce_dev.dv_xname); 544 } 545 546 void 547 cdce_init(void *xsc) 548 { 549 struct cdce_softc *sc = xsc; 550 struct ifnet *ifp = GET_IFP(sc); 551 struct cdce_chain *c; 552 usbd_status err; 553 int s, i; 554 555 s = splnet(); 556 557 if (sc->cdce_intr_no != -1 && sc->cdce_intr_pipe == NULL) { 558 DPRINTFN(1, ("cdce_init: establish interrupt pipe\n")); 559 err = usbd_open_pipe_intr(sc->cdce_ctl_iface, sc->cdce_intr_no, 560 USBD_SHORT_XFER_OK, &sc->cdce_intr_pipe, sc, 561 &sc->cdce_intr_buf, sc->cdce_intr_size, cdce_intr, 562 USBD_DEFAULT_INTERVAL); 563 if (err) { 564 printf("%s: open interrupt pipe failed: %s\n", 565 sc->cdce_dev.dv_xname, usbd_errstr(err)); 566 splx(s); 567 return; 568 } 569 } 570 571 if (cdce_tx_list_init(sc) == ENOBUFS) { 572 printf("%s: tx list init failed\n", sc->cdce_dev.dv_xname); 573 splx(s); 574 return; 575 } 576 577 if (cdce_rx_list_init(sc) == ENOBUFS) { 578 printf("%s: rx list init failed\n", sc->cdce_dev.dv_xname); 579 splx(s); 580 return; 581 } 582 583 /* Maybe set multicast / broadcast here??? */ 584 585 err = usbd_open_pipe(sc->cdce_data_iface, sc->cdce_bulkin_no, 586 USBD_EXCLUSIVE_USE, &sc->cdce_bulkin_pipe); 587 if (err) { 588 printf("%s: open rx pipe failed: %s\n", sc->cdce_dev.dv_xname, 589 usbd_errstr(err)); 590 splx(s); 591 return; 592 } 593 594 err = usbd_open_pipe(sc->cdce_data_iface, sc->cdce_bulkout_no, 595 USBD_EXCLUSIVE_USE, &sc->cdce_bulkout_pipe); 596 if (err) { 597 printf("%s: open tx pipe failed: %s\n", sc->cdce_dev.dv_xname, 598 usbd_errstr(err)); 599 splx(s); 600 return; 601 } 602 603 for (i = 0; i < CDCE_RX_LIST_CNT; i++) { 604 c = &sc->cdce_cdata.cdce_rx_chain[i]; 605 usbd_setup_xfer(c->cdce_xfer, sc->cdce_bulkin_pipe, c, 606 c->cdce_buf, CDCE_BUFSZ, USBD_SHORT_XFER_OK | USBD_NO_COPY, 607 USBD_NO_TIMEOUT, cdce_rxeof); 608 usbd_transfer(c->cdce_xfer); 609 } 610 611 ifp->if_flags |= IFF_RUNNING; 612 ifq_clr_oactive(&ifp->if_snd); 613 614 splx(s); 615 } 616 617 int 618 cdce_newbuf(struct cdce_softc *sc, struct cdce_chain *c, struct mbuf *m) 619 { 620 struct mbuf *m_new = NULL; 621 622 if (m == NULL) { 623 MGETHDR(m_new, M_DONTWAIT, MT_DATA); 624 if (m_new == NULL) { 625 printf("%s: no memory for rx list " 626 "-- packet dropped!\n", sc->cdce_dev.dv_xname); 627 return (ENOBUFS); 628 } 629 MCLGET(m_new, M_DONTWAIT); 630 if (!(m_new->m_flags & M_EXT)) { 631 printf("%s: no memory for rx list " 632 "-- packet dropped!\n", sc->cdce_dev.dv_xname); 633 m_freem(m_new); 634 return (ENOBUFS); 635 } 636 m_new->m_len = m_new->m_pkthdr.len = MCLBYTES; 637 } else { 638 m_new = m; 639 m_new->m_len = m_new->m_pkthdr.len = MCLBYTES; 640 m_new->m_data = m_new->m_ext.ext_buf; 641 } 642 643 m_adj(m_new, ETHER_ALIGN); 644 c->cdce_mbuf = m_new; 645 return (0); 646 } 647 648 int 649 cdce_rx_list_init(struct cdce_softc *sc) 650 { 651 struct cdce_cdata *cd; 652 struct cdce_chain *c; 653 int i; 654 655 cd = &sc->cdce_cdata; 656 for (i = 0; i < CDCE_RX_LIST_CNT; i++) { 657 c = &cd->cdce_rx_chain[i]; 658 c->cdce_sc = sc; 659 c->cdce_idx = i; 660 if (cdce_newbuf(sc, c, NULL) == ENOBUFS) 661 return (ENOBUFS); 662 if (c->cdce_xfer == NULL) { 663 c->cdce_xfer = usbd_alloc_xfer(sc->cdce_udev); 664 if (c->cdce_xfer == NULL) 665 return (ENOBUFS); 666 c->cdce_buf = usbd_alloc_buffer(c->cdce_xfer, 667 CDCE_BUFSZ); 668 if (c->cdce_buf == NULL) 669 return (ENOBUFS); 670 } 671 } 672 673 return (0); 674 } 675 676 int 677 cdce_tx_list_init(struct cdce_softc *sc) 678 { 679 struct cdce_cdata *cd; 680 struct cdce_chain *c; 681 int i; 682 683 cd = &sc->cdce_cdata; 684 for (i = 0; i < CDCE_TX_LIST_CNT; i++) { 685 c = &cd->cdce_tx_chain[i]; 686 c->cdce_sc = sc; 687 c->cdce_idx = i; 688 c->cdce_mbuf = NULL; 689 if (c->cdce_xfer == NULL) { 690 c->cdce_xfer = usbd_alloc_xfer(sc->cdce_udev); 691 if (c->cdce_xfer == NULL) 692 return (ENOBUFS); 693 c->cdce_buf = usbd_alloc_buffer(c->cdce_xfer, 694 CDCE_BUFSZ); 695 if (c->cdce_buf == NULL) 696 return (ENOBUFS); 697 } 698 } 699 700 return (0); 701 } 702 703 void 704 cdce_rxeof(struct usbd_xfer *xfer, void *priv, usbd_status status) 705 { 706 struct cdce_chain *c = priv; 707 struct cdce_softc *sc = c->cdce_sc; 708 struct ifnet *ifp = GET_IFP(sc); 709 struct mbuf *m; 710 struct mbuf_list ml = MBUF_LIST_INITIALIZER(); 711 int total_len = 0; 712 int s; 713 714 if (usbd_is_dying(sc->cdce_udev) || !(ifp->if_flags & IFF_RUNNING)) 715 return; 716 717 if (status != USBD_NORMAL_COMPLETION) { 718 if (status == USBD_NOT_STARTED || status == USBD_CANCELLED) 719 return; 720 if (sc->cdce_rxeof_errors == 0) 721 printf("%s: usb error on rx: %s\n", 722 sc->cdce_dev.dv_xname, usbd_errstr(status)); 723 if (status == USBD_STALLED) 724 usbd_clear_endpoint_stall_async(sc->cdce_bulkin_pipe); 725 DELAY(sc->cdce_rxeof_errors * 10000); 726 if (sc->cdce_rxeof_errors++ > 10) { 727 printf("%s: too many errors, disabling\n", 728 sc->cdce_dev.dv_xname); 729 usbd_deactivate(sc->cdce_udev); 730 return; 731 } 732 goto done; 733 } 734 735 sc->cdce_rxeof_errors = 0; 736 737 usbd_get_xfer_status(xfer, NULL, NULL, &total_len, NULL); 738 if (sc->cdce_flags & CDCE_CRC32) 739 total_len -= 4; /* Strip off added CRC */ 740 if (total_len <= 1) 741 goto done; 742 743 m = c->cdce_mbuf; 744 memcpy(mtod(m, char *), c->cdce_buf, total_len); 745 746 if (total_len < sizeof(struct ether_header)) { 747 ifp->if_ierrors++; 748 goto done; 749 } 750 751 m->m_pkthdr.len = m->m_len = total_len; 752 ml_enqueue(&ml, m); 753 754 if (cdce_newbuf(sc, c, NULL) == ENOBUFS) { 755 ifp->if_ierrors++; 756 goto done; 757 } 758 759 s = splnet(); 760 if_input(ifp, &ml); 761 splx(s); 762 763 done: 764 /* Setup new transfer. */ 765 usbd_setup_xfer(c->cdce_xfer, sc->cdce_bulkin_pipe, c, c->cdce_buf, 766 CDCE_BUFSZ, USBD_SHORT_XFER_OK | USBD_NO_COPY, USBD_NO_TIMEOUT, 767 cdce_rxeof); 768 usbd_transfer(c->cdce_xfer); 769 } 770 771 void 772 cdce_txeof(struct usbd_xfer *xfer, void *priv, usbd_status status) 773 { 774 struct cdce_chain *c = priv; 775 struct cdce_softc *sc = c->cdce_sc; 776 struct ifnet *ifp = GET_IFP(sc); 777 usbd_status err; 778 int s; 779 780 if (usbd_is_dying(sc->cdce_udev)) 781 return; 782 783 s = splnet(); 784 785 ifp->if_timer = 0; 786 ifq_clr_oactive(&ifp->if_snd); 787 788 if (status != USBD_NORMAL_COMPLETION) { 789 if (status == USBD_NOT_STARTED || status == USBD_CANCELLED) { 790 splx(s); 791 return; 792 } 793 ifp->if_oerrors++; 794 printf("%s: usb error on tx: %s\n", sc->cdce_dev.dv_xname, 795 usbd_errstr(status)); 796 if (status == USBD_STALLED) 797 usbd_clear_endpoint_stall_async(sc->cdce_bulkout_pipe); 798 splx(s); 799 return; 800 } 801 802 usbd_get_xfer_status(c->cdce_xfer, NULL, NULL, NULL, &err); 803 804 if (c->cdce_mbuf != NULL) { 805 m_freem(c->cdce_mbuf); 806 c->cdce_mbuf = NULL; 807 } 808 809 if (err) 810 ifp->if_oerrors++; 811 812 if (ifq_empty(&ifp->if_snd) == 0) 813 cdce_start(ifp); 814 815 splx(s); 816 } 817 818 void 819 cdce_intr(struct usbd_xfer *xfer, void *addr, usbd_status status) 820 { 821 struct cdce_softc *sc = addr; 822 struct usb_cdc_notification *buf = &sc->cdce_intr_buf; 823 struct usb_cdc_connection_speed *speed; 824 u_int32_t count; 825 826 if (status == USBD_CANCELLED) 827 return; 828 829 if (status != USBD_NORMAL_COMPLETION) { 830 DPRINTFN(2, ("cdce_intr: status=%d\n", status)); 831 if (status == USBD_STALLED) 832 usbd_clear_endpoint_stall_async(sc->cdce_intr_pipe); 833 return; 834 } 835 836 usbd_get_xfer_status(xfer, NULL, NULL, &count, NULL); 837 838 if (buf->bmRequestType == UCDC_NOTIFICATION) { 839 switch (buf->bNotification) { 840 case UCDC_N_NETWORK_CONNECTION: 841 DPRINTFN(1, ("cdce_intr: network %s\n", 842 UGETW(buf->wValue) ? "connected" : "disconnected")); 843 break; 844 case UCDC_N_CONNECTION_SPEED_CHANGE: 845 speed = (struct usb_cdc_connection_speed *)&buf->data; 846 DPRINTFN(1, ("cdce_intr: up=%d, down=%d\n", 847 UGETDW(speed->dwUSBitRate), 848 UGETDW(speed->dwDSBitRate))); 849 break; 850 default: 851 DPRINTF(("cdce_intr: bNotification 0x%x\n", 852 buf->bNotification)); 853 } 854 } 855 #ifdef CDCE_DEBUG 856 else { 857 printf("cdce_intr: bmRequestType=%d ", buf->bmRequestType); 858 printf("wValue=%d wIndex=%d wLength=%d\n", UGETW(buf->wValue), 859 UGETW(buf->wIndex), UGETW(buf->wLength)); 860 } 861 #endif 862 } 863