Author: sephe
Date: Mon May 16 03:26:16 2016
New Revision: 299888
URL: https://svnweb.freebsd.org/changeset/base/299888

Log:
  hyperv/hn: Combine per-packet-information parsing.
  
  MFC after:    1 week
  Sponsored by: Microsoft OSTC

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

Modified: head/sys/dev/hyperv/netvsc/hv_netvsc_drv_freebsd.c
==============================================================================
--- head/sys/dev/hyperv/netvsc/hv_netvsc_drv_freebsd.c  Mon May 16 02:44:22 
2016        (r299887)
+++ head/sys/dev/hyperv/netvsc/hv_netvsc_drv_freebsd.c  Mon May 16 03:26:16 
2016        (r299888)
@@ -1291,7 +1291,7 @@ hv_m_append(struct mbuf *m0, int len, c_
  */
 int
 netvsc_recv(struct hv_vmbus_channel *chan, netvsc_packet *packet,
-    rndis_tcp_ip_csum_info *csum_info,
+    const rndis_tcp_ip_csum_info *csum_info,
     const struct rndis_hash_info *hash_info,
     const struct rndis_hash_value *hash_value)
 {

Modified: head/sys/dev/hyperv/netvsc/hv_rndis.h
==============================================================================
--- head/sys/dev/hyperv/netvsc/hv_rndis.h       Mon May 16 02:44:22 2016        
(r299887)
+++ head/sys/dev/hyperv/netvsc/hv_rndis.h       Mon May 16 03:26:16 2016        
(r299888)
@@ -1085,7 +1085,7 @@ typedef struct rndismp_rx_bufs_info_ {
 struct hv_vmbus_channel;
 
 int netvsc_recv(struct hv_vmbus_channel *chan,
-    netvsc_packet *packet, rndis_tcp_ip_csum_info *csum_info,
+    netvsc_packet *packet, const rndis_tcp_ip_csum_info *csum_info,
     const struct rndis_hash_info *hash_info,
     const struct rndis_hash_value *hash_value);
 void netvsc_channel_rollup(struct hv_vmbus_channel *chan);

Modified: head/sys/dev/hyperv/netvsc/hv_rndis_filter.c
==============================================================================
--- head/sys/dev/hyperv/netvsc/hv_rndis_filter.c        Mon May 16 02:44:22 
2016        (r299887)
+++ head/sys/dev/hyperv/netvsc/hv_rndis_filter.c        Mon May 16 03:26:16 
2016        (r299888)
@@ -49,6 +49,22 @@ __FBSDID("$FreeBSD$");
 #include "hv_rndis.h"
 #include "hv_rndis_filter.h"
 
+struct hv_rf_recvinfo {
+       const ndis_8021q_info           *vlan_info;
+       const rndis_tcp_ip_csum_info    *csum_info;
+       const struct rndis_hash_info    *hash_info;
+       const struct rndis_hash_value   *hash_value;
+};
+
+#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)
 
 /*
  * Forward declarations
@@ -433,6 +449,84 @@ hv_rf_receive_indicate_status(rndis_devi
        }
 }
 
+static int
+hv_rf_find_recvinfo(const rndis_packet *rpkt, struct hv_rf_recvinfo *info)
+{
+       const rndis_per_packet_info *ppi;
+       uint32_t mask, len;
+
+       info->vlan_info = NULL;
+       info->csum_info = NULL;
+       info->hash_info = NULL;
+       info->hash_value = NULL;
+
+       if (rpkt->per_pkt_info_offset == 0)
+               return 0;
+
+       ppi = (const rndis_per_packet_info *)
+           ((const uint8_t *)rpkt + rpkt->per_pkt_info_offset);
+       len = rpkt->per_pkt_info_length;
+       mask = 0;
+
+       while (len != 0) {
+               const void *ppi_dptr;
+               uint32_t ppi_dlen;
+
+               if (__predict_false(ppi->size < ppi->per_packet_info_offset))
+                       return EINVAL;
+               ppi_dlen = ppi->size - ppi->per_packet_info_offset;
+               ppi_dptr = (const uint8_t *)ppi + ppi->per_packet_info_offset;
+
+               switch (ppi->type) {
+               case ieee_8021q_info:
+                       if (__predict_false(ppi_dlen < sizeof(ndis_8021q_info)))
+                               return EINVAL;
+                       info->vlan_info = ppi_dptr;
+                       mask |= HV_RF_RECVINFO_VLAN;
+                       break;
+
+               case tcpip_chksum_info:
+                       if (__predict_false(ppi_dlen <
+                           sizeof(rndis_tcp_ip_csum_info)))
+                               return EINVAL;
+                       info->csum_info = ppi_dptr;
+                       mask |= HV_RF_RECVINFO_CSUM;
+                       break;
+
+               case nbl_hash_value:
+                       if (__predict_false(ppi_dlen <
+                           sizeof(struct rndis_hash_value)))
+                               return EINVAL;
+                       info->hash_value = ppi_dptr;
+                       mask |= HV_RF_RECVINFO_HASHVAL;
+                       break;
+
+               case nbl_hash_info:
+                       if (__predict_false(ppi_dlen <
+                           sizeof(struct rndis_hash_info)))
+                               return EINVAL;
+                       info->hash_info = ppi_dptr;
+                       mask |= HV_RF_RECVINFO_HASHINF;
+                       break;
+
+               default:
+                       goto skip;
+               }
+
+               if (mask == HV_RF_RECVINFO_ALL) {
+                       /* All found; done */
+                       break;
+               }
+skip:
+               if (__predict_false(len < ppi->size))
+                       return EINVAL;
+               len -= ppi->size;
+               ppi = (const rndis_per_packet_info *)
+                   ((const uint8_t *)ppi + ppi->size);
+       }
+       return 0;
+}
+
 /*
  * RNDIS filter receive data
  */
