net/hyperv: Add support for promiscuous mode setting
authorHaiyang Zhang <haiyangz@microsoft.com>
Wed, 30 Nov 2011 15:19:08 +0000 (07:19 -0800)
committerGreg Kroah-Hartman <gregkh@suse.de>
Thu, 1 Dec 2011 18:25:26 +0000 (10:25 -0800)
Add code to accept promiscuous mode setting, and pass it to
RNDIS filter.

Signed-off-by: Haiyang Zhang <haiyangz@microsoft.com>
Signed-off-by: K. Y. Srinivasan <kys@microsoft.com>
Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
drivers/net/hyperv/hyperv_net.h
drivers/net/hyperv/netvsc_drv.c
drivers/net/hyperv/rndis_filter.c

index ac1ec8405124eba477eed5214fa141084634c894..49b131f71d7a3d2d30f2cb621ef9c90f2e6c95df 100644 (file)
@@ -87,6 +87,27 @@ struct netvsc_device_info {
        int  ring_size;
 };
 
+enum rndis_device_state {
+       RNDIS_DEV_UNINITIALIZED = 0,
+       RNDIS_DEV_INITIALIZING,
+       RNDIS_DEV_INITIALIZED,
+       RNDIS_DEV_DATAINITIALIZED,
+};
+
+struct rndis_device {
+       struct netvsc_device *net_dev;
+
+       enum rndis_device_state state;
+       bool link_state;
+       atomic_t new_req_id;
+
+       spinlock_t request_lock;
+       struct list_head req_list;
+
+       unsigned char hw_mac_adr[ETH_ALEN];
+};
+
+
 /* Interface */
 int netvsc_device_add(struct hv_device *device, void *additional_info);
 int netvsc_device_remove(struct hv_device *device);
@@ -109,6 +130,9 @@ int rndis_filter_receive(struct hv_device *dev,
 int rndis_filter_send(struct hv_device *dev,
                        struct hv_netvsc_packet *pkt);
 
+int rndis_filter_set_packet_filter(struct rndis_device *dev, u32 new_filter);
+
+
 #define NVSP_INVALID_PROTOCOL_VERSION  ((u32)0xFFFFFFFF)
 
 #define NVSP_PROTOCOL_VERSION_1                2
index 93b0e91cbf985611a5b394a779d18200de0870b2..b69c3a4d1e9e41c72c6044ffb5299316b768966f 100644 (file)
@@ -56,11 +56,51 @@ static int ring_size = 128;
 module_param(ring_size, int, S_IRUGO);
 MODULE_PARM_DESC(ring_size, "Ring buffer size (# of pages)");
 
-/* no-op so the netdev core doesn't return -EINVAL when modifying the the
- * multicast address list in SIOCADDMULTI. hv is setup to get all multicast
- * when it calls RndisFilterOnOpen() */
+struct set_multicast_work {
+       struct work_struct work;
+       struct net_device *net;
+};
+
+static void do_set_multicast(struct work_struct *w)
+{
+       struct set_multicast_work *swk =
+               container_of(w, struct set_multicast_work, work);
+       struct net_device *net = swk->net;
+
+       struct net_device_context *ndevctx = netdev_priv(net);
+       struct netvsc_device *nvdev;
+       struct rndis_device *rdev;
+
+       nvdev = hv_get_drvdata(ndevctx->device_ctx);
+       if (nvdev == NULL)
+               return;
+
+       rdev = nvdev->extension;
+       if (rdev == NULL)
+               return;
+
+       if (net->flags & IFF_PROMISC)
+               rndis_filter_set_packet_filter(rdev,
+                       NDIS_PACKET_TYPE_PROMISCUOUS);
+       else
+               rndis_filter_set_packet_filter(rdev,
+                       NDIS_PACKET_TYPE_BROADCAST |
+                       NDIS_PACKET_TYPE_ALL_MULTICAST |
+                       NDIS_PACKET_TYPE_DIRECTED);
+
+       kfree(w);
+}
+
 static void netvsc_set_multicast_list(struct net_device *net)
 {
+       struct set_multicast_work *swk =
+               kmalloc(sizeof(struct set_multicast_work), GFP_ATOMIC);
+       if (swk == NULL)
+               return;
+
+       swk->net = net;
+       INIT_WORK(&swk->work, do_set_multicast);
+       schedule_work(&swk->work);
 }
 
 static int netvsc_open(struct net_device *net)
index bafccb36004121aafef78eb08b8a5bbcbfe46ac2..418e7aac229ca267b7f216df79ba35156bc2b249 100644 (file)
 #include "hyperv_net.h"
 
 
-enum rndis_device_state {
-       RNDIS_DEV_UNINITIALIZED = 0,
-       RNDIS_DEV_INITIALIZING,
-       RNDIS_DEV_INITIALIZED,
-       RNDIS_DEV_DATAINITIALIZED,
-};
-
-struct rndis_device {
-       struct netvsc_device *net_dev;
-
-       enum rndis_device_state state;
-       bool link_state;
-       atomic_t new_req_id;
-
-       spinlock_t request_lock;
-       struct list_head req_list;
-
-       unsigned char hw_mac_adr[ETH_ALEN];
-};
-
 struct rndis_request {
        struct list_head list_ent;
        struct completion  wait_event;
@@ -522,8 +502,7 @@ static int rndis_filter_query_device_link_status(struct rndis_device *dev)
        return ret;
 }
 
-static int rndis_filter_set_packet_filter(struct rndis_device *dev,
-                                     u32 new_filter)
+int rndis_filter_set_packet_filter(struct rndis_device *dev, u32 new_filter)
 {
        struct rndis_request *request;
        struct rndis_set_request *set;