-# $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.
xnf* at xen? # Xen Netfront
#hyperv0 at pvbus? # Hyper-V guest
+#hvn* at hyperv? # Hyper-V netvsc
option PCIVERBOSE
option USBVERBOSE
-# $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.
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
--- /dev/null
+/*-
+ * 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);
+}
--- /dev/null
+/*-
+ * 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_ */
--- /dev/null
+/*-
+ * 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_ */