A work-in-progress driver for the Hyper-V NetVSC
authormikeb <mikeb@openbsd.org>
Wed, 13 Jul 2016 21:59:35 +0000 (21:59 +0000)
committermikeb <mikeb@openbsd.org>
Wed, 13 Jul 2016 21:59:35 +0000 (21:59 +0000)
Network VSC is an RNDIS device using NVSP protocol to communicate
with the Hyper-V VMBus via VMBus channels and/or shared memory. The
code was ported from FreeBSD with some API changes and simplifications.

While the Rx path is nearly complete, packet transmition is not
implemented yet.

ok deraadt, mlarkin

sys/arch/amd64/conf/GENERIC
sys/dev/pv/files.pv
sys/dev/pv/if_hvn.c [new file with mode: 0644]
sys/dev/pv/if_hvnreg.h [new file with mode: 0644]
sys/dev/pv/rndisreg.h [new file with mode: 0644]

index 7cb016a..04f24ce 100644 (file)
@@ -1,4 +1,4 @@
-#      $OpenBSD: GENERIC,v 1.423 2016/07/01 15:02:49 jcs Exp $
+#      $OpenBSD: GENERIC,v 1.424 2016/07/13 21:59:35 mikeb Exp $
 #
 # For further information on compiling OpenBSD kernels, see the config(8)
 # man page.
@@ -76,6 +76,7 @@ xen0  at pvbus?               # Xen HVM domU
 xnf*   at xen?                 # Xen Netfront
 
 #hyperv0       at pvbus?               # Hyper-V guest
+#hvn*  at hyperv?              # Hyper-V netvsc
 
 option         PCIVERBOSE
 option         USBVERBOSE
index 8f8785c..c49d39d 100644 (file)
@@ -1,4 +1,4 @@
-#      $OpenBSD: files.pv,v 1.6 2016/06/22 01:13:07 mikeb Exp $
+#      $OpenBSD: files.pv,v 1.7 2016/07/13 21:59:35 mikeb Exp $
 #
 # Config file and device description for paravirtual devices.
 # Included by ports that need it.
@@ -27,3 +27,7 @@ file  dev/pv/if_xnf.c                 xnf
 device hyperv {}
 attach hyperv at pvbus
 file   dev/pv/hyperv.c                 hyperv  needs-flag
