]> pilppa.org Git - linux-2.6-omap-h63xx.git/blobdiff - net/8021q/vlan.c
[SCTP]: fix misannotated __sctp_rcv_asconf_lookup()
[linux-2.6-omap-h63xx.git] / net / 8021q / vlan.c
index ad34e4a0326a109cb8f23a53de6125dbb514e2e2..dbc81b96509666595a7e02265446be3c8076e45b 100644 (file)
@@ -3,7 +3,7 @@
  *             Ethernet-type device handling.
  *
  * Authors:    Ben Greear <greearb@candelatech.com>
- *              Please send support related email to: vlan@scry.wanfear.com
+ *              Please send support related email to: netdev@vger.kernel.org
  *              VLAN Home Page: http://www.candelatech.com/~greear/vlan.html
  *
  * Fixes:
@@ -43,7 +43,6 @@
 
 /* Our listing of VLAN group(s) */
 static struct hlist_head vlan_group_hash[VLAN_GRP_HASH_SIZE];
-#define vlan_grp_hashfn(IDX)   ((((IDX) >> VLAN_GRP_HASH_SHIFT) ^ (IDX)) & VLAN_GRP_HASH_MASK)
 
 static char vlan_fullname[] = "802.1Q VLAN Support";
 static char vlan_version[] = DRV_VERSION;
