diff options
author | Patrick McHardy <kaber@trash.net> | 2007-07-11 22:45:24 -0400 |
---|---|---|
committer | David S. Miller <davem@davemloft.net> | 2007-07-11 22:45:24 -0400 |
commit | 8c979c26a0f093c13290320edda799d8335e50ae (patch) | |
tree | 3189e5568583a794aff9d014898ff9a74b79d7cc /net/8021q/vlan_dev.c | |
parent | 71bffe556c59a7865bf0b1ecd94530f1e296cdb0 (diff) |
[VLAN]: Fix MAC address handling
The VLAN MAC address handling is broken in multiple ways. When the address
differs when setting it, the real device is put in promiscous mode twice,
but never taken out again. Additionally it doesn't resync when the real
device's address is changed and needlessly puts it in promiscous mode when
the vlan device is still down.
Fix by moving address handling to vlan_dev_open/vlan_dev_stop and properly
deal with address changes in the device notifier. Also switch to
dev_unicast_add (which needs the exact same handling).
Since the set_mac_address handler is identical to the generic ethernet one
with these changes, kill it and use ether_setup().
Signed-off-by: Patrick McHardy <kaber@trash.net>
Signed-off-by: David S. Miller <davem@davemloft.net>
Diffstat (limited to 'net/8021q/vlan_dev.c')
-rw-r--r-- | net/8021q/vlan_dev.c | 57 |
1 files changed, 18 insertions, 39 deletions
diff --git a/net/8021q/vlan_dev.c b/net/8021q/vlan_dev.c index 95afe387b952..d4a62d1b52b4 100644 --- a/net/8021q/vlan_dev.c +++ b/net/8021q/vlan_dev.c | |||
@@ -612,44 +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 | int vlan_dev_set_mac_address(struct net_device *dev, void *addr_struct_p) | ||
616 | { | ||
617 | struct sockaddr *addr = (struct sockaddr *)(addr_struct_p); | ||
618 | int i; | ||
619 | |||
620 | if (netif_running(dev)) | ||
621 | return -EBUSY; | ||
622 | |||
623 | memcpy(dev->dev_addr, addr->sa_data, dev->addr_len); | ||
624 | |||
625 | printk("%s: Setting MAC address to ", dev->name); | ||
626 | for (i = 0; i < 6; i++) | ||
627 | printk(" %2.2x", dev->dev_addr[i]); | ||
628 | printk(".\n"); | ||
629 | |||
630 | if (memcmp(VLAN_DEV_INFO(dev)->real_dev->dev_addr, | ||
631 | dev->dev_addr, | ||
632 | dev->addr_len) != 0) { | ||
633 | if (!(VLAN_DEV_INFO(dev)->real_dev->flags & IFF_PROMISC)) { | ||
634 | int flgs = VLAN_DEV_INFO(dev)->real_dev->flags; | ||
635 | |||
636 | /* Increment our in-use promiscuity counter */ | ||
637 | dev_set_promiscuity(VLAN_DEV_INFO(dev)->real_dev, 1); | ||
638 | |||
639 | /* Make PROMISC visible to the user. */ | ||
640 | flgs |= IFF_PROMISC; | ||
641 | printk("VLAN (%s): Setting underlying device (%s) to promiscious mode.\n", | ||
642 | dev->name, VLAN_DEV_INFO(dev)->real_dev->name); | ||
643 | dev_change_flags(VLAN_DEV_INFO(dev)->real_dev, flgs); | ||
644 | } | ||
645 | } else { | ||
646 | printk("VLAN (%s): Underlying device (%s) has same MAC, not checking promiscious mode.\n", | ||
647 | dev->name, VLAN_DEV_INFO(dev)->real_dev->name); | ||
648 | } | ||
649 | |||
650 | return 0; | ||
651 | } | ||
652 | |||
653 | static inline int vlan_dmi_equals(struct dev_mc_list *dmi1, | 615 | static inline int vlan_dmi_equals(struct dev_mc_list *dmi1, |
654 | struct dev_mc_list *dmi2) | 616 | struct dev_mc_list *dmi2) |
655 | { | 617 | { |
@@ -736,15 +698,32 @@ static void vlan_flush_mc_list(struct net_device *dev) | |||
736 | 698 | ||
737 | int vlan_dev_open(struct net_device *dev) | 699 | int vlan_dev_open(struct net_device *dev) |
738 | { | 700 | { |
739 | if (!(VLAN_DEV_INFO(dev)->real_dev->flags & IFF_UP)) | 701 | struct vlan_dev_info *vlan = VLAN_DEV_INFO(dev); |
702 | struct net_device *real_dev = vlan->real_dev; | ||
703 | int err; | ||
704 | |||
705 | if (!(real_dev->flags & IFF_UP)) | ||
740 | return -ENETDOWN; | 706 | return -ENETDOWN; |
741 | 707 | ||
708 | if (compare_ether_addr(dev->dev_addr, real_dev->dev_addr)) { | ||
709 | err = dev_unicast_add(real_dev, dev->dev_addr, ETH_ALEN); | ||
710 | if (err < 0) | ||
711 | return err; | ||
712 | } | ||
713 | memcpy(vlan->real_dev_addr, real_dev->dev_addr, ETH_ALEN); | ||
714 | |||
742 | return 0; | 715 | return 0; |
743 | } | 716 | } |
744 | 717 | ||
745 | int vlan_dev_stop(struct net_device *dev) | 718 | int vlan_dev_stop(struct net_device *dev) |
746 | { | 719 | { |
720 | struct net_device *real_dev = VLAN_DEV_INFO(dev)->real_dev; | ||
721 | |||
747 | vlan_flush_mc_list(dev); | 722 | vlan_flush_mc_list(dev); |
723 | |||
724 | if (compare_ether_addr(dev->dev_addr, real_dev->dev_addr)) | ||
725 | dev_unicast_delete(real_dev, dev->dev_addr, dev->addr_len); | ||
726 | |||
748 | return 0; | 727 | return 0; |
749 | } | 728 | } |
750 | 729 | ||