diff options
Diffstat (limited to 'net/8021q/vlan.c')
-rw-r--r-- | net/8021q/vlan.c | 153 |
1 files changed, 64 insertions, 89 deletions
diff --git a/net/8021q/vlan.c b/net/8021q/vlan.c index de78c9dd713b..3678f0719934 100644 --- a/net/8021q/vlan.c +++ b/net/8021q/vlan.c | |||
@@ -278,43 +278,16 @@ static int unregister_vlan_dev(struct net_device *real_dev, | |||
278 | return ret; | 278 | return ret; |
279 | } | 279 | } |
280 | 280 | ||
281 | static int unregister_vlan_device(const char *vlan_IF_name) | 281 | static int unregister_vlan_device(struct net_device *dev) |
282 | { | 282 | { |
283 | struct net_device *dev = NULL; | ||
284 | int ret; | 283 | int ret; |
285 | 284 | ||
285 | ret = unregister_vlan_dev(VLAN_DEV_INFO(dev)->real_dev, | ||
286 | VLAN_DEV_INFO(dev)->vlan_id); | ||
287 | unregister_netdevice(dev); | ||
286 | 288 | ||
287 | dev = dev_get_by_name(vlan_IF_name); | 289 | if (ret == 1) |
288 | ret = -EINVAL; | 290 | ret = 0; |
289 | if (dev) { | ||
290 | if (dev->priv_flags & IFF_802_1Q_VLAN) { | ||
291 | rtnl_lock(); | ||
292 | |||
293 | ret = unregister_vlan_dev(VLAN_DEV_INFO(dev)->real_dev, | ||
294 | VLAN_DEV_INFO(dev)->vlan_id); | ||
295 | |||
296 | dev_put(dev); | ||
297 | unregister_netdevice(dev); | ||
298 | |||
299 | rtnl_unlock(); | ||
300 | |||
301 | if (ret == 1) | ||
302 | ret = 0; | ||
303 | } else { | ||
304 | printk(VLAN_ERR | ||
305 | "%s: ERROR: Tried to remove a non-vlan device " | ||
306 | "with VLAN code, name: %s priv_flags: %hX\n", | ||
307 | __FUNCTION__, dev->name, dev->priv_flags); | ||
308 | dev_put(dev); | ||
309 | ret = -EPERM; | ||
310 | } | ||
311 | } else { | ||
312 | #ifdef VLAN_DEBUG | ||
313 | printk(VLAN_DBG "%s: WARNING: Could not find dev.\n", __FUNCTION__); | ||
314 | #endif | ||
315 | ret = -EINVAL; | ||
316 | } | ||
317 | |||
318 | return ret; | 291 | return ret; |
319 | } | 292 | } |
320 | 293 | ||
@@ -378,12 +351,11 @@ static struct lock_class_key vlan_netdev_xmit_lock_key; | |||
378 | * Returns the device that was created, or NULL if there was | 351 | * Returns the device that was created, or NULL if there was |
379 | * an error of some kind. | 352 | * an error of some kind. |
380 | */ | 353 | */ |
381 | static struct net_device *register_vlan_device(const char *eth_IF_name, | 354 | static struct net_device *register_vlan_device(struct net_device *real_dev, |
382 | unsigned short VLAN_ID) | 355 | unsigned short VLAN_ID) |
383 | { | 356 | { |
384 | struct vlan_group *grp; | 357 | struct vlan_group *grp; |
385 | struct net_device *new_dev; | 358 | struct net_device *new_dev; |
386 | struct net_device *real_dev; /* the ethernet device */ | ||
387 | char name[IFNAMSIZ]; | 359 | char name[IFNAMSIZ]; |
388 | int i; | 360 | int i; |
389 | 361 | ||
@@ -395,46 +367,36 @@ static struct net_device *register_vlan_device(const char *eth_IF_name, | |||
395 | if (VLAN_ID >= VLAN_VID_MASK) | 367 | if (VLAN_ID >= VLAN_VID_MASK) |
396 | goto out_ret_null; | 368 | goto out_ret_null; |
397 | 369 | ||
398 | /* find the device relating to eth_IF_name. */ | ||
399 | real_dev = dev_get_by_name(eth_IF_name); | ||
400 | if (!real_dev) | ||
401 | goto out_ret_null; | ||
402 | |||
403 | if (real_dev->features & NETIF_F_VLAN_CHALLENGED) { | 370 | if (real_dev->features & NETIF_F_VLAN_CHALLENGED) { |
404 | printk(VLAN_DBG "%s: VLANs not supported on %s.\n", | 371 | printk(VLAN_DBG "%s: VLANs not supported on %s.\n", |
405 | __FUNCTION__, real_dev->name); | 372 | __FUNCTION__, real_dev->name); |
406 | goto out_put_dev; | 373 | goto out_ret_null; |
407 | } | 374 | } |
408 | 375 | ||
409 | if ((real_dev->features & NETIF_F_HW_VLAN_RX) && | 376 | if ((real_dev->features & NETIF_F_HW_VLAN_RX) && |
410 | !real_dev->vlan_rx_register) { | 377 | !real_dev->vlan_rx_register) { |
411 | printk(VLAN_DBG "%s: Device %s has buggy VLAN hw accel.\n", | 378 | printk(VLAN_DBG "%s: Device %s has buggy VLAN hw accel.\n", |
412 | __FUNCTION__, real_dev->name); | 379 | __FUNCTION__, real_dev->name); |
413 | goto out_put_dev; | 380 | goto out_ret_null; |
414 | } | 381 | } |
415 | 382 | ||
416 | if ((real_dev->features & NETIF_F_HW_VLAN_FILTER) && | 383 | if ((real_dev->features & NETIF_F_HW_VLAN_FILTER) && |
417 | (!real_dev->vlan_rx_add_vid || !real_dev->vlan_rx_kill_vid)) { | 384 | (!real_dev->vlan_rx_add_vid || !real_dev->vlan_rx_kill_vid)) { |
418 | printk(VLAN_DBG "%s: Device %s has buggy VLAN hw accel.\n", | 385 | printk(VLAN_DBG "%s: Device %s has buggy VLAN hw accel.\n", |
419 | __FUNCTION__, real_dev->name); | 386 | __FUNCTION__, real_dev->name); |
420 | goto out_put_dev; | 387 | goto out_ret_null; |
421 | } | 388 | } |
422 | 389 | ||
423 | /* From this point on, all the data structures must remain | ||
424 | * consistent. | ||
425 | */ | ||
426 | rtnl_lock(); | ||
427 | |||
428 | /* The real device must be up and operating in order to | 390 | /* The real device must be up and operating in order to |
429 | * assosciate a VLAN device with it. | 391 | * assosciate a VLAN device with it. |
430 | */ | 392 | */ |
431 | if (!(real_dev->flags & IFF_UP)) | 393 | if (!(real_dev->flags & IFF_UP)) |
432 | goto out_unlock; | 394 | goto out_ret_null; |
433 | 395 | ||
434 | if (__find_vlan_dev(real_dev, VLAN_ID) != NULL) { | 396 | if (__find_vlan_dev(real_dev, VLAN_ID) != NULL) { |
435 | /* was already registered. */ | 397 | /* was already registered. */ |
436 | printk(VLAN_DBG "%s: ALREADY had VLAN registered\n", __FUNCTION__); | 398 | printk(VLAN_DBG "%s: ALREADY had VLAN registered\n", __FUNCTION__); |
437 | goto out_unlock; | 399 | goto out_ret_null; |
438 | } | 400 | } |
439 | 401 | ||
440 | /* Gotta set up the fields for the device. */ | 402 | /* Gotta set up the fields for the device. */ |
@@ -471,7 +433,7 @@ static struct net_device *register_vlan_device(const char *eth_IF_name, | |||
471 | vlan_setup); | 433 | vlan_setup); |
472 | 434 | ||
473 | if (new_dev == NULL) | 435 | if (new_dev == NULL) |
474 | goto out_unlock; | 436 | goto out_ret_null; |
475 | 437 | ||
476 | #ifdef VLAN_DEBUG | 438 | #ifdef VLAN_DEBUG |
477 | printk(VLAN_DBG "Allocated new name -:%s:-\n", new_dev->name); | 439 | printk(VLAN_DBG "Allocated new name -:%s:-\n", new_dev->name); |
@@ -577,9 +539,8 @@ static struct net_device *register_vlan_device(const char *eth_IF_name, | |||
577 | if (real_dev->features & NETIF_F_HW_VLAN_FILTER) | 539 | if (real_dev->features & NETIF_F_HW_VLAN_FILTER) |
578 | real_dev->vlan_rx_add_vid(real_dev, VLAN_ID); | 540 | real_dev->vlan_rx_add_vid(real_dev, VLAN_ID); |
579 | 541 | ||
580 | rtnl_unlock(); | 542 | /* Account for reference in struct vlan_dev_info */ |
581 | 543 | dev_hold(real_dev); | |
582 | |||
583 | #ifdef VLAN_DEBUG | 544 | #ifdef VLAN_DEBUG |
584 | printk(VLAN_DBG "Allocated new device successfully, returning.\n"); | 545 | printk(VLAN_DBG "Allocated new device successfully, returning.\n"); |
585 | #endif | 546 | #endif |
@@ -590,17 +551,11 @@ out_free_arrays: | |||
590 | 551 | ||
591 | out_free_unregister: | 552 | out_free_unregister: |
592 | unregister_netdev(new_dev); | 553 | unregister_netdev(new_dev); |
593 | goto out_unlock; | 554 | goto out_ret_null; |
594 | 555 | ||
595 | out_free_newdev: | 556 | out_free_newdev: |
596 | free_netdev(new_dev); | 557 | free_netdev(new_dev); |
597 | 558 | ||
598 | out_unlock: | ||
599 | rtnl_unlock(); | ||
600 | |||
601 | out_put_dev: | ||
602 | dev_put(real_dev); | ||
603 | |||
604 | out_ret_null: | 559 | out_ret_null: |
605 | return NULL; | 560 | return NULL; |
606 | } | 561 | } |
@@ -693,9 +648,10 @@ out: | |||
693 | */ | 648 | */ |
694 | static int vlan_ioctl_handler(void __user *arg) | 649 | static int vlan_ioctl_handler(void __user *arg) |
695 | { | 650 | { |
696 | int err = 0; | 651 | int err; |
697 | unsigned short vid = 0; | 652 | unsigned short vid = 0; |
698 | struct vlan_ioctl_args args; | 653 | struct vlan_ioctl_args args; |
654 | struct net_device *dev = NULL; | ||
699 | 655 | ||
700 | if (copy_from_user(&args, arg, sizeof(struct vlan_ioctl_args))) | 656 | if (copy_from_user(&args, arg, sizeof(struct vlan_ioctl_args))) |
701 | return -EFAULT; | 657 | return -EFAULT; |
@@ -708,35 +664,61 @@ static int vlan_ioctl_handler(void __user *arg) | |||
708 | printk(VLAN_DBG "%s: args.cmd: %x\n", __FUNCTION__, args.cmd); | 664 | printk(VLAN_DBG "%s: args.cmd: %x\n", __FUNCTION__, args.cmd); |
709 | #endif | 665 | #endif |
710 | 666 | ||
667 | rtnl_lock(); | ||
668 | |||
711 | switch (args.cmd) { | 669 | switch (args.cmd) { |
712 | case SET_VLAN_INGRESS_PRIORITY_CMD: | 670 | case SET_VLAN_INGRESS_PRIORITY_CMD: |
671 | case SET_VLAN_EGRESS_PRIORITY_CMD: | ||
672 | case SET_VLAN_FLAG_CMD: | ||
673 | case ADD_VLAN_CMD: | ||
674 | case DEL_VLAN_CMD: | ||
675 | case GET_VLAN_REALDEV_NAME_CMD: | ||
676 | case GET_VLAN_VID_CMD: | ||
677 | err = -ENODEV; | ||
678 | dev = __dev_get_by_name(args.device1); | ||
679 | if (!dev) | ||
680 | goto out; | ||
681 | |||
682 | err = -EINVAL; | ||
683 | if (args.cmd != ADD_VLAN_CMD && | ||
684 | !(dev->priv_flags & IFF_802_1Q_VLAN)) | ||
685 | goto out; | ||
686 | } | ||
687 | |||
688 | switch (args.cmd) { | ||
689 | case SET_VLAN_INGRESS_PRIORITY_CMD: | ||
690 | err = -EPERM; | ||
713 | if (!capable(CAP_NET_ADMIN)) | 691 | if (!capable(CAP_NET_ADMIN)) |
714 | return -EPERM; | 692 | break; |
715 | err = vlan_dev_set_ingress_priority(args.device1, | 693 | vlan_dev_set_ingress_priority(dev, |
716 | args.u.skb_priority, | 694 | args.u.skb_priority, |
717 | args.vlan_qos); | 695 | args.vlan_qos); |
718 | break; | 696 | break; |
719 | 697 | ||
720 | case SET_VLAN_EGRESS_PRIORITY_CMD: | 698 | case SET_VLAN_EGRESS_PRIORITY_CMD: |
699 | err = -EPERM; | ||
721 | if (!capable(CAP_NET_ADMIN)) | 700 | if (!capable(CAP_NET_ADMIN)) |
722 | return -EPERM; | 701 | break; |
723 | err = vlan_dev_set_egress_priority(args.device1, | 702 | err = vlan_dev_set_egress_priority(dev, |
724 | args.u.skb_priority, | 703 | args.u.skb_priority, |
725 | args.vlan_qos); | 704 | args.vlan_qos); |
726 | break; | 705 | break; |
727 | 706 | ||
728 | case SET_VLAN_FLAG_CMD: | 707 | case SET_VLAN_FLAG_CMD: |
708 | err = -EPERM; | ||
729 | if (!capable(CAP_NET_ADMIN)) | 709 | if (!capable(CAP_NET_ADMIN)) |
730 | return -EPERM; | 710 | break; |
731 | err = vlan_dev_set_vlan_flag(args.device1, | 711 | err = vlan_dev_set_vlan_flag(dev, |
732 | args.u.flag, | 712 | args.u.flag, |
733 | args.vlan_qos); | 713 | args.vlan_qos); |
734 | break; | 714 | break; |
735 | 715 | ||
736 | case SET_VLAN_NAME_TYPE_CMD: | 716 | case SET_VLAN_NAME_TYPE_CMD: |
717 | err = -EPERM; | ||
737 | if (!capable(CAP_NET_ADMIN)) | 718 | if (!capable(CAP_NET_ADMIN)) |
738 | return -EPERM; | 719 | return -EPERM; |
739 | if (args.u.name_type < VLAN_NAME_TYPE_HIGHEST) { | 720 | if ((args.u.name_type >= 0) && |
721 | (args.u.name_type < VLAN_NAME_TYPE_HIGHEST)) { | ||
740 | vlan_name_type = args.u.name_type; | 722 | vlan_name_type = args.u.name_type; |
741 | err = 0; | 723 | err = 0; |
742 | } else { | 724 | } else { |
@@ -745,13 +727,10 @@ static int vlan_ioctl_handler(void __user *arg) | |||
745 | break; | 727 | break; |
746 | 728 | ||
747 | case ADD_VLAN_CMD: | 729 | case ADD_VLAN_CMD: |
730 | err = -EPERM; | ||
748 | if (!capable(CAP_NET_ADMIN)) | 731 | if (!capable(CAP_NET_ADMIN)) |
749 | return -EPERM; | 732 | break; |
750 | /* we have been given the name of the Ethernet Device we want to | 733 | if (register_vlan_device(dev, args.u.VID)) { |
751 | * talk to: args.dev1 We also have the | ||
752 | * VLAN ID: args.u.VID | ||
753 | */ | ||
754 | if (register_vlan_device(args.device1, args.u.VID)) { | ||
755 | err = 0; | 734 | err = 0; |
756 | } else { | 735 | } else { |
757 | err = -EINVAL; | 736 | err = -EINVAL; |
@@ -759,12 +738,10 @@ static int vlan_ioctl_handler(void __user *arg) | |||
759 | break; | 738 | break; |
760 | 739 | ||
761 | case DEL_VLAN_CMD: | 740 | case DEL_VLAN_CMD: |
741 | err = -EPERM; | ||
762 | if (!capable(CAP_NET_ADMIN)) | 742 | if (!capable(CAP_NET_ADMIN)) |
763 | return -EPERM; | 743 | break; |
764 | /* Here, the args.dev1 is the actual VLAN we want | 744 | err = unregister_vlan_device(dev); |
765 | * to get rid of. | ||
766 | */ | ||
767 | err = unregister_vlan_device(args.device1); | ||
768 | break; | 745 | break; |
769 | 746 | ||
770 | case GET_VLAN_INGRESS_PRIORITY_CMD: | 747 | case GET_VLAN_INGRESS_PRIORITY_CMD: |
@@ -788,9 +765,7 @@ static int vlan_ioctl_handler(void __user *arg) | |||
788 | err = -EINVAL; | 765 | err = -EINVAL; |
789 | break; | 766 | break; |
790 | case GET_VLAN_REALDEV_NAME_CMD: | 767 | case GET_VLAN_REALDEV_NAME_CMD: |
791 | err = vlan_dev_get_realdev_name(args.device1, args.u.device2); | 768 | vlan_dev_get_realdev_name(dev, args.u.device2); |
792 | if (err) | ||
793 | goto out; | ||
794 | if (copy_to_user(arg, &args, | 769 | if (copy_to_user(arg, &args, |
795 | sizeof(struct vlan_ioctl_args))) { | 770 | sizeof(struct vlan_ioctl_args))) { |
796 | err = -EFAULT; | 771 | err = -EFAULT; |
@@ -798,9 +773,7 @@ static int vlan_ioctl_handler(void __user *arg) | |||
798 | break; | 773 | break; |
799 | 774 | ||
800 | case GET_VLAN_VID_CMD: | 775 | case GET_VLAN_VID_CMD: |
801 | err = vlan_dev_get_vid(args.device1, &vid); | 776 | vlan_dev_get_vid(dev, &vid); |
802 | if (err) | ||
803 | goto out; | ||
804 | args.u.VID = vid; | 777 | args.u.VID = vid; |
805 | if (copy_to_user(arg, &args, | 778 | if (copy_to_user(arg, &args, |
806 | sizeof(struct vlan_ioctl_args))) { | 779 | sizeof(struct vlan_ioctl_args))) { |
@@ -812,9 +785,11 @@ static int vlan_ioctl_handler(void __user *arg) | |||
812 | /* pass on to underlying device instead?? */ | 785 | /* pass on to underlying device instead?? */ |
813 | printk(VLAN_DBG "%s: Unknown VLAN CMD: %x \n", | 786 | printk(VLAN_DBG "%s: Unknown VLAN CMD: %x \n", |
814 | __FUNCTION__, args.cmd); | 787 | __FUNCTION__, args.cmd); |
815 | return -EINVAL; | 788 | err = -EINVAL; |
789 | break; | ||
816 | } | 790 | } |
817 | out: | 791 | out: |
792 | rtnl_unlock(); | ||
818 | return err; | 793 | return err; |
819 | } | 794 | } |
820 | 795 | ||