diff options
Diffstat (limited to 'net')
-rw-r--r-- | net/8021q/vlan.c | 43 | ||||
-rw-r--r-- | net/8021q/vlan.h | 1 | ||||
-rw-r--r-- | net/8021q/vlan_dev.c | 57 |
3 files changed, 56 insertions, 45 deletions
diff --git a/net/8021q/vlan.c b/net/8021q/vlan.c index e7583eea6fda..b463ba47024d 100644 --- a/net/8021q/vlan.c +++ b/net/8021q/vlan.c | |||
@@ -345,12 +345,8 @@ static int vlan_dev_init(struct net_device *dev) | |||
345 | (1<<__LINK_STATE_DORMANT))) | | 345 | (1<<__LINK_STATE_DORMANT))) | |
346 | (1<<__LINK_STATE_PRESENT); | 346 | (1<<__LINK_STATE_PRESENT); |
347 | 347 | ||
348 | /* TODO: maybe just assign it to be ETHERNET? */ | ||
349 | dev->type = real_dev->type; | ||
350 | |||
351 | memcpy(dev->broadcast, real_dev->broadcast, real_dev->addr_len); | 348 | memcpy(dev->broadcast, real_dev->broadcast, real_dev->addr_len); |
352 | memcpy(dev->dev_addr, real_dev->dev_addr, real_dev->addr_len); | 349 | memcpy(dev->dev_addr, real_dev->dev_addr, real_dev->addr_len); |
353 | dev->addr_len = real_dev->addr_len; | ||
354 | 350 | ||
355 | if (real_dev->features & NETIF_F_HW_VLAN_TX) { | 351 | if (real_dev->features & NETIF_F_HW_VLAN_TX) { |
356 | dev->hard_header = real_dev->hard_header; | 352 | dev->hard_header = real_dev->hard_header; |
@@ -364,6 +360,7 @@ static int vlan_dev_init(struct net_device *dev) | |||
364 | dev->rebuild_header = vlan_dev_rebuild_header; | 360 | dev->rebuild_header = vlan_dev_rebuild_header; |
365 | } | 361 | } |
366 | dev->hard_header_parse = real_dev->hard_header_parse; | 362 | dev->hard_header_parse = real_dev->hard_header_parse; |
363 | dev->hard_header_cache = NULL; | ||
367 | 364 | ||
368 | lockdep_set_class(&dev->_xmit_lock, &vlan_netdev_xmit_lock_key); | 365 | lockdep_set_class(&dev->_xmit_lock, &vlan_netdev_xmit_lock_key); |
369 | return 0; | 366 | return 0; |
@@ -373,6 +370,8 @@ void vlan_setup(struct net_device *new_dev) | |||
373 | { | 370 | { |
374 | SET_MODULE_OWNER(new_dev); | 371 | SET_MODULE_OWNER(new_dev); |
375 | 372 | ||
373 | ether_setup(new_dev); | ||
374 | |||
376 | /* new_dev->ifindex = 0; it will be set when added to | 375 | /* new_dev->ifindex = 0; it will be set when added to |
377 | * the global list. | 376 | * the global list. |
378 | * iflink is set as well. | 377 | * iflink is set as well. |
@@ -392,7 +391,6 @@ void vlan_setup(struct net_device *new_dev) | |||
392 | new_dev->init = vlan_dev_init; | 391 | new_dev->init = vlan_dev_init; |
393 | new_dev->open = vlan_dev_open; | 392 | new_dev->open = vlan_dev_open; |
394 | new_dev->stop = vlan_dev_stop; | 393 | new_dev->stop = vlan_dev_stop; |
395 | new_dev->set_mac_address = vlan_dev_set_mac_address; | ||
396 | new_dev->set_multicast_list = vlan_dev_set_multicast_list; | 394 | new_dev->set_multicast_list = vlan_dev_set_multicast_list; |
397 | new_dev->destructor = free_netdev; | 395 | new_dev->destructor = free_netdev; |
398 | new_dev->do_ioctl = vlan_dev_ioctl; | 396 | new_dev->do_ioctl = vlan_dev_ioctl; |
@@ -592,6 +590,30 @@ out_free_newdev: | |||
592 | return err; | 590 | return err; |
593 | } | 591 | } |
594 | 592 | ||
593 | static void vlan_sync_address(struct net_device *dev, | ||
594 | struct net_device *vlandev) | ||
595 | { | ||
596 | struct vlan_dev_info *vlan = VLAN_DEV_INFO(vlandev); | ||
597 | |||
598 | /* May be called without an actual change */ | ||
599 | if (!compare_ether_addr(vlan->real_dev_addr, dev->dev_addr)) | ||
600 | return; | ||
601 | |||
602 | /* vlan address was different from the old address and is equal to | ||
603 | * the new address */ | ||
604 | if (compare_ether_addr(vlandev->dev_addr, vlan->real_dev_addr) && | ||
605 | !compare_ether_addr(vlandev->dev_addr, dev->dev_addr)) | ||
606 | dev_unicast_delete(dev, vlandev->dev_addr, ETH_ALEN); | ||
607 | |||
608 | /* vlan address was equal to the old address and is different from | ||
609 | * the new address */ | ||
610 | if (!compare_ether_addr(vlandev->dev_addr, vlan->real_dev_addr) && | ||
611 | compare_ether_addr(vlandev->dev_addr, dev->dev_addr)) | ||
612 | dev_unicast_add(dev, vlandev->dev_addr, ETH_ALEN); | ||
613 | |||
614 | memcpy(vlan->real_dev_addr, dev->dev_addr, ETH_ALEN); | ||
615 | } | ||
616 | |||
595 | static int vlan_device_event(struct notifier_block *unused, unsigned long event, void *ptr) | 617 | static int vlan_device_event(struct notifier_block *unused, unsigned long event, void *ptr) |
596 | { | 618 | { |
597 | struct net_device *dev = ptr; | 619 | struct net_device *dev = ptr; |
@@ -618,6 +640,17 @@ static int vlan_device_event(struct notifier_block *unused, unsigned long event, | |||
618 | } | 640 | } |
619 | break; | 641 | break; |
620 | 642 | ||
643 | case NETDEV_CHANGEADDR: | ||
644 | /* Adjust unicast filters on underlying device */ | ||
645 | for (i = 0; i < VLAN_GROUP_ARRAY_LEN; i++) { | ||
646 | vlandev = vlan_group_get_device(grp, i); | ||
647 | if (!vlandev) | ||
648 | continue; | ||
649 | |||
650 | vlan_sync_address(dev, vlandev); | ||
651 | } | ||
652 | break; | ||
653 | |||
621 | case NETDEV_DOWN: | 654 | case NETDEV_DOWN: |
622 | /* Put all VLANs for this dev in the down state too. */ | 655 | /* Put all VLANs for this dev in the down state too. */ |
623 | for (i = 0; i < VLAN_GROUP_ARRAY_LEN; i++) { | 656 | for (i = 0; i < VLAN_GROUP_ARRAY_LEN; i++) { |
diff --git a/net/8021q/vlan.h b/net/8021q/vlan.h index fe6bb0f7d275..62ce1c519aab 100644 --- a/net/8021q/vlan.h +++ b/net/8021q/vlan.h | |||
@@ -58,7 +58,6 @@ int vlan_dev_hard_header(struct sk_buff *skb, struct net_device *dev, | |||
58 | int vlan_dev_hard_start_xmit(struct sk_buff *skb, struct net_device *dev); | 58 | int vlan_dev_hard_start_xmit(struct sk_buff *skb, struct net_device *dev); |
59 | int vlan_dev_hwaccel_hard_start_xmit(struct sk_buff *skb, struct net_device *dev); | 59 | int vlan_dev_hwaccel_hard_start_xmit(struct sk_buff *skb, struct net_device *dev); |
60 | int vlan_dev_change_mtu(struct net_device *dev, int new_mtu); | 60 | int vlan_dev_change_mtu(struct net_device *dev, int new_mtu); |
61 | int vlan_dev_set_mac_address(struct net_device *dev, void* addr); | ||
62 | int vlan_dev_open(struct net_device* dev); | 61 | int vlan_dev_open(struct net_device* dev); |
63 | int vlan_dev_stop(struct net_device* dev); | 62 | int vlan_dev_stop(struct net_device* dev); |
64 | int vlan_dev_ioctl(struct net_device* dev, struct ifreq *ifr, int cmd); | 63 | int vlan_dev_ioctl(struct net_device* dev, struct ifreq *ifr, int cmd); |
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 | ||