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

          Line data    Source code
       1             : /*      $OpenBSD: if_urndis.c,v 1.67 2017/07/19 16:31:56 mikeb Exp $ */
       2             : 
       3             : /*
       4             :  * Copyright (c) 2010 Jonathan Armani <armani@openbsd.org>
       5             :  * Copyright (c) 2010 Fabien Romano <fabien@openbsd.org>
       6             :  * Copyright (c) 2010 Michael Knudsen <mk@openbsd.org>
       7             :  * All rights reserved.
       8             :  *
       9             :  * Permission to use, copy, modify, and distribute this software for any
      10             :  * purpose with or without fee is hereby granted, provided that the above
      11             :  * copyright notice and this permission notice appear in all copies.
      12             :  *
      13             :  * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
      14             :  * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
      15             :  * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
      16             :  * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
      17             :  * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
      18             :  * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
      19             :  * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
      20             :  */
      21             : 
      22             : #include "bpfilter.h"
      23             : 
      24             : #include <sys/param.h>
      25             : #include <sys/systm.h>
      26             : #include <sys/sockio.h>
      27             : #include <sys/rwlock.h>
      28             : #include <sys/mbuf.h>
      29             : #include <sys/kernel.h>
      30             : #include <sys/socket.h>
      31             : 
      32             : #include <sys/device.h>
      33             : 
      34             : #include <machine/bus.h>
      35             : 
      36             : #include <net/if.h>
      37             : #include <net/if_media.h>
      38             : 
      39             : #if NBPFILTER > 0
      40             : #include <net/bpf.h>
      41             : #endif
      42             : 
      43             : #include <netinet/in.h>
      44             : #include <netinet/if_ether.h>
      45             : 
      46             : #include <dev/usb/usb.h>
      47             : #include <dev/usb/usbdi.h>
      48             : #include <dev/usb/usbdi_util.h>
      49             : #include <dev/usb/usbdivar.h>
      50             : #include <dev/usb/usbdevs.h>
      51             : 
      52             : #include <dev/rndis.h>
      53             : 
      54             : #include <dev/usb/if_urndisreg.h>
      55             : 
      56             : #ifdef URNDIS_DEBUG
      57             : #define DPRINTF(x)      do { printf x; } while (0)
      58             : #else
      59             : #define DPRINTF(x)
      60             : #endif
      61             : 
      62             : #define DEVNAME(sc)     ((sc)->sc_dev.dv_xname)
      63             : 
      64             : int urndis_newbuf(struct urndis_softc *, struct urndis_chain *);
      65             : 
      66             : int urndis_ioctl(struct ifnet *, u_long, caddr_t);
      67             : #if 0
      68             : void urndis_watchdog(struct ifnet *);
      69             : #endif
      70             : 
      71             : void urndis_start(struct ifnet *);
      72             : void urndis_rxeof(struct usbd_xfer *, void *, usbd_status);
      73             : void urndis_txeof(struct usbd_xfer *, void *, usbd_status);
      74             : int urndis_rx_list_init(struct urndis_softc *);
      75             : int urndis_tx_list_init(struct urndis_softc *);
      76             : 
      77             : void urndis_init(struct urndis_softc *);
      78             : void urndis_stop(struct urndis_softc *);
      79             : 
      80             : usbd_status urndis_ctrl_msg(struct urndis_softc *, uint8_t, uint8_t,
      81             :     uint16_t, uint16_t, void *, size_t);
      82             : usbd_status urndis_ctrl_send(struct urndis_softc *, void *, size_t);
      83             : struct rndis_comp_hdr *urndis_ctrl_recv(struct urndis_softc *);
      84             : 
      85             : u_int32_t urndis_ctrl_handle(struct urndis_softc *,
      86             :     struct rndis_comp_hdr *, void **, size_t *);
      87             : u_int32_t urndis_ctrl_handle_init(struct urndis_softc *,
      88             :     const struct rndis_comp_hdr *);
      89             : u_int32_t urndis_ctrl_handle_query(struct urndis_softc *,
      90             :     const struct rndis_comp_hdr *, void **, size_t *);
      91             : u_int32_t urndis_ctrl_handle_reset(struct urndis_softc *,
      92             :     const struct rndis_comp_hdr *);
      93             : u_int32_t urndis_ctrl_handle_status(struct urndis_softc *,
      94             :     const struct rndis_comp_hdr *);
      95             : 
      96             : u_int32_t urndis_ctrl_init(struct urndis_softc *);
      97             : u_int32_t urndis_ctrl_halt(struct urndis_softc *);
      98             : u_int32_t urndis_ctrl_query(struct urndis_softc *, u_int32_t, void *, size_t,
      99             :     void **, size_t *);
     100             : u_int32_t urndis_ctrl_set(struct urndis_softc *, u_int32_t, void *, size_t);
     101             : u_int32_t urndis_ctrl_set_param(struct urndis_softc *, const char *, u_int32_t,
     102             :     void *, size_t);
     103             : #if 0
     104             : u_int32_t urndis_ctrl_reset(struct urndis_softc *);
     105             : u_int32_t urndis_ctrl_keepalive(struct urndis_softc *);
     106             : #endif
     107             : 
     108             : int urndis_encap(struct urndis_softc *, struct mbuf *, int);
     109             : void urndis_decap(struct urndis_softc *, struct urndis_chain *, u_int32_t);
     110             : 
     111             : const struct urndis_class *urndis_lookup(usb_interface_descriptor_t *);
     112             : 
     113             : int urndis_match(struct device *, void *, void *);
     114             : void urndis_attach(struct device *, struct device *, void *);
     115             : int urndis_detach(struct device *, int);
     116             : 
     117             : struct cfdriver urndis_cd = {
     118             :         NULL, "urndis", DV_IFNET
     119             : };
     120             : 
     121             : struct cfattach urndis_ca = {
     122             :         sizeof(struct urndis_softc), urndis_match, urndis_attach, urndis_detach
     123             : };
     124             : 
     125             : const struct urndis_class {
     126             :         u_int8_t class;
     127             :         u_int8_t subclass;
     128             :         u_int8_t protocol;
     129             :         const char *typestr;
     130             : } urndis_class[] = {
     131             :         { UICLASS_CDC, UISUBCLASS_ABSTRACT_CONTROL_MODEL, 0xff, "Vendor" },
     132             :         { UICLASS_WIRELESS, UISUBCLASS_RF, UIPROTO_RNDIS, "RNDIS" },
     133             :         { UICLASS_MISC, UISUBCLASS_SYNC, UIPROTO_ACTIVESYNC, "Activesync" }
     134             : };
     135             : 
     136             : usbd_status
     137           0 : urndis_ctrl_msg(struct urndis_softc *sc, uint8_t rt, uint8_t r,
     138             :     uint16_t index, uint16_t value, void *buf, size_t buflen)
     139             : {
     140           0 :         usb_device_request_t req;
     141             : 
     142           0 :         req.bmRequestType = rt;
     143           0 :         req.bRequest = r;
     144           0 :         USETW(req.wValue, value);
     145           0 :         USETW(req.wIndex, index);
     146           0 :         USETW(req.wLength, buflen);
     147             : 
     148           0 :         return usbd_do_request(sc->sc_udev, &req, buf);
     149           0 : }
     150             : 
     151             : usbd_status
     152           0 : urndis_ctrl_send(struct urndis_softc *sc, void *buf, size_t len)
     153             : {
     154             :         usbd_status err;
     155             : 
     156           0 :         if (usbd_is_dying(sc->sc_udev))
     157           0 :                 return(0);
     158             : 
     159           0 :         err = urndis_ctrl_msg(sc, UT_WRITE_CLASS_INTERFACE, UR_GET_STATUS,
     160           0 :             sc->sc_ifaceno_ctl, 0, buf, len);
     161             : 
     162           0 :         if (err != USBD_NORMAL_COMPLETION)
     163           0 :                 printf("%s: %s\n", DEVNAME(sc), usbd_errstr(err));
     164             : 
     165           0 :         return err;
     166           0 : }
     167             : 
     168             : struct rndis_comp_hdr *
     169           0 : urndis_ctrl_recv(struct urndis_softc *sc)
     170             : {
     171             : #define RNDIS_RESPONSE_LEN 0x400
     172             :         struct rndis_comp_hdr   *hdr;
     173             :         char                    *buf;
     174             :         usbd_status              err;
     175             : 
     176           0 :         buf = malloc(RNDIS_RESPONSE_LEN, M_TEMP, M_WAITOK | M_CANFAIL);
     177           0 :         if (buf == NULL) {
     178           0 :                 printf("%s: out of memory\n", DEVNAME(sc));
     179           0 :                 return NULL;
     180             :         }
     181             : 
     182           0 :         err = urndis_ctrl_msg(sc, UT_READ_CLASS_INTERFACE, UR_CLEAR_FEATURE,
     183           0 :             sc->sc_ifaceno_ctl, 0, buf, RNDIS_RESPONSE_LEN);
     184             : 
     185           0 :         if (err != USBD_NORMAL_COMPLETION && err != USBD_SHORT_XFER) {
     186           0 :                 printf("%s: %s\n", DEVNAME(sc), usbd_errstr(err));
     187           0 :                 free(buf, M_TEMP, RNDIS_RESPONSE_LEN);
     188           0 :                 return NULL;
     189             :         }
     190             : 
     191           0 :         hdr = (struct rndis_comp_hdr *)buf;
     192             :         DPRINTF(("%s: urndis_ctrl_recv: type 0x%x len %u\n",
     193             :             DEVNAME(sc),
     194             :             letoh32(hdr->rm_type),
     195             :             letoh32(hdr->rm_len)));
     196             : 
     197           0 :         if (letoh32(hdr->rm_len) > RNDIS_RESPONSE_LEN) {
     198           0 :                 printf("%s: ctrl message error: wrong size %u > %u\n",
     199           0 :                     DEVNAME(sc),
     200             :                     letoh32(hdr->rm_len),
     201             :                     RNDIS_RESPONSE_LEN);
     202           0 :                 free(buf, M_TEMP, RNDIS_RESPONSE_LEN);
     203           0 :                 return NULL;
     204             :         }
     205             : 
     206           0 :         return hdr;
     207           0 : }
     208             : 
     209             : u_int32_t
     210           0 : urndis_ctrl_handle(struct urndis_softc *sc, struct rndis_comp_hdr *hdr,
     211             :     void **buf, size_t *bufsz)
     212             : {
     213             :         u_int32_t rval;
     214             : 
     215             :         DPRINTF(("%s: urndis_ctrl_handle\n", DEVNAME(sc)));
     216             : 
     217           0 :         if (buf && bufsz) {
     218           0 :                 *buf = NULL;
     219           0 :                 *bufsz = 0;
     220           0 :         }
     221             : 
     222           0 :         switch (letoh32(hdr->rm_type)) {
     223             :                 case REMOTE_NDIS_INITIALIZE_CMPLT:
     224           0 :                         rval = urndis_ctrl_handle_init(sc, hdr);
     225           0 :                         break;
     226             : 
     227             :                 case REMOTE_NDIS_QUERY_CMPLT:
     228           0 :                         rval = urndis_ctrl_handle_query(sc, hdr, buf, bufsz);
     229           0 :                         break;
     230             : 
     231             :                 case REMOTE_NDIS_RESET_CMPLT:
     232           0 :                         rval = urndis_ctrl_handle_reset(sc, hdr);
     233           0 :                         break;
     234             : 
     235             :                 case REMOTE_NDIS_KEEPALIVE_CMPLT:
     236             :                 case REMOTE_NDIS_SET_CMPLT:
     237           0 :                         rval = letoh32(hdr->rm_status);
     238           0 :                         break;
     239             : 
     240             :                 case REMOTE_NDIS_INDICATE_STATUS_MSG:
     241           0 :                         rval = urndis_ctrl_handle_status(sc, hdr);
     242           0 :                         break;
     243             : 
     244             :                 default:
     245           0 :                         printf("%s: ctrl message error: unknown event 0x%x\n",
     246           0 :                             DEVNAME(sc), letoh32(hdr->rm_type));
     247             :                         rval = RNDIS_STATUS_FAILURE;
     248           0 :         }
     249             : 
     250           0 :         free(hdr, M_TEMP, RNDIS_RESPONSE_LEN);
     251             : 
     252           0 :         return rval;
     253             : }
     254             : 
     255             : u_int32_t
     256           0 : urndis_ctrl_handle_init(struct urndis_softc *sc,
     257             :     const struct rndis_comp_hdr *hdr)
     258             : {
     259             :         const struct rndis_init_comp    *msg;
     260             : 
     261           0 :         msg = (struct rndis_init_comp *) hdr;
     262             : 
     263             :         DPRINTF(("%s: urndis_ctrl_handle_init: len %u rid %u status 0x%x "
     264             :             "ver_major %u ver_minor %u devflags 0x%x medium 0x%x pktmaxcnt %u "
     265             :             "pktmaxsz %u align %u aflistoffset %u aflistsz %u\n",
     266             :             DEVNAME(sc),
     267             :             letoh32(msg->rm_len),
     268             :             letoh32(msg->rm_rid),
     269             :             letoh32(msg->rm_status),
     270             :             letoh32(msg->rm_ver_major),
     271             :             letoh32(msg->rm_ver_minor),
     272             :             letoh32(msg->rm_devflags),
     273             :             letoh32(msg->rm_medium),
     274             :             letoh32(msg->rm_pktmaxcnt),
     275             :             letoh32(msg->rm_pktmaxsz),
     276             :             letoh32(msg->rm_align),
     277             :             letoh32(msg->rm_aflistoffset),
     278             :             letoh32(msg->rm_aflistsz)));
     279             : 
     280           0 :         if (letoh32(msg->rm_status) != RNDIS_STATUS_SUCCESS) {
     281           0 :                 printf("%s: init failed 0x%x\n",
     282           0 :                     DEVNAME(sc),
     283             :                     letoh32(msg->rm_status));
     284             : 
     285           0 :                 return letoh32(msg->rm_status);
     286             :         }
     287             : 
     288           0 :         if (letoh32(msg->rm_devflags) != RNDIS_DF_CONNECTIONLESS) {
     289           0 :                 printf("%s: wrong device type (current type: 0x%x)\n",
     290           0 :                     DEVNAME(sc),
     291             :                     letoh32(msg->rm_devflags));
     292             : 
     293           0 :                 return RNDIS_STATUS_FAILURE;
     294             :         }
     295             : 
     296           0 :         if (letoh32(msg->rm_medium) != RNDIS_MEDIUM_802_3) {
     297           0 :                 printf("%s: medium not 802.3 (current medium: 0x%x)\n",
     298           0 :                     DEVNAME(sc), letoh32(msg->rm_medium));
     299             : 
     300           0 :                 return RNDIS_STATUS_FAILURE;
     301             :         }
     302             : 
     303           0 :         sc->sc_lim_pktsz = letoh32(msg->rm_pktmaxsz);
     304             : 
     305           0 :         return letoh32(msg->rm_status);
     306           0 : }
     307             : 
     308             : u_int32_t
     309           0 : urndis_ctrl_handle_query(struct urndis_softc *sc,
     310             :     const struct rndis_comp_hdr *hdr, void **buf, size_t *bufsz)
     311             : {
     312             :         const struct rndis_query_comp   *msg;
     313             : 
     314           0 :         msg = (struct rndis_query_comp *) hdr;
     315             : 
     316             :         DPRINTF(("%s: urndis_ctrl_handle_query: len %u rid %u status 0x%x "
     317             :             "buflen %u bufoff %u\n",
     318             :             DEVNAME(sc),
     319             :             letoh32(msg->rm_len),
     320             :             letoh32(msg->rm_rid),
     321             :             letoh32(msg->rm_status),
     322             :             letoh32(msg->rm_infobuflen),
     323             :             letoh32(msg->rm_infobufoffset)));
     324             : 
     325           0 :         if (buf && bufsz) {
     326           0 :                 *buf = NULL;
     327           0 :                 *bufsz = 0;
     328           0 :         }
     329             : 
     330           0 :         if (letoh32(msg->rm_status) != RNDIS_STATUS_SUCCESS) {
     331           0 :                 printf("%s: query failed 0x%x\n",
     332           0 :                     DEVNAME(sc),
     333             :                     letoh32(msg->rm_status));
     334             : 
     335           0 :                 return letoh32(msg->rm_status);
     336             :         }
     337             : 
     338           0 :         if (letoh32(msg->rm_infobuflen) + letoh32(msg->rm_infobufoffset) +
     339           0 :             RNDIS_HEADER_OFFSET > letoh32(msg->rm_len)) {
     340           0 :                 printf("%s: ctrl message error: invalid query info "
     341             :                     "len/offset/end_position(%u/%u/%zu) -> "
     342             :                     "go out of buffer limit %u\n",
     343           0 :                     DEVNAME(sc),
     344             :                     letoh32(msg->rm_infobuflen),
     345             :                     letoh32(msg->rm_infobufoffset),
     346             :                     letoh32(msg->rm_infobuflen) +
     347             :                     letoh32(msg->rm_infobufoffset) + RNDIS_HEADER_OFFSET,
     348             :                     letoh32(msg->rm_len));
     349           0 :                 return RNDIS_STATUS_FAILURE;
     350             :         }
     351             : 
     352           0 :         if (buf && bufsz) {
     353           0 :                 *buf = malloc(letoh32(msg->rm_infobuflen),
     354             :                     M_TEMP, M_WAITOK | M_CANFAIL);
     355           0 :                 if (*buf == NULL) {
     356           0 :                         printf("%s: out of memory\n", DEVNAME(sc));
     357           0 :                         return RNDIS_STATUS_FAILURE;
     358             :                 } else {
     359             :                         char *p;
     360           0 :                         *bufsz = letoh32(msg->rm_infobuflen);
     361             : 
     362           0 :                         p = (char *)&msg->rm_rid;
     363           0 :                         p += letoh32(msg->rm_infobufoffset);
     364           0 :                         memcpy(*buf, p, letoh32(msg->rm_infobuflen));
     365             :                 }
     366           0 :         }
     367             : 
     368           0 :         return letoh32(msg->rm_status);
     369           0 : }
     370             : 
     371             : u_int32_t
     372           0 : urndis_ctrl_handle_reset(struct urndis_softc *sc,
     373             :     const struct rndis_comp_hdr *hdr)
     374             : {
     375             :         const struct rndis_reset_comp   *msg;
     376             :         u_int32_t                        rval;
     377             : 
     378           0 :         msg = (struct rndis_reset_comp *) hdr;
     379             : 
     380           0 :         rval = letoh32(msg->rm_status);
     381             : 
     382             :         DPRINTF(("%s: urndis_ctrl_handle_reset: len %u status 0x%x "
     383             :             "adrreset %u\n",
     384             :             DEVNAME(sc),
     385             :             letoh32(msg->rm_len),
     386             :             rval,
     387             :             letoh32(msg->rm_adrreset)));
     388             : 
     389           0 :         if (rval != RNDIS_STATUS_SUCCESS) {
     390           0 :                 printf("%s: reset failed 0x%x\n", DEVNAME(sc), rval);
     391           0 :                 return rval;
     392             :         }
     393             : 
     394           0 :         if (letoh32(msg->rm_adrreset) != 0) {
     395           0 :                 u_int32_t filter;
     396             : 
     397           0 :                 filter = htole32(sc->sc_filter);
     398           0 :                 rval = urndis_ctrl_set(sc, OID_GEN_CURRENT_PACKET_FILTER,
     399             :                     &filter, sizeof(filter));
     400           0 :                 if (rval != RNDIS_STATUS_SUCCESS) {
     401           0 :                         printf("%s: unable to reset data filters\n",
     402           0 :                             DEVNAME(sc));
     403           0 :                         return rval;
     404             :                 }
     405           0 :         }
     406             : 
     407           0 :         return rval;
     408           0 : }
     409             : 
     410             : u_int32_t
     411           0 : urndis_ctrl_handle_status(struct urndis_softc *sc,
     412             :     const struct rndis_comp_hdr *hdr)
     413             : {
     414             :         const struct rndis_status_msg   *msg;
     415             :         u_int32_t                        rval;
     416             : 
     417           0 :         msg = (struct rndis_status_msg *)hdr;
     418             : 
     419           0 :         rval = letoh32(msg->rm_status);
     420             : 
     421             :         DPRINTF(("%s: urndis_ctrl_handle_status: len %u status 0x%x "
     422             :             "stbuflen %u\n",
     423             :             DEVNAME(sc),
     424             :             letoh32(msg->rm_len),
     425             :             rval,
     426             :             letoh32(msg->rm_stbuflen)));
     427             : 
     428           0 :         switch (rval) {
     429             :                 case RNDIS_STATUS_MEDIA_CONNECT:
     430             :                 case RNDIS_STATUS_MEDIA_DISCONNECT:
     431             :                 case RNDIS_STATUS_OFFLOAD_CURRENT_CONFIG:
     432             :                         rval = RNDIS_STATUS_SUCCESS;
     433           0 :                         break;
     434             : 
     435             :                 default:
     436           0 :                         printf("%s: status 0x%x\n", DEVNAME(sc), rval);
     437           0 :         }
     438             : 
     439           0 :         return rval;
     440             : }
     441             : 
     442             : u_int32_t
     443           0 : urndis_ctrl_init(struct urndis_softc *sc)
     444             : {
     445             :         struct rndis_init_req   *msg;
     446             :         u_int32_t                rval;
     447             :         struct rndis_comp_hdr   *hdr;
     448             : 
     449           0 :         msg = malloc(sizeof(*msg), M_TEMP, M_WAITOK | M_CANFAIL);
     450           0 :         if (msg == NULL) {
     451           0 :                 printf("%s: out of memory\n", DEVNAME(sc));
     452           0 :                 return RNDIS_STATUS_FAILURE;
     453             :         }
     454             : 
     455           0 :         msg->rm_type = htole32(REMOTE_NDIS_INITIALIZE_MSG);
     456           0 :         msg->rm_len = htole32(sizeof(*msg));
     457           0 :         msg->rm_rid = htole32(0);
     458           0 :         msg->rm_ver_major = htole32(1);
     459           0 :         msg->rm_ver_minor = htole32(1);
     460           0 :         msg->rm_max_xfersz = htole32(RNDIS_BUFSZ);
     461             : 
     462             :         DPRINTF(("%s: urndis_ctrl_init send: type %u len %u rid %u ver_major %u "
     463             :             "ver_minor %u max_xfersz %u\n",
     464             :             DEVNAME(sc),
     465             :             letoh32(msg->rm_type),
     466             :             letoh32(msg->rm_len),
     467             :             letoh32(msg->rm_rid),
     468             :             letoh32(msg->rm_ver_major),
     469             :             letoh32(msg->rm_ver_minor),
     470             :             letoh32(msg->rm_max_xfersz)));
     471             : 
     472           0 :         rval = urndis_ctrl_send(sc, msg, sizeof(*msg));
     473           0 :         free(msg, M_TEMP, sizeof *msg);
     474             : 
     475           0 :         if (rval != RNDIS_STATUS_SUCCESS) {
     476           0 :                 printf("%s: init failed\n", DEVNAME(sc));
     477           0 :                 return rval;
     478             :         }
     479             : 
     480           0 :         if ((hdr = urndis_ctrl_recv(sc)) == NULL) {
     481           0 :                 printf("%s: unable to get init response\n", DEVNAME(sc));
     482           0 :                 return RNDIS_STATUS_FAILURE;
     483             :         }
     484           0 :         rval = urndis_ctrl_handle(sc, hdr, NULL, NULL);
     485             : 
     486           0 :         return rval;
     487           0 : }
     488             : 
     489             : u_int32_t
     490           0 : urndis_ctrl_halt(struct urndis_softc *sc)
     491             : {
     492             :         struct rndis_halt_req   *msg;
     493             :         u_int32_t                rval;
     494             : 
     495           0 :         msg = malloc(sizeof(*msg), M_TEMP, M_WAITOK | M_CANFAIL);
     496           0 :         if (msg == NULL) {
     497           0 :                 printf("%s: out of memory\n", DEVNAME(sc));
     498           0 :                 return RNDIS_STATUS_FAILURE;
     499             :         }
     500             : 
     501           0 :         msg->rm_type = htole32(REMOTE_NDIS_HALT_MSG);
     502           0 :         msg->rm_len = htole32(sizeof(*msg));
     503           0 :         msg->rm_rid = 0;
     504             : 
     505             :         DPRINTF(("%s: urndis_ctrl_halt send: type %u len %u rid %u\n",
     506             :             DEVNAME(sc),
     507             :             letoh32(msg->rm_type),
     508             :             letoh32(msg->rm_len),
     509             :             letoh32(msg->rm_rid)));
     510             : 
     511           0 :         rval = urndis_ctrl_send(sc, msg, sizeof(*msg));
     512           0 :         free(msg, M_TEMP, sizeof *msg);
     513             : 
     514           0 :         if (rval != RNDIS_STATUS_SUCCESS)
     515           0 :                 printf("%s: halt failed\n", DEVNAME(sc));
     516             : 
     517           0 :         return rval;
     518           0 : }
     519             : 
     520             : u_int32_t
     521           0 : urndis_ctrl_query(struct urndis_softc *sc, u_int32_t oid,
     522             :     void *qbuf, size_t qlen,
     523             :     void **rbuf, size_t *rbufsz)
     524             : {
     525             :         struct rndis_query_req  *msg;
     526             :         u_int32_t                rval;
     527             :         struct rndis_comp_hdr   *hdr;
     528             : 
     529           0 :         msg = malloc(sizeof(*msg) + qlen, M_TEMP, M_WAITOK | M_CANFAIL);
     530           0 :         if (msg == NULL) {
     531           0 :                 printf("%s: out of memory\n", DEVNAME(sc));
     532           0 :                 return RNDIS_STATUS_FAILURE;
     533             :         }
     534             : 
     535           0 :         msg->rm_type = htole32(REMOTE_NDIS_QUERY_MSG);
     536           0 :         msg->rm_len = htole32(sizeof(*msg) + qlen);
     537           0 :         msg->rm_rid = 0; /* XXX */
     538           0 :         msg->rm_oid = htole32(oid);
     539           0 :         msg->rm_infobuflen = htole32(qlen);
     540           0 :         if (qlen != 0) {
     541           0 :                 msg->rm_infobufoffset = htole32(20);
     542           0 :                 memcpy((char*)msg + 20, qbuf, qlen);
     543           0 :         } else
     544           0 :                 msg->rm_infobufoffset = 0;
     545           0 :         msg->rm_devicevchdl = 0;
     546             : 
     547             :         DPRINTF(("%s: urndis_ctrl_query send: type %u len %u rid %u oid 0x%x "
     548             :             "infobuflen %u infobufoffset %u devicevchdl %u\n",
     549             :             DEVNAME(sc),
     550             :             letoh32(msg->rm_type),
     551             :             letoh32(msg->rm_len),
     552             :             letoh32(msg->rm_rid),
     553             :             letoh32(msg->rm_oid),
     554             :             letoh32(msg->rm_infobuflen),
     555             :             letoh32(msg->rm_infobufoffset),
     556             :             letoh32(msg->rm_devicevchdl)));
     557             : 
     558           0 :         rval = urndis_ctrl_send(sc, msg, sizeof(*msg));
     559           0 :         free(msg, M_TEMP, sizeof *msg + qlen);
     560             : 
     561           0 :         if (rval != RNDIS_STATUS_SUCCESS) {
     562           0 :                 printf("%s: query failed\n", DEVNAME(sc));
     563           0 :                 return rval;
     564             :         }
     565             : 
     566           0 :         if ((hdr = urndis_ctrl_recv(sc)) == NULL) {
     567           0 :                 printf("%s: unable to get query response\n", DEVNAME(sc));
     568           0 :                 return RNDIS_STATUS_FAILURE;
     569             :         }
     570           0 :         rval = urndis_ctrl_handle(sc, hdr, rbuf, rbufsz);
     571             : 
     572           0 :         return rval;
     573           0 : }
     574             : 
     575             : u_int32_t
     576           0 : urndis_ctrl_set(struct urndis_softc *sc, u_int32_t oid, void *buf, size_t len)
     577             : {
     578             :         struct rndis_set_req    *msg;
     579             :         u_int32_t                rval;
     580             :         struct rndis_comp_hdr   *hdr;
     581             : 
     582           0 :         msg = malloc(sizeof(*msg) + len, M_TEMP, M_WAITOK | M_CANFAIL);
     583           0 :         if (msg == NULL) {
     584           0 :                 printf("%s: out of memory\n", DEVNAME(sc));
     585           0 :                 return RNDIS_STATUS_FAILURE;
     586             :         }
     587             : 
     588           0 :         msg->rm_type = htole32(REMOTE_NDIS_SET_MSG);
     589           0 :         msg->rm_len = htole32(sizeof(*msg) + len);
     590           0 :         msg->rm_rid = 0; /* XXX */
     591           0 :         msg->rm_oid = htole32(oid);
     592           0 :         msg->rm_infobuflen = htole32(len);
     593           0 :         if (len != 0) {
     594           0 :                 msg->rm_infobufoffset = htole32(20);
     595           0 :                 memcpy((char*)msg + 28, buf, len);
     596           0 :         } else
     597           0 :                 msg->rm_infobufoffset = 0;
     598           0 :         msg->rm_devicevchdl = 0;
     599             : 
     600             :         DPRINTF(("%s: urndis_ctrl_set send: type %u len %u rid %u oid 0x%x "
     601             :             "infobuflen %u infobufoffset %u devicevchdl %u\n",
     602             :             DEVNAME(sc),
     603             :             letoh32(msg->rm_type),
     604             :             letoh32(msg->rm_len),
     605             :             letoh32(msg->rm_rid),
     606             :             letoh32(msg->rm_oid),
     607             :             letoh32(msg->rm_infobuflen),
     608             :             letoh32(msg->rm_infobufoffset),
     609             :             letoh32(msg->rm_devicevchdl)));
     610             : 
     611           0 :         rval = urndis_ctrl_send(sc, msg, sizeof(*msg) + len);
     612           0 :         free(msg, M_TEMP, sizeof *msg + len);
     613             : 
     614           0 :         if (rval != RNDIS_STATUS_SUCCESS) {
     615           0 :                 printf("%s: set failed\n", DEVNAME(sc));
     616           0 :                 return rval;
     617             :         }
     618             : 
     619           0 :         if ((hdr = urndis_ctrl_recv(sc)) == NULL) {
     620           0 :                 printf("%s: unable to get set response\n", DEVNAME(sc));
     621           0 :                 return RNDIS_STATUS_FAILURE;
     622             :         }
     623           0 :         rval = urndis_ctrl_handle(sc, hdr, NULL, NULL);
     624           0 :         if (rval != RNDIS_STATUS_SUCCESS)
     625           0 :                 printf("%s: set failed 0x%x\n", DEVNAME(sc), rval);
     626             : 
     627           0 :         return rval;
     628           0 : }
     629             : 
     630             : u_int32_t
     631           0 : urndis_ctrl_set_param(struct urndis_softc *sc,
     632             :     const char *name,
     633             :     u_int32_t type,
     634             :     void *buf,
     635             :     size_t len)
     636             : {
     637             :         struct rndis_set_parameter      *param;
     638             :         u_int32_t                        rval;
     639             :         size_t                           namelen, tlen;
     640             : 
     641           0 :         if (name)
     642           0 :                 namelen = strlen(name);
     643             :         else
     644             :                 namelen = 0;
     645           0 :         tlen = sizeof(*param) + len + namelen;
     646           0 :         param = malloc(tlen, M_TEMP, M_WAITOK | M_CANFAIL);
     647           0 :         if (param == NULL) {
     648           0 :                 printf("%s: out of memory\n", DEVNAME(sc));
     649           0 :                 return RNDIS_STATUS_FAILURE;
     650             :         }
     651             : 
     652           0 :         param->rm_namelen = htole32(namelen);
     653           0 :         param->rm_valuelen = htole32(len);
     654           0 :         param->rm_type = htole32(type);
     655           0 :         if (namelen != 0) {
     656           0 :                 param->rm_nameoffset = htole32(20);
     657           0 :                 memcpy(param + 20, name, namelen);
     658           0 :         } else
     659           0 :                 param->rm_nameoffset = 0;
     660           0 :         if (len != 0) {
     661           0 :                 param->rm_valueoffset = htole32(20 + namelen);
     662           0 :                 memcpy(param + 20 + namelen, buf, len);
     663           0 :         } else
     664           0 :                 param->rm_valueoffset = 0;
     665             : 
     666             :         DPRINTF(("%s: urndis_ctrl_set_param send: nameoffset %u namelen %u "
     667             :             "type 0x%x valueoffset %u valuelen %u\n",
     668             :             DEVNAME(sc),
     669             :             letoh32(param->rm_nameoffset),
     670             :             letoh32(param->rm_namelen),
     671             :             letoh32(param->rm_type),
     672             :             letoh32(param->rm_valueoffset),
     673             :             letoh32(param->rm_valuelen)));
     674             : 
     675           0 :         rval = urndis_ctrl_set(sc, OID_GEN_RNDIS_CONFIG_PARAMETER, param, tlen);
     676           0 :         free(param, M_TEMP, tlen);
     677           0 :         if (rval != RNDIS_STATUS_SUCCESS)
     678           0 :                 printf("%s: set param failed 0x%x\n", DEVNAME(sc), rval);
     679             : 
     680           0 :         return rval;
     681           0 : }
     682             : 
     683             : #if 0
     684             : /* XXX : adrreset, get it from response */
     685             : u_int32_t
     686             : urndis_ctrl_reset(struct urndis_softc *sc)
     687             : {
     688             :         struct rndis_reset_req          *reset;
     689             :         u_int32_t                        rval;
     690             :         struct rndis_comp_hdr           *hdr;
     691             : 
     692             :         reset = malloc(sizeof(*reset), M_TEMP, M_WAITOK | M_CANFAIL);
     693             :         if (reset == NULL) {
     694             :                 printf("%s: out of memory\n", DEVNAME(sc));
     695             :                 return RNDIS_STATUS_FAILURE;
     696             :         }
     697             : 
     698             :         reset->rm_type = htole32(REMOTE_NDIS_RESET_MSG);
     699             :         reset->rm_len = htole32(sizeof(*reset));
     700             :         reset->rm_rid = 0; /* XXX rm_rid == reserved ... remove ? */
     701             : 
     702             :         DPRINTF(("%s: urndis_ctrl_reset send: type %u len %u rid %u\n",
     703             :             DEVNAME(sc),
     704             :             letoh32(reset->rm_type),
     705             :             letoh32(reset->rm_len),
     706             :             letoh32(reset->rm_rid)));
     707             : 
     708             :         rval = urndis_ctrl_send(sc, reset, sizeof(*reset));
     709             :         free(reset, M_TEMP, sizeof *reset);
     710             : 
     711             :         if (rval != RNDIS_STATUS_SUCCESS) {
     712             :                 printf("%s: reset failed\n", DEVNAME(sc));
     713             :                 return rval;
     714             :         }
     715             : 
     716             :         if ((hdr = urndis_ctrl_recv(sc)) == NULL) {
     717             :                 printf("%s: unable to get reset response\n", DEVNAME(sc));
     718             :                 return RNDIS_STATUS_FAILURE;
     719             :         }
     720             :         rval = urndis_ctrl_handle(sc, hdr, NULL, NULL);
     721             : 
     722             :         return rval;
     723             : }
     724             : 
     725             : u_int32_t
     726             : urndis_ctrl_keepalive(struct urndis_softc *sc)
     727             : {
     728             :         struct rndis_keepalive_req      *keep;
     729             :         u_int32_t                        rval;
     730             :         struct rndis_comp_hdr           *hdr;
     731             : 
     732             :         keep = malloc(sizeof(*keep), M_TEMP, M_WAITOK | M_CANFAIL);
     733             :         if (keep == NULL) {
     734             :                 printf("%s: out of memory\n", DEVNAME(sc));
     735             :                 return RNDIS_STATUS_FAILURE;
     736             :         }
     737             : 
     738             :         keep->rm_type = htole32(REMOTE_NDIS_KEEPALIVE_MSG);
     739             :         keep->rm_len = htole32(sizeof(*keep));
     740             :         keep->rm_rid = 0; /* XXX rm_rid == reserved ... remove ? */
     741             : 
     742             :         DPRINTF(("%s: urndis_ctrl_keepalive: type %u len %u rid %u\n",
     743             :             DEVNAME(sc),
     744             :             letoh32(keep->rm_type),
     745             :             letoh32(keep->rm_len),
     746             :             letoh32(keep->rm_rid)));
     747             : 
     748             :         rval = urndis_ctrl_send(sc, keep, sizeof(*keep));
     749             :         free(keep, M_TEMP, sizeof *keep);
     750             : 
     751             :         if (rval != RNDIS_STATUS_SUCCESS) {
     752             :                 printf("%s: keepalive failed\n", DEVNAME(sc));
     753             :                 return rval;
     754             :         }
     755             : 
     756             :         if ((hdr = urndis_ctrl_recv(sc)) == NULL) {
     757             :                 printf("%s: unable to get keepalive response\n", DEVNAME(sc));
     758             :                 return RNDIS_STATUS_FAILURE;
     759             :         }
     760             :         rval = urndis_ctrl_handle(sc, hdr, NULL, NULL);
     761             :         if (rval != RNDIS_STATUS_SUCCESS) {
     762             :                 printf("%s: keepalive failed 0x%x\n", DEVNAME(sc), rval);
     763             :                 urndis_ctrl_reset(sc);
     764             :         }
     765             : 
     766             :         return rval;
     767             : }
     768             : #endif
     769             : 
     770             : int
     771           0 : urndis_encap(struct urndis_softc *sc, struct mbuf *m, int idx)
     772             : {
     773             :         struct urndis_chain             *c;
     774             :         usbd_status                      err;
     775             :         struct rndis_packet_msg         *msg;
     776             : 
     777           0 :         c = &sc->sc_data.sc_tx_chain[idx];
     778             : 
     779           0 :         msg = (struct rndis_packet_msg *)c->sc_buf;
     780             : 
     781           0 :         memset(msg, 0, sizeof(*msg));
     782           0 :         msg->rm_type = htole32(REMOTE_NDIS_PACKET_MSG);
     783           0 :         msg->rm_len = htole32(sizeof(*msg) + m->m_pkthdr.len);
     784             : 
     785           0 :         msg->rm_dataoffset = htole32(RNDIS_DATA_OFFSET);
     786           0 :         msg->rm_datalen = htole32(m->m_pkthdr.len);
     787             : 
     788           0 :         m_copydata(m, 0, m->m_pkthdr.len,
     789           0 :             ((char*)msg + RNDIS_DATA_OFFSET + RNDIS_HEADER_OFFSET));
     790             : 
     791             :         DPRINTF(("%s: urndis_encap type 0x%x len %u data(off %u len %u)\n",
     792             :             DEVNAME(sc),
     793             :             letoh32(msg->rm_type),
     794             :             letoh32(msg->rm_len),
     795             :             letoh32(msg->rm_dataoffset),
     796             :             letoh32(msg->rm_datalen)));
     797             : 
     798           0 :         c->sc_mbuf = m;
     799             : 
     800           0 :         usbd_setup_xfer(c->sc_xfer, sc->sc_bulkout_pipe, c, c->sc_buf,
     801           0 :             letoh32(msg->rm_len), USBD_FORCE_SHORT_XFER | USBD_NO_COPY, 10000,
     802             :             urndis_txeof);
     803             : 
     804             :         /* Transmit */
     805           0 :         err = usbd_transfer(c->sc_xfer);
     806           0 :         if (err != USBD_IN_PROGRESS) {
     807           0 :                 urndis_stop(sc);
     808           0 :                 return(EIO);
     809             :         }
     810             : 
     811           0 :         sc->sc_data.sc_tx_cnt++;
     812             : 
     813           0 :         return(0);
     814           0 : }
     815             : 
     816             : void
     817           0 : urndis_decap(struct urndis_softc *sc, struct urndis_chain *c, u_int32_t len)
     818             : {
     819             :         struct mbuf             *m;
     820           0 :         struct mbuf_list         ml = MBUF_LIST_INITIALIZER();
     821             :         struct rndis_packet_msg *msg;
     822             :         struct ifnet            *ifp;
     823             :         int                      s;
     824             :         int                      offset;
     825             : 
     826           0 :         ifp = GET_IFP(sc);
     827             :         offset = 0;
     828             : 
     829           0 :         while (len > 0) {
     830           0 :                 msg = (struct rndis_packet_msg *)((char*)c->sc_buf + offset);
     831           0 :                 m = c->sc_mbuf;
     832             : 
     833             :                 DPRINTF(("%s: urndis_decap buffer size left %u\n", DEVNAME(sc),
     834             :                     len));
     835             : 
     836           0 :                 if (len < sizeof(*msg)) {
     837           0 :                         printf("%s: urndis_decap invalid buffer len %u < "
     838             :                             "minimum header %zu\n",
     839           0 :                             DEVNAME(sc),
     840             :                             len,
     841             :                             sizeof(*msg));
     842           0 :                         return;
     843             :                 }
     844             : 
     845             :                 DPRINTF(("%s: urndis_decap len %u data(off:%u len:%u) "
     846             :                     "oobdata(off:%u len:%u nb:%u) perpacket(off:%u len:%u)\n",
     847             :                     DEVNAME(sc),
     848             :                     letoh32(msg->rm_len),
     849             :                     letoh32(msg->rm_dataoffset),
     850             :                     letoh32(msg->rm_datalen),
     851             :                     letoh32(msg->rm_oobdataoffset),
     852             :                     letoh32(msg->rm_oobdatalen),
     853             :                     letoh32(msg->rm_oobdataelements),
     854             :                     letoh32(msg->rm_pktinfooffset),
     855             :                     letoh32(msg->rm_pktinfooffset)));
     856             : 
     857           0 :                 if (letoh32(msg->rm_type) != REMOTE_NDIS_PACKET_MSG) {
     858           0 :                         printf("%s: urndis_decap invalid type 0x%x != 0x%x\n",
     859           0 :                             DEVNAME(sc),
     860             :                             letoh32(msg->rm_type),
     861             :                             REMOTE_NDIS_PACKET_MSG);
     862           0 :                         return;
     863             :                 }
     864           0 :                 if (letoh32(msg->rm_len) < sizeof(*msg)) {
     865           0 :                         printf("%s: urndis_decap invalid msg len %u < %zu\n",
     866           0 :                             DEVNAME(sc),
     867             :                             letoh32(msg->rm_len),
     868             :                             sizeof(*msg));
     869           0 :                         return;
     870             :                 }
     871           0 :                 if (letoh32(msg->rm_len) > len) {
     872           0 :                         printf("%s: urndis_decap invalid msg len %u > buffer "
     873             :                             "len %u\n",
     874           0 :                             DEVNAME(sc),
     875             :                             letoh32(msg->rm_len),
     876             :                             len);
     877           0 :                         return;
     878             :                 }
     879             : 
     880           0 :                 if (letoh32(msg->rm_dataoffset) +
     881           0 :                     letoh32(msg->rm_datalen) + RNDIS_HEADER_OFFSET
     882           0 :                         > letoh32(msg->rm_len)) {
     883           0 :                         printf("%s: urndis_decap invalid data "
     884             :                             "len/offset/end_position(%u/%u/%zu) -> "
     885             :                             "go out of receive buffer limit %u\n",
     886           0 :                             DEVNAME(sc),
     887             :                             letoh32(msg->rm_datalen),
     888             :                             letoh32(msg->rm_dataoffset),
     889             :                             letoh32(msg->rm_dataoffset) +
     890             :                             letoh32(msg->rm_datalen) + RNDIS_HEADER_OFFSET,
     891             :                             letoh32(msg->rm_len));
     892           0 :                         return;
     893             :                 }
     894             : 
     895           0 :                 if (letoh32(msg->rm_datalen) < sizeof(struct ether_header)) {
     896           0 :                         ifp->if_ierrors++;
     897             :                         DPRINTF(("%s: urndis_decap invalid ethernet size "
     898             :                             "%u < %zu\n",
     899             :                             DEVNAME(sc),
     900             :                             letoh32(msg->rm_datalen),
     901             :                             sizeof(struct ether_header)));
     902           0 :                         return;
     903             :                 }
     904             : 
     905           0 :                 memcpy(mtod(m, char*),
     906             :                     ((char*)&msg->rm_dataoffset + letoh32(msg->rm_dataoffset)),
     907             :                     letoh32(msg->rm_datalen));
     908           0 :                 m->m_pkthdr.len = m->m_len = letoh32(msg->rm_datalen);
     909             : 
     910           0 :                 if (urndis_newbuf(sc, c) == ENOBUFS) {
     911           0 :                         ifp->if_ierrors++;
     912           0 :                 } else {
     913           0 :                         ml_enqueue(&ml, m);
     914             :                 }
     915             : 
     916           0 :                 offset += letoh32(msg->rm_len);
     917           0 :                 len -= letoh32(msg->rm_len);
     918             :         }
     919             : 
     920           0 :         s = splnet();
     921           0 :         if_input(ifp, &ml);
     922           0 :         splx(s);
     923           0 : }
     924             : 
     925             : int
     926           0 : urndis_newbuf(struct urndis_softc *sc, struct urndis_chain *c)
     927             : {
     928             :         struct mbuf *m_new = NULL;
     929             : 
     930           0 :         MGETHDR(m_new, M_DONTWAIT, MT_DATA);
     931           0 :         if (m_new == NULL) {
     932           0 :                 printf("%s: no memory for rx list -- packet dropped!\n",
     933           0 :                     DEVNAME(sc));
     934           0 :                 return (ENOBUFS);
     935             :         }
     936           0 :         MCLGET(m_new, M_DONTWAIT);
     937           0 :         if (!(m_new->m_flags & M_EXT)) {
     938           0 :                 printf("%s: no memory for rx list -- packet dropped!\n",
     939           0 :                     DEVNAME(sc));
     940           0 :                 m_freem(m_new);
     941           0 :                 return (ENOBUFS);
     942             :         }
     943           0 :         m_new->m_len = m_new->m_pkthdr.len = MCLBYTES;
     944             : 
     945           0 :         m_adj(m_new, ETHER_ALIGN);
     946           0 :         c->sc_mbuf = m_new;
     947           0 :         return (0);
     948           0 : }
     949             : 
     950             : int
     951           0 : urndis_rx_list_init(struct urndis_softc *sc)
     952             : {
     953             :         struct urndis_cdata     *cd;
     954             :         struct urndis_chain     *c;
     955             :         int                      i;
     956             : 
     957           0 :         cd = &sc->sc_data;
     958           0 :         for (i = 0; i < RNDIS_RX_LIST_CNT; i++) {
     959           0 :                 c = &cd->sc_rx_chain[i];
     960           0 :                 c->sc_softc = sc;
     961           0 :                 c->sc_idx = i;
     962             : 
     963           0 :                 if (urndis_newbuf(sc, c) == ENOBUFS)
     964           0 :                         return (ENOBUFS);
     965             : 
     966           0 :                 if (c->sc_xfer == NULL) {
     967           0 :                         c->sc_xfer = usbd_alloc_xfer(sc->sc_udev);
     968           0 :                         if (c->sc_xfer == NULL)
     969           0 :                                 return (ENOBUFS);
     970           0 :                         c->sc_buf = usbd_alloc_buffer(c->sc_xfer,
     971             :                             RNDIS_BUFSZ);
     972           0 :                         if (c->sc_buf == NULL)
     973           0 :                                 return (ENOBUFS);
     974             :                 }
     975             :         }
     976             : 
     977           0 :         return (0);
     978           0 : }
     979             : 
     980             : int
     981           0 : urndis_tx_list_init(struct urndis_softc *sc)
     982             : {
     983             :         struct urndis_cdata     *cd;
     984             :         struct urndis_chain     *c;
     985             :         int                      i;
     986             : 
     987           0 :         cd = &sc->sc_data;
     988           0 :         for (i = 0; i < RNDIS_TX_LIST_CNT; i++) {
     989           0 :                 c = &cd->sc_tx_chain[i];
     990           0 :                 c->sc_softc = sc;
     991           0 :                 c->sc_idx = i;
     992           0 :                 c->sc_mbuf = NULL;
     993           0 :                 if (c->sc_xfer == NULL) {
     994           0 :                         c->sc_xfer = usbd_alloc_xfer(sc->sc_udev);
     995           0 :                         if (c->sc_xfer == NULL)
     996           0 :                                 return (ENOBUFS);
     997           0 :                         c->sc_buf = usbd_alloc_buffer(c->sc_xfer,
     998             :                             RNDIS_BUFSZ);
     999           0 :                         if (c->sc_buf == NULL)
    1000           0 :                                 return (ENOBUFS);
    1001             :                 }
    1002             :         }
    1003           0 :         return (0);
    1004           0 : }
    1005             : 
    1006             : int
    1007           0 : urndis_ioctl(struct ifnet *ifp, u_long command, caddr_t data)
    1008             : {
    1009           0 :         struct urndis_softc     *sc = ifp->if_softc;
    1010             :         int                      s, error = 0;
    1011             : 
    1012           0 :         if (usbd_is_dying(sc->sc_udev))
    1013           0 :                 return (EIO);
    1014             : 
    1015           0 :         s = splnet();
    1016             : 
    1017           0 :         switch(command) {
    1018             :         case SIOCSIFADDR:
    1019           0 :                 ifp->if_flags |= IFF_UP;
    1020           0 :                 if (!(ifp->if_flags & IFF_RUNNING))
    1021           0 :                         urndis_init(sc);
    1022             :                 break;
    1023             : 
    1024             :         case SIOCSIFFLAGS:
    1025           0 :                 if (ifp->if_flags & IFF_UP) {
    1026           0 :                         if (ifp->if_flags & IFF_RUNNING)
    1027           0 :                                 error = ENETRESET;
    1028             :                         else
    1029           0 :                                 urndis_init(sc);
    1030             :                 } else {
    1031           0 :                         if (ifp->if_flags & IFF_RUNNING)
    1032           0 :                                 urndis_stop(sc);
    1033             :                 }
    1034             :                 break;
    1035             : 
    1036             :         default:
    1037           0 :                 error = ether_ioctl(ifp, &sc->sc_arpcom, command, data);
    1038           0 :                 break;
    1039             :         }
    1040             : 
    1041           0 :         if (error == ENETRESET)
    1042           0 :                 error = 0;
    1043             : 
    1044           0 :         splx(s);
    1045           0 :         return (error);
    1046           0 : }
    1047             : 
    1048             : #if 0
    1049             : void
    1050             : urndis_watchdog(struct ifnet *ifp)
    1051             : {
    1052             :         struct urndis_softc *sc;
    1053             : 
    1054             :         sc = ifp->if_softc;
    1055             : 
    1056             :         if (usbd_is_dying(sc->sc_udev))
    1057             :                 return;
    1058             : 
    1059             :         ifp->if_oerrors++;
    1060             :         printf("%s: watchdog timeout\n", DEVNAME(sc));
    1061             : 
    1062             :         urndis_ctrl_keepalive(sc);
    1063             : }
    1064             : #endif
    1065             : 
    1066             : void
    1067           0 : urndis_init(struct urndis_softc *sc)
    1068             : {
    1069           0 :         struct ifnet            *ifp = GET_IFP(sc);
    1070             :         int                      i, s;
    1071             :         usbd_status              err;
    1072             : 
    1073           0 :         if (urndis_ctrl_init(sc) != RNDIS_STATUS_SUCCESS)
    1074           0 :                 return;
    1075             : 
    1076           0 :         s = splnet();
    1077             : 
    1078           0 :         if (urndis_tx_list_init(sc) == ENOBUFS) {
    1079           0 :                 printf("%s: tx list init failed\n",
    1080           0 :                     DEVNAME(sc));
    1081           0 :                 splx(s);
    1082           0 :                 return;
    1083             :         }
    1084             : 
    1085           0 :         if (urndis_rx_list_init(sc) == ENOBUFS) {
    1086           0 :                 printf("%s: rx list init failed\n",
    1087           0 :                     DEVNAME(sc));
    1088           0 :                 splx(s);
    1089           0 :                 return;
    1090             :         }
    1091             : 
    1092           0 :         err = usbd_open_pipe(sc->sc_iface_data, sc->sc_bulkin_no,
    1093           0 :             USBD_EXCLUSIVE_USE, &sc->sc_bulkin_pipe);
    1094           0 :         if (err) {
    1095           0 :                 printf("%s: open rx pipe failed: %s\n", DEVNAME(sc),
    1096           0 :                     usbd_errstr(err));
    1097           0 :                 splx(s);
    1098           0 :                 return;
    1099             :         }
    1100             : 
    1101           0 :         err = usbd_open_pipe(sc->sc_iface_data, sc->sc_bulkout_no,
    1102           0 :             USBD_EXCLUSIVE_USE, &sc->sc_bulkout_pipe);
    1103           0 :         if (err) {
    1104           0 :                 printf("%s: open tx pipe failed: %s\n", DEVNAME(sc),
    1105           0 :                     usbd_errstr(err));
    1106           0 :                 splx(s);
    1107           0 :                 return;
    1108             :         }
    1109             : 
    1110           0 :         for (i = 0; i < RNDIS_RX_LIST_CNT; i++) {
    1111             :                 struct urndis_chain *c;
    1112             : 
    1113           0 :                 c = &sc->sc_data.sc_rx_chain[i];
    1114           0 :                 usbd_setup_xfer(c->sc_xfer, sc->sc_bulkin_pipe, c,
    1115           0 :                     c->sc_buf, RNDIS_BUFSZ,
    1116             :                     USBD_SHORT_XFER_OK | USBD_NO_COPY,
    1117             :                     USBD_NO_TIMEOUT, urndis_rxeof);
    1118           0 :                 usbd_transfer(c->sc_xfer);
    1119             :         }
    1120             : 
    1121           0 :         ifp->if_flags |= IFF_RUNNING;
    1122           0 :         ifq_clr_oactive(&ifp->if_snd);
    1123             : 
    1124           0 :         splx(s);
    1125           0 : }
    1126             : 
    1127             : void
    1128           0 : urndis_stop(struct urndis_softc *sc)
    1129             : {
    1130             :         usbd_status      err;
    1131             :         struct ifnet    *ifp;
    1132             :         int              i;
    1133             : 
    1134           0 :         ifp = GET_IFP(sc);
    1135           0 :         ifp->if_timer = 0;
    1136           0 :         ifp->if_flags &= ~IFF_RUNNING;
    1137           0 :         ifq_clr_oactive(&ifp->if_snd);
    1138             : 
    1139           0 :         if (sc->sc_bulkin_pipe != NULL) {
    1140           0 :                 usbd_abort_pipe(sc->sc_bulkin_pipe);
    1141           0 :                 err = usbd_close_pipe(sc->sc_bulkin_pipe);
    1142           0 :                 if (err)
    1143           0 :                         printf("%s: close rx pipe failed: %s\n",
    1144           0 :                             DEVNAME(sc), usbd_errstr(err));
    1145           0 :                 sc->sc_bulkin_pipe = NULL;
    1146           0 :         }
    1147             : 
    1148           0 :         if (sc->sc_bulkout_pipe != NULL) {
    1149           0 :                 usbd_abort_pipe(sc->sc_bulkout_pipe);
    1150           0 :                 err = usbd_close_pipe(sc->sc_bulkout_pipe);
    1151           0 :                 if (err)
    1152           0 :                         printf("%s: close tx pipe failed: %s\n",
    1153           0 :                             DEVNAME(sc), usbd_errstr(err));
    1154           0 :                 sc->sc_bulkout_pipe = NULL;
    1155           0 :         }
    1156             : 
    1157           0 :         for (i = 0; i < RNDIS_RX_LIST_CNT; i++) {
    1158           0 :                 if (sc->sc_data.sc_rx_chain[i].sc_mbuf != NULL) {
    1159           0 :                         m_freem(sc->sc_data.sc_rx_chain[i].sc_mbuf);
    1160           0 :                         sc->sc_data.sc_rx_chain[i].sc_mbuf = NULL;
    1161           0 :                 }
    1162           0 :                 if (sc->sc_data.sc_rx_chain[i].sc_xfer != NULL) {
    1163           0 :                         usbd_free_xfer(sc->sc_data.sc_rx_chain[i].sc_xfer);
    1164           0 :                         sc->sc_data.sc_rx_chain[i].sc_xfer = NULL;
    1165           0 :                 }
    1166             :         }
    1167             : 
    1168           0 :         for (i = 0; i < RNDIS_TX_LIST_CNT; i++) {
    1169           0 :                 if (sc->sc_data.sc_tx_chain[i].sc_mbuf != NULL) {
    1170           0 :                         m_freem(sc->sc_data.sc_tx_chain[i].sc_mbuf);
    1171           0 :                         sc->sc_data.sc_tx_chain[i].sc_mbuf = NULL;
    1172           0 :                 }
    1173           0 :                 if (sc->sc_data.sc_tx_chain[i].sc_xfer != NULL) {
    1174           0 :                         usbd_free_xfer(sc->sc_data.sc_tx_chain[i].sc_xfer);
    1175           0 :                         sc->sc_data.sc_tx_chain[i].sc_xfer = NULL;
    1176           0 :                 }
    1177             :         }
    1178           0 : }
    1179             : 
    1180             : void
    1181           0 : urndis_start(struct ifnet *ifp)
    1182             : {
    1183             :         struct urndis_softc     *sc;
    1184             :         struct mbuf             *m_head = NULL;
    1185             : 
    1186           0 :         sc = ifp->if_softc;
    1187             : 
    1188           0 :         if (usbd_is_dying(sc->sc_udev) || ifq_is_oactive(&ifp->if_snd))
    1189           0 :                 return;
    1190             : 
    1191           0 :         m_head = ifq_deq_begin(&ifp->if_snd);
    1192           0 :         if (m_head == NULL)
    1193           0 :                 return;
    1194             : 
    1195           0 :         if (urndis_encap(sc, m_head, 0)) {
    1196           0 :                 ifq_deq_rollback(&ifp->if_snd, m_head);
    1197           0 :                 ifq_set_oactive(&ifp->if_snd);
    1198           0 :                 return;
    1199             :         }
    1200           0 :         ifq_deq_commit(&ifp->if_snd, m_head);
    1201             : 
    1202             :         /*
    1203             :          * If there's a BPF listener, bounce a copy of this frame
    1204             :          * to him.
    1205             :          */
    1206             : #if NBPFILTER > 0
    1207           0 :         if (ifp->if_bpf)
    1208           0 :                 bpf_mtap(ifp->if_bpf, m_head, BPF_DIRECTION_OUT);
    1209             : #endif
    1210             : 
    1211           0 :         ifq_set_oactive(&ifp->if_snd);
    1212             : 
    1213             :         /*
    1214             :          * Set a timeout in case the chip goes out to lunch.
    1215             :          */
    1216           0 :         ifp->if_timer = 5;
    1217             : 
    1218           0 :         return;
    1219           0 : }
    1220             : 
    1221             : void
    1222           0 : urndis_rxeof(struct usbd_xfer *xfer,
    1223             :     void *priv,
    1224             :     usbd_status status)
    1225             : {
    1226             :         struct urndis_chain     *c;
    1227             :         struct urndis_softc     *sc;
    1228             :         struct ifnet            *ifp;
    1229           0 :         u_int32_t                total_len;
    1230             : 
    1231           0 :         c = priv;
    1232           0 :         sc = c->sc_softc;
    1233           0 :         ifp = GET_IFP(sc);
    1234           0 :         total_len = 0;
    1235             : 
    1236           0 :         if (usbd_is_dying(sc->sc_udev) || !(ifp->if_flags & IFF_RUNNING))
    1237           0 :                 return;
    1238             : 
    1239           0 :         if (status != USBD_NORMAL_COMPLETION) {
    1240           0 :                 if (status == USBD_NOT_STARTED || status == USBD_CANCELLED)
    1241           0 :                         return;
    1242           0 :                 if (usbd_ratecheck(&sc->sc_rx_notice)) {
    1243             :                         DPRINTF(("%s: usb errors on rx: %s\n",
    1244             :                             DEVNAME(sc), usbd_errstr(status)));
    1245             :                 }
    1246           0 :                 if (status == USBD_STALLED)
    1247           0 :                         usbd_clear_endpoint_stall_async(sc->sc_bulkin_pipe);
    1248             : 
    1249           0 :                 ifp->if_ierrors++;
    1250           0 :                 goto done;
    1251             :         }
    1252             : 
    1253           0 :         usbd_get_xfer_status(xfer, NULL, NULL, &total_len, NULL);
    1254           0 :         urndis_decap(sc, c, total_len);
    1255             : 
    1256             : done:
    1257             :         /* Setup new transfer. */
    1258           0 :         usbd_setup_xfer(c->sc_xfer, sc->sc_bulkin_pipe, c, c->sc_buf,
    1259             :             RNDIS_BUFSZ, USBD_SHORT_XFER_OK | USBD_NO_COPY, USBD_NO_TIMEOUT,
    1260             :             urndis_rxeof);
    1261           0 :         usbd_transfer(c->sc_xfer);
    1262           0 : }
    1263             : 
    1264             : void
    1265           0 : urndis_txeof(struct usbd_xfer *xfer,
    1266             :     void *priv,
    1267             :     usbd_status status)
    1268             : {
    1269             :         struct urndis_chain     *c;
    1270             :         struct urndis_softc     *sc;
    1271             :         struct ifnet            *ifp;
    1272           0 :         usbd_status              err;
    1273             :         int                      s;
    1274             : 
    1275           0 :         c = priv;
    1276           0 :         sc = c->sc_softc;
    1277           0 :         ifp = GET_IFP(sc);
    1278             : 
    1279             :         DPRINTF(("%s: urndis_txeof\n", DEVNAME(sc)));
    1280             : 
    1281           0 :         if (usbd_is_dying(sc->sc_udev))
    1282           0 :                 return;
    1283             : 
    1284           0 :         s = splnet();
    1285             : 
    1286           0 :         ifp->if_timer = 0;
    1287           0 :         ifq_clr_oactive(&ifp->if_snd);
    1288             : 
    1289           0 :         if (status != USBD_NORMAL_COMPLETION) {
    1290           0 :                 if (status == USBD_NOT_STARTED || status == USBD_CANCELLED) {
    1291           0 :                         splx(s);
    1292           0 :                         return;
    1293             :                 }
    1294           0 :                 ifp->if_oerrors++;
    1295             :                 DPRINTF(("%s: usb error on tx: %s\n", DEVNAME(sc),
    1296             :                     usbd_errstr(status)));
    1297           0 :                 if (status == USBD_STALLED)
    1298           0 :                         usbd_clear_endpoint_stall_async(sc->sc_bulkout_pipe);
    1299           0 :                 splx(s);
    1300           0 :                 return;
    1301             :         }
    1302             : 
    1303           0 :         usbd_get_xfer_status(c->sc_xfer, NULL, NULL, NULL, &err);
    1304             : 
    1305           0 :         if (c->sc_mbuf != NULL) {
    1306           0 :                 m_freem(c->sc_mbuf);
    1307           0 :                 c->sc_mbuf = NULL;
    1308           0 :         }
    1309             : 
    1310           0 :         if (err)
    1311           0 :                 ifp->if_oerrors++;
    1312             : 
    1313           0 :         if (IFQ_IS_EMPTY(&ifp->if_snd) == 0)
    1314           0 :                 urndis_start(ifp);
    1315             : 
    1316           0 :         splx(s);
    1317           0 : }
    1318             : 
    1319             : const struct urndis_class *
    1320           0 : urndis_lookup(usb_interface_descriptor_t *id)
    1321             : {
    1322             :         const struct urndis_class       *uc;
    1323             :         int                              i;
    1324             : 
    1325             :         uc = urndis_class;
    1326           0 :         for (i = 0; i < nitems(urndis_class); i++, uc++) {
    1327           0 :                 if (uc->class == id->bInterfaceClass &&
    1328           0 :                     uc->subclass == id->bInterfaceSubClass &&
    1329           0 :                     uc->protocol == id->bInterfaceProtocol)
    1330           0 :                         return (uc);
    1331             :         }
    1332           0 :         return (NULL);
    1333           0 : }
    1334             : 
    1335             : int
    1336           0 : urndis_match(struct device *parent, void *match, void *aux)
    1337             : {
    1338           0 :         struct usb_attach_arg           *uaa = aux;
    1339             :         usb_interface_descriptor_t      *id;
    1340             : 
    1341             :         /* Advertises both RNDIS and CDC Ethernet, but RNDIS doesn't work. */
    1342           0 :         if (uaa->vendor == USB_VENDOR_FUJITSUCOMP &&
    1343           0 :             uaa->product == USB_PRODUCT_FUJITSUCOMP_VIRTETH)
    1344           0 :                 return (UMATCH_NONE);
    1345             : 
    1346           0 :         if (!uaa->iface)
    1347           0 :                 return (UMATCH_NONE);
    1348             : 
    1349           0 :         id = usbd_get_interface_descriptor(uaa->iface);
    1350           0 :         if (id == NULL)
    1351           0 :                 return (UMATCH_NONE);
    1352             : 
    1353           0 :         return (urndis_lookup(id) ?
    1354             :             UMATCH_IFACECLASS_IFACESUBCLASS_IFACEPROTO : UMATCH_NONE);
    1355           0 : }
    1356             : 
    1357             : void
    1358           0 : urndis_attach(struct device *parent, struct device *self, void *aux)
    1359             : {
    1360             :         const struct urndis_class       *uc;
    1361             :         struct urndis_softc             *sc;
    1362             :         struct usb_attach_arg           *uaa;
    1363             :         struct ifnet                    *ifp;
    1364             :         usb_interface_descriptor_t      *id;
    1365             :         usb_endpoint_descriptor_t       *ed;
    1366             :         usb_config_descriptor_t         *cd;
    1367             :         int                              i, j, altcnt;
    1368             :         int                              s;
    1369           0 :         u_char                           eaddr[ETHER_ADDR_LEN];
    1370           0 :         void                            *buf;
    1371           0 :         size_t                           bufsz;
    1372           0 :         u_int32_t                        filter;
    1373             : 
    1374           0 :         sc = (void *)self;
    1375           0 :         uaa = aux;
    1376             : 
    1377           0 :         sc->sc_attached = 0;
    1378           0 :         sc->sc_udev = uaa->device;
    1379           0 :         id = usbd_get_interface_descriptor(uaa->iface);
    1380           0 :         sc->sc_ifaceno_ctl = id->bInterfaceNumber;
    1381             : 
    1382           0 :         for (i = 0; i < uaa->nifaces; i++) {
    1383           0 :                 if (usbd_iface_claimed(sc->sc_udev, i))
    1384             :                         continue;
    1385             : 
    1386           0 :                 if (uaa->ifaces[i] != uaa->iface) {
    1387           0 :                         sc->sc_iface_data = uaa->ifaces[i];
    1388           0 :                         usbd_claim_iface(sc->sc_udev, i);
    1389           0 :                         break;
    1390             :                 }
    1391             :         }
    1392             : 
    1393           0 :         if (sc->sc_iface_data == NULL) {
    1394           0 :                 printf("%s: no data interface\n", DEVNAME(sc));
    1395           0 :                 return;
    1396             :         }
    1397             : 
    1398           0 :         uc = urndis_lookup(id);
    1399           0 :         printf("%s: using %s", DEVNAME(sc), uc->typestr);
    1400             : 
    1401           0 :         id = usbd_get_interface_descriptor(sc->sc_iface_data);
    1402           0 :         cd = usbd_get_config_descriptor(sc->sc_udev);
    1403           0 :         altcnt = usbd_get_no_alts(cd, id->bInterfaceNumber);
    1404             : 
    1405           0 :         for (j = 0; j < altcnt; j++) {
    1406           0 :                 if (usbd_set_interface(sc->sc_iface_data, j)) {
    1407           0 :                         printf(": interface alternate setting %u failed\n", j);
    1408           0 :                         return;
    1409             :                 }
    1410             :                 /* Find endpoints. */
    1411           0 :                 id = usbd_get_interface_descriptor(sc->sc_iface_data);
    1412           0 :                 sc->sc_bulkin_no = sc->sc_bulkout_no = -1;
    1413           0 :                 for (i = 0; i < id->bNumEndpoints; i++) {
    1414           0 :                         ed = usbd_interface2endpoint_descriptor(
    1415           0 :                             sc->sc_iface_data, i);
    1416           0 :                         if (!ed) {
    1417           0 :                                 printf(": no descriptor for bulk endpoint "
    1418             :                                     "%u\n", i);
    1419           0 :                                 return;
    1420             :                         }
    1421           0 :                         if (UE_GET_DIR(ed->bEndpointAddress) == UE_DIR_IN &&
    1422           0 :                             UE_GET_XFERTYPE(ed->bmAttributes) == UE_BULK) {
    1423           0 :                                 sc->sc_bulkin_no = ed->bEndpointAddress;
    1424           0 :                         }
    1425             :                         else if (
    1426           0 :                             UE_GET_DIR(ed->bEndpointAddress) == UE_DIR_OUT &&
    1427           0 :                             UE_GET_XFERTYPE(ed->bmAttributes) == UE_BULK) {
    1428           0 :                                 sc->sc_bulkout_no = ed->bEndpointAddress;
    1429           0 :                         }
    1430             :                 }
    1431             : 
    1432           0 :                 if (sc->sc_bulkin_no != -1 && sc->sc_bulkout_no != -1) {
    1433             :                         DPRINTF(("%s: in=0x%x, out=0x%x\n",
    1434             :                             DEVNAME(sc),
    1435             :                             sc->sc_bulkin_no,
    1436             :                             sc->sc_bulkout_no));
    1437             :                         goto found;
    1438             :                 }
    1439             :         }
    1440             : 
    1441           0 :         if (sc->sc_bulkin_no == -1)
    1442           0 :                 printf(": could not find data bulk in\n");
    1443           0 :         if (sc->sc_bulkout_no == -1 )
    1444           0 :                 printf(": could not find data bulk out\n");
    1445           0 :         return;
    1446             : 
    1447             :         found:
    1448             : 
    1449           0 :         ifp = GET_IFP(sc);
    1450           0 :         ifp->if_softc = sc;
    1451           0 :         ifp->if_flags = IFF_BROADCAST | IFF_SIMPLEX | IFF_MULTICAST;
    1452           0 :         ifp->if_start = urndis_start;
    1453           0 :         ifp->if_ioctl = urndis_ioctl;
    1454             : #if 0
    1455             :         ifp->if_watchdog = urndis_watchdog;
    1456             : #endif
    1457             : 
    1458           0 :         strlcpy(ifp->if_xname, DEVNAME(sc), IFNAMSIZ);
    1459             : 
    1460           0 :         s = splnet();
    1461             : 
    1462           0 :         if (urndis_ctrl_query(sc, OID_802_3_PERMANENT_ADDRESS, NULL, 0,
    1463           0 :             &buf, &bufsz) != RNDIS_STATUS_SUCCESS) {
    1464           0 :                 printf(": unable to get hardware address\n");
    1465           0 :                 splx(s);
    1466           0 :                 return;
    1467             :         }
    1468             : 
    1469           0 :         if (bufsz == ETHER_ADDR_LEN) {
    1470           0 :                 memcpy(eaddr, buf, ETHER_ADDR_LEN);
    1471           0 :                 printf(", address %s\n", ether_sprintf(eaddr));
    1472           0 :                 free(buf, M_TEMP, bufsz);
    1473             :         } else {
    1474           0 :                 printf(", invalid address\n");
    1475           0 :                 free(buf, M_TEMP, bufsz);
    1476           0 :                 splx(s);
    1477           0 :                 return;
    1478             :         }
    1479             : 
    1480             :         /* Initialize packet filter */
    1481           0 :         sc->sc_filter = NDIS_PACKET_TYPE_BROADCAST;
    1482           0 :         sc->sc_filter |= NDIS_PACKET_TYPE_ALL_MULTICAST;
    1483           0 :         filter = htole32(sc->sc_filter);
    1484           0 :         if (urndis_ctrl_set(sc, OID_GEN_CURRENT_PACKET_FILTER, &filter,
    1485           0 :             sizeof(filter)) != RNDIS_STATUS_SUCCESS) {
    1486           0 :                 printf("%s: unable to set data filters\n", DEVNAME(sc));
    1487           0 :                 splx(s);
    1488           0 :                 return;
    1489             :         }
    1490             : 
    1491           0 :         bcopy(eaddr, (char *)&sc->sc_arpcom.ac_enaddr, ETHER_ADDR_LEN);
    1492             : 
    1493           0 :         if_attach(ifp);
    1494           0 :         ether_ifattach(ifp);
    1495           0 :         sc->sc_attached = 1;
    1496             : 
    1497           0 :         splx(s);
    1498           0 : }
    1499             : 
    1500             : int
    1501           0 : urndis_detach(struct device *self, int flags)
    1502             : {
    1503             :         struct urndis_softc     *sc;
    1504             :         struct ifnet            *ifp;
    1505             :         int                      s;
    1506             : 
    1507           0 :         sc = (void*)self;
    1508             : 
    1509             :         DPRINTF(("urndis_detach: %s flags %u\n", DEVNAME(sc),
    1510             :             flags));
    1511             : 
    1512           0 :         if (!sc->sc_attached)
    1513           0 :                 return 0;
    1514             : 
    1515           0 :         s = splusb();
    1516             : 
    1517           0 :         ifp = GET_IFP(sc);
    1518             : 
    1519           0 :         if (ifp->if_softc != NULL) {
    1520           0 :                 ether_ifdetach(ifp);
    1521           0 :                 if_detach(ifp);
    1522           0 :         }
    1523             : 
    1524           0 :         urndis_stop(sc);
    1525           0 :         sc->sc_attached = 0;
    1526             : 
    1527           0 :         splx(s);
    1528             : 
    1529           0 :         return 0;
    1530           0 : }

Generated by: LCOV version 1.13