svn commit: r304832 - in head/sys: dev/hyperv/netvsc net

Sepherosa Ziehau sephe at FreeBSD.org
Fri Aug 26 05:12:10 UTC 2016


Author: sephe
Date: Fri Aug 26 05:12:09 2016
New Revision: 304832
URL: https://svnweb.freebsd.org/changeset/base/304832

Log:
  hyperv/hn: Use vmbus xact for RNDIS query.
  
  And switch MAC address query to use new RNDIS query function.
  
  MFC after:	1 week
  Sponsored by:	Microsoft
  Differential Revision:	https://reviews.freebsd.org/D7639

Modified:
  head/sys/dev/hyperv/netvsc/hv_rndis_filter.c
  head/sys/net/rndis.h

Modified: head/sys/dev/hyperv/netvsc/hv_rndis_filter.c
==============================================================================
--- head/sys/dev/hyperv/netvsc/hv_rndis_filter.c	Fri Aug 26 04:31:19 2016	(r304831)
+++ head/sys/dev/hyperv/netvsc/hv_rndis_filter.c	Fri Aug 26 05:12:09 2016	(r304832)
@@ -96,6 +96,8 @@ static void hn_rndis_sent_halt(struct hn
 static void hn_rndis_sent_cb(struct hn_send_ctx *sndc,
     struct hn_softc *sc, struct vmbus_channel *chan,
     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 __inline uint32_t
 hn_rndis_rid(struct hn_softc *sc)
@@ -695,13 +697,23 @@ cleanup:
 /*
  * RNDIS filter query device MAC address
  */
-static inline int
+static int
 hv_rf_query_device_mac(rndis_device *device)
 {
-	uint32_t size = ETHER_ADDR_LEN;
+	struct hn_softc *sc = device->sc;
+	size_t hwaddr_len;
+	int error;
 
-	return (hv_rf_query_device(device,
-	    RNDIS_OID_802_3_PERMANENT_ADDRESS, device->hw_mac_addr, &size));
+	hwaddr_len = ETHER_ADDR_LEN;
+	error = hn_rndis_query(sc, OID_802_3_PERMANENT_ADDRESS, NULL, 0,
+	    device->hw_mac_addr, &hwaddr_len);
+	if (error)
+		return error;
+	if (hwaddr_len != ETHER_ADDR_LEN) {
+		if_printf(sc->hn_ifp, "invalid hwaddr len %zu\n", hwaddr_len);
+		return EINVAL;
+	}
+	return 0;
 }
 
 /*
@@ -892,12 +904,12 @@ exit:
 
 static const void *
 hn_rndis_xact_execute(struct hn_softc *sc, struct vmbus_xact *xact, uint32_t rid,
-    size_t reqlen, size_t min_complen, uint32_t comp_type)
+    size_t reqlen, size_t *comp_len0, uint32_t comp_type)
 {
 	struct vmbus_gpa gpa[HN_XACT_REQ_PGCNT];
 	const struct rndis_comp_hdr *comp;
 	bus_addr_t paddr;
-	size_t comp_len;
+	size_t comp_len, min_complen = *comp_len0;
 	int gpa_cnt, error;
 
 	KASSERT(rid > HN_RNDIS_RID_COMPAT_MAX, ("invalid rid %u\n", rid));
@@ -946,7 +958,14 @@ hn_rndis_xact_execute(struct hn_softc *s
 	 * Check this RNDIS complete message.
 	 */
 	if (comp_len < min_complen) {
-		if_printf(sc->hn_ifp, "invalid RNDIS comp len %zu\n", comp_len);
+		if (comp_len >= sizeof(*comp)) {
+			/* rm_status field is valid */
+			if_printf(sc->hn_ifp, "invalid RNDIS comp len %zu, "
+			    "status 0x%08x\n", comp_len, comp->rm_status);
+		} else {
+			if_printf(sc->hn_ifp, "invalid RNDIS comp len %zu\n",
+			    comp_len);
+		}
 		return (NULL);
 	}
 	if (comp->rm_len < min_complen) {
@@ -965,9 +984,100 @@ hn_rndis_xact_execute(struct hn_softc *s
 		return (NULL);
 	}
 	/* All pass! */
+	*comp_len0 = comp_len;
 	return (comp);
 }
 
+static int
+hn_rndis_query(struct hn_softc *sc, uint32_t oid,
+    const void *idata, size_t idlen, void *odata, size_t *odlen0)
+{
+	struct rndis_query_req *req;
+	const struct rndis_query_comp *comp;
+	struct vmbus_xact *xact;
+	size_t reqlen, odlen = *odlen0, comp_len;
+	int error, ofs;
+	uint32_t rid;
+
+	reqlen = sizeof(*req) + idlen;
+	xact = vmbus_xact_get(sc->hn_xact, reqlen);
+	if (xact == NULL) {
+		if_printf(sc->hn_ifp, "no xact for RNDIS query\n");
+		return (ENXIO);
+	}
+	rid = hn_rndis_rid(sc);
+	req = vmbus_xact_req_data(xact);
+	req->rm_type = REMOTE_NDIS_QUERY_MSG;
+	req->rm_len = reqlen;
+	req->rm_rid = rid;
+	req->rm_oid = oid;
+	/*
+	 * XXX
+	 * This is _not_ RNDIS Spec conforming:
+	 * "This MUST be set to 0 when there is no input data
+	 *  associated with the OID."
+	 *
+	 * If this field was set to 0 according to the RNDIS Spec,
+	 * Hyper-V would set non-SUCCESS status in the query
+	 * completion.
+	 */
+	req->rm_infobufoffset = RNDIS_QUERY_REQ_INFOBUFOFFSET;
+
+	if (idlen > 0) {
+		req->rm_infobuflen = idlen;
+		/* Input data immediately follows RNDIS query. */
+		memcpy(req + 1, idata, idlen);
+	}
+
+	comp_len = sizeof(*comp) + odlen;
+	comp = hn_rndis_xact_execute(sc, xact, rid, reqlen, &comp_len,
+	    REMOTE_NDIS_QUERY_CMPLT);
+	if (comp == NULL) {
+		if_printf(sc->hn_ifp, "exec RNDIS query 0x%08x failed\n", oid);
+		error = EIO;
+		goto done;
+	}
+
+	if (comp->rm_status != RNDIS_STATUS_SUCCESS) {
+		if_printf(sc->hn_ifp, "RNDIS query 0x%08x failed: "
+		    "status 0x%08x\n", oid, comp->rm_status);
+		error = EIO;
+		goto done;
+	}
+	if (comp->rm_infobuflen == 0 || comp->rm_infobufoffset == 0) {
+		/* No output data! */
+		if_printf(sc->hn_ifp, "RNDIS query 0x%08x, no data\n", oid);
+		*odlen0 = 0;
+		error = 0;
+		goto done;
+	}
+
+	/*
+	 * Check output data length and offset.
+	 */
+	/* ofs is the offset from the beginning of comp. */
+	ofs = RNDIS_QUERY_COMP_INFOBUFABS(comp->rm_infobufoffset);
+	if (ofs < sizeof(*comp) || ofs + comp->rm_infobuflen > comp_len) {
+		if_printf(sc->hn_ifp, "RNDIS query invalid comp ib off/len, "
+		    "%u/%u\n", comp->rm_infobufoffset, comp->rm_infobuflen);
+		error = EINVAL;
+		goto done;
+	}
+
+	/*
+	 * Save output data.
+	 */
+	if (comp->rm_infobuflen < odlen)
+		odlen = comp->rm_infobuflen;
+	memcpy(odata, ((const uint8_t *)comp) + ofs, odlen);
+	*odlen0 = odlen;
+
+	error = 0;
+done:
+	vmbus_xact_put(xact);
+	return (error);
+}
+
 /*
  * RNDIS filter init device
  */
@@ -978,6 +1088,7 @@ hv_rf_init_device(rndis_device *device)
 	struct rndis_init_req *req;
 	const struct rndis_init_comp *comp;
 	struct vmbus_xact *xact;
+	size_t comp_len;
 	uint32_t rid;
 	int error;
 
@@ -998,8 +1109,9 @@ hv_rf_init_device(rndis_device *device)
 	req->rm_ver_minor = RNDIS_VERSION_MINOR;
 	req->rm_max_xfersz = HN_RNDIS_XFER_SIZE;
 
-	comp = hn_rndis_xact_execute(sc, xact, rid, sizeof(*req),
-	    RNDIS_INIT_COMP_SIZE_MIN, REMOTE_NDIS_INITIALIZE_CMPLT);
+	comp_len = RNDIS_INIT_COMP_SIZE_MIN;
+	comp = hn_rndis_xact_execute(sc, xact, rid, sizeof(*req), &comp_len,
+	    REMOTE_NDIS_INITIALIZE_CMPLT);
 	if (comp == NULL) {
 		if_printf(sc->hn_ifp, "exec RNDIS init failed\n");
 		error = EIO;

Modified: head/sys/net/rndis.h
==============================================================================
--- head/sys/net/rndis.h	Fri Aug 26 04:31:19 2016	(r304831)
+++ head/sys/net/rndis.h	Fri Aug 26 05:12:09 2016	(r304832)
@@ -172,6 +172,10 @@ struct rndis_query_req {
 	uint32_t rm_devicevchdl;
 };
 
+#define	RNDIS_QUERY_REQ_INFOBUFOFFSET		\
+	(sizeof(struct rndis_query_req) -	\
+	 __offsetof(struct rndis_query_req, rm_rid))
+
 struct rndis_query_comp {
 	uint32_t rm_type;
 	uint32_t rm_len;
@@ -181,6 +185,9 @@ struct rndis_query_comp {
 	uint32_t rm_infobufoffset;
 };
 
+#define	RNDIS_QUERY_COMP_INFOBUFABS(ofs)	\
+	((ofs) + __offsetof(struct rndis_query_req, rm_rid))
+
 /* Send a set object request. */
 #define	REMOTE_NDIS_SET_MSG		0x00000005
 #define	REMOTE_NDIS_SET_CMPLT		0x80000005


More information about the svn-src-head mailing list