diff options
author | Patrick McHardy <kaber@trash.net> | 2007-06-27 04:28:10 -0400 |
---|---|---|
committer | David S. Miller <davem@sunset.davemloft.net> | 2007-07-11 01:15:56 -0400 |
commit | 4417da668c0021903464f92db278ddae348e0299 (patch) | |
tree | a4330cbc2e69a5714fee0a04bcfbabe97109de46 | |
parent | 3fba5a8b1e3df2384b90493538161e83cf15dd5f (diff) |
[NET]: dev: secondary unicast address support
Add support for configuring secondary unicast addresses on network
devices. To support this devices capable of filtering multiple
unicast addresses need to change their set_multicast_list function
to configure unicast filters as well and assign it to dev->set_rx_mode
instead of dev->set_multicast_list. Other devices are put into promiscous
mode when secondary unicast addresses are present.
Signed-off-by: Patrick McHardy <kaber@trash.net>
Signed-off-by: David S. Miller <davem@davemloft.net>
-rw-r--r-- | include/linux/netdevice.h | 12 | ||||
-rw-r--r-- | net/core/dev.c | 144 | ||||
-rw-r--r-- | net/core/dev_mcast.c | 37 |
3 files changed, 139 insertions, 54 deletions
diff --git a/include/linux/netdevice.h b/include/linux/netdevice.h index 9e114e77e54d..2c0cc19edfb2 100644 --- a/include/linux/netdevice.h +++ b/include/linux/netdevice.h | |||
@@ -397,6 +397,9 @@ struct net_device | |||
397 | unsigned char addr_len; /* hardware address length */ | 397 | unsigned char addr_len; /* hardware address length */ |
398 | unsigned short dev_id; /* for shared network cards */ | 398 | unsigned short dev_id; /* for shared network cards */ |
399 | 399 | ||
400 | struct dev_addr_list *uc_list; /* Secondary unicast mac addresses */ | ||
401 | int uc_count; /* Number of installed ucasts */ | ||
402 | int uc_promisc; | ||
400 | struct dev_addr_list *mc_list; /* Multicast mac addresses */ | 403 | struct dev_addr_list *mc_list; /* Multicast mac addresses */ |
401 | int mc_count; /* Number of installed mcasts */ | 404 | int mc_count; /* Number of installed mcasts */ |
402 | int promiscuity; | 405 | int promiscuity; |
@@ -502,6 +505,8 @@ struct net_device | |||
502 | void *saddr, | 505 | void *saddr, |
503 | unsigned len); | 506 | unsigned len); |
504 | int (*rebuild_header)(struct sk_buff *skb); | 507 | int (*rebuild_header)(struct sk_buff *skb); |
508 | #define HAVE_SET_RX_MODE | ||
509 | void (*set_rx_mode)(struct net_device *dev); | ||
505 | #define HAVE_MULTICAST | 510 | #define HAVE_MULTICAST |
506 | void (*set_multicast_list)(struct net_device *dev); | 511 | void (*set_multicast_list)(struct net_device *dev); |
507 | #define HAVE_SET_MAC_ADDR | 512 | #define HAVE_SET_MAC_ADDR |
@@ -1008,8 +1013,11 @@ extern struct net_device *alloc_netdev(int sizeof_priv, const char *name, | |||
1008 | void (*setup)(struct net_device *)); | 1013 | void (*setup)(struct net_device *)); |
1009 | extern int register_netdev(struct net_device *dev); | 1014 | extern int register_netdev(struct net_device *dev); |
1010 | extern void unregister_netdev(struct net_device *dev); | 1015 | extern void unregister_netdev(struct net_device *dev); |
1011 | /* Functions used for multicast support */ | 1016 | /* Functions used for secondary unicast and multicast support */ |
1012 | extern void dev_mc_upload(struct net_device *dev); | 1017 | extern void dev_set_rx_mode(struct net_device *dev); |
1018 | extern void __dev_set_rx_mode(struct net_device *dev); | ||
1019 | extern int dev_unicast_delete(struct net_device *dev, void *addr, int alen); | ||
1020 | extern int dev_unicast_add(struct net_device *dev, void *addr, int alen); | ||
1013 | extern int dev_mc_delete(struct net_device *dev, void *addr, int alen, int all); | 1021 | extern int dev_mc_delete(struct net_device *dev, void *addr, int alen, int all); |
1014 | extern int dev_mc_add(struct net_device *dev, void *addr, int alen, int newonly); | 1022 | extern int dev_mc_add(struct net_device *dev, void *addr, int alen, int newonly); |
1015 | extern void dev_mc_discard(struct net_device *dev); | 1023 | extern void dev_mc_discard(struct net_device *dev); |
diff --git a/net/core/dev.c b/net/core/dev.c index 18759ccdf219..36e9bf8ec4af 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 |
@@ -2498,17 +2498,7 @@ int netdev_set_master(struct net_device *slave, struct net_device *master) | |||
2498 | return 0; | 2498 | return 0; |
2499 | } | 2499 | } |
2500 | 2500 | ||
2501 | /** | 2501 | static void __dev_set_promiscuity(struct net_device *dev, int inc) |
2502 | * dev_set_promiscuity - update promiscuity count on a device | ||
2503 | * @dev: device | ||
2504 | * @inc: modifier | ||
2505 | * | ||
2506 | * Add or remove promiscuity from a device. While the count in the device | ||
2507 | * remains above zero the interface remains promiscuous. Once it hits zero | ||
2508 | * the device reverts back to normal filtering operation. A negative inc | ||
2509 | * value is used to drop promiscuity on the device. | ||
2510 | */ | ||
2511 | void dev_set_promiscuity(struct net_device *dev, int inc) | ||
2512 | { | 2502 | { |
2513 | unsigned short old_flags = dev->flags; | 2503 | unsigned short old_flags = dev->flags; |
2514 | 2504 | ||
@@ -2517,7 +2507,6 @@ void dev_set_promiscuity(struct net_device *dev, int inc) | |||
2517 | else | 2507 | else |
2518 | dev->flags |= IFF_PROMISC; | 2508 | dev->flags |= IFF_PROMISC; |
2519 | if (dev->flags != old_flags) { | 2509 | if (dev->flags != old_flags) { |
2520 | dev_mc_upload(dev); | ||
2521 | printk(KERN_INFO "device %s %s promiscuous mode\n", | 2510 | printk(KERN_INFO "device %s %s promiscuous mode\n", |
2522 | dev->name, (dev->flags & IFF_PROMISC) ? "entered" : | 2511 | dev->name, (dev->flags & IFF_PROMISC) ? "entered" : |
2523 | "left"); | 2512 | "left"); |
@@ -2531,6 +2520,25 @@ void dev_set_promiscuity(struct net_device *dev, int inc) | |||
2531 | } | 2520 | } |
2532 | 2521 | ||
2533 | /** | 2522 | /** |
2523 | * dev_set_promiscuity - update promiscuity count on a device | ||
2524 | * @dev: device | ||
2525 | * @inc: modifier | ||
2526 | * | ||
2527 | * Add or remove promiscuity from a device. While the count in the device | ||
2528 | * remains above zero the interface remains promiscuous. Once it hits zero | ||
2529 | * the device reverts back to normal filtering operation. A negative inc | ||
2530 | * value is used to drop promiscuity on the device. | ||
2531 | */ | ||
2532 | void dev_set_promiscuity(struct net_device *dev, int inc) | ||
2533 | { | ||
2534 | unsigned short old_flags = dev->flags; | ||
2535 | |||
2536 | __dev_set_promiscuity(dev, inc); | ||
2537 | if (dev->flags != old_flags) | ||
2538 | dev_set_rx_mode(dev); | ||
2539 | } | ||
2540 | |||
2541 | /** | ||
2534 | * dev_set_allmulti - update allmulti count on a device | 2542 | * dev_set_allmulti - update allmulti count on a device |
2535 | * @dev: device | 2543 | * @dev: device |
2536 | * @inc: modifier | 2544 | * @inc: modifier |
@@ -2550,7 +2558,48 @@ void dev_set_allmulti(struct net_device *dev, int inc) | |||
2550 | if ((dev->allmulti += inc) == 0) | 2558 | if ((dev->allmulti += inc) == 0) |
2551 | dev->flags &= ~IFF_ALLMULTI; | 2559 | dev->flags &= ~IFF_ALLMULTI; |
2552 | if (dev->flags ^ old_flags) | 2560 | if (dev->flags ^ old_flags) |
2553 | dev_mc_upload(dev); | 2561 | dev_set_rx_mode(dev); |
2562 | } | ||
2563 | |||
2564 | /* | ||
2565 | * Upload unicast and multicast address lists to device and | ||
2566 | * configure RX filtering. When the device doesn't support unicast | ||
2567 | * filtering it is put in promiscous mode while unicast addresses | ||
2568 | * are present. | ||
2569 | */ | ||
2570 | void __dev_set_rx_mode(struct net_device *dev) | ||
2571 | { | ||
2572 | /* dev_open will call this function so the list will stay sane. */ | ||
2573 | if (!(dev->flags&IFF_UP)) | ||
2574 | return; | ||
2575 | |||
2576 | if (!netif_device_present(dev)) | ||
2577 | return; | ||
2578 | |||
2579 | if (dev->set_rx_mode) | ||
2580 | dev->set_rx_mode(dev); | ||
2581 | else { | ||
2582 | /* Unicast addresses changes may only happen under the rtnl, | ||
2583 | * therefore calling __dev_set_promiscuity here is safe. | ||
2584 | */ | ||
2585 | if (dev->uc_count > 0 && !dev->uc_promisc) { | ||
2586 | __dev_set_promiscuity(dev, 1); | ||
2587 | dev->uc_promisc = 1; | ||
2588 | } else if (dev->uc_count == 0 && dev->uc_promisc) { | ||
2589 | __dev_set_promiscuity(dev, -1); | ||
2590 | dev->uc_promisc = 0; | ||
2591 | } | ||
2592 | |||
2593 | if (dev->set_multicast_list) | ||
2594 | dev->set_multicast_list(dev); | ||
2595 | } | ||
2596 | } | ||
2597 | |||
2598 | void dev_set_rx_mode(struct net_device *dev) | ||
2599 | { | ||
2600 | netif_tx_lock_bh(dev); | ||
2601 | __dev_set_rx_mode(dev); | ||
2602 | netif_tx_unlock_bh(dev); | ||
2554 | } | 2603 | } |
2555 | 2604 | ||
2556 | int __dev_addr_delete(struct dev_addr_list **list, void *addr, int alen, | 2605 | int __dev_addr_delete(struct dev_addr_list **list, void *addr, int alen, |
@@ -2622,6 +2671,66 @@ void __dev_addr_discard(struct dev_addr_list **list) | |||
2622 | } | 2671 | } |
2623 | } | 2672 | } |
2624 | 2673 | ||
2674 | /** | ||
2675 | * dev_unicast_delete - Release secondary unicast address. | ||
2676 | * @dev: device | ||
2677 | * | ||
2678 | * Release reference to a secondary unicast address and remove it | ||
2679 | * from the device if the reference count drop to zero. | ||
2680 | * | ||
2681 | * The caller must hold the rtnl_mutex. | ||
2682 | */ | ||
2683 | int dev_unicast_delete(struct net_device *dev, void *addr, int alen) | ||
2684 | { | ||
2685 | int err; | ||
2686 | |||
2687 | ASSERT_RTNL(); | ||
2688 | |||
2689 | netif_tx_lock_bh(dev); | ||
2690 | err = __dev_addr_delete(&dev->uc_list, addr, alen, 0); | ||
2691 | if (!err) { | ||
2692 | dev->uc_count--; | ||
2693 | __dev_set_rx_mode(dev); | ||
2694 | } | ||
2695 | netif_tx_unlock_bh(dev); | ||
2696 | return err; | ||
2697 | } | ||
2698 | EXPORT_SYMBOL(dev_unicast_delete); | ||
2699 | |||
2700 | /** | ||
2701 | * dev_unicast_add - add a secondary unicast address | ||
2702 | * @dev: device | ||
2703 | * | ||
2704 | * Add a secondary unicast address to the device or increase | ||
2705 | * the reference count if it already exists. | ||
2706 | * | ||
2707 | * The caller must hold the rtnl_mutex. | ||
2708 | */ | ||
2709 | int dev_unicast_add(struct net_device *dev, void *addr, int alen) | ||
2710 | { | ||
2711 | int err; | ||
2712 | |||
2713 | ASSERT_RTNL(); | ||
2714 | |||
2715 | netif_tx_lock_bh(dev); | ||
2716 | err = __dev_addr_add(&dev->uc_list, addr, alen, 0); | ||
2717 | if (!err) { | ||
2718 | dev->uc_count++; | ||
2719 | __dev_set_rx_mode(dev); | ||
2720 | } | ||
2721 | netif_tx_unlock_bh(dev); | ||
2722 | return err; | ||
2723 | } | ||
2724 | EXPORT_SYMBOL(dev_unicast_add); | ||
2725 | |||
2726 | static void dev_unicast_discard(struct net_device *dev) | ||
2727 | { | ||
2728 | netif_tx_lock_bh(dev); | ||
2729 | __dev_addr_discard(&dev->uc_list); | ||
2730 | dev->uc_count = 0; | ||
2731 | netif_tx_unlock_bh(dev); | ||
2732 | } | ||
2733 | |||
2625 | unsigned dev_get_flags(const struct net_device *dev) | 2734 | unsigned dev_get_flags(const struct net_device *dev) |
2626 | { | 2735 | { |
2627 | unsigned flags; | 2736 | unsigned flags; |
@@ -2665,7 +2774,7 @@ int dev_change_flags(struct net_device *dev, unsigned flags) | |||
2665 | * Load in the correct multicast list now the flags have changed. | 2774 | * Load in the correct multicast list now the flags have changed. |
2666 | */ | 2775 | */ |
2667 | 2776 | ||
2668 | dev_mc_upload(dev); | 2777 | dev_set_rx_mode(dev); |
2669 | 2778 | ||
2670 | /* | 2779 | /* |
2671 | * Have we downed the interface. We handle IFF_UP ourselves | 2780 | * Have we downed the interface. We handle IFF_UP ourselves |
@@ -2678,7 +2787,7 @@ int dev_change_flags(struct net_device *dev, unsigned flags) | |||
2678 | ret = ((old_flags & IFF_UP) ? dev_close : dev_open)(dev); | 2787 | ret = ((old_flags & IFF_UP) ? dev_close : dev_open)(dev); |
2679 | 2788 | ||
2680 | if (!ret) | 2789 | if (!ret) |
2681 | dev_mc_upload(dev); | 2790 | dev_set_rx_mode(dev); |
2682 | } | 2791 | } |
2683 | 2792 | ||
2684 | if (dev->flags & IFF_UP && | 2793 | if (dev->flags & IFF_UP && |
@@ -3558,8 +3667,9 @@ void unregister_netdevice(struct net_device *dev) | |||
3558 | raw_notifier_call_chain(&netdev_chain, NETDEV_UNREGISTER, dev); | 3667 | raw_notifier_call_chain(&netdev_chain, NETDEV_UNREGISTER, dev); |
3559 | 3668 | ||
3560 | /* | 3669 | /* |
3561 | * Flush the multicast chain | 3670 | * Flush the unicast and multicast chains |
3562 | */ | 3671 | */ |
3672 | dev_unicast_discard(dev); | ||
3563 | dev_mc_discard(dev); | 3673 | dev_mc_discard(dev); |
3564 | 3674 | ||
3565 | if (dev->uninit) | 3675 | if (dev->uninit) |
diff --git a/net/core/dev_mcast.c b/net/core/dev_mcast.c index 702907434a47..5cc9b448c443 100644 --- a/net/core/dev_mcast.c +++ b/net/core/dev_mcast.c | |||
@@ -64,39 +64,6 @@ | |||
64 | */ | 64 | */ |
65 | 65 | ||
66 | /* | 66 | /* |
67 | * Update the multicast list into the physical NIC controller. | ||
68 | */ | ||
69 | |||
70 | static void __dev_mc_upload(struct net_device *dev) | ||
71 | { | ||
72 | /* Don't do anything till we up the interface | ||
73 | * [dev_open will call this function so the list will | ||
74 | * stay sane] | ||
75 | */ | ||
76 | |||
77 | if (!(dev->flags&IFF_UP)) | ||
78 | return; | ||
79 | |||
80 | /* | ||
81 | * Devices with no set multicast or which have been | ||
82 | * detached don't get set. | ||
83 | */ | ||
84 | |||
85 | if (dev->set_multicast_list == NULL || | ||
86 | !netif_device_present(dev)) | ||
87 | return; | ||
88 | |||
89 | dev->set_multicast_list(dev); | ||
90 | } | ||
91 | |||
92 | void dev_mc_upload(struct net_device *dev) | ||
93 | { | ||
94 | netif_tx_lock_bh(dev); | ||
95 | __dev_mc_upload(dev); | ||
96 | netif_tx_unlock_bh(dev); | ||
97 | } | ||
98 | |||
99 | /* | ||
100 | * Delete a device level multicast | 67 | * Delete a device level multicast |
101 | */ | 68 | */ |
102 | 69 | ||
@@ -114,7 +81,7 @@ int dev_mc_delete(struct net_device *dev, void *addr, int alen, int glbl) | |||
114 | * loaded filter is now wrong. Fix it | 81 | * loaded filter is now wrong. Fix it |
115 | */ | 82 | */ |
116 | 83 | ||
117 | __dev_mc_upload(dev); | 84 | __dev_set_rx_mode(dev); |
118 | } | 85 | } |
119 | netif_tx_unlock_bh(dev); | 86 | netif_tx_unlock_bh(dev); |
120 | return err; | 87 | return err; |
@@ -132,7 +99,7 @@ int dev_mc_add(struct net_device *dev, void *addr, int alen, int glbl) | |||
132 | err = __dev_addr_add(&dev->mc_list, addr, alen, glbl); | 99 | err = __dev_addr_add(&dev->mc_list, addr, alen, glbl); |
133 | if (!err) { | 100 | if (!err) { |
134 | dev->mc_count++; | 101 | dev->mc_count++; |
135 | __dev_mc_upload(dev); | 102 | __dev_set_rx_mode(dev); |
136 | } | 103 | } |
137 | netif_tx_unlock_bh(dev); | 104 | netif_tx_unlock_bh(dev); |
138 | return err; | 105 | return err; |