diff options
Diffstat (limited to 'net/8021q/vlan_dev.c')
-rw-r--r-- | net/8021q/vlan_dev.c | 167 |
1 files changed, 21 insertions, 146 deletions
diff --git a/net/8021q/vlan_dev.c b/net/8021q/vlan_dev.c index d4a62d1b52b4..4d2aa4dd42ac 100644 --- a/net/8021q/vlan_dev.c +++ b/net/8021q/vlan_dev.c | |||
@@ -612,90 +612,6 @@ void vlan_dev_get_vid(const struct net_device *dev, unsigned short *result) | |||
612 | *result = VLAN_DEV_INFO(dev)->vlan_id; | 612 | *result = VLAN_DEV_INFO(dev)->vlan_id; |
613 | } | 613 | } |
614 | 614 | ||
615 | static inline int vlan_dmi_equals(struct dev_mc_list *dmi1, | ||
616 | struct dev_mc_list *dmi2) | ||
617 | { | ||
618 | return ((dmi1->dmi_addrlen == dmi2->dmi_addrlen) && | ||
619 | (memcmp(dmi1->dmi_addr, dmi2->dmi_addr, dmi1->dmi_addrlen) == 0)); | ||
620 | } | ||
621 | |||
622 | /** dmi is a single entry into a dev_mc_list, a single node. mc_list is | ||
623 | * an entire list, and we'll iterate through it. | ||
624 | */ | ||
625 | static int vlan_should_add_mc(struct dev_mc_list *dmi, struct dev_mc_list *mc_list) | ||
626 | { | ||
627 | struct dev_mc_list *idmi; | ||
628 | |||
629 | for (idmi = mc_list; idmi != NULL; ) { | ||
630 | if (vlan_dmi_equals(dmi, idmi)) { | ||
631 | if (dmi->dmi_users > idmi->dmi_users) | ||
632 | return 1; | ||
633 | else | ||
634 | return 0; | ||
635 | } else { | ||
636 | idmi = idmi->next; | ||
637 | } | ||
638 | } | ||
639 | |||
640 | return 1; | ||
641 | } | ||
642 | |||
643 | static inline void vlan_destroy_mc_list(struct dev_mc_list *mc_list) | ||
644 | { | ||
645 | struct dev_mc_list *dmi = mc_list; | ||
646 | struct dev_mc_list *next; | ||
647 | |||
648 | while(dmi) { | ||
649 | next = dmi->next; | ||
650 | kfree(dmi); | ||
651 | dmi = next; | ||
652 | } | ||
653 | } | ||
654 | |||
655 | static void vlan_copy_mc_list(struct dev_mc_list *mc_list, struct vlan_dev_info *vlan_info) | ||
656 | { | ||
657 | struct dev_mc_list *dmi, *new_dmi; | ||
658 | |||
659 | vlan_destroy_mc_list(vlan_info->old_mc_list); | ||
660 | vlan_info->old_mc_list = NULL; | ||
661 | |||
662 | for (dmi = mc_list; dmi != NULL; dmi = dmi->next) { | ||
663 | new_dmi = kmalloc(sizeof(*new_dmi), GFP_ATOMIC); | ||
664 | if (new_dmi == NULL) { | ||
665 | printk(KERN_ERR "vlan: cannot allocate memory. " | ||
666 | "Multicast may not work properly from now.\n"); | ||
667 | return; | ||
668 | } | ||
669 | |||
670 | /* Copy whole structure, then make new 'next' pointer */ | ||
671 | *new_dmi = *dmi; | ||
672 | new_dmi->next = vlan_info->old_mc_list; | ||
673 | vlan_info->old_mc_list = new_dmi; | ||
674 | } | ||
675 | } | ||
676 | |||
677 | static void vlan_flush_mc_list(struct net_device *dev) | ||
678 | { | ||
679 | struct dev_mc_list *dmi = dev->mc_list; | ||
680 | |||
681 | while (dmi) { | ||
682 | printk(KERN_DEBUG "%s: del %.2x:%.2x:%.2x:%.2x:%.2x:%.2x mcast address from vlan interface\n", | ||
683 | dev->name, | ||
684 | dmi->dmi_addr[0], | ||
685 | dmi->dmi_addr[1], | ||
686 | dmi->dmi_addr[2], | ||
687 | dmi->dmi_addr[3], | ||
688 | dmi->dmi_addr[4], | ||
689 | dmi->dmi_addr[5]); | ||
690 | dev_mc_delete(dev, dmi->dmi_addr, dmi->dmi_addrlen, 0); | ||
691 | dmi = dev->mc_list; | ||
692 | } | ||
693 | |||
694 | /* dev->mc_list is NULL by the time we get here. */ | ||
695 | vlan_destroy_mc_list(VLAN_DEV_INFO(dev)->old_mc_list); | ||
696 | VLAN_DEV_INFO(dev)->old_mc_list = NULL; | ||
697 | } | ||
698 | |||
699 | int vlan_dev_open(struct net_device *dev) | 615 | int vlan_dev_open(struct net_device *dev) |
700 | { | 616 | { |
701 | struct vlan_dev_info *vlan = VLAN_DEV_INFO(dev); | 617 | struct vlan_dev_info *vlan = VLAN_DEV_INFO(dev); |
@@ -712,6 +628,11 @@ int vlan_dev_open(struct net_device *dev) | |||
712 | } | 628 | } |
713 | memcpy(vlan->real_dev_addr, real_dev->dev_addr, ETH_ALEN); | 629 | memcpy(vlan->real_dev_addr, real_dev->dev_addr, ETH_ALEN); |
714 | 630 | ||
631 | if (dev->flags & IFF_ALLMULTI) | ||
632 | dev_set_allmulti(real_dev, 1); | ||
633 | if (dev->flags & IFF_PROMISC) | ||
634 | dev_set_promiscuity(real_dev, 1); | ||
635 | |||
715 | return 0; | 636 | return 0; |
716 | } | 637 | } |
717 | 638 | ||
@@ -719,7 +640,11 @@ int vlan_dev_stop(struct net_device *dev) | |||
719 | { | 640 | { |
720 | struct net_device *real_dev = VLAN_DEV_INFO(dev)->real_dev; | 641 | struct net_device *real_dev = VLAN_DEV_INFO(dev)->real_dev; |
721 | 642 | ||
722 | vlan_flush_mc_list(dev); | 643 | dev_mc_unsync(real_dev, dev); |
644 | if (dev->flags & IFF_ALLMULTI) | ||
645 | dev_set_allmulti(real_dev, -1); | ||
646 | if (dev->flags & IFF_PROMISC) | ||
647 | dev_set_promiscuity(real_dev, -1); | ||
723 | 648 | ||
724 | if (compare_ether_addr(dev->dev_addr, real_dev->dev_addr)) | 649 | if (compare_ether_addr(dev->dev_addr, real_dev->dev_addr)) |
725 | dev_unicast_delete(real_dev, dev->dev_addr, dev->addr_len); | 650 | dev_unicast_delete(real_dev, dev->dev_addr, dev->addr_len); |
@@ -754,68 +679,18 @@ int vlan_dev_ioctl(struct net_device *dev, struct ifreq *ifr, int cmd) | |||
754 | return err; | 679 | return err; |
755 | } | 680 | } |
756 | 681 | ||
757 | /** Taken from Gleb + Lennert's VLAN code, and modified... */ | 682 | void vlan_change_rx_flags(struct net_device *dev, int change) |
758 | void vlan_dev_set_multicast_list(struct net_device *vlan_dev) | ||
759 | { | 683 | { |
760 | struct dev_mc_list *dmi; | 684 | struct net_device *real_dev = VLAN_DEV_INFO(dev)->real_dev; |
761 | struct net_device *real_dev; | ||
762 | int inc; | ||
763 | |||
764 | if (vlan_dev && (vlan_dev->priv_flags & IFF_802_1Q_VLAN)) { | ||
765 | /* Then it's a real vlan device, as far as we can tell.. */ | ||
766 | real_dev = VLAN_DEV_INFO(vlan_dev)->real_dev; | ||
767 | |||
768 | /* compare the current promiscuity to the last promisc we had.. */ | ||
769 | inc = vlan_dev->promiscuity - VLAN_DEV_INFO(vlan_dev)->old_promiscuity; | ||
770 | if (inc) { | ||
771 | printk(KERN_INFO "%s: dev_set_promiscuity(master, %d)\n", | ||
772 | vlan_dev->name, inc); | ||
773 | dev_set_promiscuity(real_dev, inc); /* found in dev.c */ | ||
774 | VLAN_DEV_INFO(vlan_dev)->old_promiscuity = vlan_dev->promiscuity; | ||
775 | } | ||
776 | |||
777 | inc = vlan_dev->allmulti - VLAN_DEV_INFO(vlan_dev)->old_allmulti; | ||
778 | if (inc) { | ||
779 | printk(KERN_INFO "%s: dev_set_allmulti(master, %d)\n", | ||
780 | vlan_dev->name, inc); | ||
781 | dev_set_allmulti(real_dev, inc); /* dev.c */ | ||
782 | VLAN_DEV_INFO(vlan_dev)->old_allmulti = vlan_dev->allmulti; | ||
783 | } | ||
784 | |||
785 | /* looking for addresses to add to master's list */ | ||
786 | for (dmi = vlan_dev->mc_list; dmi != NULL; dmi = dmi->next) { | ||
787 | if (vlan_should_add_mc(dmi, VLAN_DEV_INFO(vlan_dev)->old_mc_list)) { | ||
788 | dev_mc_add(real_dev, dmi->dmi_addr, dmi->dmi_addrlen, 0); | ||
789 | printk(KERN_DEBUG "%s: add %.2x:%.2x:%.2x:%.2x:%.2x:%.2x mcast address to master interface\n", | ||
790 | vlan_dev->name, | ||
791 | dmi->dmi_addr[0], | ||
792 | dmi->dmi_addr[1], | ||
793 | dmi->dmi_addr[2], | ||
794 | dmi->dmi_addr[3], | ||
795 | dmi->dmi_addr[4], | ||
796 | dmi->dmi_addr[5]); | ||
797 | } | ||
798 | } | ||
799 | 685 | ||
800 | /* looking for addresses to delete from master's list */ | 686 | if (change & IFF_ALLMULTI) |
801 | for (dmi = VLAN_DEV_INFO(vlan_dev)->old_mc_list; dmi != NULL; dmi = dmi->next) { | 687 | dev_set_allmulti(real_dev, dev->flags & IFF_ALLMULTI ? 1 : -1); |
802 | if (vlan_should_add_mc(dmi, vlan_dev->mc_list)) { | 688 | if (change & IFF_PROMISC) |
803 | /* if we think we should add it to the new list, then we should really | 689 | dev_set_promiscuity(real_dev, dev->flags & IFF_PROMISC ? 1 : -1); |
804 | * delete it from the real list on the underlying device. | 690 | } |
805 | */ | ||
806 | dev_mc_delete(real_dev, dmi->dmi_addr, dmi->dmi_addrlen, 0); | ||
807 | printk(KERN_DEBUG "%s: del %.2x:%.2x:%.2x:%.2x:%.2x:%.2x mcast address from master interface\n", | ||
808 | vlan_dev->name, | ||
809 | dmi->dmi_addr[0], | ||
810 | dmi->dmi_addr[1], | ||
811 | dmi->dmi_addr[2], | ||
812 | dmi->dmi_addr[3], | ||
813 | dmi->dmi_addr[4], | ||
814 | dmi->dmi_addr[5]); | ||
815 | } | ||
816 | } | ||
817 | 691 | ||
818 | /* save multicast list */ | 692 | /** Taken from Gleb + Lennert's VLAN code, and modified... */ |
819 | vlan_copy_mc_list(vlan_dev->mc_list, VLAN_DEV_INFO(vlan_dev)); | 693 | void vlan_dev_set_multicast_list(struct net_device *vlan_dev) |
820 | } | 694 | { |
695 | dev_mc_sync(VLAN_DEV_INFO(vlan_dev)->real_dev, vlan_dev); | ||
821 | } | 696 | } |