@@ -441,12 +535,9 @@ hv_rf_receive_data(rndis_device *device,
     struct hv_vmbus_channel *chan, netvsc_packet *pkt)
 {
        rndis_packet *rndis_pkt;
-       ndis_8021q_info *rppi_vlan_info;
        uint32_t data_offset;
-       rndis_tcp_ip_csum_info *csum_info = NULL;
-       const struct rndis_hash_info *hash_info;
-       const struct rndis_hash_value *hash_value;
        device_t dev = device->net_dev->dev->device;
+       struct hv_rf_recvinfo info;
 
        rndis_pkt = &message->msg.packet;
 
@@ -470,17 +561,18 @@ hv_rf_receive_data(rndis_device *device,
        pkt->tot_data_buf_len = rndis_pkt->data_length;
        pkt->data = (void *)((unsigned long)pkt->data + data_offset);
 
-       rppi_vlan_info = hv_get_ppi_data(rndis_pkt, ieee_8021q_info);
-       if (rppi_vlan_info) {
-               pkt->vlan_tci = rppi_vlan_info->u1.s1.vlan_id;
-       } else {
-               pkt->vlan_tci = 0;
+       if (hv_rf_find_recvinfo(rndis_pkt, &info)) {
+               pkt->status = nvsp_status_failure;
+               device_printf(dev, "recvinfo parsing failed\n");
+               return;
        }
 
-       csum_info = hv_get_ppi_data(rndis_pkt, tcpip_chksum_info);
-       hash_value = hv_get_ppi_data(rndis_pkt, nbl_hash_value);
-       hash_info = hv_get_ppi_data(rndis_pkt, nbl_hash_info);
-       netvsc_recv(chan, pkt, csum_info, hash_info, hash_value);
+       if (info.vlan_info != NULL)
+               pkt->vlan_tci = info.vlan_info->u1.s1.vlan_id;
+       else
+               pkt->vlan_tci = 0;
+
+       netvsc_recv(chan, pkt, info.csum_info, info.hash_info, info.hash_value);
 }
 
 /*
_______________________________________________
svn-src-head@freebsd.org mailing list
https://lists.freebsd.org/mailman/listinfo/svn-src-head
To unsubscribe, send any mail to "svn-src-head-unsubscr...@freebsd.org"

Reply via email to