LCOV - code coverage report
Current view: top level - dev/usb - if_cdce.c (source / functions) Hit Total Coverage
Test: 6.4 Lines: 0 457 0.0 %
Date: 2018-10-19 03:25:38 Functions: 0 15 0.0 %
Legend: Lines: hit not hit

          Line data    Source code
       1             : /*      $OpenBSD: if_cdce.c,v 1.74 2017/04/21 09:42:53 mpi Exp $ */
       2             : 
       3             : /*
       4             :  * Copyright (c) 1997, 1998, 1999, 2000-2003 Bill Paul <wpaul@windriver.com>
       5             :  * Copyright (c) 2003 Craig Boston
       6             :  * Copyright (c) 2004 Daniel Hartmeier
       7             :  * All rights reserved.
       8             :  *
       9             :  * Redistribution and use in source and binary forms, with or without
      10             :  * modification, are permitted provided that the following conditions
      11             :  * are met:
      12             :  * 1. Redistributions of source code must retain the above copyright
      13             :  *    notice, this list of conditions and the following disclaimer.
      14             :  * 2. Redistributions in binary form must reproduce the above copyright
      15             :  *    notice, this list of conditions and the following disclaimer in the
      16             :  *    documentation and/or other materials provided with the distribution.
      17             :  * 3. All advertising materials mentioning features or use of this software
      18             :  *    must display the following acknowledgement:
      19             :  *      This product includes software developed by Bill Paul.
      20             :  * 4. Neither the name of the author nor the names of any co-contributors
      21             :  *    may be used to endorse or promote products derived from this software
      22             :  *    without specific prior written permission.
      23             :  *
      24             :  * THIS SOFTWARE IS PROVIDED BY Bill Paul AND CONTRIBUTORS ``AS IS'' AND
      25             :  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
      26             :  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
      27             :  * ARE DISCLAIMED.  IN NO EVENT SHALL Bill Paul, THE VOICES IN HIS HEAD OR
      28             :  * THE CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
      29             :  * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
      30             :  * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
      31             :  * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
      32             :  * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
      33             :  * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
      34             :  * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
      35             :  */
      36             : 
      37             : /*
      38             :  * USB Communication Device Class (Ethernet Networking Control Model)
      39             :  * http://www.usb.org/developers/devclass_docs/usbcdc11.pdf
      40             :  *
      41             :  */
      42             : 
      43             : #include <bpfilter.h>
      44             : 
      45             : #include <sys/param.h>
      46             : #include <sys/systm.h>
      47             : #include <sys/sockio.h>
      48             : #include <sys/mbuf.h>
      49             : #include <sys/kernel.h>
      50             : #include <sys/socket.h>
      51             : #include <sys/device.h>
      52             : 
      53             : #include <net/if.h>
      54             : 
      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_NETCHIP, USB_PRODUCT_NETCHIP_ETHERNETGADGET }, 0 },
     104             :     {{ USB_VENDOR_COMPAQ, USB_PRODUCT_COMPAQ_IPAQLINUX }, 0 },
     105             :     {{ USB_VENDOR_AMBIT, USB_PRODUCT_AMBIT_NTL_250 }, CDCE_SWAPUNION },
     106             : };
     107             : #define cdce_lookup(v, p) \
     108             :     ((const struct cdce_type *)usb_lookup(cdce_devs, v, p))
     109             : 
     110             : int cdce_match(struct device *, void *, void *);
     111             : void cdce_attach(struct device *, struct device *, void *);
     112             : int cdce_detach(struct device *, int);
     113             : 
     114             : struct cfdriver cdce_cd = {
     115             :         NULL, "cdce", DV_IFNET
     116             : };
     117             : 
     118             : const struct cfattach cdce_ca = {
     119             :         sizeof(struct cdce_softc), cdce_match, cdce_attach, cdce_detach
     120             : };
     121             : 
     122             : int
     123           0 : cdce_match(struct device *parent, void *match, void *aux)
     124             : {
     125           0 :         struct usb_attach_arg *uaa = aux;
     126             :         usb_interface_descriptor_t *id;
     127             : 
     128           0 :         if (uaa->iface == NULL)
     129           0 :                 return (UMATCH_NONE);
     130             : 
     131           0 :         id = usbd_get_interface_descriptor(uaa->iface);
     132           0 :         if (id == NULL)
     133           0 :                 return (UMATCH_NONE);
     134             : 
     135           0 :         if (cdce_lookup(uaa->vendor, uaa->product) != NULL)
     136           0 :                 return (UMATCH_VENDOR_PRODUCT);
     137             : 
     138           0 :         if (id->bInterfaceClass == UICLASS_CDC &&
     139           0 :             (id->bInterfaceSubClass ==
     140           0 :             UISUBCLASS_ETHERNET_NETWORKING_CONTROL_MODEL ||
     141           0 :             id->bInterfaceSubClass == UISUBCLASS_MOBILE_DIRECT_LINE_MODEL))
     142           0 :                 return (UMATCH_IFACECLASS_GENERIC);
     143             : 
     144           0 :         return (UMATCH_NONE);
     145           0 : }
     146             : 
     147             : void
     148           0 : cdce_attach(struct device *parent, struct device *self, void *aux)
     149             : {
     150           0 :         struct cdce_softc               *sc = (struct cdce_softc *)self;
     151           0 :         struct usb_attach_arg           *uaa = aux;
     152             :         int                              s;
     153           0 :         struct ifnet                    *ifp = GET_IFP(sc);
     154           0 :         struct usbd_device              *dev = uaa->device;
     155             :         const struct cdce_type          *t;
     156             :         usb_interface_descriptor_t      *id;
     157             :         usb_endpoint_descriptor_t       *ed;
     158             :         struct usb_cdc_union_descriptor *ud;
     159             :         struct usb_cdc_ethernet_descriptor *ethd;
     160             :         usb_config_descriptor_t         *cd;
     161             :         const usb_descriptor_t          *desc;
     162           0 :         struct usbd_desc_iter            iter;
     163           0 :         usb_string_descriptor_t          eaddr_str;
     164           0 :         int                              i, j, numalts, len;
     165             :         int                              ctl_ifcno = -1;
     166             :         int                              data_ifcno = -1;
     167             : 
     168           0 :         sc->cdce_udev = uaa->device;
     169           0 :         sc->cdce_ctl_iface = uaa->iface;
     170           0 :         id = usbd_get_interface_descriptor(sc->cdce_ctl_iface);
     171           0 :         ctl_ifcno = id->bInterfaceNumber;
     172             : 
     173           0 :         t = cdce_lookup(uaa->vendor, uaa->product);
     174           0 :         if (t)
     175           0 :                 sc->cdce_flags = t->cdce_flags;
     176             : 
     177             :         /* Get the data interface no. and capabilities */
     178             :         ethd = NULL;
     179           0 :         usbd_desc_iter_init(dev, &iter);
     180           0 :         desc = usbd_desc_iter_next(&iter);
     181           0 :         while (desc) {
     182           0 :                 if (desc->bDescriptorType != UDESC_CS_INTERFACE) {
     183           0 :                         desc = usbd_desc_iter_next(&iter);
     184           0 :                         continue;
     185             :                 }
     186           0 :                 switch(desc->bDescriptorSubtype) {
     187             :                 case UDESCSUB_CDC_UNION:
     188           0 :                         ud = (struct usb_cdc_union_descriptor *)desc; 
     189           0 :                         if ((sc->cdce_flags & CDCE_SWAPUNION) == 0 &&
     190           0 :                             ud->bMasterInterface == ctl_ifcno)
     191           0 :                                 data_ifcno = ud->bSlaveInterface[0];
     192           0 :                         if ((sc->cdce_flags & CDCE_SWAPUNION) &&
     193           0 :                             ud->bSlaveInterface[0] == ctl_ifcno)
     194           0 :                                 data_ifcno = ud->bMasterInterface;
     195             :                         break;
     196             :                 case UDESCSUB_CDC_ENF:
     197           0 :                         if (ethd) {
     198           0 :                                 printf("%s: ", sc->cdce_dev.dv_xname);
     199           0 :                                 printf("extra ethernet descriptor\n");
     200           0 :                                 return;
     201             :                         }
     202           0 :                         ethd = (struct usb_cdc_ethernet_descriptor *)desc;
     203           0 :                         break;
     204             :                 }
     205           0 :                 desc = usbd_desc_iter_next(&iter);
     206             :         }
     207             : 
     208           0 :         if (data_ifcno == -1) {
     209             :                 DPRINTF(("cdce_attach: no union interface\n"));
     210           0 :                 sc->cdce_data_iface = sc->cdce_ctl_iface;
     211           0 :         } else {
     212             :                 DPRINTF(("cdce_attach: union interface: ctl=%d, data=%d\n",
     213             :                     ctl_ifcno, data_ifcno));
     214           0 :                 for (i = 0; i < uaa->nifaces; i++) {
     215           0 :                         if (usbd_iface_claimed(sc->cdce_udev, i))
     216             :                                 continue;
     217           0 :                         id = usbd_get_interface_descriptor(uaa->ifaces[i]);
     218           0 :                         if (id != NULL && id->bInterfaceNumber == data_ifcno) {
     219           0 :                                 sc->cdce_data_iface = uaa->ifaces[i];
     220           0 :                                 usbd_claim_iface(sc->cdce_udev, i);
     221           0 :                         }
     222             :                 }
     223             :         }
     224             : 
     225           0 :         if (sc->cdce_data_iface == NULL) {
     226           0 :                 printf("%s: no data interface\n", sc->cdce_dev.dv_xname);
     227           0 :                 return;
     228             :         }
     229             : 
     230           0 :         id = usbd_get_interface_descriptor(sc->cdce_ctl_iface);
     231           0 :         sc->cdce_intr_no = -1;
     232           0 :         for (i = 0; i < id->bNumEndpoints && sc->cdce_intr_no == -1; i++) {
     233           0 :                 ed = usbd_interface2endpoint_descriptor(sc->cdce_ctl_iface, i);
     234           0 :                 if (!ed) {
     235           0 :                         printf("%s: no descriptor for interrupt endpoint %d\n",
     236           0 :                             sc->cdce_dev.dv_xname, i);
     237           0 :                         return;
     238             :                 }
     239           0 :                 if (UE_GET_DIR(ed->bEndpointAddress) == UE_DIR_IN &&
     240           0 :                     UE_GET_XFERTYPE(ed->bmAttributes) == UE_INTERRUPT) {
     241           0 :                         sc->cdce_intr_no = ed->bEndpointAddress;
     242           0 :                         sc->cdce_intr_size = sizeof(sc->cdce_intr_buf);
     243           0 :                 }
     244             :         }
     245             : 
     246           0 :         id = usbd_get_interface_descriptor(sc->cdce_data_iface);
     247           0 :         cd = usbd_get_config_descriptor(sc->cdce_udev);
     248           0 :         numalts = usbd_get_no_alts(cd, id->bInterfaceNumber);
     249             : 
     250           0 :         for (j = 0; j < numalts; j++) {
     251           0 :                 if (usbd_set_interface(sc->cdce_data_iface, j)) {
     252           0 :                         printf("%s: interface alternate setting %d failed\n", 
     253           0 :                             sc->cdce_dev.dv_xname, j);
     254           0 :                         return;
     255             :                 } 
     256             :                 /* Find endpoints. */
     257           0 :                 id = usbd_get_interface_descriptor(sc->cdce_data_iface);
     258           0 :                 sc->cdce_bulkin_no = sc->cdce_bulkout_no = -1;
     259           0 :                 for (i = 0; i < id->bNumEndpoints; i++) {
     260           0 :                         ed = usbd_interface2endpoint_descriptor(
     261           0 :                             sc->cdce_data_iface, i);
     262           0 :                         if (!ed) {
     263           0 :                                 printf("%s: no descriptor for bulk endpoint "
     264           0 :                                     "%d\n", sc->cdce_dev.dv_xname, i);
     265           0 :                                 return;
     266             :                         }
     267           0 :                         if (UE_GET_DIR(ed->bEndpointAddress) == UE_DIR_IN &&
     268           0 :                             UE_GET_XFERTYPE(ed->bmAttributes) == UE_BULK) {
     269           0 :                                 sc->cdce_bulkin_no = ed->bEndpointAddress;
     270           0 :                         } else if (
     271           0 :                             UE_GET_DIR(ed->bEndpointAddress) == UE_DIR_OUT &&
     272           0 :                             UE_GET_XFERTYPE(ed->bmAttributes) == UE_BULK) {
     273           0 :                                 sc->cdce_bulkout_no = ed->bEndpointAddress;
     274           0 :                         }
     275             : #ifdef CDCE_DEBUG
     276             :                         else if (
     277             :                             UE_GET_DIR(ed->bEndpointAddress) != UE_DIR_IN &&
     278             :                             UE_GET_XFERTYPE(ed->bmAttributes) != UE_INTERRUPT) {
     279             :                                 printf("%s: unexpected endpoint, ep=%x attr=%x"
     280             :                                     "\n", sc->cdce_dev.dv_xname,
     281             :                                     ed->bEndpointAddress, ed->bmAttributes);
     282             :                         }
     283             : #endif
     284             :                 }
     285           0 :                 if ((sc->cdce_bulkin_no != -1) && (sc->cdce_bulkout_no != -1)) {
     286             :                         DPRINTF(("cdce_attach: intr=0x%x, in=0x%x, out=0x%x\n",
     287             :                             sc->cdce_intr_no, sc->cdce_bulkin_no,
     288             :                             sc->cdce_bulkout_no));
     289             :                         goto found;
     290             :                 }
     291             :         }
     292             :         
     293           0 :         if (sc->cdce_bulkin_no == -1) {
     294           0 :                 printf("%s: could not find data bulk in\n",
     295           0 :                     sc->cdce_dev.dv_xname);
     296           0 :                 return;
     297             :         }
     298           0 :         if (sc->cdce_bulkout_no == -1 ) {
     299           0 :                 printf("%s: could not find data bulk out\n",
     300           0 :                     sc->cdce_dev.dv_xname);
     301           0 :                 return;
     302             :         }
     303             : 
     304             : found:
     305           0 :         s = splnet();
     306             : 
     307           0 :         if (!ethd || usbd_get_string_desc(sc->cdce_udev, ethd->iMacAddress, 0,
     308             :             &eaddr_str, &len)) {
     309           0 :                 ether_fakeaddr(ifp);
     310           0 :         } else {
     311           0 :                 for (i = 0; i < ETHER_ADDR_LEN * 2; i++) {
     312           0 :                         int c = UGETW(eaddr_str.bString[i]);
     313             : 
     314           0 :                         if ('0' <= c && c <= '9')
     315           0 :                                 c -= '0';
     316           0 :                         else if ('A' <= c && c <= 'F')
     317           0 :                                 c -= 'A' - 10;
     318           0 :                         else if ('a' <= c && c <= 'f')
     319           0 :                                 c -= 'a' - 10;
     320           0 :                         c &= 0xf;
     321           0 :                         if (i % 2 == 0)
     322           0 :                                 c <<= 4;
     323           0 :                         sc->cdce_arpcom.ac_enaddr[i / 2] |= c;
     324             :                 }
     325             :         }
     326             : 
     327           0 :         printf("%s: address %s\n", sc->cdce_dev.dv_xname,
     328           0 :             ether_sprintf(sc->cdce_arpcom.ac_enaddr));
     329             : 
     330           0 :         ifp->if_softc = sc;
     331           0 :         ifp->if_flags = IFF_BROADCAST | IFF_SIMPLEX | IFF_MULTICAST;
     332           0 :         ifp->if_ioctl = cdce_ioctl;
     333           0 :         ifp->if_start = cdce_start;
     334           0 :         ifp->if_watchdog = cdce_watchdog;
     335           0 :         strlcpy(ifp->if_xname, sc->cdce_dev.dv_xname, IFNAMSIZ);
     336             : 
     337           0 :         if_attach(ifp);
     338           0 :         ether_ifattach(ifp);
     339             : 
     340           0 :         sc->cdce_attached = 1;
     341           0 :         splx(s);
     342           0 : }
     343             : 
     344             : int
     345           0 : cdce_detach(struct device *self, int flags)
     346             : {
     347           0 :         struct cdce_softc       *sc = (struct cdce_softc *)self;        
     348           0 :         struct ifnet            *ifp = GET_IFP(sc);
     349             :         int                      s;
     350             : 
     351           0 :         if (!sc->cdce_attached)
     352           0 :                 return (0);
     353             : 
     354           0 :         s = splusb();
     355             : 
     356           0 :         if (ifp->if_flags & IFF_RUNNING)
     357           0 :                 cdce_stop(sc);
     358             : 
     359           0 :         if (ifp->if_softc != NULL) {
     360           0 :                 ether_ifdetach(ifp);
     361           0 :                 if_detach(ifp);
     362           0 :         }
     363             : 
     364           0 :         sc->cdce_attached = 0;
     365           0 :         splx(s);
     366             : 
     367           0 :         return (0);
     368           0 : }
     369             : 
     370             : void
     371           0 : cdce_start(struct ifnet *ifp)
     372             : {
     373           0 :         struct cdce_softc       *sc = ifp->if_softc;
     374             :         struct mbuf             *m_head = NULL;
     375             : 
     376           0 :         if (usbd_is_dying(sc->cdce_udev) || ifq_is_oactive(&ifp->if_snd))
     377           0 :                 return;
     378             : 
     379           0 :         m_head = ifq_deq_begin(&ifp->if_snd);
     380           0 :         if (m_head == NULL)
     381           0 :                 return;
     382             : 
     383           0 :         if (cdce_encap(sc, m_head, 0)) {
     384           0 :                 ifq_deq_rollback(&ifp->if_snd, m_head);
     385           0 :                 ifq_set_oactive(&ifp->if_snd);
     386           0 :                 return;
     387             :         }
     388             : 
     389           0 :         ifq_deq_commit(&ifp->if_snd, m_head);
     390             : 
     391             : #if NBPFILTER > 0
     392           0 :         if (ifp->if_bpf)
     393           0 :                 bpf_mtap(ifp->if_bpf, m_head, BPF_DIRECTION_OUT);
     394             : #endif
     395             : 
     396           0 :         ifq_set_oactive(&ifp->if_snd);
     397             : 
     398           0 :         ifp->if_timer = 6;
     399           0 : }
     400             : 
     401             : int
     402           0 : cdce_encap(struct cdce_softc *sc, struct mbuf *m, int idx)
     403             : {
     404             :         struct cdce_chain       *c;
     405             :         usbd_status              err;
     406             :         int                      extra = 0;
     407             : 
     408           0 :         c = &sc->cdce_cdata.cdce_tx_chain[idx];
     409             : 
     410           0 :         m_copydata(m, 0, m->m_pkthdr.len, c->cdce_buf);
     411           0 :         if (sc->cdce_flags & CDCE_CRC32) {
     412             :                 /* Some devices want a 32-bit CRC appended to every frame */
     413           0 :                 u_int32_t crc;
     414             : 
     415           0 :                 crc = ether_crc32_le(c->cdce_buf, m->m_pkthdr.len) ^ ~0U;
     416           0 :                 bcopy(&crc, c->cdce_buf + m->m_pkthdr.len, 4);
     417             :                 extra = 4;
     418           0 :         }
     419           0 :         c->cdce_mbuf = m;
     420             : 
     421           0 :         usbd_setup_xfer(c->cdce_xfer, sc->cdce_bulkout_pipe, c, c->cdce_buf,
     422           0 :             m->m_pkthdr.len + extra, USBD_FORCE_SHORT_XFER | USBD_NO_COPY,
     423             :             10000, cdce_txeof);
     424           0 :         err = usbd_transfer(c->cdce_xfer);
     425           0 :         if (err != USBD_IN_PROGRESS) {
     426           0 :                 cdce_stop(sc);
     427           0 :                 return (EIO);
     428             :         }
     429             : 
     430           0 :         sc->cdce_cdata.cdce_tx_cnt++;
     431             : 
     432           0 :         return (0);
     433           0 : }
     434             : 
     435             : void
     436           0 : cdce_stop(struct cdce_softc *sc)
     437             : {
     438             :         usbd_status      err;
     439           0 :         struct ifnet    *ifp = GET_IFP(sc);
     440             :         int              i;
     441             : 
     442           0 :         ifp->if_timer = 0;
     443           0 :         ifp->if_flags &= ~IFF_RUNNING;
     444           0 :         ifq_clr_oactive(&ifp->if_snd);
     445             : 
     446           0 :         if (sc->cdce_bulkin_pipe != NULL) {
     447           0 :                 usbd_abort_pipe(sc->cdce_bulkin_pipe);
     448           0 :                 err = usbd_close_pipe(sc->cdce_bulkin_pipe);
     449           0 :                 if (err)
     450           0 :                         printf("%s: close rx pipe failed: %s\n",
     451           0 :                             sc->cdce_dev.dv_xname, usbd_errstr(err));
     452           0 :                 sc->cdce_bulkin_pipe = NULL;
     453           0 :         }
     454             : 
     455           0 :         if (sc->cdce_bulkout_pipe != NULL) {
     456           0 :                 usbd_abort_pipe(sc->cdce_bulkout_pipe);
     457           0 :                 err = usbd_close_pipe(sc->cdce_bulkout_pipe);
     458           0 :                 if (err)
     459           0 :                         printf("%s: close tx pipe failed: %s\n",
     460           0 :                             sc->cdce_dev.dv_xname, usbd_errstr(err));
     461           0 :                 sc->cdce_bulkout_pipe = NULL;
     462           0 :         }
     463             : 
     464           0 :         if (sc->cdce_intr_pipe != NULL) {
     465           0 :                 usbd_abort_pipe(sc->cdce_intr_pipe);
     466           0 :                 err = usbd_close_pipe(sc->cdce_intr_pipe);
     467           0 :                 if (err)
     468           0 :                         printf("%s: close interrupt pipe failed: %s\n",
     469           0 :                             sc->cdce_dev.dv_xname, usbd_errstr(err));
     470           0 :                 sc->cdce_intr_pipe = NULL;
     471           0 :         }
     472             : 
     473           0 :         for (i = 0; i < CDCE_RX_LIST_CNT; i++) {
     474           0 :                 if (sc->cdce_cdata.cdce_rx_chain[i].cdce_mbuf != NULL) {
     475           0 :                         m_freem(sc->cdce_cdata.cdce_rx_chain[i].cdce_mbuf);
     476           0 :                         sc->cdce_cdata.cdce_rx_chain[i].cdce_mbuf = NULL;
     477           0 :                 }
     478           0 :                 if (sc->cdce_cdata.cdce_rx_chain[i].cdce_xfer != NULL) {
     479           0 :                         usbd_free_xfer(sc->cdce_cdata.cdce_rx_chain[i].cdce_xfer);
     480           0 :                         sc->cdce_cdata.cdce_rx_chain[i].cdce_xfer = NULL;
     481           0 :                 }
     482             :         }
     483             : 
     484           0 :         for (i = 0; i < CDCE_TX_LIST_CNT; i++) {
     485           0 :                 if (sc->cdce_cdata.cdce_tx_chain[i].cdce_mbuf != NULL) {
     486           0 :                         m_freem(sc->cdce_cdata.cdce_tx_chain[i].cdce_mbuf);
     487           0 :                         sc->cdce_cdata.cdce_tx_chain[i].cdce_mbuf = NULL;
     488           0 :                 }
     489           0 :                 if (sc->cdce_cdata.cdce_tx_chain[i].cdce_xfer != NULL) {
     490           0 :                         usbd_free_xfer(
     491             :                             sc->cdce_cdata.cdce_tx_chain[i].cdce_xfer);
     492           0 :                         sc->cdce_cdata.cdce_tx_chain[i].cdce_xfer = NULL;
     493           0 :                 }
     494             :         }
     495           0 : }
     496             : 
     497             : int
     498           0 : cdce_ioctl(struct ifnet *ifp, u_long command, caddr_t data)
     499             : {
     500           0 :         struct cdce_softc       *sc = ifp->if_softc;
     501             :         int                      s, error = 0;
     502             : 
     503           0 :         if (usbd_is_dying(sc->cdce_udev))
     504           0 :                 return (EIO);
     505             : 
     506           0 :         s = splnet();
     507             : 
     508           0 :         switch(command) {
     509             :         case SIOCSIFADDR:
     510           0 :                 ifp->if_flags |= IFF_UP;
     511           0 :                 if (!(ifp->if_flags & IFF_RUNNING))
     512           0 :                         cdce_init(sc);
     513             :                 break;
     514             : 
     515             :         case SIOCSIFFLAGS:
     516           0 :                 if (ifp->if_flags & IFF_UP) {
     517           0 :                         if (ifp->if_flags & IFF_RUNNING)
     518           0 :                                 error = ENETRESET;
     519             :                         else
     520           0 :                                 cdce_init(sc);
     521             :                 } else {
     522           0 :                         if (ifp->if_flags & IFF_RUNNING)
     523           0 :                                 cdce_stop(sc);
     524             :                 }
     525             :                 break;
     526             : 
     527             :         default:
     528           0 :                 error = ether_ioctl(ifp, &sc->cdce_arpcom, command, data);
     529           0 :                 break;
     530             :         }
     531             : 
     532           0 :         if (error == ENETRESET)
     533           0 :                 error = 0;
     534             : 
     535           0 :         splx(s);
     536           0 :         return (error);
     537           0 : }
     538             : 
     539             : void
     540           0 : cdce_watchdog(struct ifnet *ifp)
     541             : {
     542           0 :         struct cdce_softc       *sc = ifp->if_softc;
     543             : 
     544           0 :         if (usbd_is_dying(sc->cdce_udev))
     545           0 :                 return;
     546             : 
     547           0 :         ifp->if_oerrors++;
     548           0 :         printf("%s: watchdog timeout\n", sc->cdce_dev.dv_xname);
     549           0 : }
     550             : 
     551             : void
     552           0 : cdce_init(void *xsc)
     553             : {
     554           0 :         struct cdce_softc       *sc = xsc;
     555           0 :         struct ifnet            *ifp = GET_IFP(sc);
     556             :         struct cdce_chain       *c;
     557             :         usbd_status              err;
     558             :         int                      s, i;
     559             : 
     560           0 :         s = splnet();
     561             : 
     562           0 :         if (sc->cdce_intr_no != -1 && sc->cdce_intr_pipe == NULL) {
     563             :                 DPRINTFN(1, ("cdce_init: establish interrupt pipe\n"));
     564           0 :                 err = usbd_open_pipe_intr(sc->cdce_ctl_iface, sc->cdce_intr_no,
     565             :                     USBD_SHORT_XFER_OK, &sc->cdce_intr_pipe, sc,
     566           0 :                     &sc->cdce_intr_buf, sc->cdce_intr_size, cdce_intr,
     567             :                     USBD_DEFAULT_INTERVAL);
     568           0 :                 if (err) {
     569           0 :                         printf("%s: open interrupt pipe failed: %s\n",
     570           0 :                             sc->cdce_dev.dv_xname, usbd_errstr(err));
     571           0 :                         splx(s);
     572           0 :                         return;
     573             :                 }
     574             :         }
     575             : 
     576           0 :         if (cdce_tx_list_init(sc) == ENOBUFS) {
     577           0 :                 printf("%s: tx list init failed\n", sc->cdce_dev.dv_xname);
     578           0 :                 splx(s);
     579           0 :                 return;
     580             :         }
     581             : 
     582           0 :         if (cdce_rx_list_init(sc) == ENOBUFS) {
     583           0 :                 printf("%s: rx list init failed\n", sc->cdce_dev.dv_xname);
     584           0 :                 splx(s);
     585           0 :                 return;
     586             :         }
     587             : 
     588             :         /* Maybe set multicast / broadcast here??? */
     589             : 
     590           0 :         err = usbd_open_pipe(sc->cdce_data_iface, sc->cdce_bulkin_no,
     591           0 :             USBD_EXCLUSIVE_USE, &sc->cdce_bulkin_pipe);
     592           0 :         if (err) {
     593           0 :                 printf("%s: open rx pipe failed: %s\n", sc->cdce_dev.dv_xname,
     594           0 :                     usbd_errstr(err));
     595           0 :                 splx(s);
     596           0 :                 return;
     597             :         }
     598             : 
     599           0 :         err = usbd_open_pipe(sc->cdce_data_iface, sc->cdce_bulkout_no,
     600           0 :             USBD_EXCLUSIVE_USE, &sc->cdce_bulkout_pipe);
     601           0 :         if (err) {
     602           0 :                 printf("%s: open tx pipe failed: %s\n", sc->cdce_dev.dv_xname,
     603           0 :                     usbd_errstr(err));
     604           0 :                 splx(s);
     605           0 :                 return;
     606             :         }
     607             : 
     608           0 :         for (i = 0; i < CDCE_RX_LIST_CNT; i++) {
     609           0 :                 c = &sc->cdce_cdata.cdce_rx_chain[i];
     610           0 :                 usbd_setup_xfer(c->cdce_xfer, sc->cdce_bulkin_pipe, c,
     611           0 :                     c->cdce_buf, CDCE_BUFSZ, USBD_SHORT_XFER_OK | USBD_NO_COPY,
     612             :                     USBD_NO_TIMEOUT, cdce_rxeof);
     613           0 :                 usbd_transfer(c->cdce_xfer);
     614             :         }
     615             : 
     616           0 :         ifp->if_flags |= IFF_RUNNING;
     617           0 :         ifq_clr_oactive(&ifp->if_snd);
     618             : 
     619           0 :         splx(s);
     620           0 : }
     621             : 
     622             : int
     623           0 : cdce_newbuf(struct cdce_softc *sc, struct cdce_chain *c, struct mbuf *m)
     624             : {
     625             :         struct mbuf     *m_new = NULL;
     626             : 
     627           0 :         if (m == NULL) {
     628           0 :                 MGETHDR(m_new, M_DONTWAIT, MT_DATA);
     629           0 :                 if (m_new == NULL) {
     630           0 :                         printf("%s: no memory for rx list "
     631           0 :                             "-- packet dropped!\n", sc->cdce_dev.dv_xname);
     632           0 :                         return (ENOBUFS);
     633             :                 }
     634           0 :                 MCLGET(m_new, M_DONTWAIT);
     635           0 :                 if (!(m_new->m_flags & M_EXT)) {
     636           0 :                         printf("%s: no memory for rx list "
     637           0 :                             "-- packet dropped!\n", sc->cdce_dev.dv_xname);
     638           0 :                         m_freem(m_new);
     639           0 :                         return (ENOBUFS);
     640             :                 }
     641           0 :                 m_new->m_len = m_new->m_pkthdr.len = MCLBYTES;
     642           0 :         } else {
     643             :                 m_new = m;
     644           0 :                 m_new->m_len = m_new->m_pkthdr.len = MCLBYTES;
     645           0 :                 m_new->m_data = m_new->m_ext.ext_buf;
     646             :         }
     647             : 
     648           0 :         m_adj(m_new, ETHER_ALIGN);
     649           0 :         c->cdce_mbuf = m_new;
     650           0 :         return (0);
     651           0 : }
     652             : 
     653             : int
     654           0 : cdce_rx_list_init(struct cdce_softc *sc)
     655             : {
     656             :         struct cdce_cdata       *cd;
     657             :         struct cdce_chain       *c;
     658             :         int                      i;
     659             : 
     660           0 :         cd = &sc->cdce_cdata;
     661           0 :         for (i = 0; i < CDCE_RX_LIST_CNT; i++) {
     662           0 :                 c = &cd->cdce_rx_chain[i];
     663           0 :                 c->cdce_sc = sc;
     664           0 :                 c->cdce_idx = i;
     665           0 :                 if (cdce_newbuf(sc, c, NULL) == ENOBUFS)
     666           0 :                         return (ENOBUFS);
     667           0 :                 if (c->cdce_xfer == NULL) {
     668           0 :                         c->cdce_xfer = usbd_alloc_xfer(sc->cdce_udev);
     669           0 :                         if (c->cdce_xfer == NULL)
     670           0 :                                 return (ENOBUFS);
     671           0 :                         c->cdce_buf = usbd_alloc_buffer(c->cdce_xfer,
     672             :                             CDCE_BUFSZ);
     673           0 :                         if (c->cdce_buf == NULL)
     674           0 :                                 return (ENOBUFS);
     675             :                 }
     676             :         }
     677             : 
     678           0 :         return (0);
     679           0 : }
     680             : 
     681             : int
     682           0 : cdce_tx_list_init(struct cdce_softc *sc)
     683             : {
     684             :         struct cdce_cdata       *cd;
     685             :         struct cdce_chain       *c;
     686             :         int                      i;
     687             : 
     688           0 :         cd = &sc->cdce_cdata;
     689           0 :         for (i = 0; i < CDCE_TX_LIST_CNT; i++) {
     690           0 :                 c = &cd->cdce_tx_chain[i];
     691           0 :                 c->cdce_sc = sc;
     692           0 :                 c->cdce_idx = i;
     693           0 :                 c->cdce_mbuf = NULL;
     694           0 :                 if (c->cdce_xfer == NULL) {
     695           0 :                         c->cdce_xfer = usbd_alloc_xfer(sc->cdce_udev);
     696           0 :                         if (c->cdce_xfer == NULL)
     697           0 :                                 return (ENOBUFS);
     698           0 :                         c->cdce_buf = usbd_alloc_buffer(c->cdce_xfer,
     699             :                             CDCE_BUFSZ);
     700           0 :                         if (c->cdce_buf == NULL)
     701           0 :                                 return (ENOBUFS);
     702             :                 }
     703             :         }
     704             : 
     705           0 :         return (0);
     706           0 : }
     707             : 
     708             : void
     709           0 : cdce_rxeof(struct usbd_xfer *xfer, void *priv, usbd_status status)
     710             : {
     711           0 :         struct cdce_chain       *c = priv;
     712           0 :         struct cdce_softc       *sc = c->cdce_sc;
     713           0 :         struct ifnet            *ifp = GET_IFP(sc);
     714             :         struct mbuf             *m;
     715           0 :         struct mbuf_list         ml = MBUF_LIST_INITIALIZER();
     716           0 :         int                      total_len = 0;
     717             :         int                      s;
     718             : 
     719           0 :         if (usbd_is_dying(sc->cdce_udev) || !(ifp->if_flags & IFF_RUNNING))
     720           0 :                 return;
     721             : 
     722           0 :         if (status != USBD_NORMAL_COMPLETION) {
     723           0 :                 if (status == USBD_NOT_STARTED || status == USBD_CANCELLED)
     724           0 :                         return;
     725           0 :                 if (sc->cdce_rxeof_errors == 0)
     726           0 :                         printf("%s: usb error on rx: %s\n",
     727           0 :                             sc->cdce_dev.dv_xname, usbd_errstr(status));
     728           0 :                 if (status == USBD_STALLED)
     729           0 :                         usbd_clear_endpoint_stall_async(sc->cdce_bulkin_pipe);
     730           0 :                 DELAY(sc->cdce_rxeof_errors * 10000);
     731           0 :                 if (sc->cdce_rxeof_errors++ > 10) {
     732           0 :                         printf("%s: too many errors, disabling\n",
     733           0 :                             sc->cdce_dev.dv_xname);
     734           0 :                         usbd_deactivate(sc->cdce_udev);
     735           0 :                         return;
     736             :                 }
     737             :                 goto done;
     738             :         }
     739             : 
     740           0 :         sc->cdce_rxeof_errors = 0;
     741             : 
     742           0 :         usbd_get_xfer_status(xfer, NULL, NULL, &total_len, NULL);
     743           0 :         if (sc->cdce_flags & CDCE_CRC32)
     744           0 :                 total_len -= 4; /* Strip off added CRC */
     745           0 :         if (total_len <= 1)
     746             :                 goto done;
     747             : 
     748           0 :         m = c->cdce_mbuf;
     749           0 :         memcpy(mtod(m, char *), c->cdce_buf, total_len);
     750             : 
     751           0 :         if (total_len < sizeof(struct ether_header)) {
     752           0 :                 ifp->if_ierrors++;
     753           0 :                 goto done;
     754             :         }
     755             : 
     756           0 :         m->m_pkthdr.len = m->m_len = total_len;
     757           0 :         ml_enqueue(&ml, m);
     758             : 
     759           0 :         if (cdce_newbuf(sc, c, NULL) == ENOBUFS) {
     760           0 :                 ifp->if_ierrors++;
     761           0 :                 goto done;
     762             :         }
     763             : 
     764           0 :         s = splnet();
     765           0 :         if_input(ifp, &ml);
     766           0 :         splx(s);
     767             : 
     768             : done:
     769             :         /* Setup new transfer. */
     770           0 :         usbd_setup_xfer(c->cdce_xfer, sc->cdce_bulkin_pipe, c, c->cdce_buf,
     771             :             CDCE_BUFSZ, USBD_SHORT_XFER_OK | USBD_NO_COPY, USBD_NO_TIMEOUT,
     772             :             cdce_rxeof);
     773           0 :         usbd_transfer(c->cdce_xfer);
     774           0 : }
     775             : 
     776             : void
     777           0 : cdce_txeof(struct usbd_xfer *xfer, void *priv, usbd_status status)
     778             : {
     779           0 :         struct cdce_chain       *c = priv;
     780           0 :         struct cdce_softc       *sc = c->cdce_sc;
     781           0 :         struct ifnet            *ifp = GET_IFP(sc);
     782           0 :         usbd_status              err;
     783             :         int                      s;
     784             : 
     785           0 :         if (usbd_is_dying(sc->cdce_udev))
     786           0 :                 return;
     787             : 
     788           0 :         s = splnet();
     789             : 
     790           0 :         ifp->if_timer = 0;
     791           0 :         ifq_clr_oactive(&ifp->if_snd);
     792             : 
     793           0 :         if (status != USBD_NORMAL_COMPLETION) {
     794           0 :                 if (status == USBD_NOT_STARTED || status == USBD_CANCELLED) {
     795           0 :                         splx(s);
     796           0 :                         return;
     797             :                 }
     798           0 :                 ifp->if_oerrors++;
     799           0 :                 printf("%s: usb error on tx: %s\n", sc->cdce_dev.dv_xname,
     800           0 :                     usbd_errstr(status));
     801           0 :                 if (status == USBD_STALLED)
     802           0 :                         usbd_clear_endpoint_stall_async(sc->cdce_bulkout_pipe);
     803           0 :                 splx(s);
     804           0 :                 return;
     805             :         }
     806             : 
     807           0 :         usbd_get_xfer_status(c->cdce_xfer, NULL, NULL, NULL, &err);
     808             : 
     809           0 :         if (c->cdce_mbuf != NULL) {
     810           0 :                 m_freem(c->cdce_mbuf);
     811           0 :                 c->cdce_mbuf = NULL;
     812           0 :         }
     813             : 
     814           0 :         if (err)
     815           0 :                 ifp->if_oerrors++;
     816             : 
     817           0 :         if (IFQ_IS_EMPTY(&ifp->if_snd) == 0)
     818           0 :                 cdce_start(ifp);
     819             : 
     820           0 :         splx(s);
     821           0 : }
     822             : 
     823             : void
     824           0 : cdce_intr(struct usbd_xfer *xfer, void *addr, usbd_status status)
     825             : {
     826           0 :         struct cdce_softc       *sc = addr;
     827           0 :         struct usb_cdc_notification *buf = &sc->cdce_intr_buf;
     828             :         struct usb_cdc_connection_speed *speed;
     829           0 :         u_int32_t                count;
     830             : 
     831           0 :         if (status == USBD_CANCELLED)
     832           0 :                 return;
     833             : 
     834           0 :         if (status != USBD_NORMAL_COMPLETION) {
     835             :                 DPRINTFN(2, ("cdce_intr: status=%d\n", status));
     836           0 :                 if (status == USBD_STALLED)
     837           0 :                         usbd_clear_endpoint_stall_async(sc->cdce_intr_pipe);
     838           0 :                 return;
     839             :         }
     840             : 
     841           0 :         usbd_get_xfer_status(xfer, NULL, NULL, &count, NULL);
     842             : 
     843           0 :         if (buf->bmRequestType == UCDC_NOTIFICATION) {
     844           0 :                 switch (buf->bNotification) {
     845             :                 case UCDC_N_NETWORK_CONNECTION:
     846             :                         DPRINTFN(1, ("cdce_intr: network %s\n",
     847             :                             UGETW(buf->wValue) ? "connected" : "disconnected"));
     848             :                         break;
     849             :                 case UCDC_N_CONNECTION_SPEED_CHANGE:
     850           0 :                         speed = (struct usb_cdc_connection_speed *)&buf->data;
     851             :                         DPRINTFN(1, ("cdce_intr: up=%d, down=%d\n",
     852             :                             UGETDW(speed->dwUSBitRate),
     853             :                             UGETDW(speed->dwDSBitRate)));
     854           0 :                         break;
     855             :                 default:
     856             :                         DPRINTF(("cdce_intr: bNotification 0x%x\n",
     857             :                             buf->bNotification));
     858             :                 }
     859             :         }
     860             : #ifdef CDCE_DEBUG
     861             :         else {
     862             :                 printf("cdce_intr: bmRequestType=%d ", buf->bmRequestType);
     863             :                 printf("wValue=%d wIndex=%d wLength=%d\n", UGETW(buf->wValue),
     864             :                     UGETW(buf->wIndex), UGETW(buf->wLength));
     865             :         }
     866             : #endif
     867           0 : }

Generated by: LCOV version 1.13