diff options
Diffstat (limited to 'net/8021q/vlan.c')
-rw-r--r-- | net/8021q/vlan.c | 90 |
1 files changed, 29 insertions, 61 deletions
diff --git a/net/8021q/vlan.c b/net/8021q/vlan.c index a29c5ab5815c..33f90e7362cc 100644 --- a/net/8021q/vlan.c +++ b/net/8021q/vlan.c | |||
@@ -41,7 +41,7 @@ | |||
41 | 41 | ||
42 | /* Global VLAN variables */ | 42 | /* Global VLAN variables */ |
43 | 43 | ||
44 | int vlan_net_id; | 44 | int vlan_net_id __read_mostly; |
45 | 45 | ||
46 | /* Our listing of VLAN group(s) */ | 46 | /* Our listing of VLAN group(s) */ |
47 | static struct hlist_head vlan_group_hash[VLAN_GRP_HASH_SIZE]; | 47 | static struct hlist_head vlan_group_hash[VLAN_GRP_HASH_SIZE]; |
@@ -140,7 +140,7 @@ static void vlan_rcu_free(struct rcu_head *rcu) | |||
140 | vlan_group_free(container_of(rcu, struct vlan_group, rcu)); | 140 | vlan_group_free(container_of(rcu, struct vlan_group, rcu)); |
141 | } | 141 | } |
142 | 142 | ||
143 | void unregister_vlan_dev(struct net_device *dev) | 143 | void unregister_vlan_dev(struct net_device *dev, struct list_head *head) |
144 | { | 144 | { |
145 | struct vlan_dev_info *vlan = vlan_dev_info(dev); | 145 | struct vlan_dev_info *vlan = vlan_dev_info(dev); |
146 | struct net_device *real_dev = vlan->real_dev; | 146 | struct net_device *real_dev = vlan->real_dev; |
@@ -159,12 +159,13 @@ void unregister_vlan_dev(struct net_device *dev) | |||
159 | if (real_dev->features & NETIF_F_HW_VLAN_FILTER) | 159 | if (real_dev->features & NETIF_F_HW_VLAN_FILTER) |
160 | ops->ndo_vlan_rx_kill_vid(real_dev, vlan_id); | 160 | ops->ndo_vlan_rx_kill_vid(real_dev, vlan_id); |
161 | 161 | ||
162 | vlan_group_set_device(grp, vlan_id, NULL); | ||
163 | grp->nr_vlans--; | 162 | grp->nr_vlans--; |
164 | 163 | ||
165 | synchronize_net(); | 164 | vlan_group_set_device(grp, vlan_id, NULL); |
165 | if (!grp->killall) | ||
166 | synchronize_net(); | ||
166 | 167 | ||
167 | unregister_netdevice(dev); | 168 | unregister_netdevice_queue(dev, head); |
168 | 169 | ||
169 | /* If the group is now empty, kill off the group. */ | 170 | /* If the group is now empty, kill off the group. */ |
170 | if (grp->nr_vlans == 0) { | 171 | if (grp->nr_vlans == 0) { |
@@ -183,27 +184,6 @@ void unregister_vlan_dev(struct net_device *dev) | |||
183 | dev_put(real_dev); | 184 | dev_put(real_dev); |
184 | } | 185 | } |
185 | 186 | ||
186 | static void vlan_transfer_operstate(const struct net_device *dev, | ||
187 | struct net_device *vlandev) | ||
188 | { | ||
189 | /* Have to respect userspace enforced dormant state | ||
190 | * of real device, also must allow supplicant running | ||
191 | * on VLAN device | ||
192 | */ | ||
193 | if (dev->operstate == IF_OPER_DORMANT) | ||
194 | netif_dormant_on(vlandev); | ||
195 | else | ||
196 | netif_dormant_off(vlandev); | ||
197 | |||
198 | if (netif_carrier_ok(dev)) { | ||
199 | if (!netif_carrier_ok(vlandev)) | ||
200 | netif_carrier_on(vlandev); | ||
201 | } else { | ||
202 | if (netif_carrier_ok(vlandev)) | ||
203 | netif_carrier_off(vlandev); | ||
204 | } | ||
205 | } | ||
206 | |||
207 | int vlan_check_real_dev(struct net_device *real_dev, u16 vlan_id) | 187 | int vlan_check_real_dev(struct net_device *real_dev, u16 vlan_id) |
208 | { | 188 | { |
209 | const char *name = real_dev->name; | 189 | const char *name = real_dev->name; |
@@ -261,7 +241,7 @@ int register_vlan_dev(struct net_device *dev) | |||
261 | /* Account for reference in struct vlan_dev_info */ | 241 | /* Account for reference in struct vlan_dev_info */ |
262 | dev_hold(real_dev); | 242 | dev_hold(real_dev); |
263 | 243 | ||
264 | vlan_transfer_operstate(real_dev, dev); | 244 | netif_stacked_transfer_operstate(real_dev, dev); |
265 | linkwatch_fire_event(dev); /* _MUST_ call rfc2863_policy() */ | 245 | linkwatch_fire_event(dev); /* _MUST_ call rfc2863_policy() */ |
266 | 246 | ||
267 | /* So, got the sucker initialized, now lets place | 247 | /* So, got the sucker initialized, now lets place |
@@ -430,6 +410,8 @@ static int vlan_device_event(struct notifier_block *unused, unsigned long event, | |||
430 | struct vlan_group *grp; | 410 | struct vlan_group *grp; |
431 | int i, flgs; | 411 | int i, flgs; |
432 | struct net_device *vlandev; | 412 | struct net_device *vlandev; |
413 | struct vlan_dev_info *vlan; | ||
414 | LIST_HEAD(list); | ||
433 | 415 | ||
434 | if (is_vlan_dev(dev)) | 416 | if (is_vlan_dev(dev)) |
435 | __vlan_device_event(dev, event); | 417 | __vlan_device_event(dev, event); |
@@ -450,7 +432,7 @@ static int vlan_device_event(struct notifier_block *unused, unsigned long event, | |||
450 | if (!vlandev) | 432 | if (!vlandev) |
451 | continue; | 433 | continue; |
452 | 434 | ||
453 | vlan_transfer_operstate(dev, vlandev); | 435 | netif_stacked_transfer_operstate(dev, vlandev); |
454 | } | 436 | } |
455 | break; | 437 | break; |
456 | 438 | ||
@@ -505,8 +487,10 @@ static int vlan_device_event(struct notifier_block *unused, unsigned long event, | |||
505 | if (!(flgs & IFF_UP)) | 487 | if (!(flgs & IFF_UP)) |
506 | continue; | 488 | continue; |
507 | 489 | ||
508 | dev_change_flags(vlandev, flgs & ~IFF_UP); | 490 | vlan = vlan_dev_info(vlandev); |
509 | vlan_transfer_operstate(dev, vlandev); | 491 | if (!(vlan->flags & VLAN_FLAG_LOOSE_BINDING)) |
492 | dev_change_flags(vlandev, flgs & ~IFF_UP); | ||
493 | netif_stacked_transfer_operstate(dev, vlandev); | ||
510 | } | 494 | } |
511 | break; | 495 | break; |
512 | 496 | ||
@@ -521,13 +505,17 @@ static int vlan_device_event(struct notifier_block *unused, unsigned long event, | |||
521 | if (flgs & IFF_UP) | 505 | if (flgs & IFF_UP) |
522 | continue; | 506 | continue; |
523 | 507 | ||
524 | dev_change_flags(vlandev, flgs | IFF_UP); | 508 | vlan = vlan_dev_info(vlandev); |
525 | vlan_transfer_operstate(dev, vlandev); | 509 | if (!(vlan->flags & VLAN_FLAG_LOOSE_BINDING)) |
510 | dev_change_flags(vlandev, flgs | IFF_UP); | ||
511 | netif_stacked_transfer_operstate(dev, vlandev); | ||
526 | } | 512 | } |
527 | break; | 513 | break; |
528 | 514 | ||
529 | case NETDEV_UNREGISTER: | 515 | case NETDEV_UNREGISTER: |
530 | /* Delete all VLANs for this dev. */ | 516 | /* Delete all VLANs for this dev. */ |
517 | grp->killall = 1; | ||
518 | |||
531 | for (i = 0; i < VLAN_GROUP_ARRAY_LEN; i++) { | 519 | for (i = 0; i < VLAN_GROUP_ARRAY_LEN; i++) { |
532 | vlandev = vlan_group_get_device(grp, i); | 520 | vlandev = vlan_group_get_device(grp, i); |
533 | if (!vlandev) | 521 | if (!vlandev) |
@@ -538,8 +526,9 @@ static int vlan_device_event(struct notifier_block *unused, unsigned long event, | |||
538 | if (grp->nr_vlans == 1) | 526 | if (grp->nr_vlans == 1) |
539 | i = VLAN_GROUP_ARRAY_LEN; | 527 | i = VLAN_GROUP_ARRAY_LEN; |
540 | 528 | ||
541 | unregister_vlan_dev(vlandev); | 529 | unregister_vlan_dev(vlandev, &list); |
542 | } | 530 | } |
531 | unregister_netdevice_many(&list); | ||
543 | break; | 532 | break; |
544 | } | 533 | } |
545 | 534 | ||
@@ -645,7 +634,7 @@ static int vlan_ioctl_handler(struct net *net, void __user *arg) | |||
645 | err = -EPERM; | 634 | err = -EPERM; |
646 | if (!capable(CAP_NET_ADMIN)) | 635 | if (!capable(CAP_NET_ADMIN)) |
647 | break; | 636 | break; |
648 | unregister_vlan_dev(dev); | 637 | unregister_vlan_dev(dev, NULL); |
649 | err = 0; | 638 | err = 0; |
650 | break; | 639 | break; |
651 | 640 | ||
@@ -676,47 +665,26 @@ out: | |||
676 | 665 | ||
677 | static int vlan_init_net(struct net *net) | 666 | static int vlan_init_net(struct net *net) |
678 | { | 667 | { |
668 | struct vlan_net *vn = net_generic(net, vlan_net_id); | ||
679 | int err; | 669 | int err; |
680 | struct vlan_net *vn; | ||
681 | |||
682 | err = -ENOMEM; | ||
683 | vn = kzalloc(sizeof(struct vlan_net), GFP_KERNEL); | ||
684 | if (vn == NULL) | ||
685 | goto err_alloc; | ||
686 | |||
687 | err = net_assign_generic(net, vlan_net_id, vn); | ||
688 | if (err < 0) | ||
689 | goto err_assign; | ||
690 | 670 | ||
691 | vn->name_type = VLAN_NAME_TYPE_RAW_PLUS_VID_NO_PAD; | 671 | vn->name_type = VLAN_NAME_TYPE_RAW_PLUS_VID_NO_PAD; |
692 | 672 | ||
693 | err = vlan_proc_init(net); | 673 | err = vlan_proc_init(net); |
694 | if (err < 0) | ||
695 | goto err_proc; | ||
696 | |||
697 | return 0; | ||
698 | 674 | ||
699 | err_proc: | ||
700 | /* nothing */ | ||
701 | err_assign: | ||
702 | kfree(vn); | ||
703 | err_alloc: | ||
704 | return err; | 675 | return err; |
705 | } | 676 | } |
706 | 677 | ||
707 | static void vlan_exit_net(struct net *net) | 678 | static void vlan_exit_net(struct net *net) |
708 | { | 679 | { |
709 | struct vlan_net *vn; | ||
710 | |||
711 | vn = net_generic(net, vlan_net_id); | ||
712 | rtnl_kill_links(net, &vlan_link_ops); | ||
713 | vlan_proc_cleanup(net); | 680 | vlan_proc_cleanup(net); |
714 | kfree(vn); | ||
715 | } | 681 | } |
716 | 682 | ||
717 | static struct pernet_operations vlan_net_ops = { | 683 | static struct pernet_operations vlan_net_ops = { |
718 | .init = vlan_init_net, | 684 | .init = vlan_init_net, |
719 | .exit = vlan_exit_net, | 685 | .exit = vlan_exit_net, |
686 | .id = &vlan_net_id, | ||
687 | .size = sizeof(struct vlan_net), | ||
720 | }; | 688 | }; |
721 | 689 | ||
722 | static int __init vlan_proto_init(void) | 690 | static int __init vlan_proto_init(void) |
@@ -726,7 +694,7 @@ static int __init vlan_proto_init(void) | |||
726 | pr_info("%s v%s %s\n", vlan_fullname, vlan_version, vlan_copyright); | 694 | pr_info("%s v%s %s\n", vlan_fullname, vlan_version, vlan_copyright); |
727 | pr_info("All bugs added by %s\n", vlan_buggyright); | 695 | pr_info("All bugs added by %s\n", vlan_buggyright); |
728 | 696 | ||
729 | err = register_pernet_gen_device(&vlan_net_id, &vlan_net_ops); | 697 | err = register_pernet_subsys(&vlan_net_ops); |
730 | if (err < 0) | 698 | if (err < 0) |
731 | goto err0; | 699 | goto err0; |
732 | 700 | ||
@@ -751,7 +719,7 @@ err4: | |||
751 | err3: | 719 | err3: |
752 | unregister_netdevice_notifier(&vlan_notifier_block); | 720 | unregister_netdevice_notifier(&vlan_notifier_block); |
753 | err2: | 721 | err2: |
754 | unregister_pernet_gen_device(vlan_net_id, &vlan_net_ops); | 722 | unregister_pernet_subsys(&vlan_net_ops); |
755 | err0: | 723 | err0: |
756 | return err; | 724 | return err; |
757 | } | 725 | } |
@@ -771,7 +739,7 @@ static void __exit vlan_cleanup_module(void) | |||
771 | for (i = 0; i < VLAN_GRP_HASH_SIZE; i++) | 739 | for (i = 0; i < VLAN_GRP_HASH_SIZE; i++) |
772 | BUG_ON(!hlist_empty(&vlan_group_hash[i])); | 740 | BUG_ON(!hlist_empty(&vlan_group_hash[i])); |
773 | 741 | ||
774 | unregister_pernet_gen_device(vlan_net_id, &vlan_net_ops); | 742 | unregister_pernet_subsys(&vlan_net_ops); |
775 | rcu_barrier(); /* Wait for completion of call_rcu()'s */ | 743 | rcu_barrier(); /* Wait for completion of call_rcu()'s */ |
776 | 744 | ||
777 | vlan_gvrp_uninit(); | 745 | vlan_gvrp_uninit(); |