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

          Line data    Source code
       1             : /*-
       2             :  * Copyright (c) 2009-2012,2016 Microsoft Corp.
       3             :  * Copyright (c) 2010-2012 Citrix Inc.
       4             :  * Copyright (c) 2012 NetApp Inc.
       5             :  * Copyright (c) 2016 Mike Belopuhov <mike@esdenera.com>
       6             :  * All rights reserved.
       7             :  *
       8             :  * Redistribution and use in source and binary forms, with or without
       9             :  * modification, are permitted provided that the following conditions
      10             :  * are met:
      11             :  * 1. Redistributions of source code must retain the above copyright
      12             :  *    notice unmodified, this list of conditions, and the following
      13             :  *    disclaimer.
      14             :  * 2. Redistributions in binary form must reproduce the above copyright
      15             :  *    notice, this list of conditions and the following disclaimer in the
      16             :  *    documentation and/or other materials provided with the distribution.
      17             :  *
      18             :  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
      19             :  * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
      20             :  * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
      21             :  * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
      22             :  * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
      23             :  * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
      24             :  * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
      25             :  * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
      26             :  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
      27             :  * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
      28             :  */
      29             : 
      30             : /*
      31             :  * The OpenBSD port was done under funding by Esdenera Networks GmbH.
      32             :  */
      33             : 
      34             : #include "bpfilter.h"
      35             : #include "vlan.h"
      36             : #include "hyperv.h"
      37             : 
      38             : #include <sys/param.h>
      39             : #include <sys/systm.h>
      40             : #include <sys/atomic.h>
      41             : #include <sys/device.h>
      42             : #include <sys/kernel.h>
      43             : #include <sys/malloc.h>
      44             : #include <sys/mbuf.h>
      45             : #include <sys/pool.h>
      46             : #include <sys/queue.h>
      47             : #include <sys/socket.h>
      48             : #include <sys/sockio.h>
      49             : #include <sys/task.h>
      50             : #include <sys/timeout.h>
      51             : 
      52             : #include <machine/bus.h>
      53             : 
      54             : #include <uvm/uvm_extern.h>
      55             : 
      56             : #include <dev/pv/hypervreg.h>
      57             : #include <dev/pv/hypervvar.h>
      58             : 
      59             : #include <dev/rndis.h>
      60             : #include <dev/pv/ndis.h>
      61             : #include <dev/pv/if_hvnreg.h>
      62             : 
      63             : #include <net/if.h>
      64             : #include <net/if_media.h>
      65             : 
      66             : #include <netinet/in.h>
      67             : #include <netinet/if_ether.h>
      68             : 
      69             : #ifdef INET6
      70             : #include <netinet/ip6.h>
      71             : #endif
      72             : 
      73             : #if NBPFILTER > 0
      74             : #include <net/bpf.h>
      75             : #endif
      76             : 
      77             : #define HVN_NVS_MSGSIZE                 32
      78             : #define HVN_NVS_BUFSIZE                 PAGE_SIZE
      79             : 
      80             : /*
      81             :  * RNDIS control interface
      82             :  */
      83             : #define HVN_RNDIS_CTLREQS               4
      84             : #define HVN_RNDIS_BUFSIZE               512
      85             : 
      86             : struct rndis_cmd {
      87             :         uint32_t                         rc_id;
      88             :         struct hvn_nvs_rndis             rc_msg;
      89             :         void                            *rc_req;
      90             :         bus_dmamap_t                     rc_dmap;
      91             :         bus_dma_segment_t                rc_segs;
      92             :         int                              rc_nsegs;
      93             :         uint64_t                         rc_gpa;
      94             :         struct rndis_packet_msg          rc_cmp;
      95             :         uint32_t                         rc_cmplen;
      96             :         uint8_t                          rc_cmpbuf[HVN_RNDIS_BUFSIZE];
      97             :         int                              rc_done;
      98             :         TAILQ_ENTRY(rndis_cmd)           rc_entry;
      99             : };
     100             : TAILQ_HEAD(rndis_queue, rndis_cmd);
     101             : 
     102             : #define HVN_MAXMTU                      (9 * 1024)
     103             : 
     104             : #define HVN_RNDIS_XFER_SIZE             2048
     105             : 
     106             : /*
     107             :  * Tx ring
     108             :  */
     109             : #define HVN_TX_DESC                     256
     110             : #define HVN_TX_FRAGS                    15              /* 31 is the max */
     111             : #define HVN_TX_FRAG_SIZE                PAGE_SIZE
     112             : #define HVN_TX_PKT_SIZE                 16384
     113             : 
     114             : #define HVN_RNDIS_PKT_LEN                                       \
     115             :         (sizeof(struct rndis_packet_msg) +                      \
     116             :          sizeof(struct rndis_pktinfo) + NDIS_VLAN_INFO_SIZE +   \
     117             :          sizeof(struct rndis_pktinfo) + NDIS_TXCSUM_INFO_SIZE)
     118             : 
     119             : struct hvn_tx_desc {
     120             :         uint32_t                         txd_id;
     121             :         int                              txd_ready;
     122             :         struct vmbus_gpa                 txd_sgl[HVN_TX_FRAGS + 1];
     123             :         int                              txd_nsge;
     124             :         struct mbuf                     *txd_buf;
     125             :         bus_dmamap_t                     txd_dmap;
     126             :         struct vmbus_gpa                 txd_gpa;
     127             :         struct rndis_packet_msg         *txd_req;
     128             : };
     129             : 
     130             : struct hvn_softc {
     131             :         struct device                    sc_dev;
     132             :         struct hv_softc                 *sc_hvsc;
     133             :         struct hv_channel               *sc_chan;
     134             :         bus_dma_tag_t                    sc_dmat;
     135             : 
     136             :         struct arpcom                    sc_ac;
     137             :         struct ifmedia                   sc_media;
     138             :         int                              sc_link_state;
     139             : 
     140             :         /* NVS protocol */
     141             :         int                              sc_proto;
     142             :         uint32_t                         sc_nvstid;
     143             :         uint8_t                          sc_nvsrsp[HVN_NVS_MSGSIZE];
     144             :         uint8_t                         *sc_nvsbuf;
     145             :         int                              sc_nvsdone;
     146             : 
     147             :         /* RNDIS protocol */
     148             :         int                              sc_ndisver;
     149             :         uint32_t                         sc_rndisrid;
     150             :         struct rndis_queue               sc_cntl_sq; /* submission queue */
     151             :         struct mutex                     sc_cntl_sqlck;
     152             :         struct rndis_queue               sc_cntl_cq; /* completion queue */
     153             :         struct mutex                     sc_cntl_cqlck;
     154             :         struct rndis_queue               sc_cntl_fq; /* free queue */
     155             :         struct mutex                     sc_cntl_fqlck;
     156             :         struct rndis_cmd                 sc_cntl_msgs[HVN_RNDIS_CTLREQS];
     157             :         struct hvn_nvs_rndis             sc_data_msg;
     158             : 
     159             :         /* Rx ring */
     160             :         void                            *sc_rx_ring;
     161             :         int                              sc_rx_size;
     162             :         uint32_t                         sc_rx_hndl;
     163             : 
     164             :         /* Tx ring */
     165             :         uint32_t                         sc_tx_next;
     166             :         uint32_t                         sc_tx_avail;
     167             :         struct hvn_tx_desc               sc_tx_desc[HVN_TX_DESC];
     168             :         bus_dmamap_t                     sc_tx_rmap;
     169             :         void                            *sc_tx_msgs;
     170             :         bus_dma_segment_t                sc_tx_mseg;
     171             : };
     172             : 
     173             : int     hvn_match(struct device *, void *, void *);
     174             : void    hvn_attach(struct device *, struct device *, void *);
     175             : int     hvn_ioctl(struct ifnet *, u_long, caddr_t);
     176             : int     hvn_media_change(struct ifnet *);
     177             : void    hvn_media_status(struct ifnet *, struct ifmediareq *);
     178             : int     hvn_iff(struct hvn_softc *);
     179             : void    hvn_init(struct hvn_softc *);
     180             : void    hvn_stop(struct hvn_softc *);
     181             : void    hvn_start(struct ifqueue *);
     182             : int     hvn_encap(struct hvn_softc *, struct mbuf *, struct hvn_tx_desc **);
     183             : void    hvn_decap(struct hvn_softc *, struct hvn_tx_desc *);
     184             : void    hvn_txeof(struct hvn_softc *, uint64_t);
     185             : int     hvn_rx_ring_create(struct hvn_softc *);
     186             : int     hvn_rx_ring_destroy(struct hvn_softc *);
     187             : int     hvn_tx_ring_create(struct hvn_softc *);
     188             : void    hvn_tx_ring_destroy(struct hvn_softc *);
     189             : int     hvn_set_capabilities(struct hvn_softc *);
     190             : int     hvn_get_lladdr(struct hvn_softc *);
     191             : int     hvn_set_lladdr(struct hvn_softc *);
     192             : void    hvn_get_link_status(struct hvn_softc *);
     193             : void    hvn_link_status(struct hvn_softc *);
     194             : 
     195             : /* NSVP */
     196             : int     hvn_nvs_attach(struct hvn_softc *);
     197             : void    hvn_nvs_intr(void *);
     198             : int     hvn_nvs_cmd(struct hvn_softc *, void *, size_t, uint64_t, int);
     199             : int     hvn_nvs_ack(struct hvn_softc *, uint64_t);
     200             : void    hvn_nvs_detach(struct hvn_softc *);
     201             : 
     202             : /* RNDIS */
     203             : int     hvn_rndis_attach(struct hvn_softc *);
     204             : int     hvn_rndis_cmd(struct hvn_softc *, struct rndis_cmd *, int);
     205             : void    hvn_rndis_input(struct hvn_softc *, uint64_t, void *);
     206             : void    hvn_rxeof(struct hvn_softc *, caddr_t, uint32_t, struct mbuf_list *);
     207             : void    hvn_rndis_complete(struct hvn_softc *, caddr_t, uint32_t);
     208             : int     hvn_rndis_output(struct hvn_softc *, struct hvn_tx_desc *);
     209             : void    hvn_rndis_status(struct hvn_softc *, caddr_t, uint32_t);
     210             : int     hvn_rndis_query(struct hvn_softc *, uint32_t, void *, size_t *);
     211             : int     hvn_rndis_set(struct hvn_softc *, uint32_t, void *, size_t);
     212             : int     hvn_rndis_close(struct hvn_softc *);
     213             : void    hvn_rndis_detach(struct hvn_softc *);
     214             : 
     215             : struct cfdriver hvn_cd = {
     216             :         NULL, "hvn", DV_IFNET
     217             : };
     218             : 
     219             : const struct cfattach hvn_ca = {
     220             :         sizeof(struct hvn_softc), hvn_match, hvn_attach
     221             : };
     222             : 
     223             : int
     224           0 : hvn_match(struct device *parent, void *match, void *aux)
     225             : {
     226           0 :         struct hv_attach_args *aa = aux;
     227             : 
     228           0 :         if (strcmp("network", aa->aa_ident))
     229           0 :                 return (0);
     230             : 
     231           0 :         return (1);
     232           0 : }
     233             : 
     234             : void
     235           0 : hvn_attach(struct device *parent, struct device *self, void *aux)
     236             : {
     237           0 :         struct hv_attach_args *aa = aux;
     238           0 :         struct hvn_softc *sc = (struct hvn_softc *)self;
     239           0 :         struct ifnet *ifp = &sc->sc_ac.ac_if;
     240             : 
     241           0 :         sc->sc_hvsc = (struct hv_softc *)parent;
     242           0 :         sc->sc_chan = aa->aa_chan;
     243           0 :         sc->sc_dmat = aa->aa_dmat;
     244             : 
     245           0 :         strlcpy(ifp->if_xname, sc->sc_dev.dv_xname, IFNAMSIZ);
     246             : 
     247           0 :         printf(" channel %u", sc->sc_chan->ch_id);
     248             : 
     249           0 :         if (hvn_nvs_attach(sc)) {
     250           0 :                 printf(": failed to init NVSP\n");
     251           0 :                 return;
     252             :         }
     253             : 
     254           0 :         if (hvn_rx_ring_create(sc)) {
     255           0 :                 printf(": failed to create Rx ring\n");
     256           0 :                 goto detach;
     257             :         }
     258             : 
     259           0 :         if (hvn_tx_ring_create(sc)) {
     260           0 :                 printf(": failed to create Tx ring\n");
     261           0 :                 goto detach;
     262             :         }
     263             : 
     264           0 :         ifp->if_flags = IFF_BROADCAST | IFF_SIMPLEX | IFF_MULTICAST;
     265           0 :         ifp->if_xflags = IFXF_MPSAFE;
     266           0 :         ifp->if_ioctl = hvn_ioctl;
     267           0 :         ifp->if_qstart = hvn_start;
     268           0 :         ifp->if_softc = sc;
     269             : 
     270           0 :         ifp->if_capabilities = IFCAP_CSUM_IPv4 | IFCAP_CSUM_TCPv4 |
     271             :             IFCAP_CSUM_TCPv6;
     272           0 :         if (sc->sc_ndisver > NDIS_VERSION_6_30)
     273           0 :                 ifp->if_capabilities |= IFCAP_CSUM_UDPv4 | IFCAP_CSUM_UDPv6;
     274             : 
     275           0 :         if (sc->sc_proto >= HVN_NVS_PROTO_VERSION_2) {
     276           0 :                 ifp->if_hardmtu = HVN_MAXMTU;
     277             : #if NVLAN > 0
     278           0 :                 ifp->if_capabilities |= IFCAP_VLAN_HWTAGGING | IFCAP_VLAN_MTU;
     279             : #endif
     280           0 :         }
     281             : 
     282           0 :         IFQ_SET_MAXLEN(&ifp->if_snd, HVN_TX_DESC - 1);
     283             : 
     284           0 :         ifmedia_init(&sc->sc_media, IFM_IMASK, hvn_media_change,
     285             :             hvn_media_status);
     286           0 :         ifmedia_add(&sc->sc_media, IFM_ETHER | IFM_MANUAL, 0, NULL);
     287           0 :         ifmedia_set(&sc->sc_media, IFM_ETHER | IFM_MANUAL);
     288             : 
     289           0 :         if_attach(ifp);
     290             : 
     291           0 :         if (hvn_rndis_attach(sc)) {
     292           0 :                 printf(": failed to init RNDIS\n");
     293           0 :                 goto detach;
     294             :         }
     295             : 
     296           0 :         printf(": NVS %d.%d NDIS %d.%d", sc->sc_proto >> 16,
     297           0 :             sc->sc_proto & 0xffff, sc->sc_ndisver >> 16 ,
     298           0 :             sc->sc_ndisver & 0xffff);
     299             : 
     300           0 :         if (hvn_set_capabilities(sc)) {
     301           0 :                 printf(": failed to setup offloading\n");
     302           0 :                 hvn_rndis_detach(sc);
     303           0 :                 goto detach;
     304             :         }
     305             : 
     306           0 :         if (hvn_get_lladdr(sc)) {
     307           0 :                 printf(": failed to obtain an ethernet address\n");
     308           0 :                 hvn_rndis_detach(sc);
     309           0 :                 goto detach;
     310             :         }
     311             : 
     312           0 :         printf(", address %s\n", ether_sprintf(sc->sc_ac.ac_enaddr));
     313             : 
     314           0 :         ether_ifattach(ifp);
     315           0 :         return;
     316             : 
     317             :  detach:
     318           0 :         hvn_rx_ring_destroy(sc);
     319           0 :         hvn_tx_ring_destroy(sc);
     320           0 :         hvn_nvs_detach(sc);
     321           0 :         if (ifp->if_qstart)
     322           0 :                 if_detach(ifp);
     323           0 : }
     324             : 
     325             : int
     326           0 : hvn_ioctl(struct ifnet *ifp, u_long command, caddr_t data)
     327             : {
     328           0 :         struct hvn_softc *sc = ifp->if_softc;
     329           0 :         struct ifreq *ifr = (struct ifreq *)data;
     330             :         int s, error = 0;
     331             : 
     332           0 :         s = splnet();
     333             : 
     334           0 :         switch (command) {
     335             :         case SIOCSIFADDR:
     336           0 :                 ifp->if_flags |= IFF_UP;
     337           0 :                 if (!(ifp->if_flags & IFF_RUNNING))
     338           0 :                         hvn_init(sc);
     339             :                 break;
     340             :         case SIOCSIFFLAGS:
     341           0 :                 if (ifp->if_flags & IFF_UP) {
     342           0 :                         if (ifp->if_flags & IFF_RUNNING)
     343           0 :                                 error = ENETRESET;
     344             :                         else
     345           0 :                                 hvn_init(sc);
     346             :                 } else {
     347           0 :                         if (ifp->if_flags & IFF_RUNNING)
     348           0 :                                 hvn_stop(sc);
     349             :                 }
     350             :                 break;
     351             :         case SIOCGIFMEDIA:
     352             :         case SIOCSIFMEDIA:
     353           0 :                 error = ifmedia_ioctl(ifp, ifr, &sc->sc_media, command);
     354           0 :                 break;
     355             :         default:
     356           0 :                 error = ether_ioctl(ifp, &sc->sc_ac, command, data);
     357           0 :         }
     358             : 
     359           0 :         if (error == ENETRESET) {
     360           0 :                 if (ifp->if_flags & IFF_RUNNING)
     361           0 :                         hvn_iff(sc);
     362             :                 error = 0;
     363           0 :         }
     364             : 
     365           0 :         splx(s);
     366             : 
     367           0 :         return (error);
     368             : }
     369             : 
     370             : int
     371           0 : hvn_media_change(struct ifnet *ifp)
     372             : {
     373           0 :         return (0);
     374             : }
     375             : 
     376             : void
     377           0 : hvn_media_status(struct ifnet *ifp, struct ifmediareq *ifmr)
     378             : {
     379           0 :         struct hvn_softc *sc = ifp->if_softc;
     380             : 
     381           0 :         hvn_get_link_status(sc);
     382           0 :         hvn_link_status(sc);
     383             : 
     384           0 :         ifmr->ifm_status = IFM_AVALID;
     385           0 :         ifmr->ifm_active = IFM_ETHER | IFM_MANUAL;
     386           0 :         if (sc->sc_link_state == LINK_STATE_UP)
     387           0 :                 ifmr->ifm_status |= IFM_ACTIVE;
     388           0 : }
     389             : 
     390             : void
     391           0 : hvn_link_status(struct hvn_softc *sc)
     392             : {
     393           0 :         struct ifnet *ifp = &sc->sc_ac.ac_if;
     394             : 
     395           0 :         if (sc->sc_link_state != ifp->if_link_state) {
     396           0 :                 ifp->if_link_state = sc->sc_link_state;
     397           0 :                 if_link_state_change(ifp);
     398           0 :         }
     399           0 : }
     400             : 
     401             : int
     402           0 : hvn_iff(struct hvn_softc *sc)
     403             : {
     404           0 :         struct ifnet *ifp = &sc->sc_ac.ac_if;
     405           0 :         uint32_t filter = 0;
     406             :         int rv;
     407             : 
     408           0 :         ifp->if_flags &= ~IFF_ALLMULTI;
     409             : 
     410           0 :         if ((ifp->if_flags & IFF_PROMISC) || sc->sc_ac.ac_multirangecnt > 0) {
     411           0 :                 ifp->if_flags |= IFF_ALLMULTI;
     412           0 :                 filter = NDIS_PACKET_TYPE_PROMISCUOUS;
     413           0 :         } else {
     414           0 :                 filter = NDIS_PACKET_TYPE_BROADCAST |
     415             :                     NDIS_PACKET_TYPE_DIRECTED;
     416           0 :                 if (sc->sc_ac.ac_multicnt > 0) {
     417           0 :                         ifp->if_flags |= IFF_ALLMULTI;
     418           0 :                         filter |= NDIS_PACKET_TYPE_ALL_MULTICAST;
     419           0 :                 }
     420             :         }
     421             : 
     422           0 :         rv = hvn_rndis_set(sc, OID_GEN_CURRENT_PACKET_FILTER,
     423             :             &filter, sizeof(filter));
     424             :         if (rv)
     425             :                 DPRINTF("%s: failed to set RNDIS filter to %#x\n",
     426             :                     sc->sc_dev.dv_xname, filter);
     427           0 :         return (rv);
     428           0 : }
     429             : 
     430             : void
     431           0 : hvn_init(struct hvn_softc *sc)
     432             : {
     433           0 :         struct ifnet *ifp = &sc->sc_ac.ac_if;
     434             : 
     435           0 :         hvn_stop(sc);
     436             : 
     437           0 :         if (hvn_iff(sc) == 0) {
     438           0 :                 ifp->if_flags |= IFF_RUNNING;
     439           0 :                 ifq_clr_oactive(&ifp->if_snd);
     440           0 :         }
     441           0 : }
     442             : 
     443             : void
     444           0 : hvn_stop(struct hvn_softc *sc)
     445             : {
     446           0 :         struct ifnet *ifp = &sc->sc_ac.ac_if;
     447             : 
     448           0 :         if (ifp->if_flags & IFF_RUNNING) {
     449           0 :                 ifp->if_flags &= ~IFF_RUNNING;
     450           0 :                 hvn_rndis_close(sc);
     451           0 :         }
     452             : 
     453           0 :         ifq_barrier(&ifp->if_snd);
     454           0 :         intr_barrier(sc->sc_chan);
     455             : 
     456           0 :         ifq_clr_oactive(&ifp->if_snd);
     457           0 : }
     458             : 
     459             : void
     460           0 : hvn_start(struct ifqueue *ifq)
     461             : {
     462           0 :         struct ifnet *ifp = ifq->ifq_if;
     463           0 :         struct hvn_softc *sc = ifp->if_softc;
     464           0 :         struct hvn_tx_desc *txd;
     465             :         struct mbuf *m;
     466             : 
     467           0 :         for (;;) {
     468           0 :                 if (!sc->sc_tx_avail) {
     469             :                         /* transient */
     470           0 :                         ifq_set_oactive(ifq);
     471           0 :                         break;
     472             :                 }
     473             : 
     474           0 :                 m = ifq_dequeue(ifq);
     475           0 :                 if (m == NULL)
     476             :                         break;
     477             : 
     478           0 :                 if (hvn_encap(sc, m, &txd)) {
     479             :                         /* the chain is too large */
     480           0 :                         ifp->if_oerrors++;
     481           0 :                         m_freem(m);
     482           0 :                         continue;
     483             :                 }
     484             : 
     485             : #if NBPFILTER > 0
     486           0 :                 if (ifp->if_bpf)
     487           0 :                         bpf_mtap_ether(ifp->if_bpf, m, BPF_DIRECTION_OUT);
     488             : #endif
     489             : 
     490           0 :                 if (hvn_rndis_output(sc, txd)) {
     491           0 :                         hvn_decap(sc, txd);
     492           0 :                         ifp->if_oerrors++;
     493           0 :                         m_freem(m);
     494           0 :                         continue;
     495             :                 }
     496             : 
     497           0 :                 sc->sc_tx_next++;
     498             :         }
     499           0 : }
     500             : 
     501             : static inline char *
     502           0 : hvn_rndis_pktinfo_append(struct rndis_packet_msg *pkt, size_t pktsize,
     503             :     size_t datalen, uint32_t type)
     504             : {
     505             :         struct rndis_pktinfo *pi;
     506           0 :         size_t pi_size = sizeof(*pi) + datalen;
     507             :         char *cp;
     508             : 
     509           0 :         KASSERT(pkt->rm_pktinfooffset + pkt->rm_pktinfolen + pi_size <=
     510             :             pktsize);
     511             : 
     512           0 :         cp = (char *)pkt + pkt->rm_pktinfooffset + pkt->rm_pktinfolen;
     513           0 :         pi = (struct rndis_pktinfo *)cp;
     514           0 :         pi->rm_size = pi_size;
     515           0 :         pi->rm_type = type;
     516           0 :         pi->rm_pktinfooffset = sizeof(*pi);
     517           0 :         pkt->rm_pktinfolen += pi_size;
     518           0 :         pkt->rm_dataoffset += pi_size;
     519           0 :         pkt->rm_len += pi_size;
     520           0 :         return ((char *)pi->rm_data);
     521             : }
     522             : 
     523             : int
     524           0 : hvn_encap(struct hvn_softc *sc, struct mbuf *m, struct hvn_tx_desc **txd0)
     525             : {
     526             :         struct hvn_tx_desc *txd;
     527             :         struct rndis_packet_msg *pkt;
     528             :         bus_dma_segment_t *seg;
     529             :         size_t pktlen;
     530             :         int i, rv;
     531             : 
     532           0 :         do {
     533           0 :                 txd = &sc->sc_tx_desc[sc->sc_tx_next % HVN_TX_DESC];
     534           0 :                 sc->sc_tx_next++;
     535           0 :         } while (!txd->txd_ready);
     536           0 :         txd->txd_ready = 0;
     537             : 
     538           0 :         pkt = txd->txd_req;
     539           0 :         memset(pkt, 0, HVN_RNDIS_PKT_LEN);
     540           0 :         pkt->rm_type = REMOTE_NDIS_PACKET_MSG;
     541           0 :         pkt->rm_len = sizeof(*pkt) + m->m_pkthdr.len;
     542           0 :         pkt->rm_dataoffset = RNDIS_DATA_OFFSET;
     543           0 :         pkt->rm_datalen = m->m_pkthdr.len;
     544           0 :         pkt->rm_pktinfooffset = sizeof(*pkt); /* adjusted below */
     545           0 :         pkt->rm_pktinfolen = 0;
     546             : 
     547           0 :         rv = bus_dmamap_load_mbuf(sc->sc_dmat, txd->txd_dmap, m, BUS_DMA_READ |
     548             :             BUS_DMA_NOWAIT);
     549           0 :         switch (rv) {
     550             :         case 0:
     551             :                 break;
     552             :         case EFBIG:
     553           0 :                 if (m_defrag(m, M_NOWAIT) == 0 &&
     554           0 :                     bus_dmamap_load_mbuf(sc->sc_dmat, txd->txd_dmap, m,
     555           0 :                     BUS_DMA_READ | BUS_DMA_NOWAIT) == 0)
     556             :                         break;
     557             :                 /* FALLTHROUGH */
     558             :         default:
     559             :                 DPRINTF("%s: failed to load mbuf\n", sc->sc_dev.dv_xname);
     560           0 :                 return (-1);
     561             :         }
     562           0 :         txd->txd_buf = m;
     563             : 
     564             : #if NVLAN > 0
     565           0 :         if (m->m_flags & M_VLANTAG) {
     566             :                 uint32_t vlan;
     567             :                 char *cp;
     568             : 
     569           0 :                 vlan = NDIS_VLAN_INFO(EVL_VLANOFTAG(m->m_pkthdr.ether_vtag),
     570             :                     EVL_PRIOFTAG(m->m_pkthdr.ether_vtag));
     571           0 :                 cp = hvn_rndis_pktinfo_append(pkt, HVN_RNDIS_PKT_LEN,
     572             :                     NDIS_VLAN_INFO_SIZE, NDIS_PKTINFO_TYPE_VLAN);
     573           0 :                 memcpy(cp, &vlan, NDIS_VLAN_INFO_SIZE);
     574           0 :         }
     575             : #endif
     576             : 
     577           0 :         if (m->m_pkthdr.csum_flags & (M_IPV4_CSUM_OUT | M_UDP_CSUM_OUT |
     578             :             M_TCP_CSUM_OUT)) {
     579             :                 uint32_t csum = NDIS_TXCSUM_INFO_IPV4;
     580             :                 char *cp;
     581             : 
     582           0 :                 if (m->m_pkthdr.csum_flags & M_IPV4_CSUM_OUT)
     583           0 :                         csum |= NDIS_TXCSUM_INFO_IPCS;
     584           0 :                 if (m->m_pkthdr.csum_flags & M_TCP_CSUM_OUT)
     585           0 :                         csum |= NDIS_TXCSUM_INFO_TCPCS;
     586           0 :                 if (m->m_pkthdr.csum_flags & M_UDP_CSUM_OUT)
     587           0 :                         csum |= NDIS_TXCSUM_INFO_UDPCS;
     588           0 :                 cp = hvn_rndis_pktinfo_append(pkt, HVN_RNDIS_PKT_LEN,
     589             :                     NDIS_TXCSUM_INFO_SIZE, NDIS_PKTINFO_TYPE_CSUM);
     590           0 :                 memcpy(cp, &csum, NDIS_TXCSUM_INFO_SIZE);
     591           0 :         }
     592             : 
     593           0 :         pktlen = pkt->rm_pktinfooffset + pkt->rm_pktinfolen;
     594           0 :         pkt->rm_pktinfooffset -= RNDIS_HEADER_OFFSET;
     595             : 
     596             :         /* Attach an RNDIS message to the first slot */
     597           0 :         txd->txd_sgl[0].gpa_page = txd->txd_gpa.gpa_page;
     598           0 :         txd->txd_sgl[0].gpa_ofs = txd->txd_gpa.gpa_ofs;
     599           0 :         txd->txd_sgl[0].gpa_len = pktlen;
     600           0 :         txd->txd_nsge = txd->txd_dmap->dm_nsegs + 1;
     601             : 
     602           0 :         for (i = 0; i < txd->txd_dmap->dm_nsegs; i++) {
     603           0 :                 seg = &txd->txd_dmap->dm_segs[i];
     604           0 :                 txd->txd_sgl[1 + i].gpa_page = atop(seg->ds_addr);
     605           0 :                 txd->txd_sgl[1 + i].gpa_ofs = seg->ds_addr & PAGE_MASK;
     606           0 :                 txd->txd_sgl[1 + i].gpa_len = seg->ds_len;
     607             :         }
     608             : 
     609           0 :         *txd0 = txd;
     610             : 
     611           0 :         atomic_dec_int(&sc->sc_tx_avail);
     612             : 
     613           0 :         return (0);
     614           0 : }
     615             : 
     616             : void
     617           0 : hvn_decap(struct hvn_softc *sc, struct hvn_tx_desc *txd)
     618             : {
     619           0 :         bus_dmamap_sync(sc->sc_dmat, txd->txd_dmap, 0, 0,
     620             :             BUS_DMASYNC_POSTREAD | BUS_DMASYNC_POSTWRITE);
     621           0 :         bus_dmamap_unload(sc->sc_dmat, txd->txd_dmap);
     622           0 :         txd->txd_buf = NULL;
     623           0 :         txd->txd_nsge = 0;
     624           0 :         txd->txd_ready = 1;
     625           0 :         atomic_inc_int(&sc->sc_tx_avail);
     626           0 : }
     627             : 
     628             : void
     629           0 : hvn_txeof(struct hvn_softc *sc, uint64_t tid)
     630             : {
     631             :         struct hvn_tx_desc *txd;
     632             :         struct mbuf *m;
     633           0 :         uint32_t id = tid >> 32;
     634             : 
     635           0 :         if ((tid & 0xffffffffU) != 0)
     636           0 :                 return;
     637           0 :         id -= HVN_NVS_CHIM_SIG;
     638           0 :         if (id >= HVN_TX_DESC)
     639           0 :                 panic("tx packet index too large: %u", id);
     640             : 
     641           0 :         txd = &sc->sc_tx_desc[id];
     642             : 
     643           0 :         if ((m = txd->txd_buf) == NULL)
     644           0 :                 panic("%s: no mbuf @%u\n", sc->sc_dev.dv_xname, id);
     645           0 :         txd->txd_buf = NULL;
     646             : 
     647           0 :         bus_dmamap_sync(sc->sc_dmat, txd->txd_dmap, 0, 0,
     648             :             BUS_DMASYNC_POSTREAD | BUS_DMASYNC_POSTWRITE);
     649           0 :         bus_dmamap_unload(sc->sc_dmat, txd->txd_dmap);
     650           0 :         m_freem(m);
     651             : 
     652           0 :         txd->txd_ready = 1;
     653             : 
     654           0 :         atomic_inc_int(&sc->sc_tx_avail);
     655             : 
     656           0 : }
     657             : 
     658             : int
     659           0 : hvn_rx_ring_create(struct hvn_softc *sc)
     660             : {
     661           0 :         struct hvn_nvs_rxbuf_conn cmd;
     662             :         struct hvn_nvs_rxbuf_conn_resp *rsp;
     663             :         uint64_t tid;
     664             : 
     665           0 :         if (sc->sc_proto <= HVN_NVS_PROTO_VERSION_2)
     666           0 :                 sc->sc_rx_size = 15 * 1024 * 1024;   /* 15MB */
     667             :         else
     668           0 :                 sc->sc_rx_size = 16 * 1024 * 1024;   /* 16MB */
     669           0 :         sc->sc_rx_ring = km_alloc(sc->sc_rx_size, &kv_any, &kp_zero,
     670           0 :             cold ? &kd_nowait : &kd_waitok);
     671           0 :         if (sc->sc_rx_ring == NULL) {
     672             :                 DPRINTF("%s: failed to allocate Rx ring buffer\n",
     673             :                     sc->sc_dev.dv_xname);
     674           0 :                 return (-1);
     675             :         }
     676           0 :         if (hv_handle_alloc(sc->sc_chan, sc->sc_rx_ring, sc->sc_rx_size,
     677           0 :             &sc->sc_rx_hndl)) {
     678             :                 DPRINTF("%s: failed to obtain a PA handle\n",
     679             :                     sc->sc_dev.dv_xname);
     680             :                 goto errout;
     681             :         }
     682             : 
     683           0 :         memset(&cmd, 0, sizeof(cmd));
     684           0 :         cmd.nvs_type = HVN_NVS_TYPE_RXBUF_CONN;
     685           0 :         cmd.nvs_gpadl = sc->sc_rx_hndl;
     686           0 :         cmd.nvs_sig = HVN_NVS_RXBUF_SIG;
     687             : 
     688           0 :         tid = atomic_inc_int_nv(&sc->sc_nvstid);
     689           0 :         if (hvn_nvs_cmd(sc, &cmd, sizeof(cmd), tid, 100))
     690             :                 goto errout;
     691             : 
     692           0 :         rsp = (struct hvn_nvs_rxbuf_conn_resp *)&sc->sc_nvsrsp;
     693           0 :         if (rsp->nvs_status != HVN_NVS_STATUS_OK) {
     694             :                 DPRINTF("%s: failed to set up the Rx ring\n",
     695             :                     sc->sc_dev.dv_xname);
     696             :                 goto errout;
     697             :         }
     698           0 :         if (rsp->nvs_nsect > 1) {
     699             :                 DPRINTF("%s: invalid number of Rx ring sections: %u\n",
     700             :                     sc->sc_dev.dv_xname, rsp->nvs_nsect);
     701           0 :                 hvn_rx_ring_destroy(sc);
     702           0 :                 return (-1);
     703             :         }
     704           0 :         return (0);
     705             : 
     706             :  errout:
     707           0 :         if (sc->sc_rx_hndl) {
     708           0 :                 hv_handle_free(sc->sc_chan, sc->sc_rx_hndl);
     709           0 :                 sc->sc_rx_hndl = 0;
     710           0 :         }
     711           0 :         if (sc->sc_rx_ring) {
     712           0 :                 km_free(sc->sc_rx_ring, sc->sc_rx_size, &kv_any, &kp_zero);
     713           0 :                 sc->sc_rx_ring = NULL;
     714           0 :         }
     715           0 :         return (-1);
     716           0 : }
     717             : 
     718             : int
     719           0 : hvn_rx_ring_destroy(struct hvn_softc *sc)
     720             : {
     721           0 :         struct hvn_nvs_rxbuf_disconn cmd;
     722             :         uint64_t tid;
     723             : 
     724           0 :         if (sc->sc_rx_ring == NULL)
     725           0 :                 return (0);
     726             : 
     727           0 :         memset(&cmd, 0, sizeof(cmd));
     728           0 :         cmd.nvs_type = HVN_NVS_TYPE_RXBUF_DISCONN;
     729           0 :         cmd.nvs_sig = HVN_NVS_RXBUF_SIG;
     730             : 
     731           0 :         tid = atomic_inc_int_nv(&sc->sc_nvstid);
     732           0 :         if (hvn_nvs_cmd(sc, &cmd, sizeof(cmd), tid, 0))
     733           0 :                 return (-1);
     734             : 
     735           0 :         delay(100);
     736             : 
     737           0 :         hv_handle_free(sc->sc_chan, sc->sc_rx_hndl);
     738             : 
     739           0 :         sc->sc_rx_hndl = 0;
     740             : 
     741           0 :         km_free(sc->sc_rx_ring, sc->sc_rx_size, &kv_any, &kp_zero);
     742           0 :         sc->sc_rx_ring = NULL;
     743             : 
     744           0 :         return (0);
     745           0 : }
     746             : 
     747             : int
     748           0 : hvn_tx_ring_create(struct hvn_softc *sc)
     749             : {
     750             :         struct hvn_tx_desc *txd;
     751             :         bus_dma_segment_t *seg;
     752             :         size_t msgsize;
     753           0 :         int i, rsegs;
     754             :         paddr_t pa;
     755             : 
     756             :         msgsize = roundup(HVN_RNDIS_PKT_LEN, 128);
     757             : 
     758             :         /* Allocate memory to store RNDIS messages */
     759           0 :         if (bus_dmamem_alloc(sc->sc_dmat, msgsize * HVN_TX_DESC, PAGE_SIZE, 0,
     760             :             &sc->sc_tx_mseg, 1, &rsegs, BUS_DMA_ZERO | BUS_DMA_WAITOK)) {
     761             :                 DPRINTF("%s: failed to allocate memory for RDNIS messages\n",
     762             :                     sc->sc_dev.dv_xname);
     763             :                 goto errout;
     764             :         }
     765           0 :         if (bus_dmamem_map(sc->sc_dmat, &sc->sc_tx_mseg, 1, msgsize *
     766             :             HVN_TX_DESC, (caddr_t *)&sc->sc_tx_msgs, BUS_DMA_WAITOK)) {
     767             :                 DPRINTF("%s: failed to establish mapping for RDNIS messages\n",
     768             :                     sc->sc_dev.dv_xname);
     769             :                 goto errout;
     770             :         }
     771           0 :         if (bus_dmamap_create(sc->sc_dmat, msgsize * HVN_TX_DESC, 1,
     772             :             msgsize * HVN_TX_DESC, 0, BUS_DMA_WAITOK, &sc->sc_tx_rmap)) {
     773             :                 DPRINTF("%s: failed to create map for RDNIS messages\n",
     774             :                     sc->sc_dev.dv_xname);
     775             :                 goto errout;
     776             :         }
     777           0 :         if (bus_dmamap_load(sc->sc_dmat, sc->sc_tx_rmap, sc->sc_tx_msgs,
     778             :             msgsize * HVN_TX_DESC, NULL, BUS_DMA_WAITOK)) {
     779             :                 DPRINTF("%s: failed to create map for RDNIS messages\n",
     780             :                     sc->sc_dev.dv_xname);
     781             :                 goto errout;
     782             :         }
     783             : 
     784           0 :         for (i = 0; i < HVN_TX_DESC; i++) {
     785           0 :                 txd = &sc->sc_tx_desc[i];
     786           0 :                 if (bus_dmamap_create(sc->sc_dmat, HVN_TX_PKT_SIZE,
     787             :                     HVN_TX_FRAGS, HVN_TX_FRAG_SIZE, PAGE_SIZE,
     788             :                     BUS_DMA_WAITOK, &txd->txd_dmap)) {
     789             :                         DPRINTF("%s: failed to create map for TX descriptors\n",
     790             :                             sc->sc_dev.dv_xname);
     791             :                         goto errout;
     792             :                 }
     793           0 :                 seg = &sc->sc_tx_rmap->dm_segs[0];
     794           0 :                 pa = seg->ds_addr + (msgsize * i);
     795           0 :                 txd->txd_gpa.gpa_page = atop(pa);
     796           0 :                 txd->txd_gpa.gpa_ofs = pa & PAGE_MASK;
     797           0 :                 txd->txd_gpa.gpa_len = msgsize;
     798           0 :                 txd->txd_req = (void *)((caddr_t)sc->sc_tx_msgs +
     799             :                     (msgsize * i));
     800           0 :                 txd->txd_id = i + HVN_NVS_CHIM_SIG;
     801           0 :                 txd->txd_ready = 1;
     802             :         }
     803           0 :         sc->sc_tx_avail = HVN_TX_DESC;
     804             : 
     805           0 :         return (0);
     806             : 
     807             :  errout:
     808           0 :         hvn_tx_ring_destroy(sc);
     809           0 :         return (-1);
     810           0 : }
     811             : 
     812             : void
     813           0 : hvn_tx_ring_destroy(struct hvn_softc *sc)
     814             : {
     815             :         struct hvn_tx_desc *txd;
     816             :         int i;
     817             : 
     818           0 :         for (i = 0; i < HVN_TX_DESC; i++) {
     819           0 :                 txd = &sc->sc_tx_desc[i];
     820           0 :                 if (txd->txd_dmap == NULL)
     821             :                         continue;
     822           0 :                 bus_dmamap_sync(sc->sc_dmat, txd->txd_dmap, 0, 0,
     823             :                     BUS_DMASYNC_POSTWRITE);
     824           0 :                 bus_dmamap_unload(sc->sc_dmat, txd->txd_dmap);
     825           0 :                 bus_dmamap_destroy(sc->sc_dmat, txd->txd_dmap);
     826           0 :                 txd->txd_dmap = NULL;
     827           0 :                 if (txd->txd_buf == NULL)
     828             :                         continue;
     829           0 :                 m_free(txd->txd_buf);
     830           0 :                 txd->txd_buf = NULL;
     831           0 :         }
     832           0 :         if (sc->sc_tx_rmap) {
     833           0 :                 bus_dmamap_sync(sc->sc_dmat, sc->sc_tx_rmap, 0, 0,
     834             :                     BUS_DMASYNC_POSTWRITE);
     835           0 :                 bus_dmamap_unload(sc->sc_dmat, sc->sc_tx_rmap);
     836           0 :                 bus_dmamap_destroy(sc->sc_dmat, sc->sc_tx_rmap);
     837           0 :         }
     838           0 :         if (sc->sc_tx_msgs) {
     839             :                 size_t msgsize = roundup(HVN_RNDIS_PKT_LEN, 128);
     840             : 
     841           0 :                 bus_dmamem_unmap(sc->sc_dmat, (caddr_t)sc->sc_tx_msgs,
     842             :                     msgsize * HVN_TX_DESC);
     843           0 :                 bus_dmamem_free(sc->sc_dmat, &sc->sc_tx_mseg, 1);
     844           0 :         }
     845           0 :         sc->sc_tx_rmap = NULL;
     846           0 :         sc->sc_tx_msgs = NULL;
     847           0 : }
     848             : 
     849             : int
     850           0 : hvn_get_lladdr(struct hvn_softc *sc)
     851             : {
     852           0 :         char enaddr[ETHER_ADDR_LEN];
     853           0 :         size_t addrlen = ETHER_ADDR_LEN;
     854             :         int rv;
     855             : 
     856           0 :         rv = hvn_rndis_query(sc, OID_802_3_PERMANENT_ADDRESS,
     857           0 :             enaddr, &addrlen);
     858           0 :         if (rv == 0 && addrlen == ETHER_ADDR_LEN)
     859           0 :                 memcpy(sc->sc_ac.ac_enaddr, enaddr, ETHER_ADDR_LEN);
     860           0 :         return (rv);
     861           0 : }
     862             : 
     863             : int
     864           0 : hvn_set_lladdr(struct hvn_softc *sc)
     865             : {
     866           0 :         return (hvn_rndis_set(sc, OID_802_3_CURRENT_ADDRESS,
     867           0 :             sc->sc_ac.ac_enaddr, ETHER_ADDR_LEN));
     868             : }
     869             : 
     870             : void
     871           0 : hvn_get_link_status(struct hvn_softc *sc)
     872             : {
     873           0 :         uint32_t state;
     874           0 :         size_t len = sizeof(state);
     875             : 
     876           0 :         if (hvn_rndis_query(sc, OID_GEN_MEDIA_CONNECT_STATUS,
     877           0 :             &state, &len) == 0)
     878           0 :                 sc->sc_link_state = (state == NDIS_MEDIA_STATE_CONNECTED) ?
     879             :                     LINK_STATE_UP : LINK_STATE_DOWN;
     880           0 : }
     881             : 
     882             : int
     883           0 : hvn_nvs_attach(struct hvn_softc *sc)
     884             : {
     885             :         const uint32_t protos[] = {
     886             :                 HVN_NVS_PROTO_VERSION_5, HVN_NVS_PROTO_VERSION_4,
     887             :                 HVN_NVS_PROTO_VERSION_2, HVN_NVS_PROTO_VERSION_1
     888             :         };
     889           0 :         struct hvn_nvs_init cmd;
     890             :         struct hvn_nvs_init_resp *rsp;
     891           0 :         struct hvn_nvs_ndis_init ncmd;
     892           0 :         struct hvn_nvs_ndis_conf ccmd;
     893             :         uint32_t ndisver, ringsize;
     894             :         uint64_t tid;
     895             :         int i;
     896             : 
     897           0 :         sc->sc_nvsbuf = malloc(HVN_NVS_BUFSIZE, M_DEVBUF, M_ZERO |
     898           0 :             (cold ? M_NOWAIT : M_WAITOK));
     899           0 :         if (sc->sc_nvsbuf == NULL) {
     900             :                 DPRINTF("%s: failed to allocate channel data buffer\n",
     901             :                     sc->sc_dev.dv_xname);
     902           0 :                 return (-1);
     903             :         }
     904             : 
     905             :         /* We need to be able to fit all RNDIS control and data messages */
     906             :         ringsize = HVN_RNDIS_CTLREQS *
     907             :             (sizeof(struct hvn_nvs_rndis) + sizeof(struct vmbus_gpa)) +
     908             :             HVN_TX_DESC * (sizeof(struct hvn_nvs_rndis) +
     909             :             (HVN_TX_FRAGS + 1) * sizeof(struct vmbus_gpa));
     910             : 
     911           0 :         sc->sc_chan->ch_flags &= ~CHF_BATCHED;
     912             : 
     913             :         /* Associate our interrupt handler with the channel */
     914           0 :         if (hv_channel_open(sc->sc_chan, ringsize, NULL, 0,
     915           0 :             hvn_nvs_intr, sc)) {
     916             :                 DPRINTF("%s: failed to open channel\n", sc->sc_dev.dv_xname);
     917           0 :                 free(sc->sc_nvsbuf, M_DEVBUF, HVN_NVS_BUFSIZE);
     918           0 :                 return (-1);
     919             :         }
     920             : 
     921           0 :         hv_evcount_attach(sc->sc_chan, sc->sc_dev.dv_xname);
     922             : 
     923           0 :         memset(&cmd, 0, sizeof(cmd));
     924           0 :         cmd.nvs_type = HVN_NVS_TYPE_INIT;
     925           0 :         for (i = 0; i < nitems(protos); i++) {
     926           0 :                 cmd.nvs_ver_min = cmd.nvs_ver_max = protos[i];
     927           0 :                 tid = atomic_inc_int_nv(&sc->sc_nvstid);
     928           0 :                 if (hvn_nvs_cmd(sc, &cmd, sizeof(cmd), tid, 100))
     929           0 :                         return (-1);
     930           0 :                 rsp = (struct hvn_nvs_init_resp *)&sc->sc_nvsrsp;
     931           0 :                 if (rsp->nvs_status == HVN_NVS_STATUS_OK) {
     932           0 :                         sc->sc_proto = protos[i];
     933           0 :                         break;
     934             :                 }
     935             :         }
     936           0 :         if (!sc->sc_proto) {
     937             :                 DPRINTF("%s: failed to negotiate NVSP version\n",
     938             :                     sc->sc_dev.dv_xname);
     939           0 :                 return (-1);
     940             :         }
     941             : 
     942           0 :         if (sc->sc_proto >= HVN_NVS_PROTO_VERSION_2) {
     943           0 :                 memset(&ccmd, 0, sizeof(ccmd));
     944           0 :                 ccmd.nvs_type = HVN_NVS_TYPE_NDIS_CONF;
     945           0 :                 ccmd.nvs_mtu = HVN_MAXMTU;
     946           0 :                 ccmd.nvs_caps = HVN_NVS_NDIS_CONF_VLAN;
     947             : 
     948           0 :                 tid = atomic_inc_int_nv(&sc->sc_nvstid);
     949           0 :                 if (hvn_nvs_cmd(sc, &ccmd, sizeof(ccmd), tid, 100))
     950           0 :                         return (-1);
     951             :         }
     952             : 
     953           0 :         memset(&ncmd, 0, sizeof(ncmd));
     954           0 :         ncmd.nvs_type = HVN_NVS_TYPE_NDIS_INIT;
     955           0 :         if (sc->sc_proto <= HVN_NVS_PROTO_VERSION_4)
     956           0 :                 ndisver = NDIS_VERSION_6_1;
     957             :         else
     958             :                 ndisver = NDIS_VERSION_6_30;
     959           0 :         ncmd.nvs_ndis_major = (ndisver & 0xffff0000) >> 16;
     960           0 :         ncmd.nvs_ndis_minor = (ndisver & 0x0000ffff);
     961             : 
     962           0 :         tid = atomic_inc_int_nv(&sc->sc_nvstid);
     963           0 :         if (hvn_nvs_cmd(sc, &ncmd, sizeof(ncmd), tid, 100))
     964           0 :                 return (-1);
     965             : 
     966           0 :         sc->sc_ndisver = ndisver;
     967             : 
     968           0 :         return (0);
     969           0 : }
     970             : 
     971             : void
     972           0 : hvn_nvs_intr(void *arg)
     973             : {
     974           0 :         struct hvn_softc *sc = arg;
     975           0 :         struct ifnet *ifp = &sc->sc_ac.ac_if;
     976             :         struct vmbus_chanpkt_hdr *cph;
     977             :         struct hvn_nvs_hdr *nvs;
     978           0 :         uint64_t rid;
     979           0 :         uint32_t rlen;
     980             :         int rv;
     981             : 
     982           0 :         for (;;) {
     983           0 :                 rv = hv_channel_recv(sc->sc_chan, sc->sc_nvsbuf,
     984             :                     HVN_NVS_BUFSIZE, &rlen, &rid, 1);
     985           0 :                 if (rv != 0 || rlen == 0) {
     986           0 :                         if (rv != EAGAIN)
     987           0 :                                 printf("%s: failed to receive an NVSP "
     988           0 :                                     "packet\n", sc->sc_dev.dv_xname);
     989             :                         break;
     990             :                 }
     991           0 :                 cph = (struct vmbus_chanpkt_hdr *)sc->sc_nvsbuf;
     992           0 :                 nvs = (struct hvn_nvs_hdr *)VMBUS_CHANPKT_CONST_DATA(cph);
     993             : 
     994           0 :                 if (cph->cph_type == VMBUS_CHANPKT_TYPE_COMP) {
     995           0 :                         switch (nvs->nvs_type) {
     996             :                         case HVN_NVS_TYPE_INIT_RESP:
     997             :                         case HVN_NVS_TYPE_RXBUF_CONNRESP:
     998             :                         case HVN_NVS_TYPE_CHIM_CONNRESP:
     999             :                         case HVN_NVS_TYPE_SUBCH_RESP:
    1000             :                                 /* copy the response back */
    1001           0 :                                 memcpy(&sc->sc_nvsrsp, nvs, HVN_NVS_MSGSIZE);
    1002           0 :                                 sc->sc_nvsdone = 1;
    1003           0 :                                 wakeup_one(&sc->sc_nvsrsp);
    1004           0 :                                 break;
    1005             :                         case HVN_NVS_TYPE_RNDIS_ACK:
    1006           0 :                                 hvn_txeof(sc, cph->cph_tid);
    1007           0 :                                 break;
    1008             :                         default:
    1009           0 :                                 printf("%s: unhandled NVSP packet type %u "
    1010           0 :                                     "on completion\n", sc->sc_dev.dv_xname,
    1011             :                                     nvs->nvs_type);
    1012           0 :                         }
    1013           0 :                 } else if (cph->cph_type == VMBUS_CHANPKT_TYPE_RXBUF) {
    1014           0 :                         switch (nvs->nvs_type) {
    1015             :                         case HVN_NVS_TYPE_RNDIS:
    1016           0 :                                 hvn_rndis_input(sc, cph->cph_tid, cph);
    1017           0 :                                 break;
    1018             :                         default:
    1019           0 :                                 printf("%s: unhandled NVSP packet type %u "
    1020           0 :                                     "on receive\n", sc->sc_dev.dv_xname,
    1021             :                                     nvs->nvs_type);
    1022           0 :                         }
    1023             :                 } else
    1024           0 :                         printf("%s: unknown NVSP packet type %u\n",
    1025           0 :                             sc->sc_dev.dv_xname, cph->cph_type);
    1026             :         }
    1027             : 
    1028           0 :         if (ifq_is_oactive(&ifp->if_snd))
    1029           0 :                 ifq_restart(&ifp->if_snd);
    1030           0 : }
    1031             : 
    1032             : int
    1033           0 : hvn_nvs_cmd(struct hvn_softc *sc, void *cmd, size_t cmdsize, uint64_t tid,
    1034             :     int timo)
    1035             : {
    1036           0 :         struct hvn_nvs_hdr *hdr = cmd;
    1037             :         int tries = 10;
    1038             :         int rv, s;
    1039             : 
    1040           0 :         KERNEL_ASSERT_LOCKED();
    1041             : 
    1042           0 :         sc->sc_nvsdone = 0;
    1043             : 
    1044           0 :         do {
    1045           0 :                 rv = hv_channel_send(sc->sc_chan, cmd, cmdsize,
    1046             :                     tid, VMBUS_CHANPKT_TYPE_INBAND,
    1047           0 :                     timo ? VMBUS_CHANPKT_FLAG_RC : 0);
    1048           0 :                 if (rv == EAGAIN) {
    1049           0 :                         if (cold)
    1050           0 :                                 delay(1000);
    1051             :                         else
    1052           0 :                                 tsleep(cmd, PRIBIO, "nvsout", 1);
    1053           0 :                 } else if (rv) {
    1054             :                         DPRINTF("%s: NVSP operation %u send error %d\n",
    1055             :                             sc->sc_dev.dv_xname, hdr->nvs_type, rv);
    1056           0 :                         return (rv);
    1057             :                 }
    1058           0 :         } while (rv != 0 && --tries > 0);
    1059             : 
    1060           0 :         if (tries == 0 && rv != 0) {
    1061           0 :                 printf("%s: NVSP operation %u send error %d\n",
    1062           0 :                     sc->sc_dev.dv_xname, hdr->nvs_type, rv);
    1063           0 :                 return (rv);
    1064             :         }
    1065             : 
    1066           0 :         if (timo == 0)
    1067           0 :                 return (0);
    1068             : 
    1069           0 :         do {
    1070           0 :                 if (cold)
    1071           0 :                         delay(1000);
    1072             :                 else
    1073           0 :                         tsleep(sc, PRIBIO | PCATCH, "nvscmd", 1);
    1074           0 :                 s = splnet();
    1075           0 :                 hvn_nvs_intr(sc);
    1076           0 :                 splx(s);
    1077           0 :         } while (--timo > 0 && sc->sc_nvsdone != 1);
    1078             : 
    1079           0 :         if (timo == 0 && sc->sc_nvsdone != 1) {
    1080           0 :                 printf("%s: NVSP operation %u timed out\n",
    1081           0 :                     sc->sc_dev.dv_xname, hdr->nvs_type);
    1082           0 :                 return (ETIMEDOUT);
    1083             :         }
    1084           0 :         return (0);
    1085           0 : }
    1086             : 
    1087             : int
    1088           0 : hvn_nvs_ack(struct hvn_softc *sc, uint64_t tid)
    1089             : {
    1090           0 :         struct hvn_nvs_rndis_ack cmd;
    1091             :         int tries = 5;
    1092             :         int rv;
    1093             : 
    1094           0 :         cmd.nvs_type = HVN_NVS_TYPE_RNDIS_ACK;
    1095           0 :         cmd.nvs_status = HVN_NVS_STATUS_OK;
    1096           0 :         do {
    1097           0 :                 rv = hv_channel_send(sc->sc_chan, &cmd, sizeof(cmd),
    1098             :                     tid, VMBUS_CHANPKT_TYPE_COMP, 0);
    1099           0 :                 if (rv == EAGAIN)
    1100           0 :                         delay(10);
    1101           0 :                 else if (rv) {
    1102             :                         DPRINTF("%s: NVSP acknowledgement error %d\n",
    1103             :                             sc->sc_dev.dv_xname, rv);
    1104           0 :                         return (rv);
    1105             :                 }
    1106           0 :         } while (rv != 0 && --tries > 0);
    1107           0 :         return (rv);
    1108           0 : }
    1109             : 
    1110             : void
    1111           0 : hvn_nvs_detach(struct hvn_softc *sc)
    1112             : {
    1113           0 :         if (hv_channel_close(sc->sc_chan) == 0) {
    1114           0 :                 free(sc->sc_nvsbuf, M_DEVBUF, HVN_NVS_BUFSIZE);
    1115           0 :                 sc->sc_nvsbuf = NULL;
    1116           0 :         }
    1117           0 : }
    1118             : 
    1119             : static inline struct rndis_cmd *
    1120           0 : hvn_alloc_cmd(struct hvn_softc *sc)
    1121             : {
    1122             :         struct rndis_cmd *rc;
    1123             : 
    1124           0 :         mtx_enter(&sc->sc_cntl_fqlck);
    1125           0 :         while ((rc = TAILQ_FIRST(&sc->sc_cntl_fq)) == NULL)
    1126           0 :                 msleep(&sc->sc_cntl_fq, &sc->sc_cntl_fqlck,
    1127             :                     PRIBIO, "nvsalloc", 1);
    1128           0 :         TAILQ_REMOVE(&sc->sc_cntl_fq, rc, rc_entry);
    1129           0 :         mtx_leave(&sc->sc_cntl_fqlck);
    1130           0 :         return (rc);
    1131             : }
    1132             : 
    1133             : static inline void
    1134           0 : hvn_submit_cmd(struct hvn_softc *sc, struct rndis_cmd *rc)
    1135             : {
    1136           0 :         mtx_enter(&sc->sc_cntl_sqlck);
    1137           0 :         TAILQ_INSERT_TAIL(&sc->sc_cntl_sq, rc, rc_entry);
    1138           0 :         mtx_leave(&sc->sc_cntl_sqlck);
    1139           0 : }
    1140             : 
    1141             : static inline struct rndis_cmd *
    1142           0 : hvn_complete_cmd(struct hvn_softc *sc, uint32_t id)
    1143             : {
    1144             :         struct rndis_cmd *rc;
    1145             : 
    1146           0 :         mtx_enter(&sc->sc_cntl_sqlck);
    1147           0 :         TAILQ_FOREACH(rc, &sc->sc_cntl_sq, rc_entry) {
    1148           0 :                 if (rc->rc_id == id) {
    1149           0 :                         TAILQ_REMOVE(&sc->sc_cntl_sq, rc, rc_entry);
    1150           0 :                         break;
    1151             :                 }
    1152             :         }
    1153           0 :         mtx_leave(&sc->sc_cntl_sqlck);
    1154           0 :         if (rc != NULL) {
    1155           0 :                 mtx_enter(&sc->sc_cntl_cqlck);
    1156           0 :                 TAILQ_INSERT_TAIL(&sc->sc_cntl_cq, rc, rc_entry);
    1157           0 :                 mtx_leave(&sc->sc_cntl_cqlck);
    1158           0 :         }
    1159           0 :         return (rc);
    1160             : }
    1161             : 
    1162             : static inline void
    1163           0 : hvn_release_cmd(struct hvn_softc *sc, struct rndis_cmd *rc)
    1164             : {
    1165           0 :         mtx_enter(&sc->sc_cntl_cqlck);
    1166           0 :         TAILQ_REMOVE(&sc->sc_cntl_cq, rc, rc_entry);
    1167           0 :         mtx_leave(&sc->sc_cntl_cqlck);
    1168           0 : }
    1169             : 
    1170             : static inline int
    1171           0 : hvn_rollback_cmd(struct hvn_softc *sc, struct rndis_cmd *rc)
    1172             : {
    1173             :         struct rndis_cmd *rn;
    1174             : 
    1175           0 :         mtx_enter(&sc->sc_cntl_sqlck);
    1176           0 :         TAILQ_FOREACH(rn, &sc->sc_cntl_sq, rc_entry) {
    1177           0 :                 if (rn == rc) {
    1178           0 :                         TAILQ_REMOVE(&sc->sc_cntl_sq, rc, rc_entry);
    1179           0 :                         mtx_leave(&sc->sc_cntl_sqlck);
    1180           0 :                         return (0);
    1181             :                 }
    1182             :         }
    1183           0 :         mtx_leave(&sc->sc_cntl_sqlck);
    1184           0 :         return (-1);
    1185           0 : }
    1186             : 
    1187             : static inline void
    1188           0 : hvn_free_cmd(struct hvn_softc *sc, struct rndis_cmd *rc)
    1189             : {
    1190           0 :         memset(rc->rc_req, 0, sizeof(struct rndis_packet_msg));
    1191           0 :         memset(&rc->rc_cmp, 0, sizeof(rc->rc_cmp));
    1192           0 :         memset(&rc->rc_msg, 0, sizeof(rc->rc_msg));
    1193           0 :         mtx_enter(&sc->sc_cntl_fqlck);
    1194           0 :         TAILQ_INSERT_TAIL(&sc->sc_cntl_fq, rc, rc_entry);
    1195           0 :         mtx_leave(&sc->sc_cntl_fqlck);
    1196           0 :         wakeup(&sc->sc_cntl_fq);
    1197           0 : }
    1198             : 
    1199             : int
    1200           0 : hvn_rndis_attach(struct hvn_softc *sc)
    1201             : {
    1202             :         struct rndis_init_req *req;
    1203             :         struct rndis_init_comp *cmp;
    1204             :         struct rndis_cmd *rc;
    1205             :         int i, rv;
    1206             : 
    1207             :         /* RNDIS control message queues */
    1208           0 :         TAILQ_INIT(&sc->sc_cntl_sq);
    1209           0 :         TAILQ_INIT(&sc->sc_cntl_cq);
    1210           0 :         TAILQ_INIT(&sc->sc_cntl_fq);
    1211           0 :         mtx_init(&sc->sc_cntl_sqlck, IPL_NET);
    1212           0 :         mtx_init(&sc->sc_cntl_cqlck, IPL_NET);
    1213           0 :         mtx_init(&sc->sc_cntl_fqlck, IPL_NET);
    1214             : 
    1215           0 :         for (i = 0; i < HVN_RNDIS_CTLREQS; i++) {
    1216           0 :                 rc = &sc->sc_cntl_msgs[i];
    1217           0 :                 if (bus_dmamap_create(sc->sc_dmat, PAGE_SIZE, 1,
    1218             :                     PAGE_SIZE, 0, BUS_DMA_WAITOK, &rc->rc_dmap)) {
    1219             :                         DPRINTF("%s: failed to create RNDIS command map\n",
    1220             :                             sc->sc_dev.dv_xname);
    1221             :                         goto errout;
    1222             :                 }
    1223           0 :                 if (bus_dmamem_alloc(sc->sc_dmat, PAGE_SIZE, PAGE_SIZE,
    1224             :                     0, &rc->rc_segs, 1, &rc->rc_nsegs, BUS_DMA_NOWAIT |
    1225             :                     BUS_DMA_ZERO)) {
    1226             :                         DPRINTF("%s: failed to allocate RNDIS command\n",
    1227             :                             sc->sc_dev.dv_xname);
    1228           0 :                         bus_dmamap_destroy(sc->sc_dmat, rc->rc_dmap);
    1229           0 :                         goto errout;
    1230             :                 }
    1231           0 :                 if (bus_dmamem_map(sc->sc_dmat, &rc->rc_segs, rc->rc_nsegs,
    1232             :                     PAGE_SIZE, (caddr_t *)&rc->rc_req, BUS_DMA_NOWAIT)) {
    1233             :                         DPRINTF("%s: failed to allocate RNDIS command\n",
    1234             :                             sc->sc_dev.dv_xname);
    1235           0 :                         bus_dmamem_free(sc->sc_dmat, &rc->rc_segs,
    1236             :                             rc->rc_nsegs);
    1237           0 :                         bus_dmamap_destroy(sc->sc_dmat, rc->rc_dmap);
    1238           0 :                         goto errout;
    1239             :                 }
    1240           0 :                 if (bus_dmamap_load(sc->sc_dmat, rc->rc_dmap, rc->rc_req,
    1241             :                     PAGE_SIZE, NULL, BUS_DMA_WAITOK)) {
    1242             :                         DPRINTF("%s: failed to load RNDIS command map\n",
    1243             :                             sc->sc_dev.dv_xname);
    1244           0 :                         bus_dmamem_free(sc->sc_dmat, &rc->rc_segs,
    1245             :                             rc->rc_nsegs);
    1246           0 :                         bus_dmamap_destroy(sc->sc_dmat, rc->rc_dmap);
    1247           0 :                         goto errout;
    1248             :                 }
    1249           0 :                 rc->rc_gpa = atop(rc->rc_dmap->dm_segs[0].ds_addr);
    1250           0 :                 TAILQ_INSERT_TAIL(&sc->sc_cntl_fq, rc, rc_entry);
    1251             :         }
    1252             : 
    1253           0 :         rc = hvn_alloc_cmd(sc);
    1254             : 
    1255           0 :         bus_dmamap_sync(sc->sc_dmat, rc->rc_dmap, 0, PAGE_SIZE,
    1256             :             BUS_DMASYNC_PREREAD);
    1257             : 
    1258           0 :         rc->rc_id = atomic_inc_int_nv(&sc->sc_rndisrid);
    1259             : 
    1260           0 :         req = rc->rc_req;
    1261           0 :         req->rm_type = REMOTE_NDIS_INITIALIZE_MSG;
    1262           0 :         req->rm_len = sizeof(*req);
    1263           0 :         req->rm_rid = rc->rc_id;
    1264           0 :         req->rm_ver_major = RNDIS_VERSION_MAJOR;
    1265           0 :         req->rm_ver_minor = RNDIS_VERSION_MINOR;
    1266           0 :         req->rm_max_xfersz = HVN_RNDIS_XFER_SIZE;
    1267             : 
    1268           0 :         rc->rc_cmplen = sizeof(*cmp);
    1269             : 
    1270           0 :         bus_dmamap_sync(sc->sc_dmat, rc->rc_dmap, 0, PAGE_SIZE,
    1271             :             BUS_DMASYNC_PREWRITE);
    1272             : 
    1273           0 :         if ((rv = hvn_rndis_cmd(sc, rc, 500)) != 0) {
    1274             :                 DPRINTF("%s: INITIALIZE_MSG failed, error %d\n",
    1275             :                     sc->sc_dev.dv_xname, rv);
    1276           0 :                 hvn_free_cmd(sc, rc);
    1277           0 :                 goto errout;
    1278             :         }
    1279           0 :         cmp = (struct rndis_init_comp *)&rc->rc_cmp;
    1280           0 :         if (cmp->rm_status != RNDIS_STATUS_SUCCESS) {
    1281             :                 DPRINTF("%s: failed to init RNDIS, error %#x\n",
    1282             :                     sc->sc_dev.dv_xname, cmp->rm_status);
    1283             :                 hvn_free_cmd(sc, rc);
    1284             :                 goto errout;
    1285             :         }
    1286             : 
    1287             :         hvn_free_cmd(sc, rc);
    1288             : 
    1289             :         /* Initialize RNDIS Data command */
    1290           0 :         memset(&sc->sc_data_msg, 0, sizeof(sc->sc_data_msg));
    1291           0 :         sc->sc_data_msg.nvs_type = HVN_NVS_TYPE_RNDIS;
    1292           0 :         sc->sc_data_msg.nvs_rndis_mtype = HVN_NVS_RNDIS_MTYPE_DATA;
    1293           0 :         sc->sc_data_msg.nvs_chim_idx = HVN_NVS_CHIM_IDX_INVALID;
    1294             : 
    1295           0 :         return (0);
    1296             : 
    1297             : errout:
    1298           0 :         for (i = 0; i < HVN_RNDIS_CTLREQS; i++) {
    1299           0 :                 rc = &sc->sc_cntl_msgs[i];
    1300           0 :                 if (rc->rc_req == NULL)
    1301             :                         continue;
    1302           0 :                 TAILQ_REMOVE(&sc->sc_cntl_fq, rc, rc_entry);
    1303           0 :                 bus_dmamem_free(sc->sc_dmat, &rc->rc_segs, rc->rc_nsegs);
    1304           0 :                 rc->rc_req = NULL;
    1305           0 :                 bus_dmamap_destroy(sc->sc_dmat, rc->rc_dmap);
    1306           0 :         }
    1307           0 :         return (-1);
    1308           0 : }
    1309             : 
    1310             : int
    1311           0 : hvn_set_capabilities(struct hvn_softc *sc)
    1312             : {
    1313           0 :         struct ndis_offload_params params;
    1314             :         size_t len = sizeof(params);
    1315             : 
    1316           0 :         memset(&params, 0, sizeof(params));
    1317             : 
    1318           0 :         params.ndis_hdr.ndis_type = NDIS_OBJTYPE_DEFAULT;
    1319           0 :         if (sc->sc_ndisver < NDIS_VERSION_6_30) {
    1320           0 :                 params.ndis_hdr.ndis_rev = NDIS_OFFLOAD_PARAMS_REV_2;
    1321           0 :                 len = params.ndis_hdr.ndis_size = NDIS_OFFLOAD_PARAMS_SIZE_6_1;
    1322           0 :         } else {
    1323           0 :                 params.ndis_hdr.ndis_rev = NDIS_OFFLOAD_PARAMS_REV_3;
    1324           0 :                 len = params.ndis_hdr.ndis_size = NDIS_OFFLOAD_PARAMS_SIZE;
    1325             :         }
    1326             : 
    1327           0 :         params.ndis_ip4csum = NDIS_OFFLOAD_PARAM_TXRX;
    1328           0 :         params.ndis_tcp4csum = NDIS_OFFLOAD_PARAM_TXRX;
    1329           0 :         params.ndis_tcp6csum = NDIS_OFFLOAD_PARAM_TXRX;
    1330           0 :         if (sc->sc_ndisver >= NDIS_VERSION_6_30) {
    1331           0 :                 params.ndis_udp4csum = NDIS_OFFLOAD_PARAM_TXRX;
    1332           0 :                 params.ndis_udp6csum = NDIS_OFFLOAD_PARAM_TXRX;
    1333           0 :         }
    1334             : 
    1335           0 :         return (hvn_rndis_set(sc, OID_TCP_OFFLOAD_PARAMETERS, &params, len));
    1336           0 : }
    1337             : 
    1338             : int
    1339           0 : hvn_rndis_cmd(struct hvn_softc *sc, struct rndis_cmd *rc, int timo)
    1340             : {
    1341           0 :         struct hvn_nvs_rndis *msg = &rc->rc_msg;
    1342           0 :         struct rndis_msghdr *hdr = rc->rc_req;
    1343           0 :         struct vmbus_gpa sgl[1];
    1344             :         int tries = 10;
    1345             :         int rv, s;
    1346             : 
    1347           0 :         KERNEL_ASSERT_LOCKED();
    1348             : 
    1349           0 :         KASSERT(timo > 0);
    1350             : 
    1351           0 :         msg->nvs_type = HVN_NVS_TYPE_RNDIS;
    1352           0 :         msg->nvs_rndis_mtype = HVN_NVS_RNDIS_MTYPE_CTRL;
    1353           0 :         msg->nvs_chim_idx = HVN_NVS_CHIM_IDX_INVALID;
    1354             : 
    1355           0 :         sgl[0].gpa_page = rc->rc_gpa;
    1356           0 :         sgl[0].gpa_len = hdr->rm_len;
    1357           0 :         sgl[0].gpa_ofs = 0;
    1358             : 
    1359           0 :         rc->rc_done = 0;
    1360             : 
    1361           0 :         hvn_submit_cmd(sc, rc);
    1362             : 
    1363           0 :         do {
    1364           0 :                 rv = hv_channel_send_sgl(sc->sc_chan, sgl, 1, &rc->rc_msg,
    1365           0 :                     sizeof(*msg), rc->rc_id);
    1366           0 :                 if (rv == EAGAIN) {
    1367           0 :                         if (cold)
    1368           0 :                                 delay(100);
    1369             :                         else
    1370           0 :                                 tsleep(rc, PRIBIO, "rndisout", 1);
    1371           0 :                 } else if (rv) {
    1372             :                         DPRINTF("%s: RNDIS operation %u send error %d\n",
    1373             :                             sc->sc_dev.dv_xname, hdr->rm_type, rv);
    1374           0 :                         hvn_rollback_cmd(sc, rc);
    1375           0 :                         return (rv);
    1376             :                 }
    1377           0 :         } while (rv != 0 && --tries > 0);
    1378             : 
    1379           0 :         if (tries == 0 && rv != 0) {
    1380           0 :                 printf("%s: RNDIS operation %u send error %d\n",
    1381           0 :                     sc->sc_dev.dv_xname, hdr->rm_type, rv);
    1382           0 :                 return (rv);
    1383             :         }
    1384             : 
    1385           0 :         bus_dmamap_sync(sc->sc_dmat, rc->rc_dmap, 0, PAGE_SIZE,
    1386             :             BUS_DMASYNC_POSTWRITE);
    1387             : 
    1388           0 :         do {
    1389           0 :                 if (cold)
    1390           0 :                         delay(1000);
    1391             :                 else
    1392           0 :                         tsleep(rc, PRIBIO | PCATCH, "rndiscmd", 1);
    1393           0 :                 s = splnet();
    1394           0 :                 hvn_nvs_intr(sc);
    1395           0 :                 splx(s);
    1396           0 :         } while (--timo > 0 && rc->rc_done != 1);
    1397             : 
    1398           0 :         bus_dmamap_sync(sc->sc_dmat, rc->rc_dmap, 0, PAGE_SIZE,
    1399             :             BUS_DMASYNC_POSTREAD);
    1400             : 
    1401           0 :         if (rc->rc_done != 1) {
    1402           0 :                 rv = timo == 0 ? ETIMEDOUT : EINTR;
    1403           0 :                 if (hvn_rollback_cmd(sc, rc)) {
    1404           0 :                         hvn_release_cmd(sc, rc);
    1405             :                         rv = 0;
    1406           0 :                 } else if (rv == ETIMEDOUT) {
    1407           0 :                         printf("%s: RNDIS operation %u timed out\n",
    1408           0 :                             sc->sc_dev.dv_xname, hdr->rm_type);
    1409           0 :                 }
    1410           0 :                 return (rv);
    1411             :         }
    1412             : 
    1413           0 :         hvn_release_cmd(sc, rc);
    1414           0 :         return (0);
    1415           0 : }
    1416             : 
    1417             : void
    1418           0 : hvn_rndis_input(struct hvn_softc *sc, uint64_t tid, void *arg)
    1419             : {
    1420           0 :         struct ifnet *ifp = &sc->sc_ac.ac_if;
    1421           0 :         struct mbuf_list ml = MBUF_LIST_INITIALIZER();
    1422           0 :         struct vmbus_chanpkt_prplist *cp = arg;
    1423             :         uint32_t off, len, type;
    1424             :         int i;
    1425             : 
    1426           0 :         if (sc->sc_rx_ring == NULL) {
    1427             :                 DPRINTF("%s: invalid rx ring\n", sc->sc_dev.dv_xname);
    1428           0 :                 return;
    1429             :         }
    1430           0 :         for (i = 0; i < cp->cp_range_cnt; i++) {
    1431           0 :                 off = cp->cp_range[i].gpa_ofs;
    1432           0 :                 len = cp->cp_range[i].gpa_len;
    1433             : 
    1434           0 :                 KASSERT(off + len <= sc->sc_rx_size);
    1435           0 :                 KASSERT(len >= RNDIS_HEADER_OFFSET + 4);
    1436             : 
    1437           0 :                 memcpy(&type, (caddr_t)sc->sc_rx_ring + off, sizeof(type));
    1438           0 :                 switch (type) {
    1439             :                 /* data message */
    1440             :                 case REMOTE_NDIS_PACKET_MSG:
    1441           0 :                         hvn_rxeof(sc, (caddr_t)sc->sc_rx_ring +
    1442             :                             off, len, &ml);
    1443           0 :                         break;
    1444             :                 /* completion messages */
    1445             :                 case REMOTE_NDIS_INITIALIZE_CMPLT:
    1446             :                 case REMOTE_NDIS_QUERY_CMPLT:
    1447             :                 case REMOTE_NDIS_SET_CMPLT:
    1448             :                 case REMOTE_NDIS_RESET_CMPLT:
    1449             :                 case REMOTE_NDIS_KEEPALIVE_CMPLT:
    1450           0 :                         hvn_rndis_complete(sc, (caddr_t)sc->sc_rx_ring +
    1451             :                             off, len);
    1452           0 :                         break;
    1453             :                 /* notification message */
    1454             :                 case REMOTE_NDIS_INDICATE_STATUS_MSG:
    1455           0 :                         hvn_rndis_status(sc, (caddr_t)sc->sc_rx_ring +
    1456             :                             off, len);
    1457           0 :                         break;
    1458             :                 default:
    1459           0 :                         printf("%s: unhandled RNDIS message type %u\n",
    1460           0 :                             sc->sc_dev.dv_xname, type);
    1461           0 :                 }
    1462             :         }
    1463           0 :         hvn_nvs_ack(sc, tid);
    1464             : 
    1465           0 :         if_input(ifp, &ml);
    1466           0 : }
    1467             : 
    1468             : static inline struct mbuf *
    1469           0 : hvn_devget(struct hvn_softc *sc, caddr_t buf, uint32_t len)
    1470             : {
    1471             :         struct mbuf *m;
    1472             : 
    1473           0 :         if (len + ETHER_ALIGN <= MHLEN)
    1474           0 :                 MGETHDR(m, M_NOWAIT, MT_DATA);
    1475             :         else
    1476           0 :                 m = MCLGETI(NULL, M_NOWAIT, NULL, len + ETHER_ALIGN);
    1477           0 :         if (m == NULL)
    1478           0 :                 return (NULL);
    1479           0 :         m->m_len = m->m_pkthdr.len = len;
    1480           0 :         m_adj(m, ETHER_ALIGN);
    1481             : 
    1482           0 :         if (m_copyback(m, 0, len, buf, M_NOWAIT)) {
    1483           0 :                 m_freem(m);
    1484           0 :                 return (NULL);
    1485             :         }
    1486             : 
    1487           0 :         return (m);
    1488           0 : }
    1489             : 
    1490             : void
    1491           0 : hvn_rxeof(struct hvn_softc *sc, caddr_t buf, uint32_t len, struct mbuf_list *ml)
    1492             : {
    1493           0 :         struct ifnet *ifp = &sc->sc_ac.ac_if;
    1494             :         struct rndis_packet_msg *pkt;
    1495             :         struct rndis_pktinfo *pi;
    1496             :         uint32_t csum, vlan;
    1497             :         struct mbuf *m;
    1498             : 
    1499           0 :         if (!(ifp->if_flags & IFF_RUNNING))
    1500           0 :                 return;
    1501             : 
    1502           0 :         if (len < sizeof(*pkt)) {
    1503           0 :                 printf("%s: data packet too short: %u\n",
    1504           0 :                     sc->sc_dev.dv_xname, len);
    1505           0 :                 return;
    1506             :         }
    1507             : 
    1508           0 :         pkt = (struct rndis_packet_msg *)buf;
    1509             : 
    1510           0 :         if (pkt->rm_dataoffset + pkt->rm_datalen > len) {
    1511           0 :                 printf("%s: data packet out of bounds: %u@%u\n",
    1512           0 :                     sc->sc_dev.dv_xname, pkt->rm_dataoffset, pkt->rm_datalen);
    1513           0 :                 return;
    1514             :         }
    1515             : 
    1516           0 :         if ((m = hvn_devget(sc, buf + RNDIS_HEADER_OFFSET + pkt->rm_dataoffset,
    1517           0 :             pkt->rm_datalen)) == NULL) {
    1518           0 :                 ifp->if_ierrors++;
    1519           0 :                 return;
    1520             :         }
    1521             : 
    1522           0 :         if (pkt->rm_pktinfooffset + pkt->rm_pktinfolen > len) {
    1523           0 :                 printf("%s: pktinfo is out of bounds: %u@%u vs %u\n",
    1524           0 :                     sc->sc_dev.dv_xname, pkt->rm_pktinfolen,
    1525             :                     pkt->rm_pktinfooffset, len);
    1526           0 :                 goto done;
    1527             :         }
    1528           0 :         pi = (struct rndis_pktinfo *)((caddr_t)pkt + RNDIS_HEADER_OFFSET +
    1529             :             pkt->rm_pktinfooffset);
    1530           0 :         while (pkt->rm_pktinfolen > 0) {
    1531           0 :                 if (pi->rm_size > pkt->rm_pktinfolen) {
    1532           0 :                         printf("%s: invalid pktinfo size: %u/%u\n",
    1533           0 :                             sc->sc_dev.dv_xname, pi->rm_size,
    1534             :                             pkt->rm_pktinfolen);
    1535           0 :                         break;
    1536             :                 }
    1537           0 :                 switch (pi->rm_type) {
    1538             :                 case NDIS_PKTINFO_TYPE_CSUM:
    1539           0 :                         memcpy(&csum, pi->rm_data, sizeof(csum));
    1540           0 :                         if (csum & NDIS_RXCSUM_INFO_IPCS_OK)
    1541           0 :                                 m->m_pkthdr.csum_flags |= M_IPV4_CSUM_IN_OK;
    1542           0 :                         if (csum & NDIS_RXCSUM_INFO_TCPCS_OK)
    1543           0 :                                 m->m_pkthdr.csum_flags |= M_TCP_CSUM_IN_OK;
    1544           0 :                         if (csum & NDIS_RXCSUM_INFO_UDPCS_OK)
    1545           0 :                                 m->m_pkthdr.csum_flags |= M_UDP_CSUM_IN_OK;
    1546             :                         break;
    1547             :                 case NDIS_PKTINFO_TYPE_VLAN:
    1548           0 :                         memcpy(&vlan, pi->rm_data, sizeof(vlan));
    1549             : #if NVLAN > 0
    1550           0 :                         if (vlan != 0xffffffff) {
    1551           0 :                                 m->m_pkthdr.ether_vtag =
    1552           0 :                                     NDIS_VLAN_INFO_ID(vlan) |
    1553           0 :                                     (NDIS_VLAN_INFO_PRI(vlan) << EVL_PRIO_BITS);
    1554           0 :                                 m->m_flags |= M_VLANTAG;
    1555           0 :                         }
    1556             : #endif
    1557             :                         break;
    1558             :                 default:
    1559             :                         DPRINTF("%s: unhandled pktinfo type %u\n",
    1560             :                             sc->sc_dev.dv_xname, pi->rm_type);
    1561             :                 }
    1562           0 :                 pkt->rm_pktinfolen -= pi->rm_size;
    1563           0 :                 pi = (struct rndis_pktinfo *)((caddr_t)pi + pi->rm_size);
    1564             :         }
    1565             : 
    1566             :  done:
    1567           0 :         ml_enqueue(ml, m);
    1568           0 : }
    1569             : 
    1570             : void
    1571           0 : hvn_rndis_complete(struct hvn_softc *sc, caddr_t buf, uint32_t len)
    1572             : {
    1573             :         struct rndis_cmd *rc;
    1574             :         uint32_t id;
    1575             : 
    1576           0 :         memcpy(&id, buf + RNDIS_HEADER_OFFSET, sizeof(id));
    1577           0 :         if ((rc = hvn_complete_cmd(sc, id)) != NULL) {
    1578           0 :                 if (len < rc->rc_cmplen)
    1579           0 :                         printf("%s: RNDIS response %u too short: %u\n",
    1580           0 :                             sc->sc_dev.dv_xname, id, len);
    1581             :                 else
    1582           0 :                         memcpy(&rc->rc_cmp, buf, rc->rc_cmplen);
    1583           0 :                 if (len > rc->rc_cmplen &&
    1584           0 :                     len - rc->rc_cmplen > HVN_RNDIS_BUFSIZE)
    1585           0 :                         printf("%s: RNDIS response %u too large: %u\n",
    1586           0 :                             sc->sc_dev.dv_xname, id, len);
    1587           0 :                 else if (len > rc->rc_cmplen)
    1588           0 :                         memcpy(&rc->rc_cmpbuf, buf + rc->rc_cmplen,
    1589             :                             len - rc->rc_cmplen);
    1590           0 :                 rc->rc_done = 1;
    1591           0 :                 wakeup_one(rc);
    1592           0 :         } else
    1593             :                 DPRINTF("%s: failed to complete RNDIS request id %u\n",
    1594             :                     sc->sc_dev.dv_xname, id);
    1595           0 : }
    1596             : 
    1597             : int
    1598           0 : hvn_rndis_output(struct hvn_softc *sc, struct hvn_tx_desc *txd)
    1599             : {
    1600           0 :         uint64_t rid = (uint64_t)txd->txd_id << 32;
    1601             :         int rv;
    1602             : 
    1603           0 :         rv = hv_channel_send_sgl(sc->sc_chan, txd->txd_sgl, txd->txd_nsge,
    1604           0 :             &sc->sc_data_msg, sizeof(sc->sc_data_msg), rid);
    1605           0 :         if (rv) {
    1606             :                 DPRINTF("%s: RNDIS data send error %d\n",
    1607             :                     sc->sc_dev.dv_xname, rv);
    1608           0 :                 return (rv);
    1609             :         }
    1610             : 
    1611           0 :         return (0);
    1612           0 : }
    1613             : 
    1614             : void
    1615           0 : hvn_rndis_status(struct hvn_softc *sc, caddr_t buf, uint32_t len)
    1616             : {
    1617             :         uint32_t status;
    1618             : 
    1619           0 :         memcpy(&status, buf + RNDIS_HEADER_OFFSET, sizeof(status));
    1620           0 :         switch (status) {
    1621             :         case RNDIS_STATUS_MEDIA_CONNECT:
    1622           0 :                 sc->sc_link_state = LINK_STATE_UP;
    1623           0 :                 break;
    1624             :         case RNDIS_STATUS_MEDIA_DISCONNECT:
    1625           0 :                 sc->sc_link_state = LINK_STATE_DOWN;
    1626           0 :                 break;
    1627             :         /* Ignore these */
    1628             :         case RNDIS_STATUS_OFFLOAD_CURRENT_CONFIG:
    1629           0 :                 return;
    1630             :         default:
    1631             :                 DPRINTF("%s: unhandled status %#x\n", sc->sc_dev.dv_xname,
    1632             :                     status);
    1633           0 :                 return;
    1634             :         }
    1635           0 :         KERNEL_LOCK();
    1636           0 :         hvn_link_status(sc);
    1637           0 :         KERNEL_UNLOCK();
    1638           0 : }
    1639             : 
    1640             : int
    1641           0 : hvn_rndis_query(struct hvn_softc *sc, uint32_t oid, void *res, size_t *length)
    1642             : {
    1643             :         struct rndis_cmd *rc;
    1644             :         struct rndis_query_req *req;
    1645             :         struct rndis_query_comp *cmp;
    1646           0 :         size_t olength = *length;
    1647             :         int rv;
    1648             : 
    1649           0 :         rc = hvn_alloc_cmd(sc);
    1650             : 
    1651           0 :         bus_dmamap_sync(sc->sc_dmat, rc->rc_dmap, 0, PAGE_SIZE,
    1652             :             BUS_DMASYNC_PREREAD);
    1653             : 
    1654           0 :         rc->rc_id = atomic_inc_int_nv(&sc->sc_rndisrid);
    1655             : 
    1656           0 :         req = rc->rc_req;
    1657           0 :         req->rm_type = REMOTE_NDIS_QUERY_MSG;
    1658           0 :         req->rm_len = sizeof(*req);
    1659           0 :         req->rm_rid = rc->rc_id;
    1660           0 :         req->rm_oid = oid;
    1661           0 :         req->rm_infobufoffset = sizeof(*req) - RNDIS_HEADER_OFFSET;
    1662             : 
    1663           0 :         rc->rc_cmplen = sizeof(*cmp);
    1664             : 
    1665           0 :         bus_dmamap_sync(sc->sc_dmat, rc->rc_dmap, 0, PAGE_SIZE,
    1666             :             BUS_DMASYNC_PREWRITE);
    1667             : 
    1668           0 :         if ((rv = hvn_rndis_cmd(sc, rc, 500)) != 0) {
    1669             :                 DPRINTF("%s: QUERY_MSG failed, error %d\n",
    1670             :                     sc->sc_dev.dv_xname, rv);
    1671           0 :                 hvn_free_cmd(sc, rc);
    1672           0 :                 return (rv);
    1673             :         }
    1674             : 
    1675           0 :         cmp = (struct rndis_query_comp *)&rc->rc_cmp;
    1676           0 :         switch (cmp->rm_status) {
    1677             :         case RNDIS_STATUS_SUCCESS:
    1678           0 :                 if (cmp->rm_infobuflen > olength) {
    1679             :                         rv = EINVAL;
    1680           0 :                         break;
    1681             :                 }
    1682           0 :                 memcpy(res, rc->rc_cmpbuf, cmp->rm_infobuflen);
    1683           0 :                 *length = cmp->rm_infobuflen;
    1684           0 :                 break;
    1685             :         default:
    1686           0 :                 *length = 0;
    1687             :                 rv = EIO;
    1688           0 :         }
    1689             : 
    1690           0 :         hvn_free_cmd(sc, rc);
    1691             : 
    1692           0 :         return (rv);
    1693           0 : }
    1694             : 
    1695             : int
    1696           0 : hvn_rndis_set(struct hvn_softc *sc, uint32_t oid, void *data, size_t length)
    1697             : {
    1698             :         struct rndis_cmd *rc;
    1699             :         struct rndis_set_req *req;
    1700             :         struct rndis_set_comp *cmp;
    1701             :         int rv;
    1702             : 
    1703           0 :         rc = hvn_alloc_cmd(sc);
    1704             : 
    1705           0 :         bus_dmamap_sync(sc->sc_dmat, rc->rc_dmap, 0, PAGE_SIZE,
    1706             :             BUS_DMASYNC_PREREAD);
    1707             : 
    1708           0 :         rc->rc_id = atomic_inc_int_nv(&sc->sc_rndisrid);
    1709             : 
    1710           0 :         req = rc->rc_req;
    1711           0 :         req->rm_type = REMOTE_NDIS_SET_MSG;
    1712           0 :         req->rm_len = sizeof(*req) + length;
    1713           0 :         req->rm_rid = rc->rc_id;
    1714           0 :         req->rm_oid = oid;
    1715           0 :         req->rm_infobufoffset = sizeof(*req) - RNDIS_HEADER_OFFSET;
    1716             : 
    1717           0 :         rc->rc_cmplen = sizeof(*cmp);
    1718             : 
    1719           0 :         if (length > 0) {
    1720           0 :                 KASSERT(sizeof(*req) + length < PAGE_SIZE);
    1721           0 :                 req->rm_infobuflen = length;
    1722           0 :                 memcpy((caddr_t)(req + 1), data, length);
    1723           0 :         }
    1724             : 
    1725           0 :         bus_dmamap_sync(sc->sc_dmat, rc->rc_dmap, 0, PAGE_SIZE,
    1726             :             BUS_DMASYNC_PREWRITE);
    1727             : 
    1728           0 :         if ((rv = hvn_rndis_cmd(sc, rc, 500)) != 0) {
    1729             :                 DPRINTF("%s: SET_MSG failed, error %d\n",
    1730             :                     sc->sc_dev.dv_xname, rv);
    1731           0 :                 hvn_free_cmd(sc, rc);
    1732           0 :                 return (rv);
    1733             :         }
    1734             : 
    1735           0 :         cmp = (struct rndis_set_comp *)&rc->rc_cmp;
    1736           0 :         if (cmp->rm_status != RNDIS_STATUS_SUCCESS)
    1737           0 :                 rv = EIO;
    1738             : 
    1739           0 :         hvn_free_cmd(sc, rc);
    1740             : 
    1741           0 :         return (rv);
    1742           0 : }
    1743             : 
    1744             : int
    1745           0 : hvn_rndis_close(struct hvn_softc *sc)
    1746             : {
    1747           0 :         uint32_t filter = 0;
    1748             :         int rv;
    1749             : 
    1750           0 :         rv = hvn_rndis_set(sc, OID_GEN_CURRENT_PACKET_FILTER,
    1751             :             &filter, sizeof(filter));
    1752             :         if (rv)
    1753             :                 DPRINTF("%s: failed to clear RNDIS filter\n",
    1754             :                     sc->sc_dev.dv_xname);
    1755           0 :         return (rv);
    1756           0 : }
    1757             : 
    1758             : void
    1759           0 : hvn_rndis_detach(struct hvn_softc *sc)
    1760             : {
    1761             :         struct rndis_cmd *rc;
    1762             :         struct rndis_halt_req *req;
    1763             :         int rv;
    1764             : 
    1765           0 :         rc = hvn_alloc_cmd(sc);
    1766             : 
    1767           0 :         bus_dmamap_sync(sc->sc_dmat, rc->rc_dmap, 0, PAGE_SIZE,
    1768             :             BUS_DMASYNC_PREREAD);
    1769             : 
    1770           0 :         rc->rc_id = atomic_inc_int_nv(&sc->sc_rndisrid);
    1771             : 
    1772           0 :         req = rc->rc_req;
    1773           0 :         req->rm_type = REMOTE_NDIS_HALT_MSG;
    1774           0 :         req->rm_len = sizeof(*req);
    1775           0 :         req->rm_rid = rc->rc_id;
    1776             : 
    1777           0 :         bus_dmamap_sync(sc->sc_dmat, rc->rc_dmap, 0, PAGE_SIZE,
    1778             :             BUS_DMASYNC_PREWRITE);
    1779             : 
    1780           0 :         if ((rv = hvn_rndis_cmd(sc, rc, 500)) != 0)
    1781             :                 DPRINTF("%s: HALT_MSG failed, error %d\n",
    1782             :                     sc->sc_dev.dv_xname, rv);
    1783             : 
    1784           0 :         hvn_free_cmd(sc, rc);
    1785           0 : }

Generated by: LCOV version 1.13