svn commit: r308014 - head/sys/dev/hyperv/netvsc

Sepherosa Ziehau sephe at FreeBSD.org
Fri Oct 28 08:08:48 UTC 2016


Author: sephe
Date: Fri Oct 28 08:08:46 2016
New Revision: 308014
URL: https://svnweb.freebsd.org/changeset/base/308014

Log:
  hyperv/hn: Reorganize RX path; mainly pull non-control code path up
  
  MFC after:	1 week
  Sponsored by:	Microsoft
  Differential Revision:	https://reviews.freebsd.org/D8356

Modified:
  head/sys/dev/hyperv/netvsc/hv_netvsc_drv_freebsd.c
  head/sys/dev/hyperv/netvsc/hv_rndis_filter.c
  head/sys/dev/hyperv/netvsc/hv_rndis_filter.h
  head/sys/dev/hyperv/netvsc/if_hnvar.h

Modified: head/sys/dev/hyperv/netvsc/hv_netvsc_drv_freebsd.c
==============================================================================
--- head/sys/dev/hyperv/netvsc/hv_netvsc_drv_freebsd.c	Fri Oct 28 07:59:02 2016	(r308013)
+++ head/sys/dev/hyperv/netvsc/hv_netvsc_drv_freebsd.c	Fri Oct 28 08:08:46 2016	(r308014)
@@ -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. */
@@ -377,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);
@@ -1006,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)
 {
 
@@ -1014,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)
 {
 
@@ -1615,15 +1642,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;
@@ -4025,6 +4046,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)
 {
@@ -4060,8 +4400,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;
@@ -4111,9 +4451,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
@@ -4177,7 +4517,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);

Modified: head/sys/dev/hyperv/netvsc/hv_rndis_filter.c
==============================================================================
--- head/sys/dev/hyperv/netvsc/hv_rndis_filter.c	Fri Oct 28 07:59:02 2016	(r308013)
+++ head/sys/dev/hyperv/netvsc/hv_rndis_filter.c	Fri Oct 28 08:08:46 2016	(r308014)
@@ -59,16 +59,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
 
@@ -89,11 +79,6 @@ __FBSDID("$FreeBSD$");
 /*
  * 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,
@@ -155,335 +140,22 @@ hn_rndis_pktinfo_append(struct rndis_pac
 	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 +165,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 +173,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;
 	}

Modified: head/sys/dev/hyperv/netvsc/hv_rndis_filter.h
==============================================================================
--- head/sys/dev/hyperv/netvsc/hv_rndis_filter.h	Fri Oct 28 07:59:02 2016	(r308013)
+++ head/sys/dev/hyperv/netvsc/hv_rndis_filter.h	Fri Oct 28 08:08:46 2016	(r308014)
@@ -31,16 +31,9 @@
 #ifndef __HV_RNDIS_FILTER_H__
 #define __HV_RNDIS_FILTER_H__
 
-#include <sys/param.h>
-#include <net/ethernet.h>
-#include <dev/hyperv/netvsc/if_hnvar.h>
+struct hn_softc;
 
-/*
- * Externs
- */
-struct hn_rx_ring;
-
-void hv_rf_on_receive(struct hn_softc *sc, struct hn_rx_ring *rxr,
-    const void *data, int dlen);
+void		hn_rndis_rx_ctrl(struct hn_softc *sc, const void *data,
+		    int dlen);
 
 #endif  /* __HV_RNDIS_FILTER_H__ */

Modified: head/sys/dev/hyperv/netvsc/if_hnvar.h
==============================================================================
--- head/sys/dev/hyperv/netvsc/if_hnvar.h	Fri Oct 28 07:59:02 2016	(r308013)
+++ head/sys/dev/hyperv/netvsc/if_hnvar.h	Fri Oct 28 08:08:46 2016	(r308014)
@@ -51,17 +51,6 @@
 
 #define HN_GPACNT_MAX			32
 
-#define HN_NDIS_VLAN_INFO_INVALID	0xffffffff
-#define HN_NDIS_RXCSUM_INFO_INVALID	0
-#define HN_NDIS_HASH_INFO_INVALID	0
-
-struct hn_recvinfo {
-	uint32_t			vlan_info;
-	uint32_t			csum_info;
-	uint32_t			hash_info;
-	uint32_t			hash_value;
-};
-
 struct hn_txdesc;
 #ifndef HN_USE_TXDESC_BUFRING
 SLIST_HEAD(hn_txdesc_list, hn_txdesc);
@@ -256,9 +245,4 @@ int		hn_rndis_get_linkstatus(struct hn_s
 /* filter: NDIS_PACKET_TYPE_. */
 int		hn_rndis_set_rxfilter(struct hn_softc *sc, uint32_t filter);
 
-int		hn_rxpkt(struct hn_rx_ring *rxr, const void *data, int dlen,
-		    const struct hn_recvinfo *info);
-void		hn_link_status_update(struct hn_softc *sc);
-void		hn_network_change(struct hn_softc *sc);
-
 #endif	/* !_IF_HNVAR_H_ */


More information about the svn-src-head mailing list