aboutsummaryrefslogtreecommitdiffstats
path: root/net/8021q/vlan.c
diff options
context:
space:
mode:
Diffstat (limited to 'net/8021q/vlan.c')
-rw-r--r--net/8021q/vlan.c43
1 files changed, 38 insertions, 5 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
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++) {