aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--include/linux/if_vlan.h1
-rw-r--r--net/8021q/vlan.c43
-rw-r--r--net/8021q/vlan.h1
-rw-r--r--net/8021q/vlan_dev.c57
4 files changed, 57 insertions, 45 deletions
diff --git a/include/linux/if_vlan.h b/include/linux/if_vlan.h
index c7912876a210..61a57dc2ac99 100644
--- a/include/linux/if_vlan.h
+++ b/include/linux/if_vlan.h
@@ -135,6 +135,7 @@ struct vlan_dev_info {
135 int old_allmulti; /* similar to above. */ 135 int old_allmulti; /* similar to above. */
136 int old_promiscuity; /* similar to above. */ 136 int old_promiscuity; /* similar to above. */
137 struct net_device *real_dev; /* the underlying device/interface */ 137 struct net_device *real_dev; /* the underlying device/interface */
138 unsigned char real_dev_addr[ETH_ALEN];
138 struct proc_dir_entry *dent; /* Holds the proc data */ 139 struct proc_dir_entry *dent; /* Holds the proc data */
139 unsigned long cnt_inc_headroom_on_tx; /* How many times did we have to grow the skb on TX. */ 140 unsigned long cnt_inc_headroom_on_tx; /* How many times did we have to grow the skb on TX. */
140 unsigned long cnt_encap_on_xmit; /* How many times did we have to encapsulate the skb on TX. */ 141 unsigned long cnt_encap_on_xmit; /* How many times did we have to encapsulate the skb on TX. */
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
593static 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
595static int vlan_device_event(struct notifier_block *unused, unsigned long event, void *ptr) 617static 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,
58int vlan_dev_hard_start_xmit(struct sk_buff *skb, struct net_device *dev); 58int vlan_dev_hard_start_xmit(struct sk_buff *skb, struct net_device *dev);
59int vlan_dev_hwaccel_hard_start_xmit(struct sk_buff *skb, struct net_device *dev); 59int vlan_dev_hwaccel_hard_start_xmit(struct sk_buff *skb, struct net_device *dev);
60int vlan_dev_change_mtu(struct net_device *dev, int new_mtu); 60int vlan_dev_change_mtu(struct net_device *dev, int new_mtu);
61int vlan_dev_set_mac_address(struct net_device *dev, void* addr);
62int vlan_dev_open(struct net_device* dev); 61int vlan_dev_open(struct net_device* dev);
63int vlan_dev_stop(struct net_device* dev); 62int vlan_dev_stop(struct net_device* dev);
64int vlan_dev_ioctl(struct net_device* dev, struct ifreq *ifr, int cmd); 63int 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
615int 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
653static inline int vlan_dmi_equals(struct dev_mc_list *dmi1, 615static 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
737int vlan_dev_open(struct net_device *dev) 699int 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
745int vlan_dev_stop(struct net_device *dev) 718int 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