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
_______________________________________________
svn-src-all@freebsd.org mailing list
https://lists.freebsd.org/mailman/listinfo/svn-src-all
To unsubscribe, send any mail to "svn-src-all-unsubscr...@freebsd.org"

Reply via email to