Skip site navigation (1)Skip section navigation (2)
Date:      Fri, 11 Nov 2016 06:23:01 +0000 (UTC)
From:      Sepherosa Ziehau <sephe@FreeBSD.org>
To:        src-committers@freebsd.org, svn-src-all@freebsd.org, svn-src-stable@freebsd.org, svn-src-stable-10@freebsd.org
Subject:   svn commit: r308506 - stable/10/sys/dev/hyperv/netvsc
Message-ID:  <201611110623.uAB6N1aI062429@repo.freebsd.org>

next in thread | raw e-mail | index | archive | help
Author: sephe
Date: Fri Nov 11 06:23:01 2016
New Revision: 308506
URL: https://svnweb.freebsd.org/changeset/base/308506

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/10/sys/dev/hyperv/netvsc/hv_netvsc_drv_freebsd.c
  stable/10/sys/dev/hyperv/netvsc/hv_rndis_filter.c
  stable/10/sys/dev/hyperv/netvsc/hv_rndis_filter.h
  stable/10/sys/dev/hyperv/netvsc/if_hnvar.h
Directory Properties:
  stable/10/   (props changed)

Modified: stable/10/sys/dev/hyperv/netvsc/hv_netvsc_drv_freebsd.c
==============================================================================
--- stable/10/sys/dev/hyperv/netvsc/hv_netvsc_drv_freebsd.c	Fri Nov 11 05:53:58 2016	(r308505)
+++ stable/10/sys/dev/hyperv/netvsc/hv_netvsc_drv_freebsd.c	Fri Nov 11 06:23:01 2016	(r308506)
@@ -168,6 +168,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;
@@ -190,6 +200,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. */
@@ -360,6 +381,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 *);
@@ -378,12 +400,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);
@@ -1021,7 +1049,7 @@ hn_netchg_status_taskfunc(void *xsc, int
 	hn_link_status(sc);
 }
 
-void
+static void
 hn_link_status_update(struct hn_softc *sc)
 {
 
@@ -1029,7 +1057,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)
 {
 
@@ -1204,7 +1232,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)
@@ -1238,6 +1266,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.
@@ -1636,15 +1700,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;
@@ -4044,6 +4102,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)
 {
@@ -4079,8 +4456,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;
@@ -4130,9 +4507,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
@@ -4196,7 +4573,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);
@@ -4233,7 +4610,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/10/sys/dev/hyperv/netvsc/hv_rndis_filter.c
==============================================================================
--- stable/10/sys/dev/hyperv/netvsc/hv_rndis_filter.c	Fri Nov 11 05:53:58 2016	(r308505)
+++ stable/10/sys/dev/hyperv/netvsc/hv_rndis_filter.c	Fri Nov 11 06:23:01 2016	(r308506)
@@ -29,12 +29,12 @@
 #include <sys/cdefs.h>
 __FBSDID("$FreeBSD$");
 
+#include "opt_inet6.h"
+#include "opt_inet.h"
+
 #include <sys/param.h>
-#include <sys/kernel.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>
@@ -61,16 +61,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
 
@@ -88,24 +78,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)
@@ -121,371 +110,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;
@@ -495,10 +135,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.
@@ -507,11 +143,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;
 	}
@@ -1354,10 +990,3 @@ hn_rndis_detach(struct hn_softc *sc)
 	/* Halt the RNDIS. */

*** DIFF OUTPUT TRUNCATED AT 1000 LINES ***



Want to link to this message? Use this URL: <https://mail-archive.FreeBSD.org/cgi/mid.cgi?201611110623.uAB6N1aI062429>