svn commit: r308626 - stable/11/sys/dev/hyperv/netvsc
Sepherosa Ziehau
sephe at FreeBSD.org
Mon Nov 14 03:49:30 UTC 2016
Author: sephe
Date: Mon Nov 14 03:49:28 2016
New Revision: 308626
URL: https://svnweb.freebsd.org/changeset/base/308626
Log:
MFC 308013-308017
308013
hyperv/hn: Nuke unnecessary indirection.
Sponsored by: Microsoft
Differential Revision: https://reviews.freebsd.org/D8355
308014
hyperv/hn: Reorganize RX path; mainly pull non-control code path up
Sponsored by: Microsoft
Differential Revision: https://reviews.freebsd.org/D8356
308015
hyperv/hn: Pull data path code up.
Sponsored by: Microsoft
Differential Revision: https://reviews.freebsd.org/D8357
308016
hyperv/hn: Cleanup RNDIS related files.
Sponsored by: Microsoft
Differential Revision: https://reviews.freebsd.org/D8358
308017
hyperv/hn: Change header guardian; in preparation for the upcoming rename.
Sponsored by: Microsoft
Differential Revision: https://reviews.freebsd.org/D8359
Modified:
stable/11/sys/dev/hyperv/netvsc/hv_netvsc_drv_freebsd.c
stable/11/sys/dev/hyperv/netvsc/hv_rndis_filter.c
stable/11/sys/dev/hyperv/netvsc/hv_rndis_filter.h
stable/11/sys/dev/hyperv/netvsc/if_hnvar.h
Directory Properties:
stable/11/ (props changed)
Modified: stable/11/sys/dev/hyperv/netvsc/hv_netvsc_drv_freebsd.c
==============================================================================
--- stable/11/sys/dev/hyperv/netvsc/hv_netvsc_drv_freebsd.c Mon Nov 14 03:36:59 2016 (r308625)
+++ stable/11/sys/dev/hyperv/netvsc/hv_netvsc_drv_freebsd.c Mon Nov 14 03:49:28 2016 (r308626)
@@ -166,6 +166,16 @@ __FBSDID("$FreeBSD$");
#define HN_EARLY_TXEOF_THRESH 8
+#define HN_RXINFO_VLAN 0x0001
+#define HN_RXINFO_CSUM 0x0002
+#define HN_RXINFO_HASHINF 0x0004
+#define HN_RXINFO_HASHVAL 0x0008
+#define HN_RXINFO_ALL \
+ (HN_RXINFO_VLAN | \
+ HN_RXINFO_CSUM | \
+ HN_RXINFO_HASHINF | \
+ HN_RXINFO_HASHVAL)
+
struct hn_txdesc {
#ifndef HN_USE_TXDESC_BUFRING
SLIST_ENTRY(hn_txdesc) link;
@@ -188,6 +198,17 @@ struct hn_txdesc {
#define HN_TXD_FLAG_ONLIST 0x1
#define HN_TXD_FLAG_DMAMAP 0x2
+#define HN_NDIS_VLAN_INFO_INVALID 0xffffffff
+#define HN_NDIS_RXCSUM_INFO_INVALID 0
+#define HN_NDIS_HASH_INFO_INVALID 0
+
+struct hn_rxinfo {
+ uint32_t vlan_info;
+ uint32_t csum_info;
+ uint32_t hash_info;
+ uint32_t hash_value;
+};
+
#define HN_LRO_LENLIM_MULTIRX_DEF (12 * ETHERMTU)
#define HN_LRO_LENLIM_DEF (25 * ETHERMTU)
/* YYY 2*MTU is a bit rough, but should be good enough. */
@@ -358,6 +379,7 @@ static void hn_chan_detach(struct hn_sof
static int hn_attach_subchans(struct hn_softc *);
static void hn_detach_allchans(struct hn_softc *);
static void hn_chan_callback(struct vmbus_channel *chan, void *xrxr);
+static void hn_chan_rollup(struct hn_rx_ring *, struct hn_tx_ring *);
static void hn_set_ring_inuse(struct hn_softc *, int);
static int hn_synth_attach(struct hn_softc *, int);
static void hn_synth_detach(struct hn_softc *);
@@ -376,12 +398,18 @@ static void hn_link_status(struct hn_sof
static int hn_sendpkt_rndis_sglist(struct hn_tx_ring *, struct hn_txdesc *);
static int hn_sendpkt_rndis_chim(struct hn_tx_ring *, struct hn_txdesc *);
static int hn_set_rxfilter(struct hn_softc *);
+static void hn_link_status_update(struct hn_softc *);
+static void hn_network_change(struct hn_softc *);
+
+static int hn_rndis_rxinfo(const void *, int, struct hn_rxinfo *);
+static void hn_rndis_rx_data(struct hn_rx_ring *, const void *, int);
+static void hn_rndis_rx_status(struct hn_softc *, const void *, int);
static void hn_nvs_handle_notify(struct hn_softc *sc,
const struct vmbus_chanpkt_hdr *pkt);
static void hn_nvs_handle_comp(struct hn_softc *sc, struct vmbus_channel *chan,
const struct vmbus_chanpkt_hdr *pkt);
-static void hn_nvs_handle_rxbuf(struct hn_softc *sc, struct hn_rx_ring *rxr,
+static void hn_nvs_handle_rxbuf(struct hn_rx_ring *rxr,
struct vmbus_channel *chan,
const struct vmbus_chanpkt_hdr *pkthdr);
static void hn_nvs_ack_rxbuf(struct vmbus_channel *chan, uint64_t tid);
@@ -1005,7 +1033,7 @@ hn_netchg_status_taskfunc(void *xsc, int
hn_link_status(sc);
}
-void
+static void
hn_link_status_update(struct hn_softc *sc)
{
@@ -1013,7 +1041,7 @@ hn_link_status_update(struct hn_softc *s
taskqueue_enqueue(sc->hn_mgmt_taskq, &sc->hn_link_task);
}
-void
+static void
hn_network_change(struct hn_softc *sc)
{
@@ -1188,7 +1216,7 @@ hn_tx_done(struct hn_nvs_sendctx *sndc,
}
}
-void
+static void
hn_chan_rollup(struct hn_rx_ring *rxr, struct hn_tx_ring *txr)
{
#if defined(INET) || defined(INET6)
@@ -1216,6 +1244,42 @@ hn_rndis_pktmsg_offset(uint32_t ofs)
return (ofs - __offsetof(struct rndis_packet_msg, rm_dataoffset));
}
+static __inline void *
+hn_rndis_pktinfo_append(struct rndis_packet_msg *pkt, size_t pktsize,
+ size_t pi_dlen, uint32_t pi_type)
+{
+ const size_t pi_size = HN_RNDIS_PKTINFO_SIZE(pi_dlen);
+ struct rndis_pktinfo *pi;
+
+ KASSERT((pi_size & RNDIS_PACKET_MSG_OFFSET_ALIGNMASK) == 0,
+ ("unaligned pktinfo size %zu, pktinfo dlen %zu", pi_size, pi_dlen));
+
+ /*
+ * Per-packet-info does not move; it only grows.
+ *
+ * NOTE:
+ * rm_pktinfooffset in this phase counts from the beginning
+ * of rndis_packet_msg.
+ */
+ KASSERT(pkt->rm_pktinfooffset + pkt->rm_pktinfolen + pi_size <= pktsize,
+ ("%u pktinfo overflows RNDIS packet msg", pi_type));
+ pi = (struct rndis_pktinfo *)((uint8_t *)pkt + pkt->rm_pktinfooffset +
+ pkt->rm_pktinfolen);
+ pkt->rm_pktinfolen += pi_size;
+
+ pi->rm_size = pi_size;
+ pi->rm_type = pi_type;
+ pi->rm_pktinfooffset = RNDIS_PKTINFO_OFFSET;
+
+ /* Data immediately follow per-packet-info. */
+ pkt->rm_dataoffset += pi_size;
+
+ /* Update RNDIS packet msg length */
+ pkt->rm_len += pi_size;
+
+ return (pi->rm_data);
+}
+
/*
* NOTE:
* If this function fails, then both txd and m_head0 will be freed.
@@ -1614,15 +1678,9 @@ hn_lro_rx(struct lro_ctrl *lc, struct mb
}
#endif
-/*
- * Called when we receive a data packet from the "wire" on the
- * specified device
- *
- * Note: This is no longer used as a callback
- */
-int
+static int
hn_rxpkt(struct hn_rx_ring *rxr, const void *data, int dlen,
- const struct hn_recvinfo *info)
+ const struct hn_rxinfo *info)
{
struct ifnet *ifp = rxr->hn_ifp;
struct mbuf *m_new;
@@ -4024,6 +4082,325 @@ hn_resume(struct hn_softc *sc)
hn_resume_mgmt(sc);
}
+static void
+hn_rndis_rx_status(struct hn_softc *sc, const void *data, int dlen)
+{
+ const struct rndis_status_msg *msg;
+ int ofs;
+
+ if (dlen < sizeof(*msg)) {
+ if_printf(sc->hn_ifp, "invalid RNDIS status\n");
+ return;
+ }
+ msg = data;
+
+ switch (msg->rm_status) {
+ case RNDIS_STATUS_MEDIA_CONNECT:
+ case RNDIS_STATUS_MEDIA_DISCONNECT:
+ hn_link_status_update(sc);
+ break;
+
+ case RNDIS_STATUS_TASK_OFFLOAD_CURRENT_CONFIG:
+ /* Not really useful; ignore. */
+ break;
+
+ case RNDIS_STATUS_NETWORK_CHANGE:
+ ofs = RNDIS_STBUFOFFSET_ABS(msg->rm_stbufoffset);
+ if (dlen < ofs + msg->rm_stbuflen ||
+ msg->rm_stbuflen < sizeof(uint32_t)) {
+ if_printf(sc->hn_ifp, "network changed\n");
+ } else {
+ uint32_t change;
+
+ memcpy(&change, ((const uint8_t *)msg) + ofs,
+ sizeof(change));
+ if_printf(sc->hn_ifp, "network changed, change %u\n",
+ change);
+ }
+ hn_network_change(sc);
+ break;
+
+ default:
+ if_printf(sc->hn_ifp, "unknown RNDIS status 0x%08x\n",
+ msg->rm_status);
+ break;
+ }
+}
+
+static int
+hn_rndis_rxinfo(const void *info_data, int info_dlen, struct hn_rxinfo *info)
+{
+ const struct rndis_pktinfo *pi = info_data;
+ uint32_t mask = 0;
+
+ while (info_dlen != 0) {
+ const void *data;
+ uint32_t dlen;
+
+ if (__predict_false(info_dlen < sizeof(*pi)))
+ return (EINVAL);
+ if (__predict_false(info_dlen < pi->rm_size))
+ return (EINVAL);
+ info_dlen -= pi->rm_size;
+
+ if (__predict_false(pi->rm_size & RNDIS_PKTINFO_SIZE_ALIGNMASK))
+ return (EINVAL);
+ if (__predict_false(pi->rm_size < pi->rm_pktinfooffset))
+ return (EINVAL);
+ dlen = pi->rm_size - pi->rm_pktinfooffset;
+ data = pi->rm_data;
+
+ switch (pi->rm_type) {
+ case NDIS_PKTINFO_TYPE_VLAN:
+ if (__predict_false(dlen < NDIS_VLAN_INFO_SIZE))
+ return (EINVAL);
+ info->vlan_info = *((const uint32_t *)data);
+ mask |= HN_RXINFO_VLAN;
+ break;
+
+ case NDIS_PKTINFO_TYPE_CSUM:
+ if (__predict_false(dlen < NDIS_RXCSUM_INFO_SIZE))
+ return (EINVAL);
+ info->csum_info = *((const uint32_t *)data);
+ mask |= HN_RXINFO_CSUM;
+ break;
+
+ case HN_NDIS_PKTINFO_TYPE_HASHVAL:
+ if (__predict_false(dlen < HN_NDIS_HASH_VALUE_SIZE))
+ return (EINVAL);
+ info->hash_value = *((const uint32_t *)data);
+ mask |= HN_RXINFO_HASHVAL;
+ break;
+
+ case HN_NDIS_PKTINFO_TYPE_HASHINF:
+ if (__predict_false(dlen < HN_NDIS_HASH_INFO_SIZE))
+ return (EINVAL);
+ info->hash_info = *((const uint32_t *)data);
+ mask |= HN_RXINFO_HASHINF;
+ break;
+
+ default:
+ goto next;
+ }
+
+ if (mask == HN_RXINFO_ALL) {
+ /* All found; done */
+ break;
+ }
+next:
+ pi = (const struct rndis_pktinfo *)
+ ((const uint8_t *)pi + pi->rm_size);
+ }
+
+ /*
+ * Final fixup.
+ * - If there is no hash value, invalidate the hash info.
+ */
+ if ((mask & HN_RXINFO_HASHVAL) == 0)
+ info->hash_info = HN_NDIS_HASH_INFO_INVALID;
+ return (0);
+}
+
+static __inline bool
+hn_rndis_check_overlap(int off, int len, int check_off, int check_len)
+{
+
+ if (off < check_off) {
+ if (__predict_true(off + len <= check_off))
+ return (false);
+ } else if (off > check_off) {
+ if (__predict_true(check_off + check_len <= off))
+ return (false);
+ }
+ return (true);
+}
+
+static void
+hn_rndis_rx_data(struct hn_rx_ring *rxr, const void *data, int dlen)
+{
+ const struct rndis_packet_msg *pkt;
+ struct hn_rxinfo info;
+ int data_off, pktinfo_off, data_len, pktinfo_len;
+
+ /*
+ * Check length.
+ */
+ if (__predict_false(dlen < sizeof(*pkt))) {
+ if_printf(rxr->hn_ifp, "invalid RNDIS packet msg\n");
+ return;
+ }
+ pkt = data;
+
+ if (__predict_false(dlen < pkt->rm_len)) {
+ if_printf(rxr->hn_ifp, "truncated RNDIS packet msg, "
+ "dlen %d, msglen %u\n", dlen, pkt->rm_len);
+ return;
+ }
+ if (__predict_false(pkt->rm_len <
+ pkt->rm_datalen + pkt->rm_oobdatalen + pkt->rm_pktinfolen)) {
+ if_printf(rxr->hn_ifp, "invalid RNDIS packet msglen, "
+ "msglen %u, data %u, oob %u, pktinfo %u\n",
+ pkt->rm_len, pkt->rm_datalen, pkt->rm_oobdatalen,
+ pkt->rm_pktinfolen);
+ return;
+ }
+ if (__predict_false(pkt->rm_datalen == 0)) {
+ if_printf(rxr->hn_ifp, "invalid RNDIS packet msg, no data\n");
+ return;
+ }
+
+ /*
+ * Check offests.
+ */
+#define IS_OFFSET_INVALID(ofs) \
+ ((ofs) < RNDIS_PACKET_MSG_OFFSET_MIN || \
+ ((ofs) & RNDIS_PACKET_MSG_OFFSET_ALIGNMASK))
+
+ /* XXX Hyper-V does not meet data offset alignment requirement */
+ if (__predict_false(pkt->rm_dataoffset < RNDIS_PACKET_MSG_OFFSET_MIN)) {
+ if_printf(rxr->hn_ifp, "invalid RNDIS packet msg, "
+ "data offset %u\n", pkt->rm_dataoffset);
+ return;
+ }
+ if (__predict_false(pkt->rm_oobdataoffset > 0 &&
+ IS_OFFSET_INVALID(pkt->rm_oobdataoffset))) {
+ if_printf(rxr->hn_ifp, "invalid RNDIS packet msg, "
+ "oob offset %u\n", pkt->rm_oobdataoffset);
+ return;
+ }
+ if (__predict_true(pkt->rm_pktinfooffset > 0) &&
+ __predict_false(IS_OFFSET_INVALID(pkt->rm_pktinfooffset))) {
+ if_printf(rxr->hn_ifp, "invalid RNDIS packet msg, "
+ "pktinfo offset %u\n", pkt->rm_pktinfooffset);
+ return;
+ }
+
+#undef IS_OFFSET_INVALID
+
+ data_off = RNDIS_PACKET_MSG_OFFSET_ABS(pkt->rm_dataoffset);
+ data_len = pkt->rm_datalen;
+ pktinfo_off = RNDIS_PACKET_MSG_OFFSET_ABS(pkt->rm_pktinfooffset);
+ pktinfo_len = pkt->rm_pktinfolen;
+
+ /*
+ * Check OOB coverage.
+ */
+ if (__predict_false(pkt->rm_oobdatalen != 0)) {
+ int oob_off, oob_len;
+
+ if_printf(rxr->hn_ifp, "got oobdata\n");
+ oob_off = RNDIS_PACKET_MSG_OFFSET_ABS(pkt->rm_oobdataoffset);
+ oob_len = pkt->rm_oobdatalen;
+
+ if (__predict_false(oob_off + oob_len > pkt->rm_len)) {
+ if_printf(rxr->hn_ifp, "invalid RNDIS packet msg, "
+ "oob overflow, msglen %u, oob abs %d len %d\n",
+ pkt->rm_len, oob_off, oob_len);
+ return;
+ }
+
+ /*
+ * Check against data.
+ */
+ if (hn_rndis_check_overlap(oob_off, oob_len,
+ data_off, data_len)) {
+ if_printf(rxr->hn_ifp, "invalid RNDIS packet msg, "
+ "oob overlaps data, oob abs %d len %d, "
+ "data abs %d len %d\n",
+ oob_off, oob_len, data_off, data_len);
+ return;
+ }
+
+ /*
+ * Check against pktinfo.
+ */
+ if (pktinfo_len != 0 &&
+ hn_rndis_check_overlap(oob_off, oob_len,
+ pktinfo_off, pktinfo_len)) {
+ if_printf(rxr->hn_ifp, "invalid RNDIS packet msg, "
+ "oob overlaps pktinfo, oob abs %d len %d, "
+ "pktinfo abs %d len %d\n",
+ oob_off, oob_len, pktinfo_off, pktinfo_len);
+ return;
+ }
+ }
+
+ /*
+ * Check per-packet-info coverage and find useful per-packet-info.
+ */
+ info.vlan_info = HN_NDIS_VLAN_INFO_INVALID;
+ info.csum_info = HN_NDIS_RXCSUM_INFO_INVALID;
+ info.hash_info = HN_NDIS_HASH_INFO_INVALID;
+ if (__predict_true(pktinfo_len != 0)) {
+ bool overlap;
+ int error;
+
+ if (__predict_false(pktinfo_off + pktinfo_len > pkt->rm_len)) {
+ if_printf(rxr->hn_ifp, "invalid RNDIS packet msg, "
+ "pktinfo overflow, msglen %u, "
+ "pktinfo abs %d len %d\n",
+ pkt->rm_len, pktinfo_off, pktinfo_len);
+ return;
+ }
+
+ /*
+ * Check packet info coverage.
+ */
+ overlap = hn_rndis_check_overlap(pktinfo_off, pktinfo_len,
+ data_off, data_len);
+ if (__predict_false(overlap)) {
+ if_printf(rxr->hn_ifp, "invalid RNDIS packet msg, "
+ "pktinfo overlap data, pktinfo abs %d len %d, "
+ "data abs %d len %d\n",
+ pktinfo_off, pktinfo_len, data_off, data_len);
+ return;
+ }
+
+ /*
+ * Find useful per-packet-info.
+ */
+ error = hn_rndis_rxinfo(((const uint8_t *)pkt) + pktinfo_off,
+ pktinfo_len, &info);
+ if (__predict_false(error)) {
+ if_printf(rxr->hn_ifp, "invalid RNDIS packet msg "
+ "pktinfo\n");
+ return;
+ }
+ }
+
+ if (__predict_false(data_off + data_len > pkt->rm_len)) {
+ if_printf(rxr->hn_ifp, "invalid RNDIS packet msg, "
+ "data overflow, msglen %u, data abs %d len %d\n",
+ pkt->rm_len, data_off, data_len);
+ return;
+ }
+ hn_rxpkt(rxr, ((const uint8_t *)pkt) + data_off, data_len, &info);
+}
+
+static __inline void
+hn_rndis_rxpkt(struct hn_rx_ring *rxr, const void *data, int dlen)
+{
+ const struct rndis_msghdr *hdr;
+
+ if (__predict_false(dlen < sizeof(*hdr))) {
+ if_printf(rxr->hn_ifp, "invalid RNDIS msg\n");
+ return;
+ }
+ hdr = data;
+
+ if (__predict_true(hdr->rm_type == REMOTE_NDIS_PACKET_MSG)) {
+ /* Hot data path. */
+ hn_rndis_rx_data(rxr, data, dlen);
+ /* Done! */
+ return;
+ }
+
+ if (hdr->rm_type == REMOTE_NDIS_INDICATE_STATUS_MSG)
+ hn_rndis_rx_status(rxr->hn_ifp->if_softc, data, dlen);
+ else
+ hn_rndis_rx_ctrl(rxr->hn_ifp->if_softc, data, dlen);
+}
+
static void
hn_nvs_handle_notify(struct hn_softc *sc, const struct vmbus_chanpkt_hdr *pkt)
{
@@ -4059,8 +4436,8 @@ hn_nvs_handle_comp(struct hn_softc *sc,
}
static void
-hn_nvs_handle_rxbuf(struct hn_softc *sc, struct hn_rx_ring *rxr,
- struct vmbus_channel *chan, const struct vmbus_chanpkt_hdr *pkthdr)
+hn_nvs_handle_rxbuf(struct hn_rx_ring *rxr, struct vmbus_channel *chan,
+ const struct vmbus_chanpkt_hdr *pkthdr)
{
const struct vmbus_chanpkt_rxbuf *pkt;
const struct hn_nvs_hdr *nvs_hdr;
@@ -4110,9 +4487,9 @@ hn_nvs_handle_rxbuf(struct hn_softc *sc,
"ofs %d, len %d\n", i, ofs, len);
continue;
}
- hv_rf_on_receive(sc, rxr, rxr->hn_rxbuf + ofs, len);
+ hn_rndis_rxpkt(rxr, rxr->hn_rxbuf + ofs, len);
}
-
+
/*
* Moved completion call back here so that all received
* messages (not just data messages) will trigger a response
@@ -4176,7 +4553,7 @@ hn_chan_callback(struct vmbus_channel *c
hn_nvs_handle_comp(sc, chan, pkt);
break;
case VMBUS_CHANPKT_TYPE_RXBUF:
- hn_nvs_handle_rxbuf(sc, rxr, chan, pkt);
+ hn_nvs_handle_rxbuf(rxr, chan, pkt);
break;
case VMBUS_CHANPKT_TYPE_INBAND:
hn_nvs_handle_notify(sc, pkt);
@@ -4213,7 +4590,7 @@ hn_chan_callback(struct vmbus_channel *c
if (bufferlen > HN_PKTBUF_LEN)
free(buffer, M_DEVBUF);
- hv_rf_channel_rollup(rxr, rxr->hn_txr);
+ hn_chan_rollup(rxr, rxr->hn_txr);
}
static void
Modified: stable/11/sys/dev/hyperv/netvsc/hv_rndis_filter.c
==============================================================================
--- stable/11/sys/dev/hyperv/netvsc/hv_rndis_filter.c Mon Nov 14 03:36:59 2016 (r308625)
+++ stable/11/sys/dev/hyperv/netvsc/hv_rndis_filter.c Mon Nov 14 03:49:28 2016 (r308626)
@@ -29,11 +29,12 @@
#include <sys/cdefs.h>
__FBSDID("$FreeBSD$");
+#include "opt_inet6.h"
+#include "opt_inet.h"
+
#include <sys/param.h>
-#include <sys/mbuf.h>
#include <sys/socket.h>
-#include <sys/lock.h>
-#include <sys/mutex.h>
+#include <sys/systm.h>
#include <sys/taskqueue.h>
#include <machine/atomic.h>
@@ -59,16 +60,6 @@ __FBSDID("$FreeBSD$");
#include <dev/hyperv/netvsc/hn_nvs.h>
#include <dev/hyperv/netvsc/hv_rndis_filter.h>
-#define HV_RF_RECVINFO_VLAN 0x1
-#define HV_RF_RECVINFO_CSUM 0x2
-#define HV_RF_RECVINFO_HASHINF 0x4
-#define HV_RF_RECVINFO_HASHVAL 0x8
-#define HV_RF_RECVINFO_ALL \
- (HV_RF_RECVINFO_VLAN | \
- HV_RF_RECVINFO_CSUM | \
- HV_RF_RECVINFO_HASHINF | \
- HV_RF_RECVINFO_HASHVAL)
-
#define HN_RNDIS_RID_COMPAT_MASK 0xffff
#define HN_RNDIS_RID_COMPAT_MAX HN_RNDIS_RID_COMPAT_MASK
@@ -86,24 +77,23 @@ __FBSDID("$FreeBSD$");
#define HN_NDIS_LSOV2_CAP_IP6 \
(NDIS_LSOV2_CAP_IP6EXT | NDIS_LSOV2_CAP_TCP6OPT)
-/*
- * Forward declarations
- */
-static void hv_rf_receive_indicate_status(struct hn_softc *sc,
- const void *data, int dlen);
-static void hv_rf_receive_data(struct hn_rx_ring *rxr,
- const void *data, int dlen);
-
-static int hn_rndis_query(struct hn_softc *sc, uint32_t oid,
- const void *idata, size_t idlen, void *odata, size_t *odlen0);
-static int hn_rndis_query2(struct hn_softc *sc, uint32_t oid,
- const void *idata, size_t idlen, void *odata, size_t *odlen0,
- size_t min_odlen);
-static int hn_rndis_set(struct hn_softc *sc, uint32_t oid, const void *data,
- size_t dlen);
-static int hn_rndis_conf_offload(struct hn_softc *sc, int mtu);
-static int hn_rndis_query_hwcaps(struct hn_softc *sc,
- struct ndis_offload *caps);
+static const void *hn_rndis_xact_exec1(struct hn_softc *,
+ struct vmbus_xact *, size_t,
+ struct hn_nvs_sendctx *, size_t *);
+static const void *hn_rndis_xact_execute(struct hn_softc *,
+ struct vmbus_xact *, uint32_t, size_t, size_t *,
+ uint32_t);
+static int hn_rndis_query(struct hn_softc *, uint32_t,
+ const void *, size_t, void *, size_t *);
+static int hn_rndis_query2(struct hn_softc *, uint32_t,
+ const void *, size_t, void *, size_t *, size_t);
+static int hn_rndis_set(struct hn_softc *, uint32_t,
+ const void *, size_t);
+static int hn_rndis_init(struct hn_softc *);
+static int hn_rndis_halt(struct hn_softc *);
+static int hn_rndis_conf_offload(struct hn_softc *, int);
+static int hn_rndis_query_hwcaps(struct hn_softc *,
+ struct ndis_offload *);
static __inline uint32_t
hn_rndis_rid(struct hn_softc *sc)
@@ -119,371 +109,22 @@ again:
return ((rid & 0xffff) << 16);
}
-void *
-hn_rndis_pktinfo_append(struct rndis_packet_msg *pkt, size_t pktsize,
- size_t pi_dlen, uint32_t pi_type)
-{
- const size_t pi_size = HN_RNDIS_PKTINFO_SIZE(pi_dlen);
- struct rndis_pktinfo *pi;
-
- KASSERT((pi_size & RNDIS_PACKET_MSG_OFFSET_ALIGNMASK) == 0,
- ("unaligned pktinfo size %zu, pktinfo dlen %zu", pi_size, pi_dlen));
-
- /*
- * Per-packet-info does not move; it only grows.
- *
- * NOTE:
- * rm_pktinfooffset in this phase counts from the beginning
- * of rndis_packet_msg.
- */
- KASSERT(pkt->rm_pktinfooffset + pkt->rm_pktinfolen + pi_size <= pktsize,
- ("%u pktinfo overflows RNDIS packet msg", pi_type));
- pi = (struct rndis_pktinfo *)((uint8_t *)pkt + pkt->rm_pktinfooffset +
- pkt->rm_pktinfolen);
- pkt->rm_pktinfolen += pi_size;
-
- pi->rm_size = pi_size;
- pi->rm_type = pi_type;
- pi->rm_pktinfooffset = RNDIS_PKTINFO_OFFSET;
-
- /* Data immediately follow per-packet-info. */
- pkt->rm_dataoffset += pi_size;
-
- /* Update RNDIS packet msg length */
- pkt->rm_len += pi_size;
-
- return (pi->rm_data);
-}
-
-/*
- * RNDIS filter receive indicate status
- */
-static void
-hv_rf_receive_indicate_status(struct hn_softc *sc, const void *data, int dlen)
-{
- const struct rndis_status_msg *msg;
- int ofs;
-
- if (dlen < sizeof(*msg)) {
- if_printf(sc->hn_ifp, "invalid RNDIS status\n");
- return;
- }
- msg = data;
-
- switch (msg->rm_status) {
- case RNDIS_STATUS_MEDIA_CONNECT:
- case RNDIS_STATUS_MEDIA_DISCONNECT:
- hn_link_status_update(sc);
- break;
-
- case RNDIS_STATUS_TASK_OFFLOAD_CURRENT_CONFIG:
- /* Not really useful; ignore. */
- break;
-
- case RNDIS_STATUS_NETWORK_CHANGE:
- ofs = RNDIS_STBUFOFFSET_ABS(msg->rm_stbufoffset);
- if (dlen < ofs + msg->rm_stbuflen ||
- msg->rm_stbuflen < sizeof(uint32_t)) {
- if_printf(sc->hn_ifp, "network changed\n");
- } else {
- uint32_t change;
-
- memcpy(&change, ((const uint8_t *)msg) + ofs,
- sizeof(change));
- if_printf(sc->hn_ifp, "network changed, change %u\n",
- change);
- }
- hn_network_change(sc);
- break;
-
- default:
- /* TODO: */
- if_printf(sc->hn_ifp, "unknown RNDIS status 0x%08x\n",
- msg->rm_status);
- break;
- }
-}
-
-static int
-hn_rndis_rxinfo(const void *info_data, int info_dlen, struct hn_recvinfo *info)
-{
- const struct rndis_pktinfo *pi = info_data;
- uint32_t mask = 0;
-
- while (info_dlen != 0) {
- const void *data;
- uint32_t dlen;
-
- if (__predict_false(info_dlen < sizeof(*pi)))
- return (EINVAL);
- if (__predict_false(info_dlen < pi->rm_size))
- return (EINVAL);
- info_dlen -= pi->rm_size;
-
- if (__predict_false(pi->rm_size & RNDIS_PKTINFO_SIZE_ALIGNMASK))
- return (EINVAL);
- if (__predict_false(pi->rm_size < pi->rm_pktinfooffset))
- return (EINVAL);
- dlen = pi->rm_size - pi->rm_pktinfooffset;
- data = pi->rm_data;
-
- switch (pi->rm_type) {
- case NDIS_PKTINFO_TYPE_VLAN:
- if (__predict_false(dlen < NDIS_VLAN_INFO_SIZE))
- return (EINVAL);
- info->vlan_info = *((const uint32_t *)data);
- mask |= HV_RF_RECVINFO_VLAN;
- break;
-
- case NDIS_PKTINFO_TYPE_CSUM:
- if (__predict_false(dlen < NDIS_RXCSUM_INFO_SIZE))
- return (EINVAL);
- info->csum_info = *((const uint32_t *)data);
- mask |= HV_RF_RECVINFO_CSUM;
- break;
-
- case HN_NDIS_PKTINFO_TYPE_HASHVAL:
- if (__predict_false(dlen < HN_NDIS_HASH_VALUE_SIZE))
- return (EINVAL);
- info->hash_value = *((const uint32_t *)data);
- mask |= HV_RF_RECVINFO_HASHVAL;
- break;
-
- case HN_NDIS_PKTINFO_TYPE_HASHINF:
- if (__predict_false(dlen < HN_NDIS_HASH_INFO_SIZE))
- return (EINVAL);
- info->hash_info = *((const uint32_t *)data);
- mask |= HV_RF_RECVINFO_HASHINF;
- break;
-
- default:
- goto next;
- }
-
- if (mask == HV_RF_RECVINFO_ALL) {
- /* All found; done */
- break;
- }
-next:
- pi = (const struct rndis_pktinfo *)
- ((const uint8_t *)pi + pi->rm_size);
- }
-
- /*
- * Final fixup.
- * - If there is no hash value, invalidate the hash info.
- */
- if ((mask & HV_RF_RECVINFO_HASHVAL) == 0)
- info->hash_info = HN_NDIS_HASH_INFO_INVALID;
- return (0);
-}
-
-static __inline bool
-hn_rndis_check_overlap(int off, int len, int check_off, int check_len)
-{
-
- if (off < check_off) {
- if (__predict_true(off + len <= check_off))
- return (false);
- } else if (off > check_off) {
- if (__predict_true(check_off + check_len <= off))
- return (false);
- }
- return (true);
-}
-
-/*
- * RNDIS filter receive data
- */
-static void
-hv_rf_receive_data(struct hn_rx_ring *rxr, const void *data, int dlen)
-{
- const struct rndis_packet_msg *pkt;
- struct hn_recvinfo info;
- int data_off, pktinfo_off, data_len, pktinfo_len;
-
- /*
- * Check length.
- */
- if (__predict_false(dlen < sizeof(*pkt))) {
- if_printf(rxr->hn_ifp, "invalid RNDIS packet msg\n");
- return;
- }
- pkt = data;
-
- if (__predict_false(dlen < pkt->rm_len)) {
- if_printf(rxr->hn_ifp, "truncated RNDIS packet msg, "
- "dlen %d, msglen %u\n", dlen, pkt->rm_len);
- return;
- }
- if (__predict_false(pkt->rm_len <
- pkt->rm_datalen + pkt->rm_oobdatalen + pkt->rm_pktinfolen)) {
- if_printf(rxr->hn_ifp, "invalid RNDIS packet msglen, "
- "msglen %u, data %u, oob %u, pktinfo %u\n",
- pkt->rm_len, pkt->rm_datalen, pkt->rm_oobdatalen,
- pkt->rm_pktinfolen);
- return;
- }
- if (__predict_false(pkt->rm_datalen == 0)) {
- if_printf(rxr->hn_ifp, "invalid RNDIS packet msg, no data\n");
- return;
- }
-
- /*
- * Check offests.
- */
-#define IS_OFFSET_INVALID(ofs) \
- ((ofs) < RNDIS_PACKET_MSG_OFFSET_MIN || \
- ((ofs) & RNDIS_PACKET_MSG_OFFSET_ALIGNMASK))
-
- /* XXX Hyper-V does not meet data offset alignment requirement */
- if (__predict_false(pkt->rm_dataoffset < RNDIS_PACKET_MSG_OFFSET_MIN)) {
- if_printf(rxr->hn_ifp, "invalid RNDIS packet msg, "
- "data offset %u\n", pkt->rm_dataoffset);
- return;
- }
- if (__predict_false(pkt->rm_oobdataoffset > 0 &&
- IS_OFFSET_INVALID(pkt->rm_oobdataoffset))) {
- if_printf(rxr->hn_ifp, "invalid RNDIS packet msg, "
- "oob offset %u\n", pkt->rm_oobdataoffset);
- return;
- }
- if (__predict_true(pkt->rm_pktinfooffset > 0) &&
- __predict_false(IS_OFFSET_INVALID(pkt->rm_pktinfooffset))) {
- if_printf(rxr->hn_ifp, "invalid RNDIS packet msg, "
- "pktinfo offset %u\n", pkt->rm_pktinfooffset);
- return;
- }
-
-#undef IS_OFFSET_INVALID
-
- data_off = RNDIS_PACKET_MSG_OFFSET_ABS(pkt->rm_dataoffset);
- data_len = pkt->rm_datalen;
- pktinfo_off = RNDIS_PACKET_MSG_OFFSET_ABS(pkt->rm_pktinfooffset);
- pktinfo_len = pkt->rm_pktinfolen;
-
- /*
- * Check OOB coverage.
- */
- if (__predict_false(pkt->rm_oobdatalen != 0)) {
- int oob_off, oob_len;
-
- if_printf(rxr->hn_ifp, "got oobdata\n");
- oob_off = RNDIS_PACKET_MSG_OFFSET_ABS(pkt->rm_oobdataoffset);
- oob_len = pkt->rm_oobdatalen;
-
- if (__predict_false(oob_off + oob_len > pkt->rm_len)) {
- if_printf(rxr->hn_ifp, "invalid RNDIS packet msg, "
- "oob overflow, msglen %u, oob abs %d len %d\n",
- pkt->rm_len, oob_off, oob_len);
- return;
- }
-
- /*
- * Check against data.
- */
- if (hn_rndis_check_overlap(oob_off, oob_len,
- data_off, data_len)) {
- if_printf(rxr->hn_ifp, "invalid RNDIS packet msg, "
- "oob overlaps data, oob abs %d len %d, "
- "data abs %d len %d\n",
- oob_off, oob_len, data_off, data_len);
- return;
- }
-
- /*
- * Check against pktinfo.
- */
- if (pktinfo_len != 0 &&
- hn_rndis_check_overlap(oob_off, oob_len,
- pktinfo_off, pktinfo_len)) {
- if_printf(rxr->hn_ifp, "invalid RNDIS packet msg, "
- "oob overlaps pktinfo, oob abs %d len %d, "
- "pktinfo abs %d len %d\n",
- oob_off, oob_len, pktinfo_off, pktinfo_len);
- return;
- }
- }
-
- /*
- * Check per-packet-info coverage and find useful per-packet-info.
- */
- info.vlan_info = HN_NDIS_VLAN_INFO_INVALID;
- info.csum_info = HN_NDIS_RXCSUM_INFO_INVALID;
- info.hash_info = HN_NDIS_HASH_INFO_INVALID;
- if (__predict_true(pktinfo_len != 0)) {
- bool overlap;
- int error;
-
- if (__predict_false(pktinfo_off + pktinfo_len > pkt->rm_len)) {
- if_printf(rxr->hn_ifp, "invalid RNDIS packet msg, "
- "pktinfo overflow, msglen %u, "
- "pktinfo abs %d len %d\n",
- pkt->rm_len, pktinfo_off, pktinfo_len);
- return;
- }
-
- /*
- * Check packet info coverage.
- */
- overlap = hn_rndis_check_overlap(pktinfo_off, pktinfo_len,
- data_off, data_len);
- if (__predict_false(overlap)) {
- if_printf(rxr->hn_ifp, "invalid RNDIS packet msg, "
- "pktinfo overlap data, pktinfo abs %d len %d, "
- "data abs %d len %d\n",
- pktinfo_off, pktinfo_len, data_off, data_len);
- return;
- }
-
- /*
- * Find useful per-packet-info.
- */
- error = hn_rndis_rxinfo(((const uint8_t *)pkt) + pktinfo_off,
- pktinfo_len, &info);
- if (__predict_false(error)) {
- if_printf(rxr->hn_ifp, "invalid RNDIS packet msg "
- "pktinfo\n");
- return;
- }
- }
-
- if (__predict_false(data_off + data_len > pkt->rm_len)) {
- if_printf(rxr->hn_ifp, "invalid RNDIS packet msg, "
- "data overflow, msglen %u, data abs %d len %d\n",
- pkt->rm_len, data_off, data_len);
- return;
- }
- hn_rxpkt(rxr, ((const uint8_t *)pkt) + data_off, data_len, &info);
-}
-
-/*
- * RNDIS filter on receive
- */
void
-hv_rf_on_receive(struct hn_softc *sc, struct hn_rx_ring *rxr,
- const void *data, int dlen)
+hn_rndis_rx_ctrl(struct hn_softc *sc, const void *data, int dlen)
{
const struct rndis_comp_hdr *comp;
const struct rndis_msghdr *hdr;
- if (__predict_false(dlen < sizeof(*hdr))) {
- if_printf(rxr->hn_ifp, "invalid RNDIS msg\n");
- return;
- }
+ KASSERT(dlen >= sizeof(*hdr), ("invalid RNDIS msg\n"));
hdr = data;
switch (hdr->rm_type) {
- case REMOTE_NDIS_PACKET_MSG:
- hv_rf_receive_data(rxr, data, dlen);
- break;
-
case REMOTE_NDIS_INITIALIZE_CMPLT:
case REMOTE_NDIS_QUERY_CMPLT:
case REMOTE_NDIS_SET_CMPLT:
case REMOTE_NDIS_KEEPALIVE_CMPLT: /* unused */
if (dlen < sizeof(*comp)) {
- if_printf(rxr->hn_ifp, "invalid RNDIS cmplt\n");
+ if_printf(sc->hn_ifp, "invalid RNDIS cmplt\n");
return;
}
comp = data;
@@ -493,10 +134,6 @@ hv_rf_on_receive(struct hn_softc *sc, st
vmbus_xact_ctx_wakeup(sc->hn_xact, comp, dlen);
break;
- case REMOTE_NDIS_INDICATE_STATUS_MSG:
- hv_rf_receive_indicate_status(sc, data, dlen);
- break;
-
case REMOTE_NDIS_RESET_CMPLT:
/*
* Reset completed, no rid.
@@ -505,11 +142,11 @@ hv_rf_on_receive(struct hn_softc *sc, st
* RESET is not issued by hn(4), so this message should
* _not_ be observed.
*/
- if_printf(rxr->hn_ifp, "RESET cmplt received\n");
+ if_printf(sc->hn_ifp, "RESET cmplt received\n");
break;
default:
- if_printf(rxr->hn_ifp, "unknown RNDIS msg 0x%x\n",
+ if_printf(sc->hn_ifp, "unknown RNDIS msg 0x%x\n",
hdr->rm_type);
break;
}
@@ -1352,10 +989,3 @@ hn_rndis_detach(struct hn_softc *sc)
/* Halt the RNDIS. */
hn_rndis_halt(sc);
*** DIFF OUTPUT TRUNCATED AT 1000 LINES ***
More information about the svn-src-all
mailing list