+
+device hvn: ether, ifnet, ifmedia
+attach hvn at hyperv
+file   dev/pv/if_hvn.c                 hvn
diff --git a/sys/dev/pv/if_hvn.c b/sys/dev/pv/if_hvn.c
new file mode 100644 (file)
index 0000000..f8e5314
--- /dev/null
@@ -0,0 +1,1485 @@
+/*-
+ * Copyright (c) 2009-2012 Microsoft Corp.
+ * Copyright (c) 2010-2012 Citrix Inc.
+ * Copyright (c) 2012 NetApp Inc. 
+ * Copyright (c) 2016 Mike Belopuhov <mike@esdenera.com>
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice unmodified, this list of conditions, and the following
+ *    disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+/*
+ * The OpenBSD port was done under funding by Esdenera Networks GmbH.
+ */
+
+#include "bpfilter.h"
+#include "vlan.h"
+#include "hyperv.h"
+
+#include <sys/param.h>
+#include <sys/systm.h>
+#include <sys/atomic.h>
+#include <sys/device.h>
+#include <sys/kernel.h>
+#include <sys/malloc.h>
+#include <sys/mbuf.h>
+#include <sys/pool.h>
+#include <sys/queue.h>
+#include <sys/socket.h>
+#include <sys/sockio.h>
+#include <sys/task.h>
+#include <sys/timeout.h>
+
+#include <machine/bus.h>
+
+#include <uvm/uvm_extern.h>
+
+#include <dev/pv/hypervreg.h>
+#include <dev/pv/hypervvar.h>
+#include <dev/pv/rndisreg.h>
+#include <dev/pv/if_hvnreg.h>
+
+#include <net/if.h>
+#include <net/if_media.h>
+
+#include <netinet/in.h>
+#include <netinet/if_ether.h>
+
+#ifdef INET6
+#include <netinet/ip6.h>
+#endif
+
+#if NBPFILTER > 0
+#include <net/bpf.h>
+#endif
+
+#define HVN_DEBUG                      1
+
+/*
+ * RNDIS control interface
+ */
+#define HVN_RNDIS_CTLREQS              4
+#define HVN_RNDIS_CMPBUFSZ             512
+
+struct rndis_cmd {
+       uint32_t                         rc_id;
+       struct rndis                    *rc_req;
+       bus_dmamap_t                     rc_dmap;
+       uint64_t                         rc_pfn;
+       struct rndis                     rc_cmp;
+       uint32_t                         rc_cmplen;
+       uint8_t                          rc_cmpbuf[HVN_RNDIS_CMPBUFSZ];
+       struct nvsp                      rc_nvsp;
+       struct mutex                     rc_mtx;
+       TAILQ_ENTRY(rndis_cmd)           rc_entry;
+};
+TAILQ_HEAD(rndis_queue, rndis_cmd);
+
+/*
+ * Rx ring
+ */
+#define HVN_RX_BUFID                   0xcafe
+
+/*
+ * Tx ring
+ */
+#define HVN_TX_DESC                    128
+#define HVN_TX_BUFID                   0xface
+
+struct hvn_softc {
+       struct device                    sc_dev;
+       struct hv_softc                 *sc_hvsc;
+       struct hv_channel               *sc_chan;
+       bus_dma_tag_t                    sc_dmat;
+
+       struct arpcom                    sc_ac;
+       struct ifmedia                   sc_media;
+       int                              sc_link_state;
+       int                              sc_promisc;
+
+       /* NVSP protocol */
+       int                              sc_proto;
+       uint32_t                         sc_nvsptid;
+       struct nvsp                      sc_nvsp;
+       uint8_t                         *sc_nvspbuf;
+#define  HVN_NVSP_BUFSIZE               (PAGE_SIZE * 4)
+       struct mutex                     sc_nvsplck;
+
+       /* RNDIS protocol */
+       uint32_t                         sc_rndisrid;
+       struct rndis_queue               sc_cntl_sq; /* submission queue */
+       struct mutex                     sc_cntl_sqlck;
+       struct rndis_queue               sc_cntl_cq; /* completion queue */
+       struct mutex                     sc_cntl_cqlck;
+       struct rndis_queue               sc_cntl_fq; /* free queue */
+       struct mutex                     sc_cntl_fqlck;
+       struct rndis_cmd                 sc_cntl_msgs[HVN_RNDIS_CTLREQS];
+
+       /* Rx ring */
+       void                            *sc_rx_ring;
+       int                              sc_rx_size;
+       uint32_t                         sc_rx_hndl;
+
+       /* Tx ring */
+       void                            *sc_tx_ring;
+       int                              sc_tx_size;
+       uint32_t                         sc_tx_hndl;
+};
+
+int    hvn_match(struct device *, void *, void *);
+void   hvn_attach(struct device *, struct device *, void *);
+int    hvn_ioctl(struct ifnet *, u_long, caddr_t);
+int    hvn_media_change(struct ifnet *);
+void   hvn_media_status(struct ifnet *, struct ifmediareq *);
+int    hvn_iff(struct hvn_softc *);
+void   hvn_init(struct hvn_softc *);
+void   hvn_stop(struct hvn_softc *);
+void   hvn_start(struct ifnet *);
+void   hvn_intr(void *);
+void   hvn_txeof(struct hvn_softc *, uint64_t);
+void   hvn_rxeof(struct hvn_softc *, void *);
+int    hvn_rx_ring_create(struct hvn_softc *);
+int    hvn_rx_ring_destroy(struct hvn_softc *);
+int    hvn_tx_ring_create(struct hvn_softc *);
+int    hvn_tx_ring_destroy(struct hvn_softc *);
+int    hvn_get_lladdr(struct hvn_softc *);
+int    hvn_set_lladdr(struct hvn_softc *);
+void   hvn_get_link_status(struct hvn_softc *);
+void   hvn_link_status(struct hvn_softc *);
+
+/* NSVP */
+int    hvn_nvsp_attach(struct hvn_softc *);
+void   hvn_nvsp_intr(void *);
+int    hvn_nvsp_output(struct hvn_softc *, struct nvsp *, uint64_t, int);
+int    hvn_nvsp_ack(struct hvn_softc *, struct nvsp *, uint64_t);
+void   hvn_nvsp_detach(struct hvn_softc *);
+
+/* RNDIS */
+int    hvn_rndis_attach(struct hvn_softc *);
+int    hvn_rndis_ctloutput(struct hvn_softc *, struct rndis_cmd *, int);
+void   hvn_rndis_filter(struct hvn_softc *sc, uint64_t, void *);
+void   hvn_rndis_input(struct hvn_softc *, caddr_t, uint32_t,
+           struct mbuf_list *);
+void   hvn_rndis_complete(struct hvn_softc *, caddr_t, uint32_t);
+void   hvn_rndis_status(struct hvn_softc *, caddr_t, uint32_t);
+int    hvn_rndis_query(struct hvn_softc *, uint32_t, void *, size_t *);
+int    hvn_rndis_set(struct hvn_softc *, uint32_t, void *, size_t);
+int    hvn_rndis_open(struct hvn_softc *);
+int    hvn_rndis_close(struct hvn_softc *);
+void   hvn_rndis_detach(struct hvn_softc *);
+
+struct cfdriver hvn_cd = {
+       NULL, "hvn", DV_IFNET
+};
+
+const struct cfattach hvn_ca = {
+       sizeof(struct hvn_softc), hvn_match, hvn_attach
+};
+
+int
+hvn_match(struct device *parent, void *match, void *aux)
+{
+       struct hv_attach_args *aa = aux;
+
+       if (strcmp("network", aa->aa_ident))
+               return (0);
+
+       return (1);
+}
+
+void
+hvn_attach(struct device *parent, struct device *self, void *aux)
+{
+       struct hv_attach_args *aa = aux;
+       struct hvn_softc *sc = (struct hvn_softc *)self;
+       struct ifnet *ifp = &sc->sc_ac.ac_if;
+
+       sc->sc_hvsc = (struct hv_softc *)parent;
+       sc->sc_chan = aa->aa_chan;
+       sc->sc_dmat = aa->aa_dmat;
+
+       strlcpy(ifp->if_xname, sc->sc_dev.dv_xname, IFNAMSIZ);
+
+       DPRINTF("\n");
+
+       if (hvn_nvsp_attach(sc)) {
+               printf(": failed to init NVSP\n");
+               return;
+       }
+
+       if (hvn_rx_ring_create(sc)) {
+               printf(": failed to create Rx ring\n");
+               goto detach;
+       }
+
+       if (hvn_tx_ring_create(sc)) {
+               printf(": failed to create Tx ring\n");
+               goto detach;
+       }
+
+       ifp->if_flags = IFF_BROADCAST | IFF_SIMPLEX | IFF_MULTICAST;
+       ifp->if_xflags = IFXF_MPSAFE;
+       ifp->if_ioctl = hvn_ioctl;
+       ifp->if_start = hvn_start;
+       ifp->if_softc = sc;
+
+       ifp->if_capabilities = IFCAP_CSUM_IPv4 | IFCAP_CSUM_TCPv4 |
+           IFCAP_CSUM_UDPv4;
+#if NVLAN > 0
+       ifp->if_capabilities |= IFCAP_VLAN_HWTAGGING;
+#endif
+
+       IFQ_SET_MAXLEN(&ifp->if_snd, HVN_TX_DESC - 1);
+
+       ifmedia_init(&sc->sc_media, IFM_IMASK, hvn_media_change,
+           hvn_media_status);
+       ifmedia_add(&sc->sc_media, IFM_ETHER | IFM_MANUAL, 0, NULL);
+       ifmedia_set(&sc->sc_media, IFM_ETHER | IFM_MANUAL);
+
+       if_attach(ifp);
+
+       if (hvn_rndis_attach(sc)) {
+               printf(": failed to init RNDIS\n");
+               goto detach;
+       }
+
+       if (hvn_get_lladdr(sc)) {
+               printf(": failed to obtain an ethernet address\n");
+               hvn_rndis_detach(sc);
+               goto detach;
+       }
+
+       DPRINTF("%s", sc->sc_dev.dv_xname);
+       printf(": channel %u, address %s\n", sc->sc_chan->ch_relid,
+           ether_sprintf(sc->sc_ac.ac_enaddr));
+
+       ether_ifattach(ifp);
+       return;
+
+ detach:
+       hvn_rx_ring_destroy(sc);
+       hvn_tx_ring_destroy(sc);
+       hvn_nvsp_detach(sc);
+       if (ifp->if_start)
+               if_detach(ifp);
+}
+
+int
+hvn_ioctl(struct ifnet *ifp, u_long command, caddr_t data)
+{
+       struct hvn_softc *sc = ifp->if_softc;
+       struct ifreq *ifr = (struct ifreq *)data;
+       int s, error = 0;
+
+       s = splnet();
+
+       switch (command) {
+       case SIOCSIFADDR:
+               ifp->if_flags |= IFF_UP;
+               if (!(ifp->if_flags & IFF_RUNNING))
+                       hvn_init(sc);
+               break;
+       case SIOCSIFFLAGS:
+               if (ifp->if_flags & IFF_UP) {
+                       if (ifp->if_flags & IFF_RUNNING)
+                               error = ENETRESET;
+                       else
+                               hvn_init(sc);
+               } else {
+                       if (ifp->if_flags & IFF_RUNNING)
+                               hvn_stop(sc);
+               }
+               break;
+       case SIOCGIFMEDIA:
+       case SIOCSIFMEDIA:
+               error = ifmedia_ioctl(ifp, ifr, &sc->sc_media, command);
+               break;
+       default:
+               error = ether_ioctl(ifp, &sc->sc_ac, command, data);
+       }
+
+       if (error == ENETRESET) {
+               if (ifp->if_flags & IFF_RUNNING)
+                       hvn_iff(sc);
+               error = 0;
+       }
+
+       splx(s);
+
+       return (error);
+}
+
+int
+hvn_media_change(struct ifnet *ifp)
+{
+       return (0);
+}
+
+void
+hvn_media_status(struct ifnet *ifp, struct ifmediareq *ifmr)
+{
+       struct hvn_softc *sc = ifp->if_softc;
+
+       hvn_get_link_status(sc);
+       hvn_link_status(sc);
+
+       ifmr->ifm_status = IFM_AVALID;
+       ifmr->ifm_active = IFM_ETHER | IFM_MANUAL;
+       if (sc->sc_link_state == LINK_STATE_UP)
+               ifmr->ifm_status |= IFM_ACTIVE;
+}
+
+void
+hvn_link_status(struct hvn_softc *sc)
+{
+       struct ifnet *ifp = &sc->sc_ac.ac_if;
+
+       if (sc->sc_link_state != ifp->if_link_state) {
+               ifp->if_link_state = sc->sc_link_state;
+               if_link_state_change(ifp);
+       }
+}
+
+int
+hvn_iff(struct hvn_softc *sc)
+{
+       /* XXX */
+       sc->sc_promisc = 0;
+
+       return (0);
+}
+
+void
+hvn_init(struct hvn_softc *sc)
+{
+       struct ifnet *ifp = &sc->sc_ac.ac_if;
+
+       hvn_stop(sc);
+
+       hvn_iff(sc);
+
+       if (hvn_rndis_open(sc) == 0) {
+               ifp->if_flags |= IFF_RUNNING;
+               ifq_clr_oactive(&ifp->if_snd);
+       }
+}
+
+void
+hvn_stop(struct hvn_softc *sc)
+{
+       struct ifnet *ifp = &sc->sc_ac.ac_if;
+
+       if (ifp->if_flags & IFF_RUNNING) {
+               ifp->if_flags &= ~IFF_RUNNING;
+               hvn_rndis_close(sc);
+       }
+
+       ifq_barrier(&ifp->if_snd);
+       intr_barrier(sc->sc_chan);
+
+       ifq_clr_oactive(&ifp->if_snd);
+}
+
+void
+hvn_start(struct ifnet *ifp)
+{
+       struct mbuf *m;
+
+       if (!(ifp->if_flags & IFF_RUNNING) || ifq_is_oactive(&ifp->if_snd))
+               return;
+
+       for (;;) {
+               m = ifq_deq_begin(&ifp->if_snd);
+               if (m == NULL)
+                       break;
+
+               ifq_deq_commit(&ifp->if_snd, m);
+
+#if NBPFILTER > 0
+               if (ifp->if_bpf)
+                       bpf_mtap_ether(ifp->if_bpf, m, BPF_DIRECTION_OUT);
+#endif
+
+               m_freem(m);
+               ifp->if_oerrors++;
+       }
+}
+
+#if 0
+void
+hvn_intr(void *arg)
+{
+       struct hvn_softc *sc = arg;
+       struct ifnet *ifp = &sc->sc_ac.ac_if;
+       uint64_t rid;
+       uint32_t rlen;
+       int rv;
+
+       if (!(ifp->if_flags & IFF_RUNNING))
+               return;
+
+       if (ifq_is_oactive(&ifp->if_snd))
+               ifq_restart(&ifp->if_snd);
+}
+#endif
+
+void
+hvn_txeof(struct hvn_softc *sc, uint64_t tid)
+{
+       struct ifnet *ifp = &sc->sc_ac.ac_if;
+
+       printf("%s: tx tid %llu\n", ifp->if_xname, tid);
+}
+
+int
+hvn_rx_ring_create(struct hvn_softc *sc)
+{
+       struct nvsp *pkt = &sc->sc_nvsp;
+       struct nvsp_send_rx_buf *msg;
+       struct nvsp_send_rx_buf_comp *cmp;
+       uint64_t tid;
+
+       if (sc->sc_proto <= NVSP_PROTOCOL_VERSION_2)
+               sc->sc_rx_size = 15 * 1024 * 1024;      /* 15MB */
+       else
+               sc->sc_rx_size = 16 * 1024 * 1024;      /* 16MB */
+       sc->sc_rx_ring = km_alloc(sc->sc_rx_size, &kv_any, &kp_zero,
+           cold ? &kd_nowait : &kd_waitok);
+       if (sc->sc_rx_ring == NULL) {
+               DPRINTF("%s: failed to allocate Rx ring buffer\n",
+                   sc->sc_dev.dv_xname);
+               return (-1);
+       }
+       if (hv_handle_alloc(sc->sc_chan, sc->sc_rx_ring, sc->sc_rx_size,
+           &sc->sc_rx_hndl)) {
+               DPRINTF("%s: failed to obtain a PA handle\n",
+                   sc->sc_dev.dv_xname);
+               goto errout;
+       }
+
+       memset(pkt, 0, sizeof(*pkt));
+       pkt->msg_type = nvsp_type_send_rx_buf;
+       msg = (struct nvsp_send_rx_buf *)&pkt->msg;
+       msg->gpadl_handle = sc->sc_rx_hndl;
+       msg->id = HVN_RX_BUFID;
+
+       tid = atomic_inc_int_nv(&sc->sc_nvsptid);
+       if (hvn_nvsp_output(sc, pkt, tid, 100))
+               goto errout;
+
+       cmp = (struct nvsp_send_rx_buf_comp *)&pkt->msg;
+       if (cmp->status != nvsp_status_success) {
+               DPRINTF("%s: failed to set up the Rx ring\n",
+                   sc->sc_dev.dv_xname);
+               goto errout;
+       }
+       if (cmp->num_sections > 1) {
+               DPRINTF("%s: invalid number of Rx ring sections: %d\n",
+                   sc->sc_dev.dv_xname, cmp->num_sections);
+               hvn_rx_ring_destroy(sc);
+               return (-1);
+       }
+       return (0);
+
+ errout:
+       if (sc->sc_rx_hndl) {
+               hv_handle_free(sc->sc_chan, sc->sc_rx_hndl);
+               sc->sc_rx_hndl = 0;
+       }
+       if (sc->sc_rx_ring) {
+               km_free(sc->sc_rx_ring, sc->sc_rx_size, &kv_any, &kp_zero);
+               sc->sc_rx_ring = NULL;
+       }
+       return (-1);
+}
+
+int
+hvn_rx_ring_destroy(struct hvn_softc *sc)
+{
+       struct nvsp *pkt = &sc->sc_nvsp;
+       struct nvsp_revoke_rx_buf *msg;
+       uint64_t tid;
+
+       if (sc->sc_rx_ring == NULL)
+               return (0);
+
+       memset(pkt, 0, sizeof(*pkt));
+       pkt->msg_type = nvsp_type_revoke_rx_buf;
+       msg = (struct nvsp_revoke_rx_buf *)&pkt->msg;
+       msg->id = HVN_RX_BUFID;
+
+       tid = atomic_inc_int_nv(&sc->sc_nvsptid);
+       if (hvn_nvsp_output(sc, pkt, tid, 0))
+               return (-1);
+
+       delay(100);
+
+       hv_handle_free(sc->sc_chan, sc->sc_rx_hndl);
+
+       sc->sc_rx_hndl = 0;
+
+       km_free(sc->sc_rx_ring, sc->sc_rx_size, &kv_any, &kp_zero);
+       sc->sc_rx_ring = NULL;
+
+       return (0);
+}
+
+int
+hvn_tx_ring_create(struct hvn_softc *sc)
+{
+       struct nvsp *pkt = &sc->sc_nvsp;
+       struct nvsp_send_tx_buf *msg;
+       struct nvsp_send_tx_buf_comp *cmp;
+       uint64_t tid;
+
+       sc->sc_tx_size = 15 * 1024 * 1024;      /* 15MB */
+       sc->sc_tx_ring = km_alloc(sc->sc_tx_size, &kv_any, &kp_zero,
+           cold ? &kd_nowait : &kd_waitok);
+       if (sc->sc_tx_ring == NULL) {
+               DPRINTF("%s: failed to allocate Tx ring buffer\n",
+                   sc->sc_dev.dv_xname);
+               return (-1);
+       }
+       if (hv_handle_alloc(sc->sc_chan, sc->sc_tx_ring, sc->sc_tx_size,
+           &sc->sc_tx_hndl)) {
+               DPRINTF("%s: failed to obtain a PA handle\n",
+                   sc->sc_dev.dv_xname);
+               goto errout;
+       }
+
+       memset(pkt, 0, sizeof(*pkt));
+       pkt->msg_type = nvsp_type_send_tx_buf;
+       msg = (struct nvsp_send_tx_buf *)&pkt->msg;
+       msg->gpadl_handle = sc->sc_tx_hndl;
+       msg->id = HVN_TX_BUFID;
+
+       tid = atomic_inc_int_nv(&sc->sc_nvsptid);
+       if (hvn_nvsp_output(sc, pkt, tid, 100))
+               goto errout;
+
+       cmp = (struct nvsp_send_tx_buf_comp *)&pkt->msg;
+       if (cmp->status != nvsp_status_success) {
+               DPRINTF("%s: failed to set up the Tx ring\n",
+                   sc->sc_dev.dv_xname);
+               goto errout;
+       }
+       return (0);
+
+ errout:
+       if (sc->sc_tx_hndl) {
+               hv_handle_free(sc->sc_chan, sc->sc_tx_hndl);
+               sc->sc_tx_hndl = 0;
+       }
+       if (sc->sc_tx_ring) {
+               km_free(sc->sc_tx_ring, sc->sc_tx_size, &kv_any, &kp_zero);
+               sc->sc_tx_ring = NULL;
+       }
+       return (-1);
+}
+
+int
+hvn_tx_ring_destroy(struct hvn_softc *sc)
+{
+       struct nvsp *pkt = &sc->sc_nvsp;
+       struct nvsp_revoke_tx_buf *msg;
+       uint64_t tid;
+
+       if (sc->sc_tx_ring == NULL)
+               return (0);
+
+       memset(pkt, 0, sizeof(*pkt));
+       pkt->msg_type = nvsp_type_revoke_tx_buf;
+       msg = (struct nvsp_revoke_tx_buf *)&pkt->msg;
+       msg->id = HVN_TX_BUFID;
+
+       tid = atomic_inc_int_nv(&sc->sc_nvsptid);
+       if (hvn_nvsp_output(sc, pkt, tid, 0))
+               return (-1);
+
+       delay(100);
+
+       hv_handle_free(sc->sc_chan, sc->sc_tx_hndl);
+
+       sc->sc_tx_hndl = 0;
+
+       km_free(sc->sc_tx_ring, sc->sc_tx_size, &kv_any, &kp_zero);
+       sc->sc_tx_ring = NULL;
+
+       return (0);
+}
+
+int
+hvn_get_lladdr(struct hvn_softc *sc)
+{
+       char enaddr[ETHER_ADDR_LEN];
+       size_t addrlen = ETHER_ADDR_LEN;
+       int rv;
+
+       rv = hvn_rndis_query(sc, RNDIS_OID_802_3_PERMANENT_ADDRESS,
+           enaddr, &addrlen);
+       if (rv == 0 && addrlen == ETHER_ADDR_LEN)
+               memcpy(sc->sc_ac.ac_enaddr, enaddr, ETHER_ADDR_LEN);
+       return (rv);
+}
+
+int
+hvn_set_lladdr(struct hvn_softc *sc)
+{
+       return (hvn_rndis_set(sc, RNDIS_OID_802_3_CURRENT_ADDRESS,
+           sc->sc_ac.ac_enaddr, ETHER_ADDR_LEN));
+}
+
+void
+hvn_get_link_status(struct hvn_softc *sc)
+{
+       uint32_t state;
+       size_t len = sizeof(state);
+
+       if (hvn_rndis_query(sc, RNDIS_OID_GEN_MEDIA_CONNECT_STATUS,
+           &state, &len) == 0)
+               sc->sc_link_state = (state == 0) ? LINK_STATE_UP :
+                   LINK_STATE_DOWN;
+}
+
+int
+hvn_nvsp_attach(struct hvn_softc *sc)
+{
+       const uint32_t protos[] = {
+               NVSP_PROTOCOL_VERSION_5, NVSP_PROTOCOL_VERSION_4,
+               NVSP_PROTOCOL_VERSION_2, NVSP_PROTOCOL_VERSION_1
+       };
+       struct nvsp *pkt = &sc->sc_nvsp;
+       struct nvsp_init *init;
+       struct nvsp_init_comp *cmp;
+       struct nvsp_send_ndis_version *ver;
+       uint64_t tid;
+       uint32_t ndisver;
+       int i;
+
+       /* 4 page sized buffer for channel messages */
+       sc->sc_nvspbuf = km_alloc(HVN_NVSP_BUFSIZE, &kv_any, &kp_zero,
+           (cold ? &kd_nowait : &kd_waitok));
+       if (sc->sc_nvspbuf == NULL) {
+               DPRINTF("%s: failed to allocate channel data buffer\n",
+                   sc->sc_dev.dv_xname);
+               return (-1);
+       }
+       sc->sc_chan->ch_buflen = PAGE_SIZE * 4;
+
+       /* Associate our interrupt handler with the channel */
+       if (hv_channel_open(sc->sc_chan, NULL, 0, hvn_nvsp_intr, sc)) {
+               DPRINTF("%s: failed to open channel\n", sc->sc_dev.dv_xname);
+               km_free(sc->sc_nvspbuf, HVN_NVSP_BUFSIZE, &kv_any, &kp_zero);
+               return (-1);
+       }
+
+       mtx_init(&sc->sc_nvsplck, IPL_NET);
+
+       memset(pkt, 0, sizeof(pkt));
+       pkt->msg_type = nvsp_type_init;
+       init = (struct nvsp_init *)&pkt->msg;
+
+       for (i = 0; i < nitems(protos); i++) {
+               init->protocol_version = init->protocol_version_2 = protos[i];
+               tid = atomic_inc_int_nv(&sc->sc_nvsptid);
+               if (hvn_nvsp_output(sc, pkt, tid, 100))
+                       return (-1);
+               cmp = (struct nvsp_init_comp *)&pkt->msg;
+               if (cmp->status == nvsp_status_success) {
+                       sc->sc_proto = protos[i];
+                       break;
+               }
+       }
+       if (!sc->sc_proto) {
+               DPRINTF("%s: failed to negotiate NVSP version\n",
+                   sc->sc_dev.dv_xname);
+               return (-1);
+       }
+
+       memset(pkt, 0, sizeof(pkt));
+       pkt->msg_type = nvsp_type_send_ndis_vers;
+       ver = (struct nvsp_send_ndis_version *)&pkt->msg;
+       if (sc->sc_proto <= NVSP_PROTOCOL_VERSION_4)
+               ndisver = NDIS_VERSION_6_1;
+       else
+               ndisver = NDIS_VERSION_6_30;
+       ver->ndis_major_vers = (ndisver & 0xffff0000) >> 16;
+       ver->ndis_minor_vers = (ndisver & 0x0000ffff);
+
+       tid = atomic_inc_int_nv(&sc->sc_nvsptid);
+       if (hvn_nvsp_output(sc, pkt, tid, 100))
+               return (-1);
+
+       DPRINTF("%s: NVSP %u.%u, NDIS %u.%u\n", sc->sc_dev.dv_xname,
+           sc->sc_proto >> 16, sc->sc_proto & 0xffff,
+           ndisver >> 16, ndisver & 0xffff);
+
+       return (0);
+}
+
+void
+hvn_nvsp_intr(void *arg)
+{
+       struct hvn_softc *sc = arg;
+       struct hv_pktdesc *d;
+       struct nvsp *pkt;
+       uint64_t rid;
+       uint32_t rlen;
+       int rv;
+
+       for (;;) {
+               rv = hv_channel_recv(sc->sc_chan, sc->sc_nvspbuf,
+                   HVN_NVSP_BUFSIZE, &rlen, &rid, 1);
+               if (rv != 0 || rlen == 0) {
+                       if (rv != EAGAIN)
+                               printf("%s: failed to receive an NVSP "
+                                   "packet\n", sc->sc_dev.dv_xname);
+                       break;
+               }
+               d = (struct hv_pktdesc *)sc->sc_nvspbuf;
+               pkt = (struct nvsp *)((char *)d + (d->offset << 3));
+
+               if (d->type == HV_PKT_COMPLETION) {
+                       switch (pkt->msg_type) {
+                       case nvsp_type_init_comp:
+                       case nvsp_type_send_rx_buf_comp:
+                       case nvsp_type_send_tx_buf_comp:
+                       case nvsp_type_subchannel:
+                               /* copy the response back */
+                               memcpy(&sc->sc_nvsp, pkt, sizeof(sc->sc_nvsp));
+                               wakeup_one(&sc->sc_nvsp);
+                               break;
+                       case nvsp_type_send_rndis_pkt_comp:
+                               hvn_txeof(sc, d->tid);
+                               break;
+                       default:
+                               printf("%s: unhandled NVSP packet type %d "
+                                   "on completion\n", sc->sc_dev.dv_xname,
+                                   pkt->msg_type);
+                       }
+               } else if (d->type == HV_PKT_DATA_USING_TRANSFER_PAGES) {
+                       switch (pkt->msg_type) {
+                       case nvsp_type_send_rndis_pkt:
+                               hvn_rndis_filter(sc, d->tid, d + 1);
+                               break;
+                       default:
+                               printf("%s: unhandled NVSP packet type %d "
+                                   "on receive\n", sc->sc_dev.dv_xname,
+                                   pkt->msg_type);
+                       }
+               } else
+                       printf("%s: unknown NVSP packet type %u\n",
+                           sc->sc_dev.dv_xname, d->type);
+       }
+}
+
+int
+hvn_nvsp_output(struct hvn_softc *sc, struct nvsp *pkt, uint64_t tid, int timo)
+{
+       int tries = 10;
+       int rv;
+
+       do {
+               rv = hv_channel_send(sc->sc_chan, pkt, sizeof(*pkt),
+                   tid, HV_PKT_DATA_IN_BAND,
+                   timo ? HV_PKTFLAG_COMPLETION_REQUESTED : 0);
+               if (rv == EAGAIN) {
+                       if (timo)
+                               tsleep(pkt, PRIBIO, "hvnsend", timo / 10);
+                       else
+                               delay(100);
+               } else if (rv) {
+                       DPRINTF("%s: NVSP operation %d send error %d\n",
+                           sc->sc_dev.dv_xname, pkt->msg_type, rv);
+                       return (rv);
+               }
+       } while (rv != 0 && --tries > 0);
+
+       if (timo) {
+               mtx_enter(&sc->sc_nvsplck);
+               rv = msleep(&sc->sc_nvsp, &sc->sc_nvsplck, PRIBIO, "hvnvsp",
+                   timo);
+               mtx_leave(&sc->sc_nvsplck);
+#ifdef HVN_DEBUG
+               switch (rv) {
+               case EINTR:
+                       rv = 0;
+                       break;
+               case EWOULDBLOCK:
+                       printf("%s: NVSP opertaion %d timed out\n",
+                           sc->sc_dev.dv_xname, pkt->msg_type);
+               }
+       }
+#endif
+       return (rv);
+}
+
+int
+hvn_nvsp_ack(struct hvn_softc *sc, struct nvsp *pkt, uint64_t tid)
+{
+       int tries = 5;
+       int rv;
+
+       do {
+               rv = hv_channel_send(sc->sc_chan, pkt, sizeof(*pkt),
+                   tid, HV_PKT_COMPLETION, 0);
+               if (rv == EAGAIN)
+                       delay(100);
+               else if (rv) {
+                       DPRINTF("%s: NVSP acknowledgement error %d\n",
+                           sc->sc_dev.dv_xname, rv);
+                       return (rv);
+               }
+       } while (rv != 0 && --tries > 0);
+       return (rv);
+}
+
+void
+hvn_nvsp_detach(struct hvn_softc *sc)
+{
+       if (hv_channel_close(sc->sc_chan) == 0) {
+               km_free(sc->sc_nvspbuf, HVN_NVSP_BUFSIZE, &kv_any, &kp_zero);
+               sc->sc_nvspbuf = NULL;
+       }
+}
+
+static inline void
+hexdump(const char *header, void *data, size_t size)
+{
+       uint8_t *ptr = data;
+       int i;
+
+       for (i = 0; i < size; i++) {
+               if ((i % 16) == 0)
+                       printf("%s%s+0x%02x:", i > 0 ? "\n" : "", header, i);
+               printf(" %02x", ptr[i]);
+       }
+       printf("\n");
+}
+
+static inline struct rndis_cmd *
+hvn_alloc_cmd(struct hvn_softc *sc)
+{
+       struct rndis_cmd *rc;
+
+       mtx_enter(&sc->sc_cntl_fqlck);
+       while ((rc = TAILQ_FIRST(&sc->sc_cntl_fq)) == NULL)
+               msleep(&sc->sc_cntl_fq, &sc->sc_cntl_fqlck,
+                   PRIBIO, "hvnrr", 1);
+       TAILQ_REMOVE(&sc->sc_cntl_fq, rc, rc_entry);
+       mtx_leave(&sc->sc_cntl_fqlck);
+       return (rc);
+}
+
+static inline void
+hvn_submit_cmd(struct hvn_softc *sc, struct rndis_cmd *rc)
+{
+       mtx_enter(&sc->sc_cntl_sqlck);
+       TAILQ_INSERT_TAIL(&sc->sc_cntl_sq, rc, rc_entry);
+       mtx_leave(&sc->sc_cntl_sqlck);
+}
+
+static inline struct rndis_cmd *
+hvn_complete_cmd(struct hvn_softc *sc, uint32_t id)
+{
+       struct rndis_cmd *rc;
+
+       mtx_enter(&sc->sc_cntl_sqlck);
+       TAILQ_FOREACH(rc, &sc->sc_cntl_sq, rc_entry) {
+               if (rc->rc_id == id) {
+                       TAILQ_REMOVE(&sc->sc_cntl_sq, rc, rc_entry);
+                       break;
+               }
+       }
+       mtx_leave(&sc->sc_cntl_sqlck);
+       if (rc != NULL) {
+               mtx_enter(&sc->sc_cntl_cqlck);
+               TAILQ_INSERT_TAIL(&sc->sc_cntl_cq, rc, rc_entry);
+               mtx_leave(&sc->sc_cntl_cqlck);
+       }
+       return (rc);
+}
+
+static inline int
+hvn_rollback_cmd(struct hvn_softc *sc, struct rndis_cmd *rc)
+{
+       struct rndis_cmd *rn;
+
+       mtx_enter(&sc->sc_cntl_sqlck);
+       TAILQ_FOREACH(rn, &sc->sc_cntl_sq, rc_entry) {
+               if (rn == rc) {
+                       TAILQ_REMOVE(&sc->sc_cntl_sq, rc, rc_entry);
+                       mtx_leave(&sc->sc_cntl_sqlck);
+                       return (0);
+               }
+       }
+       mtx_leave(&sc->sc_cntl_sqlck);
+       return (-1);
+}
+
+static inline void
+hvn_free_cmd(struct hvn_softc *sc, struct rndis_cmd *rc)
+{
+       memset(rc->rc_req, 0, sizeof(*rc->rc_req));
+       memset(&rc->rc_cmp, 0, sizeof(rc->rc_cmp));
+       memset(&rc->rc_nvsp, 0, sizeof(rc->rc_nvsp));
+       mtx_enter(&sc->sc_cntl_fqlck);
+       TAILQ_INSERT_TAIL(&sc->sc_cntl_fq, rc, rc_entry);
+       mtx_leave(&sc->sc_cntl_fqlck);
+       wakeup(&sc->sc_cntl_fq);
+}
+
+int
+hvn_rndis_attach(struct hvn_softc *sc)
+{
+       struct rndis_init_req *req;
+       struct rndis_init_comp *cmp;
+       struct rndis_cmd *rc;
+       int i, rv;
+
+       /* RNDIS control message queues */
+       TAILQ_INIT(&sc->sc_cntl_sq);
+       TAILQ_INIT(&sc->sc_cntl_cq);
+       TAILQ_INIT(&sc->sc_cntl_fq);
+       mtx_init(&sc->sc_cntl_sqlck, IPL_NET);
+       mtx_init(&sc->sc_cntl_cqlck, IPL_NET);
+       mtx_init(&sc->sc_cntl_fqlck, IPL_NET);
+
+       for (i = 0; i < HVN_RNDIS_CTLREQS; i++) {
+               rc = &sc->sc_cntl_msgs[i];
+               if (bus_dmamap_create(sc->sc_dmat, PAGE_SIZE, 1,
+                   PAGE_SIZE, 0, BUS_DMA_WAITOK, &rc->rc_dmap)) {
+                       DPRINTF("%s: failed to create RNDIS command map\n",
+                           sc->sc_dev.dv_xname);
+                       goto errout;
+               }
+               rc->rc_req = km_alloc(PAGE_SIZE, &kv_any, &kp_zero,
+                   &kd_waitok);
+               if (rc->rc_req == NULL) {
+                       DPRINTF("%s: failed to allocate RNDIS command\n",
+                           sc->sc_dev.dv_xname);
+                       bus_dmamap_destroy(sc->sc_dmat, rc->rc_dmap);
+                       goto errout;
+               }
+               if (bus_dmamap_load(sc->sc_dmat, rc->rc_dmap, rc->rc_req,
+                   PAGE_SIZE, NULL, BUS_DMA_WAITOK)) {
+                       DPRINTF("%s: failed to load RNDIS command map\n",
+                           sc->sc_dev.dv_xname);
+                       km_free(rc->rc_req, PAGE_SIZE, &kv_any, &kp_zero);
+                       bus_dmamap_destroy(sc->sc_dmat, rc->rc_dmap);
+                       goto errout;
+               }
+               rc->rc_pfn = atop(rc->rc_dmap->dm_segs[0].ds_addr);
+               mtx_init(&rc->rc_mtx, IPL_NET);
+               TAILQ_INSERT_TAIL(&sc->sc_cntl_fq, rc, rc_entry);
+       }
+
+       rc = hvn_alloc_cmd(sc);
+
+       bus_dmamap_sync(sc->sc_dmat, rc->rc_dmap, 0, PAGE_SIZE,
+           BUS_DMASYNC_PREREAD);
+
+       rc->rc_req->msg_type = RNDIS_INITIALIZE_MSG;
+       rc->rc_req->msg_len = RNDIS_MESSAGE_SIZE(*req);
+       rc->rc_cmplen = RNDIS_MESSAGE_SIZE(*cmp);
+       rc->rc_id = atomic_inc_int_nv(&sc->sc_rndisrid);
+       req = (struct rndis_init_req *)&rc->rc_req->msg;
+       req->request_id = rc->rc_id;
+       req->major_version = RNDIS_MAJOR_VERSION;
+       req->minor_version = RNDIS_MINOR_VERSION;
+       req->max_xfer_size = 2048; /* XXX */
+
+       bus_dmamap_sync(sc->sc_dmat, rc->rc_dmap, 0, PAGE_SIZE,
+           BUS_DMASYNC_PREWRITE);
+
+       if ((rv = hvn_rndis_ctloutput(sc, rc, 500)) != 0) {
+               DPRINTF("%s: INITIALIZE_MSG failed, error %u\n",
+                   sc->sc_dev.dv_xname, rv);
+               hvn_free_cmd(sc, rc);
+               goto errout;
+       }
+       cmp = (struct rndis_init_comp *)&rc->rc_cmp.msg;
+       if (cmp->status != RNDIS_STATUS_SUCCESS) {
+               DPRINTF("%s: failed to init RNDIS, error %#x\n",
+                   sc->sc_dev.dv_xname, cmp->status);
+               hvn_free_cmd(sc, rc);
+               goto errout;
+       }
+       DPRINTF("%s: RNDIS %u.%u\n", sc->sc_dev.dv_xname,
+           cmp->major_version, cmp->minor_version);
+
+       hvn_free_cmd(sc, rc);
+
+       return (0);
+
+errout:
+       for (i = 0; i < HVN_RNDIS_CTLREQS; i++) {
+               rc = &sc->sc_cntl_msgs[i];
+               if (rc->rc_req == NULL)
+                       continue;
+               TAILQ_REMOVE(&sc->sc_cntl_fq, rc, rc_entry);
+               km_free(rc->rc_req, PAGE_SIZE, &kv_any, &kp_zero);
+               rc->rc_req = NULL;
+               bus_dmamap_destroy(sc->sc_dmat, rc->rc_dmap);
+       }
+       return (-1);
+}
+
+int
+hvn_rndis_ctloutput(struct hvn_softc *sc, struct rndis_cmd *rc, int timo)
+{
+       struct nvsp_send_rndis_pkt *msg;
+       struct hv_page_buffer pb[2];
+       int tries = 10;
+       int rv;
+
+       KASSERT(timo > 0);
+
+       rc->rc_nvsp.msg_type = nvsp_type_send_rndis_pkt;
+       msg = (struct nvsp_send_rndis_pkt *)&rc->rc_nvsp.msg;
+       msg->chan_type = 1; /* control */
+       msg->send_buf_section_idx = NVSP_INVALID_SECTION_INDEX;
+
+       pb[0].pfn = rc->rc_pfn;
+       pb[0].length = rc->rc_req->msg_len;
+       pb[0].offset = 0;
+
+       hvn_submit_cmd(sc, rc);
+
+       do {
+               rv = hv_channel_sendbuf(sc->sc_chan, pb, 1, &rc->rc_nvsp,
+                   sizeof(struct nvsp), rc->rc_id);
+               if (rv == EAGAIN)
+                       tsleep(rc, PRIBIO, "hvnsendbuf", timo / 10);
+               else if (rv) {
+                       DPRINTF("%s: RNDIS operation %d send error %d\n",
+                           sc->sc_dev.dv_xname, rc->rc_req->msg_type, rv);
+                       return (rv);
+               }
+       } while (rv != 0 && --tries > 0);
+
+       bus_dmamap_sync(sc->sc_dmat, rc->rc_dmap, 0, PAGE_SIZE,
+           BUS_DMASYNC_POSTWRITE);
+
+       mtx_enter(&rc->rc_mtx);
+       rv = msleep(rc, &rc->rc_mtx, PRIBIO, "rndisctl", timo);
+       mtx_leave(&rc->rc_mtx);
+
+       bus_dmamap_sync(sc->sc_dmat, rc->rc_dmap, 0, PAGE_SIZE,
+           BUS_DMASYNC_POSTREAD);
+
+#ifdef HVN_DEBUG
+       switch (rv) {
+       case EINTR:
+               rv = 0;
+               break;
+       case EWOULDBLOCK:
+               if (hvn_rollback_cmd(sc, rc)) {
+                       /* failed to rollback? go for one sleep cycle */
+                       tsleep(rc, PRIBIO, "rndisctl2", 1);
+                       rv = 0;
+                       break;
+               }
+               printf("%s: RNDIS opertaion %d timed out\n", sc->sc_dev.dv_xname,
+                   rc->rc_req->msg_type);
+       }
+#endif
+       return (rv);
+}
+
+void
+hvn_rndis_filter(struct hvn_softc *sc, uint64_t tid, void *arg)
+{
+       struct ifnet *ifp = &sc->sc_ac.ac_if;
+       struct mbuf_list ml = MBUF_LIST_INITIALIZER();
+       struct nvsp pkt;
+       struct hv_transfer_page_header *hdr = arg;
+       struct nvsp_send_rndis_pkt_comp *cmp;
+       uint32_t off, len, type, status = 0;
+       int i;
+
+       if (hdr->set_id != HVN_RX_BUFID) {
+               DPRINTF("%s: transfer page invalid set id %#x\n",
+                   sc->sc_dev.dv_xname, hdr->set_id);
+               return;
+       }
+       if (sc->sc_rx_ring == NULL) {
+               DPRINTF("%s: invalid rx ring\n", sc->sc_dev.dv_xname);
+               return;
+       }
+       for (i = 0; i < hdr->range_count; i++) {
+               off = hdr->range[i].byte_offset;
+               len = hdr->range[i].byte_count;
+
+               KASSERT(off + len <= sc->sc_rx_size);
+               KASSERT(len >= RNDIS_HEADER_SIZE + 4);
+
+               memcpy(&type, (caddr_t)sc->sc_rx_ring + off, sizeof(type));
+               switch (type) {
+               /* data message */
+               case RNDIS_PACKET_MSG:
+                       hvn_rndis_input(sc, (caddr_t)sc->sc_rx_ring +
+                           off, len, &ml);
+                       break;
+               /* completion messages */
+               case RNDIS_INITIALIZE_CMPLT:
+               case RNDIS_QUERY_CMPLT:
+               case RNDIS_SET_CMPLT:
+               case RNDIS_RESET_CMPLT:
+               case RNDIS_KEEPALIVE_CMPLT:
+                       hvn_rndis_complete(sc, (caddr_t)sc->sc_rx_ring +
+                           off, len);
+                       break;
+               /* notification message */
+               case RNDIS_INDICATE_STATUS_MSG:
+                       hvn_rndis_status(sc, (caddr_t)sc->sc_rx_ring +
+                           off, len);
+                       break;
+               default:
+                       printf("%s: unhandled RNDIS message type %u\n",
+                           sc->sc_dev.dv_xname, type);
+               }
+       }
+       memset(&pkt, 0, sizeof(pkt));
+       pkt.msg_type = nvsp_type_send_rndis_pkt_comp;
+       cmp = (struct nvsp_send_rndis_pkt_comp *)&pkt.msg;
+       cmp->status = status;   /* XXX */
+       hvn_nvsp_ack(sc, &pkt, tid);
+
+       if (MBUF_LIST_FIRST(&ml))
+               if_input(ifp, &ml);
+}
+
+static inline struct mbuf *
+hvn_devget(struct hvn_softc *sc, caddr_t buf, uint32_t len)
+{
+       struct mbuf *m;
+
+       if (len + ETHER_ALIGN <= MHLEN)
+               MGETHDR(m, M_NOWAIT, MT_DATA);
+       else
+               m = MCLGETI(NULL, M_NOWAIT, NULL, len + ETHER_ALIGN);
+       if (m == NULL)
+               return (NULL);
+       m->m_len = m->m_pkthdr.len = len;
+       m_adj(m, ETHER_ALIGN);
+
+       if (m_copyback(m, 0, len, buf, M_NOWAIT)) {
+               m_freem(m);
+               return (NULL);
+       }
+
+       return (m);
+}
+
+void
+hvn_rndis_input(struct hvn_softc *sc, caddr_t buf, uint32_t len,
+    struct mbuf_list *ml)
+{
+       struct ifnet *ifp = &sc->sc_ac.ac_if;
+       struct rndis_pkt *pkt;
+       struct rndis_pkt_info *ppi;
+       struct rndis_tcp_ip_csum_info *csum;
+       struct ndis_8021q_info *vlan;
+       struct mbuf *m;
+
+       if (!(ifp->if_flags & IFF_RUNNING))
+               return;
+
+       if (len < RNDIS_HEADER_SIZE + sizeof(*pkt)) {
+               printf("%s: data packet too short: %u\n",
+                   sc->sc_dev.dv_xname, len);
+               return;
+       }
+
+       pkt = (struct rndis_pkt *)(buf + RNDIS_HEADER_SIZE);
+
+       if (pkt->data_offset + pkt->data_length > len) {
+               printf("%s: data packet out of bounds: %u@%u\n",
+                   sc->sc_dev.dv_xname, pkt->data_offset, pkt->data_length);
+               return;
+       }
+
+       if ((m = hvn_devget(sc, buf + RNDIS_HEADER_SIZE + pkt->data_offset,
+           pkt->data_length)) == NULL) {
+               ifp->if_ierrors++;
+               return;
+       }
+
+       while (pkt->pkt_info_length > 0) {
+               if (pkt->pkt_info_offset + pkt->pkt_info_length > len) {
+                       printf("%s: PPI out of bounds: %u@%u\n",
+                           sc->sc_dev.dv_xname, pkt->pkt_info_length,
+                           pkt->pkt_info_offset);
+                       break;
+               }
+               ppi = (struct rndis_pkt_info *)((caddr_t)pkt +
+                   pkt->pkt_info_offset);
+               if (ppi->size > pkt->pkt_info_length) {
+                       printf("%s: invalid PPI size: %u/%u\n",
+                           sc->sc_dev.dv_xname, ppi->size,
+                           pkt->pkt_info_length);
+                       break;
+               }
+               switch (ppi->type) {
+               case tcpip_chksum_info:
+                       csum = (struct rndis_tcp_ip_csum_info *)
+                           ((caddr_t)ppi + ppi->size);
+                       if (csum->recv.ip_csum_succeeded)
+                               m->m_pkthdr.csum_flags |= M_IPV4_CSUM_IN_OK;
+                       if (csum->recv.tcp_csum_succeeded)
+                               m->m_pkthdr.csum_flags |= M_TCP_CSUM_IN_OK;
+                       if (csum->recv.udp_csum_succeeded)
+                               m->m_pkthdr.csum_flags |= M_UDP_CSUM_IN_OK;
+                       break;
+               case ieee_8021q_info:
+                       vlan = (struct ndis_8021q_info *)
+                           ((caddr_t)ppi + ppi->size);
+#if NVLAN > 0
+                       m->m_pkthdr.ether_vtag = vlan->vlan_id;
+                       m->m_flags |= M_VLANTAG;
+#endif
+                       break;
+               default:
+                       DPRINTF("%s: unhandled PPI %u\n", sc->sc_dev.dv_xname,
+                           ppi->type);
+               }
+               pkt->pkt_info_length -= ppi->size;
+       }
+
+       ml_enqueue(ml, m);
+}
+
+void
+hvn_rndis_complete(struct hvn_softc *sc, caddr_t buf, uint32_t len)
+{
+       struct rndis_cmd *rc;
+       uint32_t id;
+
+       memcpy(&id, buf + RNDIS_HEADER_SIZE, sizeof(id));
+       if ((rc = hvn_complete_cmd(sc, id)) != NULL) {
+               if (len < rc->rc_cmplen)
+                       printf("%s: RNDIS response %u too short: %u\n",
+                           sc->sc_dev.dv_xname, id, len);
+               else
+                       memcpy(&rc->rc_cmp, buf, rc->rc_cmplen);
+               if (len > rc->rc_cmplen &&
+                   len - rc->rc_cmplen > HVN_RNDIS_CMPBUFSZ)
+                       printf("%s: RNDIS response %u too large: %u\n",
+                           sc->sc_dev.dv_xname, id, len);
+               else if (len > rc->rc_cmplen)
+                       memcpy(&rc->rc_cmpbuf, buf + rc->rc_cmplen,
+                           len - rc->rc_cmplen);
+               wakeup_one(rc);
+       } else
+               DPRINTF("%s: failed to complete RNDIS request id %u\n",
+                   sc->sc_dev.dv_xname, id);
+}
+
+void
+hvn_rndis_status(struct hvn_softc *sc, caddr_t buf, uint32_t len)
+{
+       uint32_t sta;
+
+       memcpy(&sta, buf + RNDIS_HEADER_SIZE, sizeof(sta));
+       switch (sta) {
+       case RNDIS_STATUS_MEDIA_CONNECT:
+               sc->sc_link_state = LINK_STATE_UP;
+               break;
+       case RNDIS_STATUS_MEDIA_DISCONNECT:
+               sc->sc_link_state = LINK_STATE_DOWN;
+               break;
+       /* Ignore these */
+       case RNDIS_STATUS_OFFLOAD_CURRENT_CONFIG:
+               break;
+       default:
+               DPRINTF("%s: unhandled status %#x\n", sc->sc_dev.dv_xname, sta);
+               return;
+       }
+       KERNEL_LOCK();
+       hvn_link_status(sc);
+       KERNEL_UNLOCK();
+}
+
+int
+hvn_rndis_query(struct hvn_softc *sc, uint32_t oid, void *res, size_t *length)
+{
+       struct rndis_cmd *rc;
+       struct rndis_query_req *req;
+       struct rndis_query_comp *cmp;
+       size_t olength = *length;
+       int rv;
+
+       rc = hvn_alloc_cmd(sc);
+
+       bus_dmamap_sync(sc->sc_dmat, rc->rc_dmap, 0, PAGE_SIZE,
+           BUS_DMASYNC_PREREAD);
+
+       rc->rc_req->msg_type = RNDIS_QUERY_MSG;
+       rc->rc_req->msg_len = RNDIS_MESSAGE_SIZE(*req);
+       rc->rc_cmplen = RNDIS_MESSAGE_SIZE(*cmp);
+       rc->rc_id = atomic_inc_int_nv(&sc->sc_rndisrid);
+       req = (struct rndis_query_req *)&rc->rc_req->msg;
+       req->request_id = rc->rc_id;
+       req->oid = oid;
+       req->info_buffer_offset = sizeof(*req);
+
+       bus_dmamap_sync(sc->sc_dmat, rc->rc_dmap, 0, PAGE_SIZE,
+           BUS_DMASYNC_PREWRITE);
+
+       if ((rv = hvn_rndis_ctloutput(sc, rc, 500)) != 0) {
+               DPRINTF("%s: QUERY_MSG failed, error %d\n",
+                   sc->sc_dev.dv_xname, rv);
+               hvn_free_cmd(sc, rc);
+               return (rv);
+       }
+
+       cmp = (struct rndis_query_comp *)&rc->rc_cmp.msg;
+       switch (cmp->status) {
+       case RNDIS_STATUS_SUCCESS:
+               if (cmp->info_buffer_length > olength) {
+                       rv = EINVAL;
+                       break;
+               }
+               memcpy(res, rc->rc_cmpbuf, cmp->info_buffer_length);
+               *length = cmp->info_buffer_length;
+               break;
+       default:
+               *length = 0;
+               rv = EIO;
+       }
+
+       hvn_free_cmd(sc, rc);
+
+       return (rv);
+}
+
+int
+hvn_rndis_set(struct hvn_softc *sc, uint32_t oid, void *data, size_t length)
+{
+       struct rndis_cmd *rc;
+       struct rndis_set_req *req;
+       struct rndis_set_comp *cmp;
+       int rv;
+
+       rc = hvn_alloc_cmd(sc);
+
+       bus_dmamap_sync(sc->sc_dmat, rc->rc_dmap, 0, PAGE_SIZE,
+           BUS_DMASYNC_PREREAD);
+
+       rc->rc_req->msg_type = RNDIS_SET_MSG;
+       rc->rc_req->msg_len = RNDIS_MESSAGE_SIZE(*req) + length;
+       rc->rc_cmplen = RNDIS_MESSAGE_SIZE(*cmp);
+       rc->rc_id = atomic_inc_int_nv(&sc->sc_rndisrid);
+       req = (struct rndis_set_req *)&rc->rc_req->msg;
+       memset(req, 0, sizeof(*req));
+       req->request_id = rc->rc_id;
+       req->oid = oid;
+       req->info_buffer_offset = sizeof(*req);
+
+       if (length > 0) {
+               KASSERT(sizeof(*req) + length < sizeof(struct rndis));
+               req->info_buffer_length = length;
+               memcpy((caddr_t)(req + 1), data, length);
+       }
+
+       bus_dmamap_sync(sc->sc_dmat, rc->rc_dmap, 0, PAGE_SIZE,
+           BUS_DMASYNC_PREWRITE);
+
+       if ((rv = hvn_rndis_ctloutput(sc, rc, 500)) != 0) {
+               DPRINTF("%s: SET_MSG failed, error %u\n",
+                   sc->sc_dev.dv_xname, rv);
+               hvn_free_cmd(sc, rc);
+               return (rv);
+       }
+
+       cmp = (struct rndis_set_comp *)&rc->rc_cmp.msg;
+       if (cmp->status != RNDIS_STATUS_SUCCESS)
+               rv = EIO;
+
+       hvn_free_cmd(sc, rc);
+
+       return (rv);
+}
+
+int
+hvn_rndis_open(struct hvn_softc *sc)
+{
+       uint32_t filter;
+       int rv;
+
+       if (sc->sc_promisc)
+               filter = NDIS_PACKET_TYPE_PROMISCUOUS;
+       else
+               filter = NDIS_PACKET_TYPE_BROADCAST |
+                   NDIS_PACKET_TYPE_ALL_MULTICAST |
+                   NDIS_PACKET_TYPE_DIRECTED;
+
+       rv = hvn_rndis_set(sc, RNDIS_OID_GEN_CURRENT_PACKET_FILTER,
+           &filter, sizeof(filter));
+       if (rv)
+               DPRINTF("%s: failed to set RNDIS filter to %#x\n",
+                   sc->sc_dev.dv_xname, filter);
+       return (rv);
+}
+
+int
+hvn_rndis_close(struct hvn_softc *sc)
+{
+       uint32_t filter = 0;
+       int rv;
+
+       rv = hvn_rndis_set(sc, RNDIS_OID_GEN_CURRENT_PACKET_FILTER,
+           &filter, sizeof(filter));
+       if (rv)
+               DPRINTF("%s: failed to clear RNDIS filter\n",
+                   sc->sc_dev.dv_xname);
+       return (rv);
+}
+
+void
+hvn_rndis_detach(struct hvn_softc *sc)
+{
+       struct rndis_cmd *rc;
+       struct rndis_halt_req *req;
+       int rv;
+
+       rc = hvn_alloc_cmd(sc);
+
+       bus_dmamap_sync(sc->sc_dmat, rc->rc_dmap, 0, PAGE_SIZE,
+           BUS_DMASYNC_PREREAD);
+
+       rc->rc_req->msg_type = RNDIS_HALT_MSG;
+       rc->rc_req->msg_len = RNDIS_MESSAGE_SIZE(*req);
+       rc->rc_id = atomic_inc_int_nv(&sc->sc_rndisrid);
+       req = (struct rndis_halt_req *)&rc->rc_req->msg;
+       req->request_id = rc->rc_id;
+
+       bus_dmamap_sync(sc->sc_dmat, rc->rc_dmap, 0, PAGE_SIZE,
+           BUS_DMASYNC_PREWRITE);
+
+       if ((rv = hvn_rndis_ctloutput(sc, rc, 500)) != 0)
+               DPRINTF("%s: HALT_MSG failed, error %u\n",
+                   sc->sc_dev.dv_xname, rv);
+
+       hvn_free_cmd(sc, rc);
+}
diff --git a/sys/dev/pv/if_hvnreg.h b/sys/dev/pv/if_hvnreg.h
new file mode 100644 (file)
index 0000000..af57d44
--- /dev/null
@@ -0,0 +1,830 @@
+/*-
+ * Copyright (c) 2009-2012 Microsoft Corp.
+ * Copyright (c) 2010-2012 Citrix Inc.
+ * Copyright (c) 2012 NetApp Inc.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice unmodified, this list of conditions, and the following
+ *    disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifndef _IF_HVNREG_H_
+#define _IF_HVNREG_H_
+
+#define NVSP_PROTOCOL_VERSION_1                        0x00002
+#define NVSP_PROTOCOL_VERSION_2                        0x30002
+#define NVSP_PROTOCOL_VERSION_4                        0x40000
+#define NVSP_PROTOCOL_VERSION_5                        0x50000
+
+#define VERSION_4_OFFLOAD_SIZE                  22
+
+#define NVSP_OPERATIONAL_STATUS_OK             0x00000000
+#define NVSP_OPERATIONAL_STATUS_DEGRADED       0x00000001
+#define NVSP_OPERATIONAL_STATUS_NONRECOVERABLE 0x00000002
+#define NVSP_OPERATIONAL_STATUS_NO_CONTACT     0x00000003
+#define NVSP_OPERATIONAL_STATUS_LOST_COMM      0x00000004
+
+/*
+ * Maximun number of transfer pages (packets) the VSP will use on a receive
+ */
+#define NVSP_MAX_PACKETS_PER_RECEIVE           375
+
+enum nvsp_type {
+       nvsp_type_none = 0,
+
+       /*
+        * Init Messages
+        */
+       nvsp_type_init = 1,
+       nvsp_type_init_comp = 2,
+
+       nvsp_type_version_start = 100,
+
+       /*
+        * Version 1 Messages
+        */
+       nvsp_type_send_ndis_vers = nvsp_type_version_start,
+
+       nvsp_type_send_rx_buf,
+       nvsp_type_send_rx_buf_comp,
+       nvsp_type_revoke_rx_buf,
+
+       nvsp_type_send_tx_buf,
+       nvsp_type_send_tx_buf_comp,
+       nvsp_type_revoke_tx_buf,
+
+       nvsp_type_send_rndis_pkt,
+       nvsp_type_send_rndis_pkt_comp,
+
+       /*
+        * Version 2 Messages
+        */
+       nvsp_type_send_chimney_delegated_buf,
+       nvsp_type_send_chimney_delegated_buf_comp,
+       nvsp_type_revoke_chimney_delegated_buf,
+
+       nvsp_type_resume_chimney_rx_indication,
+
+       nvsp_type_terminate_chimney,
+       nvsp_type_terminate_chimney_comp,
+
+       nvsp_type_indicate_chimney_event,
+
+       nvsp_type_send_chimney_packet,
+       nvsp_type_send_chimney_packet_comp,
+
+       nvsp_type_post_chimney_rx_req,
+       nvsp_type_post_chimney_rx_req_comp,
+
+       nvsp_type_alloc_rx_buf,
+       nvsp_type_alloc_rx_buf_comp,
+
+       nvsp_type_free_rx_buf,
+
+       nvsp_type_send_vmq_rndis_pkt,
+       nvsp_type_send_vmq_rndis_pkt_comp,
+
+       nvsp_type_send_ndis_config,
+
+       nvsp_type_alloc_chimney_handle,
+       nvsp_type_alloc_chimney_handle_comp,
+
+       /*
+        * Version 4 Messages
+        */
+       nvsp_type_send_vf_association,
+       nvsp_type_switch_data_path,
+       nvsp_type_uplink_connect_state_deprecated,
+
+       /*
+        * Version 5 Messages
+        */
+       nvsp_type_oid_query_ex,
+       nvsp_type_oid_query_ex_comp,
+       nvsp_type_subchannel,
+       nvsp_type_send_indirection_table,
+};
+
+enum nvsp_status {
+       nvsp_status_none = 0,
+       nvsp_status_success,
+       nvsp_status_failure,
+       /* Deprecated */
+       nvsp_status_prot_vers_range_too_new,
+       /* Deprecated */
+       nvsp_status_prot_vers_range_too_old,
+       nvsp_status_invalid_rndis_pkt,
+       nvsp_status_busy,
+       nvsp_status_max,
+};
+
+/*
+ * Init Messages
+ */
+
+/*
+ * This message is used by the VSC to initialize the channel
+ * after the channels has been opened. This message should
+ * never include anything other then versioning (i.e. this
+ * message will be the same for ever).
+ *
+ * Forever is a long time.  The values have been redefined
+ * in Win7 to indicate major and minor protocol version
+ * number.
+ */
+struct nvsp_init {
+       uint32_t                                protocol_version;
+       uint32_t                                protocol_version_2;
+} __packed;
+
+/*
+ * This message is used by the VSP to complete the initialization
+ * of the channel. This message should never include anything other
+ * then versioning (i.e. this message will be the same forever).
+ */
+struct nvsp_init_comp {
+       /* Deprecated */
+       uint32_t                                negotiated_prot_vers;
+       uint32_t                                max_mdl_chain_len;
+       uint32_t                                status;
+} __packed;
+
+/*
+ * Version 1 Messages
+ */
+
+/*
+ * This message is used by the VSC to send the NDIS version
+ * to the VSP. The VSP can use this information when handling
+ * OIDs sent by the VSC.
+ */
+struct nvsp_send_ndis_version {
+       uint32_t                                ndis_major_vers;
+       /* Deprecated */
+       uint32_t                                ndis_minor_vers;
+} __packed;
+
+/*
+ * This message is used by the VSC to send a receive buffer
+ * to the VSP. The VSP can then use the receive buffer to
+ * send data to the VSC.
+ */
+struct nvsp_send_rx_buf {
+       uint32_t                                gpadl_handle;
+       uint16_t                                id;
+} __packed;
+
+struct nvsp_rx_buf_section {
+       uint32_t                                offset;
+       uint32_t                                sub_allocation_size;
+       uint32_t                                num_sub_allocations;
+       uint32_t                                end_offset;
+} __packed;
+
+/*
+ * This message is used by the VSP to acknowledge a receive
+ * buffer send by the VSC.  This message must be sent by the
+ * VSP before the VSP uses the receive buffer.
+ */
+struct nvsp_send_rx_buf_comp {
+       uint32_t                                status;
+       uint32_t                                num_sections;
+
+       /*
+        * The receive buffer is split into two parts, a large
+        * suballocation section and a small suballocation
+        * section. These sections are then suballocated by a
+        * certain size.
+        *
+        * For example, the following break up of the receive
+        * buffer has 6 large suballocations and 10 small
+        * suballocations.
+        *
+        * |            Large Section          |  |   Small Section   |
+        * ------------------------------------------------------------
+        * |     |     |     |     |     |     |  | | | | | | | | | | |
+        * |                                      |
+        * LargeOffset                            SmallOffset
+        */
+       struct nvsp_rx_buf_section              sections[1];
+} __packed;
+
+/*
+ * This message is sent by the VSC to revoke the receive buffer.
+ * After the VSP completes this transaction, the VSP should never
+ * use the receive buffer again.
+ */
+struct nvsp_revoke_rx_buf {
+       uint16_t                                id;
+} __packed;
+
+/*
+ * This message is used by the VSC to send a send buffer
+ * to the VSP. The VSC can then use the send buffer to
+ * send data to the VSP.
+ */
+struct nvsp_send_tx_buf {
+       uint32_t                                gpadl_handle;
+       uint16_t                                id;
+} __packed;
+
+/*
+ * This message is used by the VSP to acknowledge a send
+ * buffer sent by the VSC. This message must be sent by the
+ * VSP before the VSP uses the sent buffer.
+ */
+struct nvsp_send_tx_buf_comp {
+       uint32_t                                status;
+
+       /*
+        * The VSC gets to choose the size of the send buffer and
+        * the VSP gets to choose the sections size of the buffer.
+        * This was done to enable dynamic reconfigurations when
+        * the cost of GPA-direct buffers decreases.
+        */
+       uint32_t                                section_size;
+} __packed;
+
+/*
+ * This message is sent by the VSC to revoke the send buffer.
+ * After the VSP completes this transaction, the vsp should never
+ * use the send buffer again.
+ */
+struct nvsp_revoke_tx_buf {
+       uint16_t                                id;
+} __packed;
+
+/*
+ * This message is used by both the VSP and the VSC to send
+ * an RNDIS message to the opposite channel endpoint.
+ */
+struct nvsp_send_rndis_pkt {
+       /*
+        * This field is specified by RNIDS.  They assume there's
+        * two different channels of communication. However,
+        * the Network VSP only has one.  Therefore, the channel
+        * travels with the RNDIS packet.
+        */
+       uint32_t                                chan_type;
+
+       /*
+        * This field is used to send part or all of the data
+        * through a send buffer. This values specifies an
+        * index into the send buffer.  If the index is
+        * 0xFFFFFFFF, then the send buffer is not being used
+        * and all of the data was sent through other VMBus
+        * mechanisms.
+        */
+       uint32_t                                send_buf_section_idx;
+       uint32_t                                send_buf_section_size;
+} __packed;
+
+/*
+ * This message is used by both the VSP and the VSC to complete
+ * a RNDIS message to the opposite channel endpoint.  At this
+ * point, the initiator of this message cannot use any resources
+ * associated with the original RNDIS packet.
+ */
+struct nvsp_send_rndis_pkt_comp {
+       uint32_t                                status;
+} __packed;
+
+
+/*
+ * Version 2 Messages
+ */
+
+/*
+ * This message is used by the VSC to send the NDIS version
+ * to the VSP. The VSP can use this information when handling
+ * OIDs sent by the VSC.
+ */
+struct nvsp_netvsc_capabilities {
+       union {
+               uint64_t                        as_uint64;
+               struct {
+                       uint64_t                vmq           : 1;
+                       uint64_t                chimney       : 1;
+                       uint64_t                sriov         : 1;
+                       uint64_t                ieee8021q     : 1;
+                       uint64_t                correlationid : 1;
+                       uint64_t                teaming       : 1;
+               } ;
+       };
+} __packed;
+
+struct nvsp_send_ndis_config {
+       uint32_t                                mtu;
+       uint32_t                                reserved;
+       struct nvsp_netvsc_capabilities
+                                               capabilities;
+} __packed;
+
+/*
+ * NvspMessage2TypeSendChimneyDelegatedBuffer
+ */
+struct nvsp_send_chimney_buf {
+       /*
+        * On WIN7 beta, delegated_obj_max_size is defined as a uint32_t
+        * Since WIN7 RC, it was split into two uint16_t.  To have the same
+        * struct layout, delegated_obj_max_size shall be the first field.
+        */
+       uint16_t                                delegated_obj_max_size;
+
+       /*
+        * The revision # of chimney protocol used between NVSC and NVSP.
+        *
+        * This revision is NOT related to the chimney revision between
+        * NDIS protocol and miniport drivers.
+        */
+       uint16_t                                revision;
+
+       uint32_t                                gpadl_handle;
+} __packed;
+
+
+/* Unsupported chimney revision 0 (only present in WIN7 beta) */
+#define NVSP_CHIMNEY_REVISION_0                        0
+
+/* WIN7 Beta Chimney QFE */
+#define NVSP_CHIMNEY_REVISION_1                        1
+
+/* The chimney revision since WIN7 RC */
+#define NVSP_CHIMNEY_REVISION_2                        2
+
+
+/*
+ * NvspMessage2TypeSendChimneyDelegatedBufferComplete
+ */
+struct nvsp_send_chimney_buf_comp {
+       uint32_t                                status;
+
+       /*
+        * Maximum number outstanding sends and pre-posted receives.
+        *
+        * NVSC should not post more than SendQuota/ReceiveQuota packets.
+        * Otherwise, it can block the non-chimney path for an indefinite
+        * amount of time.
+        * (since chimney sends/receives are affected by the remote peer).
+        *
+        * Note: NVSP enforces the quota restrictions on a per-VMBCHANNEL
+        * basis.  It doesn't enforce the restriction separately for chimney
+        * send/receive.  If NVSC doesn't voluntarily enforce "SendQuota",
+        * it may kill its own network connectivity.
+        */
+       uint32_t                                tx_quota;
+       uint32_t                                rx_quota;
+} __packed;
+
+/*
+ * NvspMessage2TypeRevokeChimneyDelegatedBuffer
+ */
+struct nvsp_revoke_chimney_buf {
+       uint32_t                                gpadl_handle;
+} __packed;
+
+
+#define NVSP_CHIMNEY_OBJECT_TYPE_NEIGHBOR      0
+#define NVSP_CHIMNEY_OBJECT_TYPE_PATH4         1
+#define NVSP_CHIMNEY_OBJECT_TYPE_PATH6         2
+#define NVSP_CHIMNEY_OBJECT_TYPE_TCP           3
+
+/*
+ * NvspMessage2TypeAllocateChimneyHandle
+ */
+struct nvsp_alloc_chimney_handle {
+       uint64_t                                vsc_context;
+       uint32_t                                object_type;
+} __packed;
+
+/*
+ * NvspMessage2TypeAllocateChimneyHandleComplete
+ */
+struct nvsp_alloc_chimney_handle_comp {
+       uint32_t                                vsp_handle;
+} __packed;
+
+
+/*
+ * NvspMessage2TypeResumeChimneyRXIndication
+ */
+struct nvsp_resume_chimney_rx_indication {
+       /*
+        * Handle identifying the offloaded connection
+        */
+       uint32_t                                vsp_tcp_handle;
+} __packed;
+
+/*
+ * NvspMessage2TypeTerminateChimney
+ */
+struct nvsp_terminate_chimney {
+       /*
+       * Handle identifying the offloaded object
+       */
+       uint32_t                                vsp_handle;
+
+       /*
+        * Terminate Offload Flags
+        *     Bit 0:
+        *         When set to 0, terminate the offload at the destination NIC
+        *     Bit 1-31:  Reserved, shall be zero
+        */
+       uint32_t                                flags;
+
+       union {
+               /*
+                * This field is valid only when bit 0 of flags is clear.
+                * It specifies the index into the premapped delegated
+                * object buffer.  The buffer was sent through the
+                * NvspMessage2TypeSendChimneyDelegatedBuffer
+                * message at initialization time.
+                *
+                * NVSP will write the delegated state into the delegated
+                * buffer upon upload completion.
+                */
+               uint32_t                        index;
+
+               /*
+                * This field is valid only when bit 0 of flags is set.
+                *
+                * The seqence number of the most recently accepted RX
+                * indication when VSC sets its TCP context into
+                * "terminating" state.
+                *
+                * This allows NVSP to determines if there are any in-flight
+                * RX indications for which the acceptance state is still
+                * undefined.
+                */
+               uint64_t                        last_accepted_rx_seq_no;
+       };
+} __packed;
+
+/*
+ * NvspMessage2TypeTerminateChimneyComplete
+ */
+struct nvsp_terminate_chimney_comp {
+       uint64_t                                vsc_context;
+       uint32_t                                flags;
+} __packed;
+
+/*
+ * NvspMessage2TypeIndicateChimneyEvent
+ */
+struct nvsp_indicate_chimney_event {
+       /*
+        * When VscTcpContext is 0, event_type is an NDIS_STATUS;
+        * Otherwise, EventType is an TCP connection event (defined
+        * in NdisTcpOffloadEventHandler chimney DDK document).
+        */
+       uint32_t                                event_type;
+
+       /*
+        * When VscTcpContext is 0, EventType is an NDIS_STATUS;
+        * Otherwise, EventType is an TCP connection event specific
+        * information (defined in NdisTcpOffloadEventHandler
+        * chimney DDK document).
+        */
+       uint32_t                                event_specific_info;
+
+       /*
+        * If not 0, the event is per-TCP connection event.  This field
+        * contains the VSC's TCP context. If 0, the event indication is
+        * global.
+        */
+       uint64_t                                vsc_tcp_context;
+} __packed;
+
+
+#define NVSP_INVALID_OOB_INDEX                 0xffffu
+#define NVSP_INVALID_SECTION_INDEX             0xffffffff
+
+/*
+ * NvspMessage2TypeSendChimneyPacket
+ */
+struct nvsp_send_chimney_pkt {
+       /*
+        * Identify the TCP connection for which this chimney send is
+        */
+       uint32_t                                vsp_tcp_handle;
+
+       /*
+        * This field is used to send part or all of the data
+        * through a send buffer. This values specifies an
+        * index into the send buffer. If the index is
+        * 0xFFFF, then the send buffer is not being used
+        * and all of the data was sent through other VMBus
+        * mechanisms.
+        */
+       uint16_t                                send_buf_section_index;
+       uint16_t                                send_buf_section_size;
+
+       /*
+        * OOB Data Index
+        * This an index to the OOB data buffer. If the index is 0xFFFFFFFF,
+        * then there is no OOB data.
+        *
+        * This field shall be always 0xFFFFFFFF for now. It is reserved for
+        * the future.
+        */
+       uint16_t                                oob_data_index;
+
+       /*
+        * DisconnectFlags = 0
+        * Normal chimney send. See MiniportTcpOffloadSend for details.
+        *
+        * DisconnectFlags = TCP_DISCONNECT_GRACEFUL_CLOSE (0x01)
+        * Graceful disconnect. See MiniportTcpOffloadDisconnect for details.
+        *
+        * DisconnectFlags = TCP_DISCONNECT_ABORTIVE_CLOSE (0x02)
+        * Abortive disconnect. See MiniportTcpOffloadDisconnect for details.
+        */
+       uint16_t                                disconnect_flags;
+
+       uint32_t                                seq_no;
+} __packed;
+
+/*
+ * NvspMessage2TypeSendChimneyPacketComplete
+ */
+struct nvsp_send_chimney_pkt_comp {
+       /*
+        * The NDIS_STATUS for the chimney send
+        */
+       uint32_t                                status;
+
+       /*
+        * Number of bytes that have been sent to the peer (and ACKed by the peer).
+        */
+       uint32_t                                bytes_transferred;
+} __packed;
+
+/*
+ * NvspMessage2TypePostChimneyRecvRequest
+ */
+struct nvsp_post_chimney_rx_req {
+       /*
+        * Identify the TCP connection which this chimney receive request
+        * is for.
+        */
+       uint32_t                                vsp_tcp_handle;
+
+       /*
+        * OOB Data Index
+        * This an index to the OOB data buffer. If the index is 0xFFFFFFFF,
+        * then there is no OOB data.
+        *
+        * This field shall be always 0xFFFFFFFF for now. It is reserved for
+        * the future.
+        */
+       uint32_t                                oob_data_index;
+
+       /*
+        * Bit 0
+        *      When it is set, this is a "no-push" receive.
+        *      When it is clear, this is a "push" receive.
+        *
+        * Bit 1-15:  Reserved and shall be zero
+        */
+       uint16_t                                flags;
+
+       /*
+        * For debugging and diagnoses purpose.
+        * The SeqNo is per TCP connection and starts from 0.
+        */
+       uint32_t                                seq_no;
+} __packed;
+
+/*
+ * NvspMessage2TypePostChimneyRecvRequestComplete
+ */
+struct nvsp_post_chimney_rx_req_comp {
+       /*
+        * The NDIS_STATUS for the chimney send
+        */
+       uint32_t                                status;
+
+       /*
+        * Number of bytes that have been sent to the peer (and ACKed by
+        * the peer).
+        */
+       uint32_t                                bytes_xferred;
+} __packed;
+
+/*
+ * NvspMessage2TypeAllocateReceiveBuffer
+ */
+struct nvsp_alloc_rx_buf {
+       /*
+        * Allocation ID to match the allocation request and response
+        */
+       uint32_t                                allocation_id;
+
+       /*
+        * Length of the VM shared memory receive buffer that needs to
+        * be allocated
+        */
+       uint32_t                                length;
+} __packed;
+
+/*
+ * NvspMessage2TypeAllocateReceiveBufferComplete
+ */
+struct nvsp_alloc_rx_buf_comp {
+       /*
+        * The NDIS_STATUS code for buffer allocation
+        */
+       uint32_t                                status;
+
+       /*
+        * Allocation ID from NVSP_MESSAGE_ALLOCATE_RECEIVE_BUFFER
+        */
+       uint32_t                                allocation_id;
+
+       /*
+        * GPADL handle for the allocated receive buffer
+        */
+       uint32_t                                gpadl_handle;
+
+       /*
+        * Receive buffer ID that is further used in
+        * NvspMessage2SendVmqRndisPacket
+        */
+       uint64_t                                rx_buf_id;
+} __packed;
+
+/*
+ * NvspMessage2TypeFreeReceiveBuffer
+ */
+struct nvsp_free_rx_buf {
+       /*
+        * Receive buffer ID previous returned in
+        * NvspMessage2TypeAllocateReceiveBufferComplete message
+        */
+       uint64_t                                rx_buf_id;
+} __packed;
+
+/*
+ * This structure is used in defining the buffers in
+ * NVSP_MESSAGE_SEND_VMQ_RNDIS_PACKET structure
+ */
+struct nvsp_xfer_page_range {
+       /*
+        * Specifies the ID of the receive buffer that has the buffer. This
+        * ID can be the general receive buffer ID specified in
+        * NvspMessage1TypeSendReceiveBuffer or it can be the shared memory
+        * receive buffer ID allocated by the VSC and specified in
+        * NvspMessage2TypeAllocateReceiveBufferComplete message
+        */
+       uint64_t                                xfer_page_set_id;
+
+       /*
+        * Number of bytes
+        */
+       uint32_t                                byte_count;
+
+       /*
+        * Offset in bytes from the beginning of the buffer
+        */
+       uint32_t                                byte_offset;
+} __packed;
+
+/*
+ * NvspMessage2SendVmqRndisPacket
+ */
+struct nvsp_send_vmq_rndis_pkt {
+       /*
+        * This field is specified by RNIDS. They assume there's
+        * two different channels of communication. However,
+        * the Network VSP only has one. Therefore, the channel
+        * travels with the RNDIS packet. It must be RMC_DATA
+        */
+       uint32_t                                channel_type;
+
+       /*
+        * Only the Range element corresponding to the RNDIS header of
+        * the first RNDIS message in the multiple RNDIS messages sent
+        * in one NVSP message.  Information about the data portions as well
+        * as the subsequent RNDIS messages in the same NVSP message are
+        * embedded in the RNDIS header itself
+        */
+       struct nvsp_xfer_page_range             range;
+} __packed;
+
+/*
+ * This message is used by the VSC to complete
+ * a RNDIS VMQ message to the VSP.  At this point,
+ * the initiator of this message can use any resources
+ * associated with the original RNDIS VMQ packet.
+ */
+struct nvsp_send_vmq_rndis_pkt_comp {
+       uint32_t                                status;
+} __packed;
+
+/*
+ * Version 5 messages
+ */
+enum nvsp_subchannel_operation {
+       NVSP_SUBCHANNEL_NONE = 0,
+       NVSP_SUBCHANNE_ALLOCATE,
+       NVSP_SUBCHANNE_MAX
+};
+
+struct nvsp_subchannel_req {
+       uint32_t                                op;
+       uint32_t                                num_subchannels;
+} __packed;
+
+struct nvsp_subchannel_comp {
+       uint32_t                                status;
+       /* Actual number of subchannels allocated */
+       uint32_t                                num_subchannels;
+} __packed;
+
+struct nvsp_send_indirect_table {
+       /* The number of entries in the send indirection table */
+       uint32_t                                count;
+       /*
+        * The offset of the send indireciton table from top of
+        * this struct. The send indirection table tells which channel
+        * to put the send traffic on. Each entry is a channel number.
+        */
+       uint32_t                                offset;
+} __packed;
+
+/*
+ * All messages
+ */
+struct nvsp {
+       uint32_t                                msg_type;
+
+       union {
+       struct nvsp_init                        init;
+       struct nvsp_init_comp                   init_compl;
+
+       /* Version 1 */
+       struct nvsp_send_ndis_version           send_ndis_vers;
+
+       struct nvsp_send_rx_buf                 send_rx_buf;
+       struct nvsp_send_rx_buf_comp            send_rx_buf_comp;
+       struct nvsp_revoke_rx_buf               revoke_rx_buf;
+
+       struct nvsp_send_tx_buf                 send_tx_buf;
+       struct nvsp_send_tx_buf_comp            send_tx_buf_comp;
+       struct nvsp_revoke_tx_buf               revoke_tx_buf;
+
+       struct nvsp_send_rndis_pkt              send_rndis_pkt;
+       struct nvsp_send_rndis_pkt_comp         send_rndis_pkt_comp;
+
+       /* Version 2 */
+       struct nvsp_send_ndis_config            send_ndis_config;
+
+       struct nvsp_send_chimney_buf            send_chimney_buf;
+       struct nvsp_send_chimney_buf_comp       send_chimney_buf_comp;
+       struct nvsp_revoke_chimney_buf          revoke_chimney_buf;
+
+       struct nvsp_resume_chimney_rx_indication resume_chimney_rx_indication;
+       struct nvsp_terminate_chimney           terminate_chimney;
+       struct nvsp_terminate_chimney_comp      terminate_chimney_comp;
+       struct nvsp_indicate_chimney_event      indicate_chimney_event;
+
+       struct nvsp_send_chimney_pkt            send_chimney_packet;
+       struct nvsp_send_chimney_pkt_comp       send_chimney_packet_comp;
+       struct nvsp_post_chimney_rx_req         post_chimney_rx_req;
+       struct nvsp_post_chimney_rx_req_comp    post_chimney_rx_req_comp;
+
+       struct nvsp_alloc_rx_buf                alloc_rx_buffer;
+       struct nvsp_alloc_rx_buf_comp           alloc_rx_buffer_comp;
+       struct nvsp_free_rx_buf                 free_rx_buffer;
+
+       struct nvsp_send_vmq_rndis_pkt          send_vmq_rndis_pkt;
+       struct nvsp_send_vmq_rndis_pkt_comp     send_vmq_rndis_pkt_comp;
+       struct nvsp_alloc_chimney_handle        alloc_chimney_handle;
+       struct nvsp_alloc_chimney_handle_comp   alloc_chimney_handle_comp;
+
+       /* Version 5 */
+       struct nvsp_subchannel_req              subchannel_req;
+       struct nvsp_subchannel_comp             subchn_comp;
+       struct nvsp_send_indirect_table         send_table;
+       }                                       msg;
+} __packed;
+
+#endif /* _IF_HVNREG_H_ */
diff --git a/sys/dev/pv/rndisreg.h b/sys/dev/pv/rndisreg.h
new file mode 100644 (file)
index 0000000..48cc645
--- /dev/null
@@ -0,0 +1,974 @@
+/*-
+ * Copyright (c) 2009-2012 Microsoft Corp.
+ * Copyright (c) 2010-2012 Citrix Inc.
+ * Copyright (c) 2012 NetApp Inc.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice unmodified, this list of conditions, and the following
+ *    disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifndef _RNDISREG_H_
+#define _RNDISREG_H_
+
+/*
+ * NDIS protocol version numbers
+ */
+#define NDIS_VERSION_5_0                       0x00050000
+#define NDIS_VERSION_5_1                       0x00050001
+#define NDIS_VERSION_6_0                       0x00060000
+#define NDIS_VERSION_6_1                       0x00060001
+#define NDIS_VERSION_6_30                      0x0006001e
+
+/*
+ * Status codes
+ */
+
+#define STATUS_SUCCESS                         0x00000000
+#define STATUS_UNSUCCESSFUL                    0xC0000001
+#define STATUS_PENDING                         0x00000103
+#define STATUS_INSUFFICIENT_RESOURCES          0xC000009A
+#define STATUS_BUFFER_OVERFLOW                 0x80000005
+#define STATUS_NOT_SUPPORTED                   0xC00000BB
+
+#define RNDIS_STATUS_SUCCESS                   0x00000000
+#define RNDIS_STATUS_PENDING                   0x00000103
+#define RNDIS_STATUS_NOT_RECOGNIZED            0x00010001
+#define RNDIS_STATUS_NOT_COPIED                        0x00010002
+#define RNDIS_STATUS_NOT_ACCEPTED              0x00010003
+#define RNDIS_STATUS_CALL_ACTIVE               0x00010007
+
+#define RNDIS_STATUS_ONLINE                    0x40010003
+#define RNDIS_STATUS_RESET_START               0x40010004
+#define RNDIS_STATUS_RESET_END                 0x40010005
+#define RNDIS_STATUS_RING_STATUS               0x40010006
+#define RNDIS_STATUS_CLOSED                    0x40010007
+#define RNDIS_STATUS_WAN_LINE_UP               0x40010008
+#define RNDIS_STATUS_WAN_LINE_DOWN             0x40010009
+#define RNDIS_STATUS_WAN_FRAGMENT              0x4001000A
+#define RNDIS_STATUS_MEDIA_CONNECT             0x4001000B
+#define RNDIS_STATUS_MEDIA_DISCONNECT          0x4001000C
+#define RNDIS_STATUS_HARDWARE_LINE_UP          0x4001000D
+#define RNDIS_STATUS_HARDWARE_LINE_DOWN                0x4001000E
+#define RNDIS_STATUS_INTERFACE_UP              0x4001000F
+#define RNDIS_STATUS_INTERFACE_DOWN            0x40010010
+#define RNDIS_STATUS_MEDIA_BUSY                        0x40010011
+#define RNDIS_STATUS_MEDIA_SPECIFIC_INDICATION 0x40010012
+#define RNDIS_STATUS_WW_INDICATION             0x40010012
+#define RNDIS_STATUS_LINK_SPEED_CHANGE         0x40010013
+
+#define RNDIS_STATUS_OFFLOAD_CURRENT_CONFIG    0x40020006
+
+#define RNDIS_STATUS_NOT_RESETTABLE            0x80010001
+#define RNDIS_STATUS_SOFT_ERRORS               0x80010003
+#define RNDIS_STATUS_HARD_ERRORS               0x80010004
+#define RNDIS_STATUS_BUFFER_OVERFLOW           0x80000005
+
+#define RNDIS_STATUS_FAILURE                   0xC0000001
+#define RNDIS_STATUS_RESOURCES                 0xC000009A
+#define RNDIS_STATUS_CLOSING                   0xC0010002
+#define RNDIS_STATUS_BAD_VERSION               0xC0010004
+#define RNDIS_STATUS_BAD_CHARACTERISTICS       0xC0010005
+#define RNDIS_STATUS_ADAPTER_NOT_FOUND         0xC0010006
+#define RNDIS_STATUS_OPEN_FAILED               0xC0010007
+#define RNDIS_STATUS_DEVICE_FAILED             0xC0010008
+#define RNDIS_STATUS_MULTICAST_FULL            0xC0010009
+#define RNDIS_STATUS_MULTICAST_EXISTS          0xC001000A
+#define RNDIS_STATUS_MULTICAST_NOT_FOUND       0xC001000B
+#define RNDIS_STATUS_REQUEST_ABORTED           0xC001000C
+#define RNDIS_STATUS_RESET_IN_PROGRESS         0xC001000D
+#define RNDIS_STATUS_CLOSING_INDICATING                0xC001000E
+#define RNDIS_STATUS_NOT_SUPPORTED             0xC00000BB
+#define RNDIS_STATUS_INVALID_PACKET            0xC001000F
+#define RNDIS_STATUS_OPEN_LIST_FULL            0xC0010010
+#define RNDIS_STATUS_ADAPTER_NOT_READY         0xC0010011
+#define RNDIS_STATUS_ADAPTER_NOT_OPEN          0xC0010012
+#define RNDIS_STATUS_NOT_INDICATING            0xC0010013
+#define RNDIS_STATUS_INVALID_LENGTH            0xC0010014
+#define RNDIS_STATUS_INVALID_DATA              0xC0010015
+#define RNDIS_STATUS_BUFFER_TOO_SHORT          0xC0010016
+#define RNDIS_STATUS_INVALID_OID               0xC0010017
+#define RNDIS_STATUS_ADAPTER_REMOVED           0xC0010018
+#define RNDIS_STATUS_UNSUPPORTED_MEDIA         0xC0010019
+#define RNDIS_STATUS_GROUP_ADDRESS_IN_USE      0xC001001A
+#define RNDIS_STATUS_FILE_NOT_FOUND            0xC001001B
+#define RNDIS_STATUS_ERROR_READING_FILE                0xC001001C
+#define RNDIS_STATUS_ALREADY_MAPPED            0xC001001D
+#define RNDIS_STATUS_RESOURCE_CONFLICT         0xC001001E
+#define RNDIS_STATUS_NO_CABLE                  0xC001001F
+
+#define RNDIS_STATUS_INVALID_SAP               0xC0010020
+#define RNDIS_STATUS_SAP_IN_USE                        0xC0010021
+#define RNDIS_STATUS_INVALID_ADDRESS           0xC0010022
+#define RNDIS_STATUS_VC_NOT_ACTIVATED          0xC0010023
+#define RNDIS_STATUS_DEST_OUT_OF_ORDER         0xC0010024
+#define RNDIS_STATUS_VC_NOT_AVAILABLE          0xC0010025
+#define RNDIS_STATUS_CELLRATE_NOT_AVAILABLE    0xC0010026
+#define RNDIS_STATUS_INCOMPATABLE_QOS          0xC0010027
+#define RNDIS_STATUS_AAL_PARAMS_UNSUPPORTED    0xC0010028
+#define RNDIS_STATUS_NO_ROUTE_TO_DESTINATION   0xC0010029
+
+#define RNDIS_STATUS_TOKEN_RING_OPEN_ERROR     0xC0011000
+
+
+/*
+ * Object Identifiers used by NdisRequest Query/Set Information
+ */
+
+/*
+ * General Objects
+ */
+
+#define RNDIS_OID_GEN_SUPPORTED_LIST           0x00010101
+#define RNDIS_OID_GEN_HARDWARE_STATUS          0x00010102
+#define RNDIS_OID_GEN_MEDIA_SUPPORTED          0x00010103
+#define RNDIS_OID_GEN_MEDIA_IN_USE             0x00010104
+#define RNDIS_OID_GEN_MAXIMUM_LOOKAHEAD                0x00010105
+#define RNDIS_OID_GEN_MAXIMUM_FRAME_SIZE       0x00010106
+#define RNDIS_OID_GEN_LINK_SPEED               0x00010107
+#define RNDIS_OID_GEN_TRANSMIT_BUFFER_SPACE    0x00010108
+#define RNDIS_OID_GEN_RECEIVE_BUFFER_SPACE     0x00010109
+#define RNDIS_OID_GEN_TRANSMIT_BLOCK_SIZE      0x0001010A
+#define RNDIS_OID_GEN_RECEIVE_BLOCK_SIZE       0x0001010B
+#define RNDIS_OID_GEN_VENDOR_ID                        0x0001010C
+#define RNDIS_OID_GEN_VENDOR_DESCRIPTION       0x0001010D
+#define RNDIS_OID_GEN_CURRENT_PACKET_FILTER    0x0001010E
+#define RNDIS_OID_GEN_CURRENT_LOOKAHEAD                0x0001010F
+#define RNDIS_OID_GEN_DRIVER_VERSION           0x00010110
+#define RNDIS_OID_GEN_MAXIMUM_TOTAL_SIZE       0x00010111
+#define RNDIS_OID_GEN_PROTOCOL_OPTIONS         0x00010112
+#define RNDIS_OID_GEN_MAC_OPTIONS              0x00010113
+#define RNDIS_OID_GEN_MEDIA_CONNECT_STATUS     0x00010114
+#define RNDIS_OID_GEN_MAXIMUM_SEND_PACKETS     0x00010115
+#define RNDIS_OID_GEN_VENDOR_DRIVER_VERSION    0x00010116
+#define RNDIS_OID_GEN_NETWORK_LAYER_ADDRESSES  0x00010118
+#define RNDIS_OID_GEN_TRANSPORT_HEADER_OFFSET  0x00010119
+#define RNDIS_OID_GEN_MACHINE_NAME             0x0001021A
+#define RNDIS_OID_GEN_RNDIS_CONFIG_PARAMETER   0x0001021B
+
+#define RNDIS_OID_GEN_XMIT_OK                  0x00020101
+#define RNDIS_OID_GEN_RCV_OK                   0x00020102
+#define RNDIS_OID_GEN_XMIT_ERROR               0x00020103
+#define RNDIS_OID_GEN_RCV_ERROR                        0x00020104
+#define RNDIS_OID_GEN_RCV_NO_BUFFER            0x00020105
+
+#define RNDIS_OID_GEN_DIRECTED_BYTES_XMIT      0x00020201
+#define RNDIS_OID_GEN_DIRECTED_FRAMES_XMIT     0x00020202
+#define RNDIS_OID_GEN_MULTICAST_BYTES_XMIT     0x00020203
+#define RNDIS_OID_GEN_MULTICAST_FRAMES_XMIT    0x00020204
+#define RNDIS_OID_GEN_BROADCAST_BYTES_XMIT     0x00020205
+#define RNDIS_OID_GEN_BROADCAST_FRAMES_XMIT    0x00020206
+#define RNDIS_OID_GEN_DIRECTED_BYTES_RCV       0x00020207
+#define RNDIS_OID_GEN_DIRECTED_FRAMES_RCV      0x00020208
+#define RNDIS_OID_GEN_MULTICAST_BYTES_RCV      0x00020209
+#define RNDIS_OID_GEN_MULTICAST_FRAMES_RCV     0x0002020A
+#define RNDIS_OID_GEN_BROADCAST_BYTES_RCV      0x0002020B
+#define RNDIS_OID_GEN_BROADCAST_FRAMES_RCV     0x0002020C
+
+#define RNDIS_OID_GEN_RCV_CRC_ERROR            0x0002020D
+#define RNDIS_OID_GEN_TRANSMIT_QUEUE_LENGTH    0x0002020E
+
+#define RNDIS_OID_GEN_GET_TIME_CAPS            0x0002020F
+#define RNDIS_OID_GEN_GET_NETCARD_TIME         0x00020210
+
+/*
+ * These are connection-oriented general OIDs.
+ * These replace the above OIDs for connection-oriented media.
+ */
+#define RNDIS_OID_GEN_CO_SUPPORTED_LIST                0x00010101
+#define RNDIS_OID_GEN_CO_HARDWARE_STATUS       0x00010102
+#define RNDIS_OID_GEN_CO_MEDIA_SUPPORTED       0x00010103
+#define RNDIS_OID_GEN_CO_MEDIA_IN_USE          0x00010104
+#define RNDIS_OID_GEN_CO_LINK_SPEED            0x00010105
+#define RNDIS_OID_GEN_CO_VENDOR_ID             0x00010106
+#define RNDIS_OID_GEN_CO_VENDOR_DESCRIPTION    0x00010107
+#define RNDIS_OID_GEN_CO_DRIVER_VERSION                0x00010108
+#define RNDIS_OID_GEN_CO_PROTOCOL_OPTIONS      0x00010109
+#define RNDIS_OID_GEN_CO_MAC_OPTIONS           0x0001010A
+#define RNDIS_OID_GEN_CO_MEDIA_CONNECT_STATUS  0x0001010B
+#define RNDIS_OID_GEN_CO_VENDOR_DRIVER_VERSION 0x0001010C
+#define RNDIS_OID_GEN_CO_MINIMUM_LINK_SPEED    0x0001010D
+
+#define RNDIS_OID_GEN_CO_GET_TIME_CAPS         0x00010201
+#define RNDIS_OID_GEN_CO_GET_NETCARD_TIME      0x00010202
+
+/*
+ * These are connection-oriented statistics OIDs.
+ */
+#define RNDIS_OID_GEN_CO_XMIT_PDUS_OK          0x00020101
+#define RNDIS_OID_GEN_CO_RCV_PDUS_OK           0x00020102
+#define RNDIS_OID_GEN_CO_XMIT_PDUS_ERROR       0x00020103
+#define RNDIS_OID_GEN_CO_RCV_PDUS_ERROR                0x00020104
+#define RNDIS_OID_GEN_CO_RCV_PDUS_NO_BUFFER    0x00020105
+
+
+#define RNDIS_OID_GEN_CO_RCV_CRC_ERROR         0x00020201
+#define RNDIS_OID_GEN_CO_TRANSMIT_QUEUE_LENGTH 0x00020202
+#define RNDIS_OID_GEN_CO_BYTES_XMIT            0x00020203
+#define RNDIS_OID_GEN_CO_BYTES_RCV             0x00020204
+#define RNDIS_OID_GEN_CO_BYTES_XMIT_OUTSTANDING        0x00020205
+#define RNDIS_OID_GEN_CO_NETCARD_LOAD          0x00020206
+
+/*
+ * These are objects for Connection-oriented media call-managers.
+ */
+#define RNDIS_OID_CO_ADD_PVC                   0xFF000001
+#define RNDIS_OID_CO_DELETE_PVC                        0xFF000002
+#define RNDIS_OID_CO_GET_CALL_INFORMATION      0xFF000003
+#define RNDIS_OID_CO_ADD_ADDRESS               0xFF000004
+#define RNDIS_OID_CO_DELETE_ADDRESS            0xFF000005
+#define RNDIS_OID_CO_GET_ADDRESSES             0xFF000006
+#define RNDIS_OID_CO_ADDRESS_CHANGE            0xFF000007
+#define RNDIS_OID_CO_SIGNALING_ENABLED         0xFF000008
+#define RNDIS_OID_CO_SIGNALING_DISABLED                0xFF000009
+
+
+/*
+ * 802.3 Objects (Ethernet)
+ */
+
+#define RNDIS_OID_802_3_PERMANENT_ADDRESS      0x01010101
+#define RNDIS_OID_802_3_CURRENT_ADDRESS                0x01010102
+#define RNDIS_OID_802_3_MULTICAST_LIST         0x01010103
+#define RNDIS_OID_802_3_MAXIMUM_LIST_SIZE      0x01010104
+#define RNDIS_OID_802_3_MAC_OPTIONS            0x01010105
+
+/*
+ *
+ */
+#define NDIS_802_3_MAC_OPTION_PRIORITY         0x00000001
+
+#define RNDIS_OID_802_3_RCV_ERROR_ALIGNMENT    0x01020101
+#define RNDIS_OID_802_3_XMIT_ONE_COLLISION     0x01020102
+#define RNDIS_OID_802_3_XMIT_MORE_COLLISIONS   0x01020103
+
+#define RNDIS_OID_802_3_XMIT_DEFERRED          0x01020201
+#define RNDIS_OID_802_3_XMIT_MAX_COLLISIONS    0x01020202
+#define RNDIS_OID_802_3_RCV_OVERRUN            0x01020203
+#define RNDIS_OID_802_3_XMIT_UNDERRUN          0x01020204
+#define RNDIS_OID_802_3_XMIT_HEARTBEAT_FAILURE 0x01020205
+#define RNDIS_OID_802_3_XMIT_TIMES_CRS_LOST    0x01020206
+#define RNDIS_OID_802_3_XMIT_LATE_COLLISIONS   0x01020207
+
+
+/*
+ * RNDIS MP custom OID for test
+ */
+#define OID_RNDISMP_GET_RECEIVE_BUFFERS                0xFFA0C90D
+
+
+/*
+ * Remote NDIS message types
+ */
+#define RNDIS_PACKET_MSG                       0x00000001
+#define RNDIS_INITIALIZE_MSG                   0x00000002
+#define RNDIS_HALT_MSG                         0x00000003
+#define RNDIS_QUERY_MSG                                0x00000004
+#define RNDIS_SET_MSG                          0x00000005
+#define RNDIS_RESET_MSG                                0x00000006
+#define RNDIS_INDICATE_STATUS_MSG              0x00000007
+#define RNDIS_KEEPALIVE_MSG                    0x00000008
+
+#define RCONDIS_MP_CREATE_VC_MSG               0x00008001
+#define RCONDIS_MP_DELETE_VC_MSG               0x00008002
+#define RCONDIS_MP_ACTIVATE_VC_MSG             0x00008005
+#define RCONDIS_MP_DEACTIVATE_VC_MSG           0x00008006
+#define RCONDIS_INDICATE_STATUS_MSG            0x00008007
+
+/*
+ * Remote NDIS message completion types
+ */
+#define RNDIS_INITIALIZE_CMPLT                 0x80000002
+#define RNDIS_QUERY_CMPLT                      0x80000004
+#define RNDIS_SET_CMPLT                                0x80000005
+#define RNDIS_RESET_CMPLT                      0x80000006
+#define RNDIS_KEEPALIVE_CMPLT                  0x80000008
+
+#define RCONDIS_MP_CREATE_VC_CMPLT             0x80008001
+#define RCONDIS_MP_DELETE_VC_CMPLT             0x80008002
+#define RCONDIS_MP_ACTIVATE_VC_CMPLT           0x80008005
+#define RCONDIS_MP_DEACTIVATE_VC_CMPLT         0x80008006
+
+/*
+ * Reserved message type for private communication between
+ * lower-layer host driver and remote device, if necessary.
+ */
+#define RNDIS_BUS_MSG                          0xff000001
+
+/*
+ * Defines for DeviceFlags in rndis_initialize_comp
+ */
+#define RNDIS_DF_CONNECTIONLESS                        0x00000001
+#define RNDIS_DF_CONNECTION_ORIENTED           0x00000002
+#define RNDIS_DF_RAW_DATA                      0x00000004
+
+/*
+ * Remote NDIS medium types.
+ */
+#define RNDIS_MEDIUM_802_3                     0x00000000
+#define RNDIS_MEDIUM_802_5                     0x00000001
+#define RNDIS_MEDIUM_FDDI                      0x00000002
+#define RNDIS_MEDIUM_WAN                       0x00000003
+#define RNDIS_MEDIUM_LOCAL_TALK                        0x00000004
+#define RNDIS_MEDIUM_ARCNET_RAW                        0x00000006
+#define RNDIS_MEDIUM_ARCNET_878_2              0x00000007
+#define RNDIS_MEDIUM_ATM                       0x00000008
+#define RNDIS_MEDIUM_WIRELESS_WAN              0x00000009
+#define RNDIS_MEDIUM_IRDA                      0x0000000a
+#define RNDIS_MEDIUM_CO_WAN                    0x0000000b
+/* Not a real medium, defined as an upper bound */
+#define RNDIS_MEDIUM_MAX                       0x0000000d
+
+/*
+ * Remote NDIS medium connection states.
+ */
+#define RNDIS_MEDIA_STATE_CONNECTED            0x00000000
+#define RNDIS_MEDIA_STATE_DISCONNECTED         0x00000001
+
+/*
+ * Remote NDIS version numbers
+ */
+#define RNDIS_MAJOR_VERSION                    0x00000001
+#define RNDIS_MINOR_VERSION                    0x00000000
+
+/*
+ * Remote NDIS offload parameters
+ */
+#define RNDIS_OBJECT_TYPE_DEFAULT              0x80
+
+#define RNDIS_OFFLOAD_PARAMS_REVISION_3                3
+#define RNDIS_OFFLOAD_PARAMS_NO_CHANGE         0
+#define RNDIS_OFFLOAD_PARAMS_LSOV2_DISABLED    1
+#define RNDIS_OFFLOAD_PARAMS_LSOV2_ENABLED     2
+#define RNDIS_OFFLOAD_PARAMS_LSOV1_ENABLED     2
+#define RNDIS_OFFLOAD_PARAMS_RSC_DISABLED      1
+#define RNDIS_OFFLOAD_PARAMS_RSC_ENABLED       2
+#define RNDIS_OFFLOAD_PARAMS_TX_RX_DISABLED    1
+#define RNDIS_OFFLOAD_PARAMS_TX_ENABLED_RX_DISABLED 2
+#define RNDIS_OFFLOAD_PARAMS_RX_ENABLED_TX_DISABLED 3
+#define RNDIS_OFFLOAD_PARAMS_TX_RX_ENABLED     4
+
+#define RNDIS_TCP_LARGE_SEND_OFFLOAD_V2_TYPE   1
+#define RNDIS_TCP_LARGE_SEND_OFFLOAD_IPV4      0
+#define RNDIS_TCP_LARGE_SEND_OFFLOAD_IPV6      1
+
+#define RNDIS_OID_TCP_OFFLOAD_CURRENT_CONFIG   0xFC01020B /* query only */
+#define RNDIS_OID_TCP_OFFLOAD_PARAMS           0xFC01020C /* set only */
+#define RNDIS_OID_TCP_OFFLOAD_HARDWARE_CAPS    0xFC01020D/* query only */
+#define RNDIS_OID_TCPCON_OFFLOAD_CURRENT_CONFIG        0xFC01020E /* query only */
+#define RNDIS_OID_TCPCON_OFFLOAD_HARDWARE_CAPS 0xFC01020F /* query */
+#define RNDIS_OID_OFFLOAD_ENCAPSULATION                0x0101010A /* set/query */
+
+/*
+ * NdisInitialize message
+ */
+struct rndis_init_req {
+       /* RNDIS request ID */
+       uint32_t                        request_id;
+       uint32_t                        major_version;
+       uint32_t                        minor_version;
+       uint32_t                        max_xfer_size;
+};
+
+/*
+ * Response to NdisInitialize
+ */
+struct rndis_init_comp {
+       /* RNDIS request ID */
+       uint32_t                        request_id;
+       /* RNDIS status */
+       uint32_t                        status;
+       uint32_t                        major_version;
+       uint32_t                        minor_version;
+       uint32_t                        device_flags;
+       /* RNDIS medium */
+       uint32_t                        medium;
+       uint32_t                        max_pkts_per_msg;
+       uint32_t                        max_xfer_size;
+       uint32_t                        pkt_align_factor;
+       uint32_t                        af_list_offset;
+       uint32_t                        af_list_size;
+};
+
+/*
+ * Call manager devices only: Information about an address family
+ * supported by the device is appended to the response to NdisInitialize.
+ */
+struct rndis_co_address_family {
+       /* RNDIS AF */
+       uint32_t                        address_family;
+       uint32_t                        major_version;
+       uint32_t                        minor_version;
+};
+
+/*
+ * NdisHalt message
+ */
+struct rndis_halt_req {
+       /* RNDIS request ID */
+       uint32_t                        request_id;
+};
+
+/*
+ * NdisQueryRequest message
+ */
+struct rndis_query_req {
+       /* RNDIS request ID */
+       uint32_t                        request_id;
+       /* RNDIS OID */
+       uint32_t                        oid;
+       uint32_t                        info_buffer_length;
+       uint32_t                        info_buffer_offset;
+       /* RNDIS handle */
+       uint32_t                        device_vc_handle;
+};
+
+/*
+ * Response to NdisQueryRequest
+ */
+struct rndis_query_comp {
+       /* RNDIS request ID */
+       uint32_t                        request_id;
+       /* RNDIS status */
+       uint32_t                        status;
+       uint32_t                        info_buffer_length;
+       uint32_t                        info_buffer_offset;
+};
+
+/*
+ * NdisSetRequest message
+ */
+struct rndis_set_req {
+       /* RNDIS request ID */
+       uint32_t                        request_id;
+       /* RNDIS OID */
+       uint32_t                        oid;
+       uint32_t                        info_buffer_length;
+       uint32_t                        info_buffer_offset;
+       /* RNDIS handle */
+       uint32_t                        device_vc_handle;
+};
+
+/*
+ * Response to NdisSetRequest
+ */
+struct rndis_set_comp {
+       /* RNDIS request ID */
+       uint32_t                        request_id;
+       /* RNDIS status */
+       uint32_t                        status;
+};
+
+/*
+ * NdisReset message
+ */
+struct rndis_reset_req {
+       uint32_t                        reserved;
+};
+
+/*
+ * Response to NdisReset
+ */
+struct rndis_reset_comp {
+       /* RNDIS status */
+       uint32_t                        status;
+       uint32_t                        addressing_reset;
+};
+
+/*
+ * NdisMIndicateStatus message
+ */
+struct rndis_indicate_status {
+       /* RNDIS status */
+       uint32_t                        status;
+       uint32_t                        status_buf_length;
+       uint32_t                        status_buf_offset;
+};
+
+/*
+ * Diagnostic information passed as the status buffer in
+ * rndis_indicate_status messages signifying error conditions.
+ */
+struct rndis_diagnostic_info {
+       /* RNDIS status */
+       uint32_t                        diag_status;
+       uint32_t                        error_offset;
+};
+
+/*
+ * NdisKeepAlive message
+ */
+struct rndis_keepalive_req {
+       /* RNDIS request ID */
+       uint32_t                        request_id;
+};
+
+/*
+ * Response to NdisKeepAlive
+ */
+struct rndis_keepalive_comp {
+       /* RNDIS request ID */
+       uint32_t                        request_id;
+       /* RNDIS status */
+       uint32_t                        status;
+};
+
+/*
+ * Data message. All offset fields contain byte offsets from the
+ * beginning of the rndis_pkt structure. All length fields are in
+ * bytes.  VcHandle is set to 0 for connectionless data, otherwise
+ * it contains the VC handle.
+ */
+struct rndis_pkt {
+       uint32_t                        data_offset;
+       uint32_t                        data_length;
+       uint32_t                        oob_data_offset;
+       uint32_t                        oob_data_length;
+       uint32_t                        num_oob_data_elements;
+       uint32_t                        pkt_info_offset;
+       uint32_t                        pkt_info_length;
+       /* RNDIS handle */
+       uint32_t                        vc_handle;
+       uint32_t                        reserved;
+};
+
+struct rndis_pkt_ex {
+       uint32_t                        data_offset;
+       uint32_t                        data_length;
+       uint32_t                        oob_data_offset;
+       uint32_t                        oob_data_length;
+       uint32_t                        num_oob_data_elements;
+       uint32_t                        pkt_info_offset;
+       uint32_t                        pkt_info_length;
+       /* RNDIS handle */
+       uint32_t                        vc_handle;
+       uint32_t                        reserved;
+       uint64_t                        data_buf_id;
+       uint32_t                        data_buf_offset;
+       uint64_t                        next_header_buf_id;
+       uint32_t                        next_header_byte_offset;
+       uint32_t                        next_header_byte_count;
+};
+
+/*
+ * Optional Out of Band data associated with a Data message.
+ */
+struct rndis_oobd {
+       uint32_t                        size;
+       /* RNDIS class ID */
+       uint32_t                        type;
+       uint32_t                        class_info_offset;
+};
+
+/*
+ * Packet extension field contents associated with a Data message.
+ */
+struct rndis_pkt_info {
+       uint32_t                        size;
+       uint32_t                        type;
+       uint32_t                        pkt_info_offset;
+};
+
+enum ndis_pkt_info_type {
+       tcpip_chksum_info,
+       ipsec_info,
+       tcp_large_send_info,
+       classification_handle_info,
+       ndis_reserved,
+       sgl_info,
+       ieee_8021q_info,
+       original_pkt_info,
+       pkt_cancel_id,
+       original_netbuf_list,
+       cached_netbuf_list,
+       short_pkt_padding_info,
+       max_perpkt_info
+};
+
+struct ndis_8021q_info {
+       union {
+               struct {
+                       uint32_t        user_pri : 3;  /* User Priority */
+                       uint32_t        cfi      : 1;  /* Canonical Format ID */
+                       uint32_t        vlan_id  : 12;
+                       uint32_t        reserved : 16;
+               };
+               uint32_t                value;
+       };
+} ndis_8021q_info;
+
+struct rndis_objhdr {
+       uint8_t                         type;
+       uint8_t                         revision;
+       uint16_t                        size;
+};
+
+struct rndis_offload_params {
+       struct rndis_objhdr             header;
+       uint8_t                         ipv4_csum;
+       uint8_t                         tcp_ipv4_csum;
+       uint8_t                         udp_ipv4_csum;
+       uint8_t                         tcp_ipv6_csum;
+       uint8_t                         udp_ipv6_csum;
+       uint8_t                         lso_v1;
+       uint8_t                         ip_sec_v1;
+       uint8_t                         lso_v2_ipv4;
+       uint8_t                         lso_v2_ipv6;
+       uint8_t                         tcp_connection_ipv4;
+       uint8_t                         tcp_connection_ipv6;
+       uint32_t                        flags;
+       uint8_t                         ip_sec_v2;
+       uint8_t                         ip_sec_v2_ipv4;
+       struct {
+               uint8_t                 rsc_ipv4;
+               uint8_t                 rsc_ipv6;
+       };
+       struct {
+               uint8_t                 encap_packet_task_offload;
+               uint8_t                 encap_types;
+       };
+};
+
+struct rndis_tcp_ip_csum_info {
+       union {
+               struct {
+                       uint32_t        is_ipv4:1;
+                       uint32_t        is_ipv6:1;
+                       uint32_t        tcp_csum:1;
+                       uint32_t        udp_csum:1;
+                       uint32_t        ip_header_csum:1;
+                       uint32_t        reserved:11;
+                       uint32_t        tcp_header_offset:10;
+               } xmit;
+               struct {
+                       uint32_t        tcp_csum_failed:1;
+                       uint32_t        udp_csum_failed:1;
+                       uint32_t        ip_csum_failed:1;
+                       uint32_t        tcp_csum_succeeded:1;
+                       uint32_t        udp_csum_succeeded:1;
+                       uint32_t        ip_csum_succeeded:1;
+                       uint32_t        loopback:1;
+                       uint32_t        tcp_csum_value_invalid:1;
+                       uint32_t        ip_csum_value_invalid:1;
+               } recv;
+               uint32_t                value;
+       };
+};
+
+struct rndis_tcp_tso_info {
+       union {
+               struct {
+                       uint32_t        unused:30;
+                       uint32_t        type:1;
+                       uint32_t        reserved2:1;
+               } xmit;
+               struct {
+                       uint32_t        mss:20;
+                       uint32_t        tcp_header_offset:10;
+                       uint32_t        type:1;
+                       uint32_t        reserved2:1;
+               } lso_v1_xmit;
+               struct  {
+                       uint32_t        tcp_payload:30;
+                       uint32_t        type:1;
+                       uint32_t        reserved2:1;
+               } lso_v1_xmit_comp;
+               struct  {
+                       uint32_t        mss:20;
+                       uint32_t        tcp_header_offset:10;
+                       uint32_t        type:1;
+                       uint32_t        ip_version:1;
+               } lso_v2_xmit;
+               struct  {
+                       uint32_t        reserved:30;
+                       uint32_t        type:1;
+                       uint32_t        reserved2:1;
+               } lso_v2_xmit_comp;
+               uint32_t                value;
+       };
+};
+
+#define RNDIS_VLAN_PPI_SIZE    (sizeof(rndis_pkt_info) +       \
+       sizeof(ndis_8021q_info))
+
+#define RNDIS_CSUM_PPI_SIZE    (sizeof(rndis_pkt_info) +       \
+       sizeof(rndis_tcp_ip_csum_info))
+
+#define RNDIS_TSO_PPI_SIZE     (sizeof(rndis_pkt_info) +       \
+       sizeof(rndis_tcp_tso_info))
+
+/*
+ * Format of Information buffer passed in a SetRequest for the OID
+ * OID_GEN_RNDIS_CONFIG_PARAMETER.
+ */
+struct rndis_config_param_info {
+       uint32_t                        name_offset;
+       uint32_t                        name_length;
+       uint32_t                        param_type;
+       uint32_t                        value_offset;
+       uint32_t                        value_length;
+};
+
+/*
+ * Values for ParameterType in rndis_config_param_info
+ */
+#define RNDIS_CONFIG_PARAM_TYPE_INTEGER        0
+#define RNDIS_CONFIG_PARAM_TYPE_STRING 2
+
+
+/*
+ * CONDIS Miniport messages for connection oriented devices
+ * that do not implement a call manager.
+ */
+
+/*
+ * CoNdisMiniportCreateVc message
+ */
+struct rcondis_mp_create_vc {
+       /* RNDIS request ID */
+       uint32_t                        request_id;
+       /* RNDIS handle */
+       uint32_t                        ndis_vc_handle;
+};
+
+/*
+ * Response to CoNdisMiniportCreateVc
+ */
+struct rcondis_mp_create_vc_comp {
+       /* RNDIS request ID */
+       uint32_t                        request_id;
+       /* RNDIS handle */
+       uint32_t                        device_vc_handle;
+       /* RNDIS status */
+       uint32_t                        status;
+};
+
+/*
+ * CoNdisMiniportDeleteVc message
+ */
+struct rcondis_mp_delete_vc {
+       /* RNDIS request ID */
+       uint32_t                        request_id;
+       /* RNDIS handle */
+       uint32_t                        device_vc_handle;
+};
+
+/*
+ * Response to CoNdisMiniportDeleteVc
+ */
+struct rcondis_mp_delete_vc_comp {
+       /* RNDIS request ID */
+       uint32_t                        request_id;
+       /* RNDIS status */
+       uint32_t                        status;
+};
+
+/*
+ * CoNdisMiniportQueryRequest message
+ */
+struct rcondis_mp_query_req {
+       /* RNDIS request ID */
+       uint32_t                        request_id;
+       /* RNDIS request type */
+       uint32_t                        request_type;
+       /* RNDIS OID */
+       uint32_t                        oid;
+       /* RNDIS handle */
+       uint32_t                        device_vc_handle;
+       uint32_t                        info_buf_length;
+       uint32_t                        info_buf_offset;
+};
+
+/*
+ * CoNdisMiniportSetRequest message
+ */
+struct rcondis_mp_set_req {
+       /* RNDIS request ID */
+       uint32_t                        request_id;
+       /* RNDIS request type */
+       uint32_t                        request_type;
+       /* RNDIS OID */
+       uint32_t                        oid;
+       /* RNDIS handle */
+       uint32_t                        device_vc_handle;
+       uint32_t                        info_buf_length;
+       uint32_t                        info_buf_offset;
+};
+
+/*
+ * CoNdisIndicateStatus message
+ */
+struct rcondis_indicate_status {
+       /* RNDIS handle */
+       uint32_t                        ndis_vc_handle;
+       /* RNDIS status */
+       uint32_t                        status;
+       uint32_t                        status_buf_length;
+       uint32_t                        status_buf_offset;
+};
+
+/*
+ * CONDIS Call/VC parameters
+ */
+
+struct rcondis_specific_params {
+       uint32_t                        type;
+       uint32_t                        length;
+       uint32_t                        offset;
+};
+
+struct rcondis_media_params {
+       uint32_t                        flags;
+       uint32_t                        reserved1;
+       uint32_t                        reserved2;
+       struct rcondis_specific_params  media_specific;
+};
+
+struct rndis_flowspec {
+       uint32_t                        token_rate;
+       uint32_t                        token_bucket_size;
+       uint32_t                        peak_bandwidth;
+       uint32_t                        latency;
+       uint32_t                        delay_variation;
+       uint32_t                        service_type;
+       uint32_t                        max_sdu_size;
+       uint32_t                        minimum_policed_size;
+};
+
+struct rcondis_call_manager_params {
+       struct rndis_flowspec           transmit;
+       struct rndis_flowspec           receive;
+       struct rcondis_specific_params  call_mgr_specific;
+};
+
+/*
+ * CoNdisMiniportActivateVc message
+ */
+struct rcondis_mp_activate_vc_req {
+       /* RNDIS request ID */
+       uint32_t                        request_id;
+       uint32_t                        flags;
+       /* RNDIS handle */
+       uint32_t                        device_vc_handle;
+       uint32_t                        media_params_offset;
+       uint32_t                        media_params_length;
+       uint32_t                        call_mgr_params_offset;
+       uint32_t                        call_mgr_params_length;
+};
+
+/*
+ * Response to CoNdisMiniportActivateVc
+ */
+struct rcondis_mp_activate_vc_comp {
+       /* RNDIS request ID */
+       uint32_t                        request_id;
+       /* RNDIS status */
+       uint32_t                        status;
+};
+
+/*
+ * CoNdisMiniportDeactivateVc message
+ */
+struct rcondis_mp_deactivate_vc_req {
+       /* RNDIS request ID */
+       uint32_t                        request_id;
+       uint32_t                        flags;
+       /* RNDIS handle */
+       uint32_t                        device_vc_handle;
+};
+
+/*
+ * Response to CoNdisMiniportDeactivateVc
+ */
+struct rcondis_mp_deactivate_vc_comp {
+       /* RNDIS request ID */
+       uint32_t                        request_id;
+       /* RNDIS status */
+       uint32_t                        status;
+};
+
+/*
+ * Container with all of the RNDIS messages
+ */
+union rndis_msg_cont {
+       struct rndis_pkt                        pkt;
+       struct rndis_init_req                   init_req;
+       struct rndis_halt_req                   halt_req;
+       struct rndis_query_req                  query_req;
+       struct rndis_set_req                    set_req;
+       struct rndis_reset_req                  reset_req;
+       struct rndis_keepalive_req              keepalive_req;
+       struct rndis_indicate_status            indicate_status;
+       struct rndis_init_comp                  init_comp;
+       struct rndis_query_comp                 query_comp;
+       struct rndis_set_comp                   set_comp;
+       struct rndis_reset_comp                 reset_comp;
+       struct rndis_keepalive_comp             keepalive_comp;
+       struct rcondis_mp_create_vc             co_mp_create_vc;
+       struct rcondis_mp_delete_vc             co_mp_delete_vc;
+       struct rcondis_indicate_status          co_mp_status;
+       struct rcondis_mp_activate_vc_req       co_mp_activate_vc;
+       struct rcondis_mp_deactivate_vc_req     co_mp_deactivate_vc;
+       struct rcondis_mp_create_vc_comp        co_mp_create_vc_comp;
+       struct rcondis_mp_delete_vc_comp        co_mp_delete_vc_comp;
+       struct rcondis_mp_activate_vc_comp      co_mp_activate_vc_comp;
+       struct rcondis_mp_deactivate_vc_comp    co_mp_deactivate_vc_comp;
+       struct rndis_pkt_ex                     pkt_ex;
+};
+
+/*
+ * Remote NDIS message format
+ */
+struct rndis {
+       uint32_t                        msg_type;
+
+       /*
+        * Total length of this message, from the beginning
+        * of the struct, in bytes.
+        */
+       uint32_t                        msg_len;
+
+       /* Actual message */
+       union rndis_msg_cont            msg;
+};
+
+/*
+ * get the size of an RNDIS message. Pass in the message type,
+ * rndis_set_req, rndis_packet for example
+ */
+#define RNDIS_HEADER_SIZE                              8
+#define RNDIS_MESSAGE_SIZE(message)                    \
+       (sizeof(message) + RNDIS_HEADER_SIZE)
+
+#define NDIS_PACKET_TYPE_DIRECTED              0x00000001
+#define NDIS_PACKET_TYPE_MULTICAST             0x00000002
+#define NDIS_PACKET_TYPE_ALL_MULTICAST         0x00000004
+#define NDIS_PACKET_TYPE_BROADCAST             0x00000008
+#define NDIS_PACKET_TYPE_SOURCE_ROUTING                0x00000010
+#define NDIS_PACKET_TYPE_PROMISCUOUS           0x00000020
+#define NDIS_PACKET_TYPE_SMT                   0x00000040
+#define NDIS_PACKET_TYPE_ALL_LOCAL             0x00000080
+#define NDIS_PACKET_TYPE_GROUP                 0x00000100
+#define NDIS_PACKET_TYPE_ALL_FUNCTIONAL                0x00000200
+#define NDIS_PACKET_TYPE_FUNCTIONAL            0x00000400
+#define NDIS_PACKET_TYPE_MAC_FRAME             0x00000800
+
+#endif /* _RNDISREG_H_ */