root/dev/usb/if_cdcef.c

/* [<][>][^][v][top][bottom][index][help] */

DEFINITIONS

This source file includes following definitions.
  1. cdcef_match
  2. cdcef_attach
  3. cdcef_do_request
  4. cdcef_start
  5. cdcef_txeof
  6. cdcef_start_timeout
  7. cdcef_rxeof
  8. cdcef_newbuf
  9. cdcef_ioctl
  10. cdcef_watchdog
  11. cdcef_init
  12. cdcef_encap
  13. cdcef_stop

    1 /*      $OpenBSD: if_cdcef.c,v 1.17 2007/06/14 06:55:10 mbalmer Exp $   */
    2 
    3 /*
    4  * Copyright (c) 2007 Dale Rahn <drahn@openbsd.org>
    5  * Copyright (c) 2006 Uwe Stuehler <uwe@openbsd.org>
    6  *
    7  * Permission to use, copy, modify, and distribute this software for any
    8  * purpose with or without fee is hereby granted, provided that the above
    9  * copyright notice and this permission notice appear in all copies.
   10  *
   11  * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
   12  * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
   13  * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
   14  * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
   15  * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
   16  * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
   17  * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
   18  */
   19 
   20 /*
   21  * USB Communication Device Class Ethernet Emulation Model function driver
   22  * (counterpart of the host-side cdce(4) driver)
   23  */
   24 #include <bpfilter.h>
   25 
   26 
   27 #include <sys/param.h>
   28 #include <sys/device.h>
   29 #include <sys/socket.h>
   30 #include <sys/systm.h>
   31 #include <sys/mbuf.h>
   32 #include <sys/timeout.h>
   33 
   34 #include <net/if.h>
   35 
   36 #include <dev/usb/usb.h>
   37 #include <dev/usb/usbdi.h>
   38 #include <dev/usb/usbf.h>
   39 #include <dev/usb/usbcdc.h>
   40 
   41 #if NBPFILTER > 0
   42 #include <net/bpf.h>
   43 #endif
   44 
   45 #include <netinet/in.h>
   46 #include <netinet/in_systm.h>
   47 #include <netinet/in_var.h>
   48 #include <netinet/ip.h>
   49 #include <netinet/if_ether.h>
   50 
   51 
   52 #define CDCEF_VENDOR_ID         0x0001
   53 #define CDCEF_PRODUCT_ID        0x0001
   54 #define CDCEF_DEVICE_CODE       0x0100
   55 #define CDCEF_VENDOR_STRING     "OpenBSD.org"
   56 #define CDCEF_PRODUCT_STRING    "CDC Ethernet Emulation"
   57 #define CDCEF_SERIAL_STRING     "1.00"
   58 
   59 #define CDCEF_BUFSZ             1600
   60 
   61 
   62 struct cdcef_softc {
   63         struct usbf_function    sc_dev;
   64         usbf_config_handle      sc_config;
   65         usbf_interface_handle   sc_iface;
   66         usbf_endpoint_handle    sc_ep_in;
   67         usbf_endpoint_handle    sc_ep_out;
   68         usbf_pipe_handle        sc_pipe_in;
   69         usbf_pipe_handle        sc_pipe_out;
   70         usbf_xfer_handle        sc_xfer_in;
   71         usbf_xfer_handle        sc_xfer_out;
   72         void                    *sc_buffer_in;
   73         void                    *sc_buffer_out;
   74 
   75         struct timeout          start_to;
   76 
   77         struct mbuf             *sc_xmit_mbuf;
   78 
   79         struct arpcom           sc_arpcom;
   80 #define GET_IFP(sc) (&(sc)->sc_arpcom.ac_if)
   81 
   82         int                     sc_rxeof_errors;
   83         int                     sc_unit;
   84         int                     sc_attached;
   85         int                     sc_listening;
   86 };
   87 
   88 int             cdcef_match(struct device *, void *, void *);
   89 void            cdcef_attach(struct device *, struct device *, void *);
   90 
   91 usbf_status     cdcef_do_request(usbf_function_handle,
   92                                  usb_device_request_t *, void **);
   93 
   94 void            cdcef_start(struct ifnet *);
   95 
   96 void            cdcef_txeof(usbf_xfer_handle, usbf_private_handle,
   97                             usbf_status);
   98 void            cdcef_rxeof(usbf_xfer_handle, usbf_private_handle,
   99                             usbf_status);
  100 int             cdcef_ioctl(struct ifnet *ifp, u_long command, caddr_t data);
  101 void            cdcef_watchdog(struct ifnet *ifp);
  102 void            cdcef_init(struct cdcef_softc *);
  103 void            cdcef_stop(struct cdcef_softc *);
  104 int             cdcef_encap(struct cdcef_softc *sc, struct mbuf *m, int idx);
  105 struct mbuf *   cdcef_newbuf(void);
  106 void            cdcef_start_timeout (void *);
  107 
  108 struct cfattach cdcef_ca = {
  109         sizeof(struct cdcef_softc), cdcef_match, cdcef_attach
  110 };
  111 
  112 struct cfdriver cdcef_cd = {
  113         NULL, "cdcef", DV_DULL
  114 };
  115 
  116 struct usbf_function_methods cdcef_methods = {
  117         NULL,                   /* set_config */
  118         cdcef_do_request
  119 };
  120 
  121 #ifndef CDCEF_DEBUG
  122 #define DPRINTF(x)      do {} while (0)
  123 #else
  124 #define DPRINTF(x)      printf x
  125 #endif
  126 
  127 #define DEVNAME(sc)     ((sc)->sc_dev.bdev.dv_xname)
  128 
  129 /*
  130  * USB function match/attach/detach
  131  */
  132 
  133 int
  134 cdcef_match(struct device *parent, void *match, void *aux)
  135 {
  136         return UMATCH_GENERIC;
  137 }
  138 
  139 void
  140 cdcef_attach(struct device *parent, struct device *self, void *aux)
  141 {
  142         struct cdcef_softc *sc = (struct cdcef_softc *)self;
  143         struct usbf_attach_arg *uaa = aux;
  144         usbf_device_handle dev = uaa->device;
  145         char *devinfop;
  146         struct ifnet *ifp;
  147         usbf_status err;
  148         usb_cdc_union_descriptor_t udesc;
  149         int s;
  150         u_int16_t macaddr_hi;
  151 
  152 
  153         /* Set the device identification according to the function. */
  154         usbf_devinfo_setup(dev, UDCLASS_IN_INTERFACE, 0, 0, CDCEF_VENDOR_ID,
  155             CDCEF_PRODUCT_ID, CDCEF_DEVICE_CODE, CDCEF_VENDOR_STRING,
  156             CDCEF_PRODUCT_STRING, CDCEF_SERIAL_STRING);
  157 
  158         devinfop = usbf_devinfo_alloc(dev);
  159         printf(": %s\n", devinfop);
  160         usbf_devinfo_free(devinfop);
  161 
  162         /* Fill in the fields needed by the parent device. */
  163         sc->sc_dev.methods = &cdcef_methods;
  164 
  165         /* timeout to start delayed tranfers */
  166         timeout_set(&sc->start_to, cdcef_start_timeout, sc);
  167 
  168         /*
  169          * Build descriptors according to the device class specification.
  170          */
  171         err = usbf_add_config(dev, &sc->sc_config);
  172         if (err) {
  173                 printf("%s: usbf_add_config failed\n", DEVNAME(sc));
  174                 return;
  175         }
  176         err = usbf_add_interface(sc->sc_config, UICLASS_CDC,
  177             UISUBCLASS_ETHERNET_NETWORKING_CONTROL_MODEL, 0, NULL,
  178             &sc->sc_iface);
  179         if (err) {
  180                 printf("%s: usbf_add_interface failed\n", DEVNAME(sc));
  181                 return;
  182         }
  183         /* XXX don't use hard-coded values 128 and 16. */
  184         err = usbf_add_endpoint(sc->sc_iface, UE_DIR_IN | 2, UE_BULK,
  185             64, 16, &sc->sc_ep_in) ||
  186             usbf_add_endpoint(sc->sc_iface, UE_DIR_OUT | 1, UE_BULK,
  187             64, 16, &sc->sc_ep_out);
  188         if (err) {
  189                 printf("%s: usbf_add_endpoint failed\n", DEVNAME(sc));
  190                 return;
  191         }
  192 
  193         /* Append a CDC union descriptor. */
  194         bzero(&udesc, sizeof udesc);
  195         udesc.bLength = sizeof udesc;
  196         udesc.bDescriptorType = UDESC_CS_INTERFACE;
  197         udesc.bDescriptorSubtype = UDESCSUB_CDC_UNION;
  198         udesc.bSlaveInterface[0] = usbf_interface_number(sc->sc_iface);
  199         err = usbf_add_config_desc(sc->sc_config,
  200             (usb_descriptor_t *)&udesc, NULL);
  201         if (err) {
  202                 printf("%s: usbf_add_config_desc failed\n", DEVNAME(sc));
  203                 return;
  204         }
  205 
  206         /*
  207          * Close the configuration and build permanent descriptors.
  208          */
  209         err = usbf_end_config(sc->sc_config);
  210         if (err) {
  211                 printf("%s: usbf_end_config failed\n", DEVNAME(sc));
  212                 return;
  213         }
  214 
  215         /* Preallocate xfers and data buffers. */
  216         sc->sc_xfer_in = usbf_alloc_xfer(dev);
  217         sc->sc_xfer_out = usbf_alloc_xfer(dev);
  218         sc->sc_buffer_in = usbf_alloc_buffer(sc->sc_xfer_in,
  219             CDCEF_BUFSZ);
  220         sc->sc_buffer_out = usbf_alloc_buffer(sc->sc_xfer_out,
  221             CDCEF_BUFSZ);
  222         if (sc->sc_buffer_in == NULL || sc->sc_buffer_out == NULL) {
  223                 printf("%s: usbf_alloc_buffer failed\n", DEVNAME(sc));
  224                 return;
  225         }
  226 
  227         /* Open the bulk pipes. */
  228         err = usbf_open_pipe(sc->sc_iface,
  229             usbf_endpoint_address(sc->sc_ep_out), &sc->sc_pipe_out) ||
  230             usbf_open_pipe(sc->sc_iface,
  231             usbf_endpoint_address(sc->sc_ep_in), &sc->sc_pipe_in);
  232         if (err) {
  233                 printf("%s: usbf_open_pipe failed\n", DEVNAME(sc));
  234                 return;
  235         }
  236 
  237         /* Get ready to receive packets. */
  238         usbf_setup_xfer(sc->sc_xfer_out, sc->sc_pipe_out, sc,
  239             sc->sc_buffer_out, CDCEF_BUFSZ, USBD_SHORT_XFER_OK, 0, cdcef_rxeof);
  240         err = usbf_transfer(sc->sc_xfer_out);
  241         if (err && err != USBF_IN_PROGRESS) {
  242                 printf("%s: usbf_transfer failed\n", DEVNAME(sc));
  243                 return;
  244         }
  245 
  246         s = splnet();
  247 
  248         macaddr_hi = htons(0x2acb);
  249         bcopy(&macaddr_hi, &sc->sc_arpcom.ac_enaddr[0], sizeof(u_int16_t));
  250         bcopy(&ticks, &sc->sc_arpcom.ac_enaddr[2], sizeof(u_int32_t));
  251         sc->sc_arpcom.ac_enaddr[5] = (u_int8_t)(sc->sc_unit);
  252 
  253         printf("%s: address %s\n", DEVNAME(sc),
  254             ether_sprintf(sc->sc_arpcom.ac_enaddr));
  255 
  256         ifp = GET_IFP(sc);
  257         ifp->if_softc = sc;
  258         ifp->if_flags = IFF_BROADCAST | IFF_SIMPLEX | IFF_MULTICAST;
  259         ifp->if_ioctl = cdcef_ioctl;
  260         ifp->if_start = cdcef_start;
  261         ifp->if_watchdog = cdcef_watchdog;
  262         strlcpy(ifp->if_xname, DEVNAME(sc), IFNAMSIZ);
  263 
  264         IFQ_SET_READY(&ifp->if_snd);
  265 
  266         if_attach(ifp);
  267         ether_ifattach(ifp);
  268 
  269         sc->sc_attached = 1;
  270         splx(s);
  271 }
  272 
  273 usbf_status
  274 cdcef_do_request(usbf_function_handle fun, usb_device_request_t *req,
  275     void **data)
  276 {
  277         printf("cdcef_do_request\n");
  278         return USBF_STALLED;
  279 }
  280 
  281 void
  282 cdcef_start(struct ifnet *ifp)
  283 {
  284         struct cdcef_softc      *sc = ifp->if_softc;
  285         struct mbuf             *m_head = NULL;
  286 
  287         if(ifp->if_flags & IFF_OACTIVE)
  288                 return;
  289 
  290         IFQ_POLL(&ifp->if_snd, m_head);
  291         if (m_head == NULL) {
  292                 return;
  293         }
  294 
  295         if (sc->sc_listening == 0 || m_head->m_pkthdr.len > CDCEF_BUFSZ) {
  296                 /*
  297                  * drop packet because reciever is not listening,
  298                  * or if packet is larger than xmit buffer
  299                  */
  300                 IFQ_DEQUEUE(&ifp->if_snd, m_head);
  301                 m_freem(m_head);
  302                 return;
  303         }
  304 
  305         if (cdcef_encap(sc, m_head, 0)) {
  306                 ifp->if_flags |= IFF_OACTIVE;
  307                 return;
  308         }
  309 
  310         IFQ_DEQUEUE(&ifp->if_snd, m_head);
  311 
  312 #if NBPFILTER > 0
  313         if (ifp->if_bpf)
  314                 bpf_mtap(ifp->if_bpf, m_head, BPF_DIRECTION_OUT);
  315 #endif
  316                                         
  317         ifp->if_flags |= IFF_OACTIVE;
  318 
  319         ifp->if_timer = 6;
  320 }
  321 
  322 void
  323 cdcef_txeof(usbf_xfer_handle xfer, usbf_private_handle priv,
  324     usbf_status err)
  325 {
  326         struct cdcef_softc *sc = priv;
  327         struct ifnet *ifp = GET_IFP(sc);
  328         int s;
  329 
  330         s = splnet();
  331 #if 0
  332         printf("cdcef_txeof: xfer=%p, priv=%p, %s\n", xfer, priv,
  333             usbf_errstr(err));
  334 #endif
  335 
  336         ifp->if_timer = 0;
  337         ifp->if_flags &= ~IFF_OACTIVE;
  338 
  339         if (sc->sc_xmit_mbuf != NULL) {
  340                 m_freem(sc->sc_xmit_mbuf);
  341                 sc->sc_xmit_mbuf = NULL;
  342         }
  343 
  344         if (err)
  345                 ifp->if_oerrors++;
  346         else
  347                 ifp->if_opackets++;
  348 
  349         if (IFQ_IS_EMPTY(&ifp->if_snd) == 0)
  350                 timeout_add(&sc->start_to, 1); /* XXX  */
  351 
  352         splx(s);
  353 }
  354 void
  355 cdcef_start_timeout (void *v)
  356 {
  357         struct cdcef_softc *sc = v;
  358         struct ifnet *ifp = GET_IFP(sc);
  359         int s;
  360 
  361         s = splnet();
  362         cdcef_start(ifp);
  363         splx(s);
  364 }
  365 
  366 
  367 void
  368 cdcef_rxeof(usbf_xfer_handle xfer, usbf_private_handle priv,
  369     usbf_status status)
  370 {
  371         struct cdcef_softc      *sc = priv;
  372         int total_len = 0;
  373         struct ifnet            *ifp = GET_IFP(sc);
  374         struct mbuf             *m = NULL;
  375 
  376 
  377         int s;
  378 
  379 #if 0
  380         printf("cdcef_rxeof: xfer=%p, priv=%p, %s\n", xfer, priv,
  381             usbf_errstr(status));
  382 #endif
  383 
  384         if (status != USBF_NORMAL_COMPLETION) {
  385                 if (status == USBF_NOT_STARTED || status == USBF_CANCELLED)     
  386                         return;
  387                 if (sc->sc_rxeof_errors == 0)
  388                         printf("%s: usb error on rx: %s\n",
  389                             DEVNAME(sc), usbf_errstr(status));
  390                 /* XXX - no stalls on client */
  391                 if (sc->sc_rxeof_errors++ > 10) {
  392                         printf("%s: too many errors, disabling\n",
  393                             DEVNAME(sc));
  394                         /* sc->sc_dying = 1; */
  395                         // return;
  396                 }
  397                 goto done;
  398         }
  399         sc->sc_rxeof_errors = 0;
  400 
  401         /* upon first incoming packet we know the host is listening */
  402         if (sc->sc_listening == 0) {
  403                 sc->sc_listening = 1;
  404         }
  405 
  406 
  407         usbf_get_xfer_status(xfer, NULL, NULL, &total_len, NULL);
  408 
  409         /* total_len -= 4; Strip off CRC added for Zaurus - XXX*/
  410         if (total_len <= 1)
  411                 goto done;
  412 
  413         if (total_len < sizeof(struct ether_header)) {
  414                 ifp->if_ierrors++;
  415                 goto done;
  416         }
  417 
  418         s = splnet();
  419         if (ifp->if_flags & IFF_RUNNING) {
  420                 m = cdcef_newbuf();
  421                 if (m == NULL) {
  422                         /* message? */
  423                         ifp->if_ierrors++;
  424                         goto done1;
  425                 }
  426 
  427                 m->m_pkthdr.len = m->m_len = total_len;
  428                 bcopy(sc->sc_buffer_out, mtod(m, char *), total_len);
  429                 m->m_pkthdr.rcvif = ifp;
  430 
  431                 ifp->if_ipackets++;
  432 
  433 #if NBPFILTER > 0
  434                 if (ifp->if_bpf)
  435                         bpf_mtap(ifp->if_bpf, m, BPF_DIRECTION_IN);
  436 #endif
  437 
  438                 ether_input_mbuf(ifp, m);
  439         }
  440 
  441 done1:
  442         splx(s);
  443 
  444 done:
  445         /* Setup another xfer. */
  446         usbf_setup_xfer(xfer, sc->sc_pipe_out, sc, sc->sc_buffer_out,
  447             CDCEF_BUFSZ, USBD_SHORT_XFER_OK, 0, cdcef_rxeof);
  448 
  449         status = usbf_transfer(xfer);
  450         if (status && status != USBF_IN_PROGRESS) {
  451                 printf("%s: usbf_transfer failed\n", DEVNAME(sc));
  452                 return;
  453         }
  454 }
  455 
  456 struct mbuf *
  457 cdcef_newbuf(void)
  458 {
  459         struct mbuf             *m;
  460 
  461         MGETHDR(m, M_DONTWAIT, MT_DATA);
  462         if (m == NULL)
  463                 return (NULL);
  464 
  465         MCLGET(m, M_DONTWAIT);
  466         if (!(m->m_flags & M_EXT)) {
  467                 m_freem(m);
  468                 return (NULL);
  469         }
  470 
  471         m->m_len = m->m_pkthdr.len = MCLBYTES;
  472         m_adj(m, ETHER_ALIGN);
  473 
  474         return (m);
  475 }
  476 
  477 int
  478 cdcef_ioctl(struct ifnet *ifp, u_long command, caddr_t data)
  479 {
  480         struct cdcef_softc      *sc = ifp->if_softc;
  481         struct ifaddr           *ifa = (struct ifaddr *)data;
  482         struct ifreq            *ifr = (struct ifreq *)data;
  483         int                      s, error = 0;
  484 
  485         s = splnet();
  486 
  487         switch (command) {
  488         case SIOCSIFADDR:
  489                 ifp->if_flags |= IFF_UP;
  490                 cdcef_init(sc);
  491                 switch (ifa->ifa_addr->sa_family) {
  492                 case AF_INET:
  493                         arp_ifinit(&sc->sc_arpcom, ifa);
  494                         break;
  495                 }
  496                 break;
  497 
  498         case SIOCSIFMTU:
  499                 if (ifr->ifr_mtu > ETHERMTU)
  500                         error = EINVAL;
  501                 else
  502                         ifp->if_mtu = ifr->ifr_mtu;
  503                 break;
  504 
  505         case SIOCSIFFLAGS:
  506                 if (ifp->if_flags & IFF_UP) {
  507                         if (!(ifp->if_flags & IFF_RUNNING))
  508                                 cdcef_init(sc);
  509                 } else {
  510                         if (ifp->if_flags & IFF_RUNNING)
  511                                 cdcef_stop(sc);
  512                 }
  513                 error = 0;
  514                 break;
  515 
  516         case SIOCADDMULTI:
  517         case SIOCDELMULTI:
  518                 error = (command == SIOCADDMULTI) ?
  519                     ether_addmulti(ifr, &sc->sc_arpcom) :
  520                     ether_delmulti(ifr, &sc->sc_arpcom);
  521 
  522                 if (error == ENETRESET)
  523                         error = 0;
  524                 break;
  525 
  526         default:
  527                 error = EINVAL;
  528                 break;
  529         }
  530 
  531         splx(s);
  532 
  533         return (error);
  534 }
  535 
  536 void
  537 cdcef_watchdog(struct ifnet *ifp)
  538 {
  539         struct cdcef_softc      *sc = ifp->if_softc;
  540         int s;
  541 
  542 #if 0
  543         if (sc->sc_dying)
  544                 return;
  545 #endif
  546 
  547         ifp->if_oerrors++;
  548         printf("%s: watchdog timeout\n", DEVNAME(sc));
  549 
  550         s = splusb();
  551         ifp->if_timer = 0;
  552         ifp->if_flags &= ~IFF_OACTIVE;
  553 
  554         /* cancel recieve pipe? */
  555         usbf_abort_pipe(sc->sc_pipe_in); /* in is tx pipe */
  556         splx(s);
  557 }
  558 
  559 void
  560 cdcef_init(struct cdcef_softc *sc)
  561 {
  562         int s;
  563         struct ifnet    *ifp = GET_IFP(sc);
  564         if (ifp->if_flags & IFF_RUNNING)
  565                 return;
  566         s = splnet();
  567 
  568         ifp->if_flags |= IFF_RUNNING;
  569         ifp->if_flags &= ~IFF_OACTIVE;
  570 
  571         splx(s);
  572 }
  573 
  574 int
  575 cdcef_encap(struct cdcef_softc *sc, struct mbuf *m, int idx)
  576 {
  577         usbf_status err;
  578 
  579         m_copydata(m, 0, m->m_pkthdr.len, sc->sc_buffer_in);
  580         /* NO CRC */
  581 
  582         usbf_setup_xfer(sc->sc_xfer_in, sc->sc_pipe_in, sc, sc->sc_buffer_in,
  583             m->m_pkthdr.len, USBD_FORCE_SHORT_XFER | USBD_NO_COPY,
  584             10000, cdcef_txeof);
  585 
  586         err = usbf_transfer(sc->sc_xfer_in);
  587         if (err && err != USBD_IN_PROGRESS) {
  588                 printf("encap error\n");
  589                 cdcef_stop(sc);
  590                 return (EIO);
  591         }
  592         sc->sc_xmit_mbuf = m;
  593 
  594         return (0);
  595 }
  596 
  597 
  598 void
  599 cdcef_stop(struct cdcef_softc *sc)
  600 {
  601         struct ifnet    *ifp = GET_IFP(sc);
  602 
  603         ifp->if_timer = 0;
  604         ifp->if_flags &= ~(IFF_RUNNING | IFF_OACTIVE);
  605 
  606         /* cancel recieve pipe? */
  607 
  608         if (sc->sc_xmit_mbuf != NULL) {
  609                 m_freem(sc->sc_xmit_mbuf);
  610                 sc->sc_xmit_mbuf = NULL;
  611         }
  612 }

/* [<][>][^][v][top][bottom][index][help] */