diff options
Diffstat (limited to 'net/8021q/vlan.c')
-rw-r--r-- | net/8021q/vlan.c | 43 |
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 | ||
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++) { |