* Authors: Ben Greear <greearb@candelatech.com>
* Please send support related email to: vlan@scry.wanfear.com
* VLAN Home Page: http://www.candelatech.com/~greear/vlan.html
- *
+ *
* Fixes:
* Fix for packet capture - Nick Eggleston <nick@dccinc.com>;
* Add HW acceleration hooks - David S. Miller <davem@redhat.com>;
.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. */
/*
* Function vlan_proto_init (pro)
*
- * Initialize VLAN protocol layer,
+ * Initialize VLAN protocol layer,
*
*/
static int __init vlan_proto_init(void)
/* proc file system initialization */
err = vlan_proc_init();
if (err < 0) {
- printk(KERN_ERR
+ printk(KERN_ERR
"%s %s: can't create entry in proc filesystem!\n",
__FUNCTION__, VLAN_NAME);
return err;
return 0;
}
-/* Cleanup all vlan devices
+/* Cleanup all vlan devices
* Note: devices that have been registered that but not
* brought up will exist but have no module ref count.
*/
/*
* Module 'remove' entry point.
* o delete /proc/net/router directory and static entries.
- */
+ */
static void __exit vlan_cleanup_module(void)
{
int i;
struct vlan_group *grp = __vlan_find_group(real_dev->ifindex);
if (grp)
- return grp->vlan_devices[VID];
+ return grp->vlan_devices[VID];
return NULL;
}
}
}
- return ret;
+ return ret;
}
static int unregister_vlan_device(const char *vlan_IF_name)
if (ret == 1)
ret = 0;
} else {
- printk(VLAN_ERR
+ printk(VLAN_ERR
"%s: ERROR: Tried to remove a non-vlan device "
"with VLAN code, name: %s priv_flags: %hX\n",
__FUNCTION__, dev->name, dev->priv_flags);
static void vlan_setup(struct net_device *new_dev)
{
SET_MODULE_OWNER(new_dev);
-
+
/* new_dev->ifindex = 0; it will be set when added to
* the global list.
* iflink is set as well.
/* Make this thing known as a VLAN device */
new_dev->priv_flags |= IFF_802_1Q_VLAN;
-
+
/* Set us up to have no queue, as the underlying Hardware device
* can do all the queueing we could want.
*/
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.
default:
snprintf(name, IFNAMSIZ, "vlan%.4i", VLAN_ID);
};
-
+
new_dev = alloc_netdev(sizeof(struct vlan_dev_info), name,
vlan_setup);
+
if (new_dev == NULL)
goto out_unlock;
new_dev->flags = real_dev->flags;
new_dev->flags &= ~IFF_UP;
- new_dev->state = real_dev->state & VLAN_LINK_STATE_MASK;
+ new_dev->state = (real_dev->state & ((1<<__LINK_STATE_NOCARRIER) |
+ (1<<__LINK_STATE_DORMANT))) |
+ (1<<__LINK_STATE_PRESENT);
/* need 4 bytes for extra VLAN header info,
* hope the underlying device can handle it.
VLAN_MEM_DBG("new_dev->priv malloc, addr: %p size: %i\n",
new_dev->priv,
sizeof(struct vlan_dev_info));
-
+
memcpy(new_dev->broadcast, real_dev->broadcast, real_dev->addr_len);
memcpy(new_dev->dev_addr, real_dev->dev_addr, real_dev->addr_len);
new_dev->addr_len = real_dev->addr_len;
printk(VLAN_DBG "About to go find the group for idx: %i\n",
real_dev->ifindex);
#endif
-
+
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.
*/
* so it cannot "appear" on us.
*/
if (!grp) { /* need to add a new group */
- grp = kmalloc(sizeof(struct vlan_group), GFP_KERNEL);
+ grp = kzalloc(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,
+ hlist_add_head_rcu(&grp->hlist,
&vlan_group_hash[vlan_grp_hashfn(real_dev->ifindex)]);
if (real_dev->features & NETIF_F_HW_VLAN_RX)
real_dev->vlan_rx_register(real_dev, grp);
}
-
+
grp->vlan_devices[VLAN_ID] = new_dev;
if (vlan_proc_add_dev(new_dev)<0)/* create it's proc entry */
- printk(KERN_WARNING "VLAN: failed to add proc entry for %s\n",
- new_dev->name);
+ printk(KERN_WARNING "VLAN: failed to add proc entry for %s\n",
+ new_dev->name);
if (real_dev->features & NETIF_F_HW_VLAN_FILTER)
real_dev->vlan_rx_add_vid(real_dev, VLAN_ID);
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;
- 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);
- }
+ vlan_transfer_operstate(dev, vlandev);
}
break;
vlandev = grp->vlan_devices[i];
if (!vlandev)
continue;
-
+
flgs = vlandev->flags;
if (flgs & IFF_UP)
continue;
dev_change_flags(vlandev, flgs | IFF_UP);
}
break;
-
+
case NETDEV_UNREGISTER:
/* Delete all VLANs for this dev. */
for (i = 0; i < VLAN_GROUP_ARRAY_LEN; i++) {
/* TODO: Implement
err = vlan_dev_get_ingress_priority(args);
if (copy_to_user((void*)arg, &args,
- sizeof(struct vlan_ioctl_args))) {
- err = -EFAULT;
+ sizeof(struct vlan_ioctl_args))) {
+ err = -EFAULT;
}
*/
err = -EINVAL;
/* TODO: Implement
err = vlan_dev_get_egress_priority(args.device1, &(args.args);
if (copy_to_user((void*)arg, &args,
- sizeof(struct vlan_ioctl_args))) {
- err = -EFAULT;
+ sizeof(struct vlan_ioctl_args))) {
+ err = -EFAULT;
}
*/
err = -EINVAL;
args.u.VID = vid;
if (copy_to_user(arg, &args,
sizeof(struct vlan_ioctl_args))) {
- err = -EFAULT;
+ err = -EFAULT;
}
break;