X-Git-Url: http://git.onelab.eu/?a=blobdiff_plain;f=net%2F8021q%2Fvlan.c;h=18fcb9fa518db4c4574d283ba8abdd35df9183fd;hb=97bf2856c6014879bd04983a3e9dfcdac1e7fe85;hp=df99704107b202a91d1ddb98b12b36f0c02e14ab;hpb=9bf4aaab3e101692164d49b7ca357651eb691cb6;p=linux-2.6.git diff --git a/net/8021q/vlan.c b/net/8021q/vlan.c index df9970410..18fcb9fa5 100644 --- a/net/8021q/vlan.c +++ b/net/8021q/vlan.c @@ -19,6 +19,7 @@ */ #include /* for copy_from_user */ +#include #include #include #include @@ -35,15 +36,16 @@ #include "vlan.h" #include "vlanproc.h" +#define DRV_VERSION "1.8" + /* Global VLAN variables */ /* Our listing of VLAN group(s) */ -struct hlist_head vlan_group_hash[VLAN_GRP_HASH_SIZE]; +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 unsigned int vlan_version = 1; -static unsigned int vlan_release = 8; +static char vlan_version[] = DRV_VERSION; static char vlan_copyright[] = "Ben Greear "; static char vlan_buggyright[] = "David S. Miller "; @@ -51,7 +53,7 @@ static int vlan_device_event(struct notifier_block *, unsigned long, void *); static int vlan_ioctl_handler(void __user *); static int unregister_vlan_dev(struct net_device *, unsigned short ); -struct notifier_block vlan_notifier_block = { +static struct notifier_block vlan_notifier_block = { .notifier_call = vlan_device_event, }; @@ -60,18 +62,11 @@ struct notifier_block vlan_notifier_block = { /* Determines interface naming scheme. */ unsigned short vlan_name_type = VLAN_NAME_TYPE_RAW_PLUS_VID_NO_PAD; -/* DO reorder the header by default */ -unsigned short vlan_default_dev_flags = 1; - static struct packet_type vlan_packet_type = { .type = __constant_htons(ETH_P_8021Q), .func = vlan_skb_recv, /* VLAN receive method */ }; -/* Bits of netdev state that are propogated from real device to virtual */ -#define VLAN_LINK_STATE_MASK \ - ((1<<__LINK_STATE_PRESENT)|(1<<__LINK_STATE_NOCARRIER)) - /* End of global variables definitions. */ /* @@ -84,8 +79,8 @@ static int __init vlan_proto_init(void) { int err; - printk(VLAN_INF "%s v%u.%u %s\n", - vlan_fullname, vlan_version, vlan_release, vlan_copyright); + printk(VLAN_INF "%s v%s %s\n", + vlan_fullname, vlan_version, vlan_copyright); printk(VLAN_INF "All bugs added by %s\n", vlan_buggyright); @@ -95,13 +90,18 @@ static int __init vlan_proto_init(void) printk(KERN_ERR "%s %s: can't create entry in proc filesystem!\n", __FUNCTION__, VLAN_NAME); - return 1; + return err; } dev_add_pack(&vlan_packet_type); /* Register us to receive netdevice events */ - register_netdevice_notifier(&vlan_notifier_block); + err = register_netdevice_notifier(&vlan_notifier_block); + if (err < 0) { + dev_remove_pack(&vlan_packet_type); + vlan_proc_cleanup(); + return err; + } vlan_ioctl_set(vlan_ioctl_handler); @@ -340,6 +340,34 @@ 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. @@ -436,6 +464,7 @@ 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; @@ -446,7 +475,9 @@ 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 & 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. @@ -484,7 +515,7 @@ static struct net_device *register_vlan_device(const char *eth_IF_name, 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_default_dev_flags; + VLAN_DEV_INFO(new_dev)->flags = 1; #ifdef VLAN_DEBUG printk(VLAN_DBG "About to go find the group for idx: %i\n", @@ -494,6 +525,12 @@ 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. */ @@ -503,12 +540,11 @@ 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 = 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, @@ -537,7 +573,7 @@ static struct net_device *register_vlan_device(const char *eth_IF_name, out_free_unregister: unregister_netdev(new_dev); - goto out_put_dev; + goto out_unlock; out_free_newdev: free_netdev(new_dev); @@ -568,18 +604,13 @@ static int vlan_device_event(struct notifier_block *unused, unsigned long event, switch (event) { case NETDEV_CHANGE: - /* Propogate real device state to vlan devices */ - flgs = dev->state & VLAN_LINK_STATE_MASK; + /* Propagate real device state to vlan devices */ for (i = 0; i < VLAN_GROUP_ARRAY_LEN; i++) { vlandev = grp->vlan_devices[i]; if (!vlandev) continue; - 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; @@ -646,15 +677,9 @@ out: static int vlan_ioctl_handler(void __user *arg) { int err = 0; + unsigned short vid = 0; struct vlan_ioctl_args args; - /* everything here needs root permissions, except aguably the - * hack ioctls for sending packets. However, I know _I_ don't - * want users running that on my network! --BLG - */ - if (!capable(CAP_NET_ADMIN)) - return -EPERM; - if (copy_from_user(&args, arg, sizeof(struct vlan_ioctl_args))) return -EFAULT; @@ -668,24 +693,32 @@ static int vlan_ioctl_handler(void __user *arg) switch (args.cmd) { case SET_VLAN_INGRESS_PRIORITY_CMD: + if (!capable(CAP_NET_ADMIN)) + return -EPERM; err = vlan_dev_set_ingress_priority(args.device1, args.u.skb_priority, args.vlan_qos); break; case SET_VLAN_EGRESS_PRIORITY_CMD: + if (!capable(CAP_NET_ADMIN)) + return -EPERM; err = vlan_dev_set_egress_priority(args.device1, args.u.skb_priority, args.vlan_qos); break; case SET_VLAN_FLAG_CMD: + if (!capable(CAP_NET_ADMIN)) + return -EPERM; err = vlan_dev_set_vlan_flag(args.device1, args.u.flag, args.vlan_qos); break; case SET_VLAN_NAME_TYPE_CMD: + if (!capable(CAP_NET_ADMIN)) + return -EPERM; if ((args.u.name_type >= 0) && (args.u.name_type < VLAN_NAME_TYPE_HIGHEST)) { vlan_name_type = args.u.name_type; @@ -695,17 +728,9 @@ static int vlan_ioctl_handler(void __user *arg) } break; - /* TODO: Figure out how to pass info back... - case GET_VLAN_INGRESS_PRIORITY_IOCTL: - err = vlan_dev_get_ingress_priority(args); - break; - - case GET_VLAN_EGRESS_PRIORITY_IOCTL: - err = vlan_dev_get_egress_priority(args); - break; - */ - case ADD_VLAN_CMD: + if (!capable(CAP_NET_ADMIN)) + return -EPERM; /* we have been given the name of the Ethernet Device we want to * talk to: args.dev1 We also have the * VLAN ID: args.u.VID @@ -718,20 +743,64 @@ static int vlan_ioctl_handler(void __user *arg) break; case DEL_VLAN_CMD: + if (!capable(CAP_NET_ADMIN)) + return -EPERM; /* Here, the args.dev1 is the actual VLAN we want * to get rid of. */ err = unregister_vlan_device(args.device1); break; + case GET_VLAN_INGRESS_PRIORITY_CMD: + /* TODO: Implement + err = vlan_dev_get_ingress_priority(args); + if (copy_to_user((void*)arg, &args, + sizeof(struct vlan_ioctl_args))) { + err = -EFAULT; + } + */ + err = -EINVAL; + break; + case GET_VLAN_EGRESS_PRIORITY_CMD: + /* 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; + } + */ + err = -EINVAL; + break; + case GET_VLAN_REALDEV_NAME_CMD: + err = vlan_dev_get_realdev_name(args.device1, args.u.device2); + if (err) + goto out; + if (copy_to_user(arg, &args, + sizeof(struct vlan_ioctl_args))) { + err = -EFAULT; + } + break; + + case GET_VLAN_VID_CMD: + err = vlan_dev_get_vid(args.device1, &vid); + if (err) + goto out; + args.u.VID = vid; + if (copy_to_user(arg, &args, + sizeof(struct vlan_ioctl_args))) { + err = -EFAULT; + } + break; + default: /* pass on to underlying device instead?? */ printk(VLAN_DBG "%s: Unknown VLAN CMD: %x \n", __FUNCTION__, args.cmd); return -EINVAL; }; - +out: return err; } MODULE_LICENSE("GPL"); +MODULE_VERSION(DRV_VERSION);