tcp: tcp_synack_options() fix
[safe/jmp/linux-2.6] / net / 8021q / vlan.c
index 6b5c9dd..3c1c8c1 100644 (file)
@@ -22,6 +22,7 @@
 #include <linux/module.h>
 #include <linux/netdevice.h>
 #include <linux/skbuff.h>
+#include <linux/slab.h>
 #include <linux/init.h>
 #include <linux/rculist.h>
 #include <net/p8022.h>
@@ -41,7 +42,7 @@
 
 /* Global VLAN variables */
 
-int vlan_net_id;
+int vlan_net_id __read_mostly;
 
 /* Our listing of VLAN group(s) */
 static struct hlist_head vlan_group_hash[VLAN_GRP_HASH_SIZE];
@@ -159,10 +160,11 @@ void unregister_vlan_dev(struct net_device *dev, struct list_head *head)
        if (real_dev->features & NETIF_F_HW_VLAN_FILTER)
                ops->ndo_vlan_rx_kill_vid(real_dev, vlan_id);
 
-       vlan_group_set_device(grp, vlan_id, NULL);
        grp->nr_vlans--;
 
-       synchronize_net();
+       vlan_group_set_device(grp, vlan_id, NULL);
+       if (!grp->killall)
+               synchronize_net();
 
        unregister_netdevice_queue(dev, head);
 
@@ -183,27 +185,6 @@ void unregister_vlan_dev(struct net_device *dev, struct list_head *head)
        dev_put(real_dev);
 }
 
-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
-        * on VLAN device
-        */
-       if (dev->operstate == IF_OPER_DORMANT)
-               netif_dormant_on(vlandev);
-       else
-               netif_dormant_off(vlandev);
-
-       if (netif_carrier_ok(dev)) {
-               if (!netif_carrier_ok(vlandev))
-                       netif_carrier_on(vlandev);
-       } else {
-               if (netif_carrier_ok(vlandev))
-                       netif_carrier_off(vlandev);
-       }
-}
-
 int vlan_check_real_dev(struct net_device *real_dev, u16 vlan_id)
 {
        const char *name = real_dev->name;
@@ -261,7 +242,7 @@ int register_vlan_dev(struct net_device *dev)
        /* Account for reference in struct vlan_dev_info */
        dev_hold(real_dev);
 
-       vlan_transfer_operstate(real_dev, dev);
+       netif_stacked_transfer_operstate(real_dev, dev);
        linkwatch_fire_event(dev); /* _MUST_ call rfc2863_policy() */
 
        /* So, got the sucker initialized, now lets place
@@ -281,8 +262,11 @@ out_uninit_applicant:
        if (ngrp)
                vlan_gvrp_uninit_applicant(real_dev);
 out_free_group:
-       if (ngrp)
-               vlan_group_free(ngrp);
+       if (ngrp) {
+               hlist_del_rcu(&ngrp->hlist);
+               /* Free the group, after all cpu's are done. */
+               call_rcu(&ngrp->rcu, vlan_rcu_free);
+       }
        return err;
 }
 
@@ -373,13 +357,13 @@ static void vlan_sync_address(struct net_device *dev,
         * the new address */
        if (compare_ether_addr(vlandev->dev_addr, vlan->real_dev_addr) &&
            !compare_ether_addr(vlandev->dev_addr, dev->dev_addr))
-               dev_unicast_delete(dev, vlandev->dev_addr);
+               dev_uc_del(dev, vlandev->dev_addr);
 
        /* vlan address was equal to the old address and is different from
         * the new address */
        if (!compare_ether_addr(vlandev->dev_addr, vlan->real_dev_addr) &&
            compare_ether_addr(vlandev->dev_addr, dev->dev_addr))
-               dev_unicast_add(dev, vlandev->dev_addr);
+               dev_uc_add(dev, vlandev->dev_addr);
 
        memcpy(vlan->real_dev_addr, dev->dev_addr, ETH_ALEN);
 }
@@ -395,6 +379,8 @@ static void vlan_transfer_features(struct net_device *dev,
 #if defined(CONFIG_FCOE) || defined(CONFIG_FCOE_MODULE)
        vlandev->fcoe_ddp_xid = dev->fcoe_ddp_xid;
 #endif
+       vlandev->real_num_tx_queues = dev->real_num_tx_queues;
+       BUG_ON(vlandev->real_num_tx_queues > vlandev->num_tx_queues);
 
        if (old_features != vlandev->features)
                netdev_features_change(vlandev);
@@ -427,6 +413,8 @@ static int vlan_device_event(struct notifier_block *unused, unsigned long event,
        struct vlan_group *grp;
        int i, flgs;
        struct net_device *vlandev;
+       struct vlan_dev_info *vlan;
+       LIST_HEAD(list);
 
        if (is_vlan_dev(dev))
                __vlan_device_event(dev, event);
@@ -447,7 +435,7 @@ static int vlan_device_event(struct notifier_block *unused, unsigned long event,
                        if (!vlandev)
                                continue;
 
-                       vlan_transfer_operstate(dev, vlandev);
+                       netif_stacked_transfer_operstate(dev, vlandev);
                }
                break;
 
@@ -502,8 +490,10 @@ static int vlan_device_event(struct notifier_block *unused, unsigned long event,
                        if (!(flgs & IFF_UP))
                                continue;
 
-                       dev_change_flags(vlandev, flgs & ~IFF_UP);
-                       vlan_transfer_operstate(dev, vlandev);
+                       vlan = vlan_dev_info(vlandev);
+                       if (!(vlan->flags & VLAN_FLAG_LOOSE_BINDING))
+                               dev_change_flags(vlandev, flgs & ~IFF_UP);
+                       netif_stacked_transfer_operstate(dev, vlandev);
                }
                break;
 
@@ -518,13 +508,17 @@ static int vlan_device_event(struct notifier_block *unused, unsigned long event,
                        if (flgs & IFF_UP)
                                continue;
 
-                       dev_change_flags(vlandev, flgs | IFF_UP);
-                       vlan_transfer_operstate(dev, vlandev);
+                       vlan = vlan_dev_info(vlandev);
+                       if (!(vlan->flags & VLAN_FLAG_LOOSE_BINDING))
+                               dev_change_flags(vlandev, flgs | IFF_UP);
+                       netif_stacked_transfer_operstate(dev, vlandev);
                }
                break;
 
        case NETDEV_UNREGISTER:
                /* Delete all VLANs for this dev. */
+               grp->killall = 1;
+
                for (i = 0; i < VLAN_GROUP_ARRAY_LEN; i++) {
                        vlandev = vlan_group_get_device(grp, i);
                        if (!vlandev)
@@ -535,9 +529,14 @@ static int vlan_device_event(struct notifier_block *unused, unsigned long event,
                        if (grp->nr_vlans == 1)
                                i = VLAN_GROUP_ARRAY_LEN;
 
-                       unregister_vlan_dev(vlandev, NULL);
+                       unregister_vlan_dev(vlandev, &list);
                }
+               unregister_netdevice_many(&list);
                break;
+
+       case NETDEV_PRE_TYPE_CHANGE:
+               /* Forbid underlaying device to change its type. */
+               return NOTIFY_BAD;
        }
 
 out:
@@ -671,49 +670,28 @@ out:
        return err;
 }
 
-static int vlan_init_net(struct net *net)
+static int __net_init vlan_init_net(struct net *net)
 {
+       struct vlan_net *vn = net_generic(net, vlan_net_id);
        int err;
-       struct vlan_net *vn;
-
-       err = -ENOMEM;
-       vn = kzalloc(sizeof(struct vlan_net), GFP_KERNEL);
-       if (vn == NULL)
-               goto err_alloc;
-
-       err = net_assign_generic(net, vlan_net_id, vn);
-       if (err < 0)
-               goto err_assign;
 
        vn->name_type = VLAN_NAME_TYPE_RAW_PLUS_VID_NO_PAD;
 
        err = vlan_proc_init(net);
-       if (err < 0)
-               goto err_proc;
 
-       return 0;
-
-err_proc:
-       /* nothing */
-err_assign:
-       kfree(vn);
-err_alloc:
        return err;
 }
 
-static void vlan_exit_net(struct net *net)
+static void __net_exit vlan_exit_net(struct net *net)
 {
-       struct vlan_net *vn;
-
-       vn = net_generic(net, vlan_net_id);
-       rtnl_kill_links(net, &vlan_link_ops);
        vlan_proc_cleanup(net);
-       kfree(vn);
 }
 
 static struct pernet_operations vlan_net_ops = {
        .init = vlan_init_net,
        .exit = vlan_exit_net,
+       .id   = &vlan_net_id,
+       .size = sizeof(struct vlan_net),
 };
 
 static int __init vlan_proto_init(void)
@@ -723,7 +701,7 @@ static int __init vlan_proto_init(void)
        pr_info("%s v%s %s\n", vlan_fullname, vlan_version, vlan_copyright);
        pr_info("All bugs added by %s\n", vlan_buggyright);
 
-       err = register_pernet_gen_device(&vlan_net_id, &vlan_net_ops);
+       err = register_pernet_subsys(&vlan_net_ops);
        if (err < 0)
                goto err0;
 
@@ -748,7 +726,7 @@ err4:
 err3:
        unregister_netdevice_notifier(&vlan_notifier_block);
 err2:
-       unregister_pernet_gen_device(vlan_net_id, &vlan_net_ops);
+       unregister_pernet_subsys(&vlan_net_ops);
 err0:
        return err;
 }
@@ -768,7 +746,7 @@ static void __exit vlan_cleanup_module(void)
        for (i = 0; i < VLAN_GRP_HASH_SIZE; i++)
                BUG_ON(!hlist_empty(&vlan_group_hash[i]));
 
-       unregister_pernet_gen_device(vlan_net_id, &vlan_net_ops);
+       unregister_pernet_subsys(&vlan_net_ops);
        rcu_barrier(); /* Wait for completion of call_rcu()'s */
 
        vlan_gvrp_uninit();