diff options
author | Linus Torvalds <torvalds@woody.linux-foundation.org> | 2007-07-12 16:31:22 -0400 |
---|---|---|
committer | Linus Torvalds <torvalds@woody.linux-foundation.org> | 2007-07-12 16:31:22 -0400 |
commit | e1bd2ac5a6b7a8b625e40c9e9f8b6dea4cf22f85 (patch) | |
tree | 9366e9fb481da2c7195ca3f2bafeffebbf001363 /net/core/dev.c | |
parent | 0b9062f6b57a87f22309c6b920a51aaa66ce2a13 (diff) | |
parent | 15028aad00ddf241581fbe74a02ec89cbb28d35d (diff) |
Merge branch 'master' of master.kernel.org:/pub/scm/linux/kernel/git/davem/net-2.6
* 'master' of master.kernel.org:/pub/scm/linux/kernel/git/davem/net-2.6: (183 commits)
[TG3]: Update version to 3.78.
[TG3]: Add missing NVRAM strapping.
[TG3]: Enable auto MDI.
[TG3]: Fix the polarity bit.
[TG3]: Fix irq_sync race condition.
[NET_SCHED]: ematch: module autoloading
[TCP]: tcp probe wraparound handling and other changes
[RTNETLINK]: rtnl_link: allow specifying initial device address
[RTNETLINK]: rtnl_link API simplification
[VLAN]: Fix MAC address handling
[ETH]: Validate address in eth_mac_addr
[NET]: Fix races in net_rx_action vs netpoll.
[AF_UNIX]: Rewrite garbage collector, fixes race.
[NETFILTER]: {ip, nf}_conntrack_sctp: fix remotely triggerable NULL ptr dereference (CVE-2007-2876)
[NET]: Make all initialized struct seq_operations const.
[UDP]: Fix length check.
[IPV6]: Remove unneeded pointer idev from addrconf_cleanup().
[DECNET]: Another unnecessary net/tcp.h inclusion in net/dn.h
[IPV6]: Make IPV6_{RECV,2292}RTHDR boolean options.
[IPV6]: Do not send RH0 anymore.
...
Fixed up trivial conflict in Documentation/feature-removal-schedule.txt
manually.
Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
Diffstat (limited to 'net/core/dev.c')
-rw-r--r-- | net/core/dev.c | 270 |
1 files changed, 241 insertions, 29 deletions
diff --git a/net/core/dev.c b/net/core/dev.c index ee051bb398a0..4221dcda88d7 100644 --- a/net/core/dev.c +++ b/net/core/dev.c | |||
@@ -942,7 +942,7 @@ int dev_open(struct net_device *dev) | |||
942 | /* | 942 | /* |
943 | * Initialize multicasting status | 943 | * Initialize multicasting status |
944 | */ | 944 | */ |
945 | dev_mc_upload(dev); | 945 | dev_set_rx_mode(dev); |
946 | 946 | ||
947 | /* | 947 | /* |
948 | * Wakeup transmit queue engine | 948 | * Wakeup transmit queue engine |
@@ -1429,7 +1429,9 @@ gso: | |||
1429 | skb->next = nskb; | 1429 | skb->next = nskb; |
1430 | return rc; | 1430 | return rc; |
1431 | } | 1431 | } |
1432 | if (unlikely(netif_queue_stopped(dev) && skb->next)) | 1432 | if (unlikely((netif_queue_stopped(dev) || |
1433 | netif_subqueue_stopped(dev, skb->queue_mapping)) && | ||
1434 | skb->next)) | ||
1433 | return NETDEV_TX_BUSY; | 1435 | return NETDEV_TX_BUSY; |
1434 | } while (skb->next); | 1436 | } while (skb->next); |
1435 | 1437 | ||
@@ -1510,8 +1512,10 @@ int dev_queue_xmit(struct sk_buff *skb) | |||
1510 | skb_headroom(skb)); | 1512 | skb_headroom(skb)); |
1511 | 1513 | ||
1512 | if (!(dev->features & NETIF_F_GEN_CSUM) && | 1514 | if (!(dev->features & NETIF_F_GEN_CSUM) && |
1513 | (!(dev->features & NETIF_F_IP_CSUM) || | 1515 | !((dev->features & NETIF_F_IP_CSUM) && |
1514 | skb->protocol != htons(ETH_P_IP))) | 1516 | skb->protocol == htons(ETH_P_IP)) && |
1517 | !((dev->features & NETIF_F_IPV6_CSUM) && | ||
1518 | skb->protocol == htons(ETH_P_IPV6))) | ||
1515 | if (skb_checksum_help(skb)) | 1519 | if (skb_checksum_help(skb)) |
1516 | goto out_kfree_skb; | 1520 | goto out_kfree_skb; |
1517 | } | 1521 | } |
@@ -1545,6 +1549,8 @@ gso: | |||
1545 | spin_lock(&dev->queue_lock); | 1549 | spin_lock(&dev->queue_lock); |
1546 | q = dev->qdisc; | 1550 | q = dev->qdisc; |
1547 | if (q->enqueue) { | 1551 | if (q->enqueue) { |
1552 | /* reset queue_mapping to zero */ | ||
1553 | skb->queue_mapping = 0; | ||
1548 | rc = q->enqueue(skb, q); | 1554 | rc = q->enqueue(skb, q); |
1549 | qdisc_run(dev); | 1555 | qdisc_run(dev); |
1550 | spin_unlock(&dev->queue_lock); | 1556 | spin_unlock(&dev->queue_lock); |
@@ -1574,7 +1580,8 @@ gso: | |||
1574 | 1580 | ||
1575 | HARD_TX_LOCK(dev, cpu); | 1581 | HARD_TX_LOCK(dev, cpu); |
1576 | 1582 | ||
1577 | if (!netif_queue_stopped(dev)) { | 1583 | if (!netif_queue_stopped(dev) && |
1584 | !netif_subqueue_stopped(dev, skb->queue_mapping)) { | ||
1578 | rc = 0; | 1585 | rc = 0; |
1579 | if (!dev_hard_start_xmit(skb, dev)) { | 1586 | if (!dev_hard_start_xmit(skb, dev)) { |
1580 | HARD_TX_UNLOCK(dev); | 1587 | HARD_TX_UNLOCK(dev); |
@@ -2496,17 +2503,7 @@ int netdev_set_master(struct net_device *slave, struct net_device *master) | |||
2496 | return 0; | 2503 | return 0; |
2497 | } | 2504 | } |
2498 | 2505 | ||
2499 | /** | 2506 | static void __dev_set_promiscuity(struct net_device *dev, int inc) |
2500 | * dev_set_promiscuity - update promiscuity count on a device | ||
2501 | * @dev: device | ||
2502 | * @inc: modifier | ||
2503 | * | ||
2504 | * Add or remove promiscuity from a device. While the count in the device | ||
2505 | * remains above zero the interface remains promiscuous. Once it hits zero | ||
2506 | * the device reverts back to normal filtering operation. A negative inc | ||
2507 | * value is used to drop promiscuity on the device. | ||
2508 | */ | ||
2509 | void dev_set_promiscuity(struct net_device *dev, int inc) | ||
2510 | { | 2507 | { |
2511 | unsigned short old_flags = dev->flags; | 2508 | unsigned short old_flags = dev->flags; |
2512 | 2509 | ||
@@ -2515,7 +2512,6 @@ void dev_set_promiscuity(struct net_device *dev, int inc) | |||
2515 | else | 2512 | else |
2516 | dev->flags |= IFF_PROMISC; | 2513 | dev->flags |= IFF_PROMISC; |
2517 | if (dev->flags != old_flags) { | 2514 | if (dev->flags != old_flags) { |
2518 | dev_mc_upload(dev); | ||
2519 | printk(KERN_INFO "device %s %s promiscuous mode\n", | 2515 | printk(KERN_INFO "device %s %s promiscuous mode\n", |
2520 | dev->name, (dev->flags & IFF_PROMISC) ? "entered" : | 2516 | dev->name, (dev->flags & IFF_PROMISC) ? "entered" : |
2521 | "left"); | 2517 | "left"); |
@@ -2529,6 +2525,25 @@ void dev_set_promiscuity(struct net_device *dev, int inc) | |||
2529 | } | 2525 | } |
2530 | 2526 | ||
2531 | /** | 2527 | /** |
2528 | * dev_set_promiscuity - update promiscuity count on a device | ||
2529 | * @dev: device | ||
2530 | * @inc: modifier | ||
2531 | * | ||
2532 | * Add or remove promiscuity from a device. While the count in the device | ||
2533 | * remains above zero the interface remains promiscuous. Once it hits zero | ||
2534 | * the device reverts back to normal filtering operation. A negative inc | ||
2535 | * value is used to drop promiscuity on the device. | ||
2536 | */ | ||
2537 | void dev_set_promiscuity(struct net_device *dev, int inc) | ||
2538 | { | ||
2539 | unsigned short old_flags = dev->flags; | ||
2540 | |||
2541 | __dev_set_promiscuity(dev, inc); | ||
2542 | if (dev->flags != old_flags) | ||
2543 | dev_set_rx_mode(dev); | ||
2544 | } | ||
2545 | |||
2546 | /** | ||
2532 | * dev_set_allmulti - update allmulti count on a device | 2547 | * dev_set_allmulti - update allmulti count on a device |
2533 | * @dev: device | 2548 | * @dev: device |
2534 | * @inc: modifier | 2549 | * @inc: modifier |
@@ -2548,7 +2563,176 @@ void dev_set_allmulti(struct net_device *dev, int inc) | |||
2548 | if ((dev->allmulti += inc) == 0) | 2563 | if ((dev->allmulti += inc) == 0) |
2549 | dev->flags &= ~IFF_ALLMULTI; | 2564 | dev->flags &= ~IFF_ALLMULTI; |
2550 | if (dev->flags ^ old_flags) | 2565 | if (dev->flags ^ old_flags) |
2551 | dev_mc_upload(dev); | 2566 | dev_set_rx_mode(dev); |
2567 | } | ||
2568 | |||
2569 | /* | ||
2570 | * Upload unicast and multicast address lists to device and | ||
2571 | * configure RX filtering. When the device doesn't support unicast | ||
2572 | * filtering it is put in promiscous mode while unicast addresses | ||
2573 | * are present. | ||
2574 | */ | ||
2575 | void __dev_set_rx_mode(struct net_device *dev) | ||
2576 | { | ||
2577 | /* dev_open will call this function so the list will stay sane. */ | ||
2578 | if (!(dev->flags&IFF_UP)) | ||
2579 | return; | ||
2580 | |||
2581 | if (!netif_device_present(dev)) | ||
2582 | return; | ||
2583 | |||
2584 | if (dev->set_rx_mode) | ||
2585 | dev->set_rx_mode(dev); | ||
2586 | else { | ||
2587 | /* Unicast addresses changes may only happen under the rtnl, | ||
2588 | * therefore calling __dev_set_promiscuity here is safe. | ||
2589 | */ | ||
2590 | if (dev->uc_count > 0 && !dev->uc_promisc) { | ||
2591 | __dev_set_promiscuity(dev, 1); | ||
2592 | dev->uc_promisc = 1; | ||
2593 | } else if (dev->uc_count == 0 && dev->uc_promisc) { | ||
2594 | __dev_set_promiscuity(dev, -1); | ||
2595 | dev->uc_promisc = 0; | ||
2596 | } | ||
2597 | |||
2598 | if (dev->set_multicast_list) | ||
2599 | dev->set_multicast_list(dev); | ||
2600 | } | ||
2601 | } | ||
2602 | |||
2603 | void dev_set_rx_mode(struct net_device *dev) | ||
2604 | { | ||
2605 | netif_tx_lock_bh(dev); | ||
2606 | __dev_set_rx_mode(dev); | ||
2607 | netif_tx_unlock_bh(dev); | ||
2608 | } | ||
2609 | |||
2610 | int __dev_addr_delete(struct dev_addr_list **list, int *count, | ||
2611 | void *addr, int alen, int glbl) | ||
2612 | { | ||
2613 | struct dev_addr_list *da; | ||
2614 | |||
2615 | for (; (da = *list) != NULL; list = &da->next) { | ||
2616 | if (memcmp(da->da_addr, addr, da->da_addrlen) == 0 && | ||
2617 | alen == da->da_addrlen) { | ||
2618 | if (glbl) { | ||
2619 | int old_glbl = da->da_gusers; | ||
2620 | da->da_gusers = 0; | ||
2621 | if (old_glbl == 0) | ||
2622 | break; | ||
2623 | } | ||
2624 | if (--da->da_users) | ||
2625 | return 0; | ||
2626 | |||
2627 | *list = da->next; | ||
2628 | kfree(da); | ||
2629 | (*count)--; | ||
2630 | return 0; | ||
2631 | } | ||
2632 | } | ||
2633 | return -ENOENT; | ||
2634 | } | ||
2635 | |||
2636 | int __dev_addr_add(struct dev_addr_list **list, int *count, | ||
2637 | void *addr, int alen, int glbl) | ||
2638 | { | ||
2639 | struct dev_addr_list *da; | ||
2640 | |||
2641 | for (da = *list; da != NULL; da = da->next) { | ||
2642 | if (memcmp(da->da_addr, addr, da->da_addrlen) == 0 && | ||
2643 | da->da_addrlen == alen) { | ||
2644 | if (glbl) { | ||
2645 | int old_glbl = da->da_gusers; | ||
2646 | da->da_gusers = 1; | ||
2647 | if (old_glbl) | ||
2648 | return 0; | ||
2649 | } | ||
2650 | da->da_users++; | ||
2651 | return 0; | ||
2652 | } | ||
2653 | } | ||
2654 | |||
2655 | da = kmalloc(sizeof(*da), GFP_ATOMIC); | ||
2656 | if (da == NULL) | ||
2657 | return -ENOMEM; | ||
2658 | memcpy(da->da_addr, addr, alen); | ||
2659 | da->da_addrlen = alen; | ||
2660 | da->da_users = 1; | ||
2661 | da->da_gusers = glbl ? 1 : 0; | ||
2662 | da->next = *list; | ||
2663 | *list = da; | ||
2664 | (*count)++; | ||
2665 | return 0; | ||
2666 | } | ||
2667 | |||
2668 | void __dev_addr_discard(struct dev_addr_list **list) | ||
2669 | { | ||
2670 | struct dev_addr_list *tmp; | ||
2671 | |||
2672 | while (*list != NULL) { | ||
2673 | tmp = *list; | ||
2674 | *list = tmp->next; | ||
2675 | if (tmp->da_users > tmp->da_gusers) | ||
2676 | printk("__dev_addr_discard: address leakage! " | ||
2677 | "da_users=%d\n", tmp->da_users); | ||
2678 | kfree(tmp); | ||
2679 | } | ||
2680 | } | ||
2681 | |||
2682 | /** | ||
2683 | * dev_unicast_delete - Release secondary unicast address. | ||
2684 | * @dev: device | ||
2685 | * | ||
2686 | * Release reference to a secondary unicast address and remove it | ||
2687 | * from the device if the reference count drop to zero. | ||
2688 | * | ||
2689 | * The caller must hold the rtnl_mutex. | ||
2690 | */ | ||
2691 | int dev_unicast_delete(struct net_device *dev, void *addr, int alen) | ||
2692 | { | ||
2693 | int err; | ||
2694 | |||
2695 | ASSERT_RTNL(); | ||
2696 | |||
2697 | netif_tx_lock_bh(dev); | ||
2698 | err = __dev_addr_delete(&dev->uc_list, &dev->uc_count, addr, alen, 0); | ||
2699 | if (!err) | ||
2700 | __dev_set_rx_mode(dev); | ||
2701 | netif_tx_unlock_bh(dev); | ||
2702 | return err; | ||
2703 | } | ||
2704 | EXPORT_SYMBOL(dev_unicast_delete); | ||
2705 | |||
2706 | /** | ||
2707 | * dev_unicast_add - add a secondary unicast address | ||
2708 | * @dev: device | ||
2709 | * | ||
2710 | * Add a secondary unicast address to the device or increase | ||
2711 | * the reference count if it already exists. | ||
2712 | * | ||
2713 | * The caller must hold the rtnl_mutex. | ||
2714 | */ | ||
2715 | int dev_unicast_add(struct net_device *dev, void *addr, int alen) | ||
2716 | { | ||
2717 | int err; | ||
2718 | |||
2719 | ASSERT_RTNL(); | ||
2720 | |||
2721 | netif_tx_lock_bh(dev); | ||
2722 | err = __dev_addr_add(&dev->uc_list, &dev->uc_count, addr, alen, 0); | ||
2723 | if (!err) | ||
2724 | __dev_set_rx_mode(dev); | ||
2725 | netif_tx_unlock_bh(dev); | ||
2726 | return err; | ||
2727 | } | ||
2728 | EXPORT_SYMBOL(dev_unicast_add); | ||
2729 | |||
2730 | static void dev_unicast_discard(struct net_device *dev) | ||
2731 | { | ||
2732 | netif_tx_lock_bh(dev); | ||
2733 | __dev_addr_discard(&dev->uc_list); | ||
2734 | dev->uc_count = 0; | ||
2735 | netif_tx_unlock_bh(dev); | ||
2552 | } | 2736 | } |
2553 | 2737 | ||
2554 | unsigned dev_get_flags(const struct net_device *dev) | 2738 | unsigned dev_get_flags(const struct net_device *dev) |
@@ -2594,7 +2778,7 @@ int dev_change_flags(struct net_device *dev, unsigned flags) | |||
2594 | * Load in the correct multicast list now the flags have changed. | 2778 | * Load in the correct multicast list now the flags have changed. |
2595 | */ | 2779 | */ |
2596 | 2780 | ||
2597 | dev_mc_upload(dev); | 2781 | dev_set_rx_mode(dev); |
2598 | 2782 | ||
2599 | /* | 2783 | /* |
2600 | * Have we downed the interface. We handle IFF_UP ourselves | 2784 | * Have we downed the interface. We handle IFF_UP ourselves |
@@ -2607,7 +2791,7 @@ int dev_change_flags(struct net_device *dev, unsigned flags) | |||
2607 | ret = ((old_flags & IFF_UP) ? dev_close : dev_open)(dev); | 2791 | ret = ((old_flags & IFF_UP) ? dev_close : dev_open)(dev); |
2608 | 2792 | ||
2609 | if (!ret) | 2793 | if (!ret) |
2610 | dev_mc_upload(dev); | 2794 | dev_set_rx_mode(dev); |
2611 | } | 2795 | } |
2612 | 2796 | ||
2613 | if (dev->flags & IFF_UP && | 2797 | if (dev->flags & IFF_UP && |
@@ -3107,6 +3291,22 @@ int register_netdevice(struct net_device *dev) | |||
3107 | } | 3291 | } |
3108 | } | 3292 | } |
3109 | 3293 | ||
3294 | /* Fix illegal checksum combinations */ | ||
3295 | if ((dev->features & NETIF_F_HW_CSUM) && | ||
3296 | (dev->features & (NETIF_F_IP_CSUM|NETIF_F_IPV6_CSUM))) { | ||
3297 | printk(KERN_NOTICE "%s: mixed HW and IP checksum settings.\n", | ||
3298 | dev->name); | ||
3299 | dev->features &= ~(NETIF_F_IP_CSUM|NETIF_F_IPV6_CSUM); | ||
3300 | } | ||
3301 | |||
3302 | if ((dev->features & NETIF_F_NO_CSUM) && | ||
3303 | (dev->features & (NETIF_F_HW_CSUM|NETIF_F_IP_CSUM|NETIF_F_IPV6_CSUM))) { | ||
3304 | printk(KERN_NOTICE "%s: mixed no checksumming and other settings.\n", | ||
3305 | dev->name); | ||
3306 | dev->features &= ~(NETIF_F_IP_CSUM|NETIF_F_IPV6_CSUM|NETIF_F_HW_CSUM); | ||
3307 | } | ||
3308 | |||
3309 | |||
3110 | /* Fix illegal SG+CSUM combinations. */ | 3310 | /* Fix illegal SG+CSUM combinations. */ |
3111 | if ((dev->features & NETIF_F_SG) && | 3311 | if ((dev->features & NETIF_F_SG) && |
3112 | !(dev->features & NETIF_F_ALL_CSUM)) { | 3312 | !(dev->features & NETIF_F_ALL_CSUM)) { |
@@ -3343,16 +3543,18 @@ static struct net_device_stats *internal_stats(struct net_device *dev) | |||
3343 | } | 3543 | } |
3344 | 3544 | ||
3345 | /** | 3545 | /** |
3346 | * alloc_netdev - allocate network device | 3546 | * alloc_netdev_mq - allocate network device |
3347 | * @sizeof_priv: size of private data to allocate space for | 3547 | * @sizeof_priv: size of private data to allocate space for |
3348 | * @name: device name format string | 3548 | * @name: device name format string |
3349 | * @setup: callback to initialize device | 3549 | * @setup: callback to initialize device |
3550 | * @queue_count: the number of subqueues to allocate | ||
3350 | * | 3551 | * |
3351 | * Allocates a struct net_device with private data area for driver use | 3552 | * Allocates a struct net_device with private data area for driver use |
3352 | * and performs basic initialization. | 3553 | * and performs basic initialization. Also allocates subquue structs |
3554 | * for each queue on the device at the end of the netdevice. | ||
3353 | */ | 3555 | */ |
3354 | struct net_device *alloc_netdev(int sizeof_priv, const char *name, | 3556 | struct net_device *alloc_netdev_mq(int sizeof_priv, const char *name, |
3355 | void (*setup)(struct net_device *)) | 3557 | void (*setup)(struct net_device *), unsigned int queue_count) |
3356 | { | 3558 | { |
3357 | void *p; | 3559 | void *p; |
3358 | struct net_device *dev; | 3560 | struct net_device *dev; |
@@ -3361,7 +3563,9 @@ struct net_device *alloc_netdev(int sizeof_priv, const char *name, | |||
3361 | BUG_ON(strlen(name) >= sizeof(dev->name)); | 3563 | BUG_ON(strlen(name) >= sizeof(dev->name)); |
3362 | 3564 | ||
3363 | /* ensure 32-byte alignment of both the device and private area */ | 3565 | /* ensure 32-byte alignment of both the device and private area */ |
3364 | alloc_size = (sizeof(*dev) + NETDEV_ALIGN_CONST) & ~NETDEV_ALIGN_CONST; | 3566 | alloc_size = (sizeof(*dev) + NETDEV_ALIGN_CONST + |
3567 | (sizeof(struct net_device_subqueue) * queue_count)) & | ||
3568 | ~NETDEV_ALIGN_CONST; | ||
3365 | alloc_size += sizeof_priv + NETDEV_ALIGN_CONST; | 3569 | alloc_size += sizeof_priv + NETDEV_ALIGN_CONST; |
3366 | 3570 | ||
3367 | p = kzalloc(alloc_size, GFP_KERNEL); | 3571 | p = kzalloc(alloc_size, GFP_KERNEL); |
@@ -3374,15 +3578,22 @@ struct net_device *alloc_netdev(int sizeof_priv, const char *name, | |||
3374 | (((long)p + NETDEV_ALIGN_CONST) & ~NETDEV_ALIGN_CONST); | 3578 | (((long)p + NETDEV_ALIGN_CONST) & ~NETDEV_ALIGN_CONST); |
3375 | dev->padded = (char *)dev - (char *)p; | 3579 | dev->padded = (char *)dev - (char *)p; |
3376 | 3580 | ||
3377 | if (sizeof_priv) | 3581 | if (sizeof_priv) { |
3378 | dev->priv = netdev_priv(dev); | 3582 | dev->priv = ((char *)dev + |
3583 | ((sizeof(struct net_device) + | ||
3584 | (sizeof(struct net_device_subqueue) * | ||
3585 | queue_count) + NETDEV_ALIGN_CONST) | ||
3586 | & ~NETDEV_ALIGN_CONST)); | ||
3587 | } | ||
3588 | |||
3589 | dev->egress_subqueue_count = queue_count; | ||
3379 | 3590 | ||
3380 | dev->get_stats = internal_stats; | 3591 | dev->get_stats = internal_stats; |
3381 | setup(dev); | 3592 | setup(dev); |
3382 | strcpy(dev->name, name); | 3593 | strcpy(dev->name, name); |
3383 | return dev; | 3594 | return dev; |
3384 | } | 3595 | } |
3385 | EXPORT_SYMBOL(alloc_netdev); | 3596 | EXPORT_SYMBOL(alloc_netdev_mq); |
3386 | 3597 | ||
3387 | /** | 3598 | /** |
3388 | * free_netdev - free network device | 3599 | * free_netdev - free network device |
@@ -3471,8 +3682,9 @@ void unregister_netdevice(struct net_device *dev) | |||
3471 | raw_notifier_call_chain(&netdev_chain, NETDEV_UNREGISTER, dev); | 3682 | raw_notifier_call_chain(&netdev_chain, NETDEV_UNREGISTER, dev); |
3472 | 3683 | ||
3473 | /* | 3684 | /* |
3474 | * Flush the multicast chain | 3685 | * Flush the unicast and multicast chains |
3475 | */ | 3686 | */ |
3687 | dev_unicast_discard(dev); | ||
3476 | dev_mc_discard(dev); | 3688 | dev_mc_discard(dev); |
3477 | 3689 | ||
3478 | if (dev->uninit) | 3690 | if (dev->uninit) |