linux 2.6.16.38 w/ vs2.0.3-rc1
[linux-2.6.git] / net / 8021q / vlan.c
index 18fcb9f..fa76220 100644 (file)
@@ -67,6 +67,10 @@ static struct packet_type vlan_packet_type = {
        .func = vlan_skb_recv, /* VLAN receive method */
 };
 
+/* Bits of netdev state that are propagated from real device to virtual */
+#define VLAN_LINK_STATE_MASK \
+       ((1<<__LINK_STATE_PRESENT)|(1<<__LINK_STATE_NOCARRIER))
+
 /* End of global variables definitions. */
 
 /*
@@ -340,34 +344,6 @@ static void vlan_setup(struct net_device *new_dev)
        new_dev->do_ioctl = vlan_dev_ioctl;
 }
 
-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);
-       }
-}
-
-/*
- * vlan network devices have devices nesting below it, and are a special
- * "super class" of normal network devices; split their locks off into a
- * separate class since they always nest.
- */
-static struct lock_class_key vlan_netdev_xmit_lock_key;
-
-
 /*  Attach a VLAN device to a mac address (ie Ethernet Card).
  *  Returns the device that was created, or NULL if there was
  *  an error of some kind.
@@ -464,7 +440,6 @@ static struct net_device *register_vlan_device(const char *eth_IF_name,
                    
        new_dev = alloc_netdev(sizeof(struct vlan_dev_info), name,
                               vlan_setup);
-
        if (new_dev == NULL)
                goto out_unlock;
 
@@ -475,9 +450,7 @@ static struct net_device *register_vlan_device(const char *eth_IF_name,
        new_dev->flags = real_dev->flags;
        new_dev->flags &= ~IFF_UP;
 
-       new_dev->state = (real_dev->state & ((1<<__LINK_STATE_NOCARRIER) |
-                                            (1<<__LINK_STATE_DORMANT))) |
-                        (1<<__LINK_STATE_PRESENT); 
+       new_dev->state = real_dev->state & VLAN_LINK_STATE_MASK;
 
        /* need 4 bytes for extra VLAN header info,
         * hope the underlying device can handle it.
@@ -525,12 +498,6 @@ static struct net_device *register_vlan_device(const char *eth_IF_name,
        if (register_netdevice(new_dev))
                goto out_free_newdev;
 
-       lockdep_set_class(&new_dev->_xmit_lock, &vlan_netdev_xmit_lock_key);
-
-       new_dev->iflink = real_dev->ifindex;
-       vlan_transfer_operstate(real_dev, new_dev);
-       linkwatch_fire_event(new_dev); /* _MUST_ call rfc2863_policy() */
-
        /* So, got the sucker initialized, now lets place
         * it into our local structure.
         */
@@ -540,11 +507,12 @@ static struct net_device *register_vlan_device(const char *eth_IF_name,
         * so it cannot "appear" on us.
         */
        if (!grp) { /* need to add a new group */
-               grp = kzalloc(sizeof(struct vlan_group), GFP_KERNEL);
+               grp = kmalloc(sizeof(struct vlan_group), GFP_KERNEL);
                if (!grp)
                        goto out_free_unregister;
                                        
                /* printk(KERN_ALERT "VLAN REGISTER:  Allocated new group.\n"); */
+               memset(grp, 0, sizeof(struct vlan_group));
                grp->real_dev_ifindex = real_dev->ifindex;
 
                hlist_add_head_rcu(&grp->hlist, 
@@ -605,12 +573,25 @@ static int vlan_device_event(struct notifier_block *unused, unsigned long event,
        switch (event) {
        case NETDEV_CHANGE:
                /* Propagate real device state to vlan devices */
+               flgs = dev->state & VLAN_LINK_STATE_MASK;
                for (i = 0; i < VLAN_GROUP_ARRAY_LEN; i++) {
                        vlandev = grp->vlan_devices[i];
                        if (!vlandev)
                                continue;
 
-                       vlan_transfer_operstate(dev, 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);
+                       }
+
+                       if ((vlandev->state & VLAN_LINK_STATE_MASK) != flgs) {
+                               vlandev->state = (vlandev->state &~ VLAN_LINK_STATE_MASK) 
+                                       | flgs;
+                               netdev_state_change(vlandev);
+                       }
                }
                break;