@@ -60,6 +59,11 @@ static struct packet_type vlan_packet_type = {
 
 /* End of global variables definitions. */
 
+static inline unsigned int vlan_grp_hashfn(unsigned int idx)
+{
+       return ((idx >> VLAN_GRP_HASH_SHIFT) ^ idx) & VLAN_GRP_HASH_MASK;
+}
+
 /* Must be invoked with RCU read lock (no preempt) */
 static struct vlan_group *__vlan_find_group(int real_dev_ifindex)
 {
@@ -94,7 +98,7 @@ static void vlan_group_free(struct vlan_group *grp)
 {
        int i;
 
-       for (i=0; i < VLAN_GROUP_ARRAY_SPLIT_PARTS; i++)
+       for (i = 0; i < VLAN_GROUP_ARRAY_SPLIT_PARTS; i++)
                kfree(grp->vlan_devices_arrays[i]);
        kfree(grp);
 }
@@ -132,33 +136,17 @@ static void vlan_rcu_free(struct rcu_head *rcu)
        vlan_group_free(container_of(rcu, struct vlan_group, rcu));
 }
 
-
-/* This returns 0 if everything went fine.
- * It will return 1 if the group was killed as a result.
- * A negative return indicates failure.
- *
- * The RTNL lock must be held.
- */
-static int unregister_vlan_dev(struct net_device *real_dev,
-                              unsigned short vlan_id)
+void unregister_vlan_dev(struct net_device *dev)
 {
-       struct net_device *dev;
-       int real_dev_ifindex = real_dev->ifindex;
+       struct vlan_dev_info *vlan = vlan_dev_info(dev);
+       struct net_device *real_dev = vlan->real_dev;
        struct vlan_group *grp;
-       unsigned int i;
-       int ret;
-
-       if (vlan_id >= VLAN_VID_MASK)
-               return -EINVAL;
+       unsigned short vlan_id = vlan->vlan_id;
 
        ASSERT_RTNL();
-       grp = __vlan_find_group(real_dev_ifindex);
-       if (!grp)
-               return -ENOENT;
 
-       dev = vlan_group_get_device(grp, vlan_id);
-       if (!dev)
-               return -ENOENT;
+       grp = __vlan_find_group(real_dev->ifindex);
+       BUG_ON(!grp);
 
        vlan_proc_rem_dev(dev);
 
@@ -169,20 +157,12 @@ static int unregister_vlan_dev(struct net_device *real_dev,
                real_dev->vlan_rx_kill_vid(real_dev, vlan_id);
 
        vlan_group_set_device(grp, vlan_id, NULL);
-       synchronize_net();
+       grp->nr_vlans--;
 
-       /* Caller unregisters (and if necessary, puts) VLAN device, but we
-        * get rid of the reference to real_dev here.
-        */
-       dev_put(real_dev);
+       synchronize_net();
 
        /* If the group is now empty, kill off the group. */
-       ret = 0;
-       for (i = 0; i < VLAN_VID_MASK; i++)
-               if (vlan_group_get_device(grp, i))
-                       break;
-
-       if (i == VLAN_VID_MASK) {
+       if (grp->nr_vlans == 0) {
                if (real_dev->features & NETIF_F_HW_VLAN_RX)
                        real_dev->vlan_rx_register(real_dev, NULL);
 
@@ -190,26 +170,16 @@ static int unregister_vlan_dev(struct net_device *real_dev,
 
                /* Free the group, after all cpu's are done. */
                call_rcu(&grp->rcu, vlan_rcu_free);
-               ret = 1;
        }
 
-       return ret;
-}
-
-int unregister_vlan_device(struct net_device *dev)
-{
-       int ret;
+       /* Get rid of the vlan's reference to real_dev */
+       dev_put(real_dev);
 
-       ret = unregister_vlan_dev(VLAN_DEV_INFO(dev)->real_dev,
-                                 VLAN_DEV_INFO(dev)->vlan_id);
        unregister_netdevice(dev);
-
-       if (ret == 1)
-               ret = 0;
-       return ret;
 }
 
-static void vlan_transfer_operstate(const struct net_device *dev, struct net_device *vlandev)
+static void vlan_transfer_operstate(const struct net_device *dev,
+                                   struct net_device *vlandev)
 {
        /* Have to respect userspace enforced dormant state
         * of real device, also must allow supplicant running
@@ -264,7 +234,7 @@ int vlan_check_real_dev(struct net_device *real_dev, unsigned short vlan_id)
 
 int register_vlan_dev(struct net_device *dev)
 {
-       struct vlan_dev_info *vlan = VLAN_DEV_INFO(dev);
+       struct vlan_dev_info *vlan = vlan_dev_info(dev);
        struct net_device *real_dev = vlan->real_dev;
        unsigned short vlan_id = vlan->vlan_id;
        struct vlan_group *grp, *ngrp = NULL;
@@ -291,6 +261,8 @@ int register_vlan_dev(struct net_device *dev)
         * it into our local structure.
         */
        vlan_group_set_device(grp, vlan_id, dev);
+       grp->nr_vlans++;
+
        if (ngrp && real_dev->features & NETIF_F_HW_VLAN_RX)
                real_dev->vlan_rx_register(real_dev, ngrp);
        if (real_dev->features & NETIF_F_HW_VLAN_FILTER)
@@ -361,10 +333,10 @@ static int register_vlan_device(struct net_device *real_dev,
         */
        new_dev->mtu = real_dev->mtu;
 
-       VLAN_DEV_INFO(new_dev)->vlan_id = VLAN_ID; /* 1 through VLAN_VID_MASK */
-       VLAN_DEV_INFO(new_dev)->real_dev = real_dev;
-       VLAN_DEV_INFO(new_dev)->dent = NULL;
-       VLAN_DEV_INFO(new_dev)->flags = VLAN_FLAG_REORDER_HDR;
+       vlan_dev_info(new_dev)->vlan_id = VLAN_ID; /* 1 through VLAN_VID_MASK */
+       vlan_dev_info(new_dev)->real_dev = real_dev;
+       vlan_dev_info(new_dev)->dent = NULL;
+       vlan_dev_info(new_dev)->flags = VLAN_FLAG_REORDER_HDR;
 
        new_dev->rtnl_link_ops = &vlan_link_ops;
        err = register_vlan_dev(new_dev);
@@ -381,7 +353,7 @@ out_free_newdev:
 static void vlan_sync_address(struct net_device *dev,
                              struct net_device *vlandev)
 {
-       struct vlan_dev_info *vlan = VLAN_DEV_INFO(vlandev);
+       struct vlan_dev_info *vlan = vlan_dev_info(vlandev);
 
        /* May be called without an actual change */
        if (!compare_ether_addr(vlan->real_dev_addr, dev->dev_addr))
@@ -402,7 +374,8 @@ static void vlan_sync_address(struct net_device *dev,
        memcpy(vlan->real_dev_addr, dev->dev_addr, ETH_ALEN);
 }
 
-static int vlan_device_event(struct notifier_block *unused, unsigned long event, void *ptr)
+static int vlan_device_event(struct notifier_block *unused, unsigned long event,
+                            void *ptr)
 {
        struct net_device *dev = ptr;
        struct vlan_group *grp = __vlan_find_group(dev->ifindex);
@@ -479,20 +452,16 @@ static int vlan_device_event(struct notifier_block *unused, unsigned long event,
        case NETDEV_UNREGISTER:
                /* Delete all VLANs for this dev. */
                for (i = 0; i < VLAN_GROUP_ARRAY_LEN; i++) {
-                       int ret;
-
                        vlandev = vlan_group_get_device(grp, i);
                        if (!vlandev)
                                continue;
 
-                       ret = unregister_vlan_dev(dev,
-                                                 VLAN_DEV_INFO(vlandev)->vlan_id);
-
-                       unregister_netdevice(vlandev);
+                       /* unregistration of last vlan destroys group, abort
+                        * afterwards */
+                       if (grp->nr_vlans == 1)
+                               i = VLAN_GROUP_ARRAY_LEN;
 
-                       /* Group was destroyed? */
-                       if (ret == 1)
-                               break;
+                       unregister_vlan_dev(vlandev);
                }
                break;
        }
@@ -598,16 +567,16 @@ static int vlan_ioctl_handler(struct net *net, void __user *arg)
                err = -EPERM;
                if (!capable(CAP_NET_ADMIN))
                        break;
-               err = unregister_vlan_device(dev);
+               unregister_vlan_dev(dev);
+               err = 0;
                break;
 
        case GET_VLAN_REALDEV_NAME_CMD:
                err = 0;
                vlan_dev_get_realdev_name(dev, args.u.device2);
                if (copy_to_user(arg, &args,
-                                sizeof(struct vlan_ioctl_args))) {
+                                sizeof(struct vlan_ioctl_args)))
                        err = -EFAULT;
-               }
                break;
 
        case GET_VLAN_VID_CMD:
@@ -615,9 +584,8 @@ static int vlan_ioctl_handler(struct net *net, void __user *arg)
                vlan_dev_get_vid(dev, &vid);
                args.u.VID = vid;
                if (copy_to_user(arg, &args,
-                                sizeof(struct vlan_ioctl_args))) {
+                                sizeof(struct vlan_ioctl_args)))
                      err = -EFAULT;
-               }
                break;
 
        default: