8021q: Check return of dev_set_promiscuity/allmulti
authorWang Chen <wangchen@cn.fujitsu.com>
Tue, 15 Jul 2008 03:59:03 +0000 (20:59 -0700)
committerDavid S. Miller <davem@davemloft.net>
Tue, 15 Jul 2008 03:59:03 +0000 (20:59 -0700)
dev_set_promiscuity/allmulti might overflow.
Commit: "netdevice: Fix promiscuity and allmulti overflow" in net-next makes
dev_set_promiscuity/allmulti return error number if overflow happened.

Here, we check all positive increment for promiscuity and allmulti
to get error return.

Signed-off-by: Wang Chen <wangchen@cn.fujitsu.com>
Acked-by: Patrick McHardy <kaber@trash.net>
Signed-off-by: David S. Miller <davem@davemloft.net>
net/8021q/vlan_dev.c

index 8efa399823e397570190f0562c6a7957d3e46f55..9efd3c67c1db1537afbb7eb4b53ce7a770e2136d 100644 (file)
@@ -518,19 +518,35 @@ static int vlan_dev_open(struct net_device *dev)
        if (compare_ether_addr(dev->dev_addr, real_dev->dev_addr)) {
                err = dev_unicast_add(real_dev, dev->dev_addr, ETH_ALEN);
                if (err < 0)
-                       return err;
+                       goto out;
        }
-       memcpy(vlan->real_dev_addr, real_dev->dev_addr, ETH_ALEN);
 
-       if (dev->flags & IFF_ALLMULTI)
-               dev_set_allmulti(real_dev, 1);
-       if (dev->flags & IFF_PROMISC)
-               dev_set_promiscuity(real_dev, 1);
+       if (dev->flags & IFF_ALLMULTI) {
+               err = dev_set_allmulti(real_dev, 1);
+               if (err < 0)
+                       goto del_unicast;
+       }
+       if (dev->flags & IFF_PROMISC) {
+               err = dev_set_promiscuity(real_dev, 1);
+               if (err < 0)
+                       goto clear_allmulti;
+       }
+
+       memcpy(vlan->real_dev_addr, real_dev->dev_addr, ETH_ALEN);
 
        if (vlan->flags & VLAN_FLAG_GVRP)
                vlan_gvrp_request_join(dev);
 
        return 0;
+
+clear_allmulti:
+       if (dev->flags & IFF_ALLMULTI)
+               dev_set_allmulti(real_dev, -1);
+del_unicast:
+       if (compare_ether_addr(dev->dev_addr, real_dev->dev_addr))
+               dev_unicast_delete(real_dev, dev->dev_addr, ETH_ALEN);
+out:
+       return err;
 }
 
 static int vlan_dev_stop(struct net_device *dev)