aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--include/linux/netdevice.h4
-rw-r--r--net/8021q/vlan_dev.c7
-rw-r--r--net/core/dev.c96
-rw-r--r--net/core/dev_mcast.c39
4 files changed, 110 insertions, 36 deletions
diff --git a/include/linux/netdevice.h b/include/linux/netdevice.h
index b0813c3286b1..047d432bde55 100644
--- a/include/linux/netdevice.h
+++ b/include/linux/netdevice.h
@@ -1414,12 +1414,16 @@ extern void dev_set_rx_mode(struct net_device *dev);
1414extern void __dev_set_rx_mode(struct net_device *dev); 1414extern void __dev_set_rx_mode(struct net_device *dev);
1415extern int dev_unicast_delete(struct net_device *dev, void *addr, int alen); 1415extern int dev_unicast_delete(struct net_device *dev, void *addr, int alen);
1416extern int dev_unicast_add(struct net_device *dev, void *addr, int alen); 1416extern int dev_unicast_add(struct net_device *dev, void *addr, int alen);
1417extern int dev_unicast_sync(struct net_device *to, struct net_device *from);
1418extern void dev_unicast_unsync(struct net_device *to, struct net_device *from);
1417extern int dev_mc_delete(struct net_device *dev, void *addr, int alen, int all); 1419extern int dev_mc_delete(struct net_device *dev, void *addr, int alen, int all);
1418extern int dev_mc_add(struct net_device *dev, void *addr, int alen, int newonly); 1420extern int dev_mc_add(struct net_device *dev, void *addr, int alen, int newonly);
1419extern int dev_mc_sync(struct net_device *to, struct net_device *from); 1421extern int dev_mc_sync(struct net_device *to, struct net_device *from);
1420extern void dev_mc_unsync(struct net_device *to, struct net_device *from); 1422extern void dev_mc_unsync(struct net_device *to, struct net_device *from);
1421extern int __dev_addr_delete(struct dev_addr_list **list, int *count, void *addr, int alen, int all); 1423extern int __dev_addr_delete(struct dev_addr_list **list, int *count, void *addr, int alen, int all);
1422extern int __dev_addr_add(struct dev_addr_list **list, int *count, void *addr, int alen, int newonly); 1424extern int __dev_addr_add(struct dev_addr_list **list, int *count, void *addr, int alen, int newonly);
1425extern int __dev_addr_sync(struct dev_addr_list **to, int *to_count, struct dev_addr_list **from, int *from_count);
1426extern void __dev_addr_unsync(struct dev_addr_list **to, int *to_count, struct dev_addr_list **from, int *from_count);
1423extern void dev_set_promiscuity(struct net_device *dev, int inc); 1427extern void dev_set_promiscuity(struct net_device *dev, int inc);
1424extern void dev_set_allmulti(struct net_device *dev, int inc); 1428extern void dev_set_allmulti(struct net_device *dev, int inc);
1425extern void netdev_state_change(struct net_device *dev); 1429extern void netdev_state_change(struct net_device *dev);
diff --git a/net/8021q/vlan_dev.c b/net/8021q/vlan_dev.c
index 8059fa42b085..77f04e49a1a0 100644
--- a/net/8021q/vlan_dev.c
+++ b/net/8021q/vlan_dev.c
@@ -563,6 +563,7 @@ static int vlan_dev_stop(struct net_device *dev)
563 struct net_device *real_dev = vlan_dev_info(dev)->real_dev; 563 struct net_device *real_dev = vlan_dev_info(dev)->real_dev;
564 564
565 dev_mc_unsync(real_dev, dev); 565 dev_mc_unsync(real_dev, dev);
566 dev_unicast_unsync(real_dev, dev);
566 if (dev->flags & IFF_ALLMULTI) 567 if (dev->flags & IFF_ALLMULTI)
567 dev_set_allmulti(real_dev, -1); 568 dev_set_allmulti(real_dev, -1);
568 if (dev->flags & IFF_PROMISC) 569 if (dev->flags & IFF_PROMISC)
@@ -634,9 +635,10 @@ static void vlan_dev_change_rx_flags(struct net_device *dev, int change)
634 dev_set_promiscuity(real_dev, dev->flags & IFF_PROMISC ? 1 : -1); 635 dev_set_promiscuity(real_dev, dev->flags & IFF_PROMISC ? 1 : -1);
635} 636}
636 637
637static void vlan_dev_set_multicast_list(struct net_device *vlan_dev) 638static void vlan_dev_set_rx_mode(struct net_device *vlan_dev)
638{ 639{
639 dev_mc_sync(vlan_dev_info(vlan_dev)->real_dev, vlan_dev); 640 dev_mc_sync(vlan_dev_info(vlan_dev)->real_dev, vlan_dev);
641 dev_unicast_sync(vlan_dev_info(vlan_dev)->real_dev, vlan_dev);
640} 642}
641 643
642/* 644/*
@@ -702,7 +704,8 @@ void vlan_setup(struct net_device *dev)
702 dev->open = vlan_dev_open; 704 dev->open = vlan_dev_open;
703 dev->stop = vlan_dev_stop; 705 dev->stop = vlan_dev_stop;
704 dev->set_mac_address = vlan_dev_set_mac_address; 706 dev->set_mac_address = vlan_dev_set_mac_address;
705 dev->set_multicast_list = vlan_dev_set_multicast_list; 707 dev->set_rx_mode = vlan_dev_set_rx_mode;
708 dev->set_multicast_list = vlan_dev_set_rx_mode;
706 dev->change_rx_flags = vlan_dev_change_rx_flags; 709 dev->change_rx_flags = vlan_dev_change_rx_flags;
707 dev->do_ioctl = vlan_dev_ioctl; 710 dev->do_ioctl = vlan_dev_ioctl;
708 dev->destructor = free_netdev; 711 dev->destructor = free_netdev;
diff --git a/net/core/dev.c b/net/core/dev.c
index c9c593e1ba6f..edaff2720e10 100644
--- a/net/core/dev.c
+++ b/net/core/dev.c
@@ -2962,6 +2962,102 @@ int dev_unicast_add(struct net_device *dev, void *addr, int alen)
2962} 2962}
2963EXPORT_SYMBOL(dev_unicast_add); 2963EXPORT_SYMBOL(dev_unicast_add);
2964 2964
2965int __dev_addr_sync(struct dev_addr_list **to, int *to_count,
2966 struct dev_addr_list **from, int *from_count)
2967{
2968 struct dev_addr_list *da, *next;
2969 int err = 0;
2970
2971 da = *from;
2972 while (da != NULL) {
2973 next = da->next;
2974 if (!da->da_synced) {
2975 err = __dev_addr_add(to, to_count,
2976 da->da_addr, da->da_addrlen, 0);
2977 if (err < 0)
2978 break;
2979 da->da_synced = 1;
2980 da->da_users++;
2981 } else if (da->da_users == 1) {
2982 __dev_addr_delete(to, to_count,
2983 da->da_addr, da->da_addrlen, 0);
2984 __dev_addr_delete(from, from_count,
2985 da->da_addr, da->da_addrlen, 0);
2986 }
2987 da = next;
2988 }
2989 return err;
2990}
2991
2992void __dev_addr_unsync(struct dev_addr_list **to, int *to_count,
2993 struct dev_addr_list **from, int *from_count)
2994{
2995 struct dev_addr_list *da, *next;
2996
2997 da = *from;
2998 while (da != NULL) {
2999 next = da->next;
3000 if (da->da_synced) {
3001 __dev_addr_delete(to, to_count,
3002 da->da_addr, da->da_addrlen, 0);
3003 da->da_synced = 0;
3004 __dev_addr_delete(from, from_count,
3005 da->da_addr, da->da_addrlen, 0);
3006 }
3007 da = next;
3008 }
3009}
3010
3011/**
3012 * dev_unicast_sync - Synchronize device's unicast list to another device
3013 * @to: destination device
3014 * @from: source device
3015 *
3016 * Add newly added addresses to the destination device and release
3017 * addresses that have no users left. The source device must be
3018 * locked by netif_tx_lock_bh.
3019 *
3020 * This function is intended to be called from the dev->set_rx_mode
3021 * function of layered software devices.
3022 */
3023int dev_unicast_sync(struct net_device *to, struct net_device *from)
3024{
3025 int err = 0;
3026
3027 netif_tx_lock_bh(to);
3028 err = __dev_addr_sync(&to->uc_list, &to->uc_count,
3029 &from->uc_list, &from->uc_count);
3030 if (!err)
3031 __dev_set_rx_mode(to);
3032 netif_tx_unlock_bh(to);
3033 return err;
3034}
3035EXPORT_SYMBOL(dev_unicast_sync);
3036
3037/**
3038 * dev_unicast_unsync - Remove synchronized addresses from the destination
3039 * device
3040 * @to: destination device
3041 * @from: source device
3042 *
3043 * Remove all addresses that were added to the destination device by
3044 * dev_unicast_sync(). This function is intended to be called from the
3045 * dev->stop function of layered software devices.
3046 */
3047void dev_unicast_unsync(struct net_device *to, struct net_device *from)
3048{
3049 netif_tx_lock_bh(from);
3050 netif_tx_lock_bh(to);
3051
3052 __dev_addr_unsync(&to->uc_list, &to->uc_count,
3053 &from->uc_list, &from->uc_count);
3054 __dev_set_rx_mode(to);
3055
3056 netif_tx_unlock_bh(to);
3057 netif_tx_unlock_bh(from);
3058}
3059EXPORT_SYMBOL(dev_unicast_unsync);
3060
2965static void __dev_addr_discard(struct dev_addr_list **list) 3061static void __dev_addr_discard(struct dev_addr_list **list)
2966{ 3062{
2967 struct dev_addr_list *tmp; 3063 struct dev_addr_list *tmp;
diff --git a/net/core/dev_mcast.c b/net/core/dev_mcast.c
index cadbfbf7e7f5..cec582563e0d 100644
--- a/net/core/dev_mcast.c
+++ b/net/core/dev_mcast.c
@@ -113,32 +113,15 @@ int dev_mc_add(struct net_device *dev, void *addr, int alen, int glbl)
113 * locked by netif_tx_lock_bh. 113 * locked by netif_tx_lock_bh.
114 * 114 *
115 * This function is intended to be called from the dev->set_multicast_list 115 * This function is intended to be called from the dev->set_multicast_list
116 * function of layered software devices. 116 * or dev->set_rx_mode function of layered software devices.
117 */ 117 */
118int dev_mc_sync(struct net_device *to, struct net_device *from) 118int dev_mc_sync(struct net_device *to, struct net_device *from)
119{ 119{
120 struct dev_addr_list *da, *next;
121 int err = 0; 120 int err = 0;
122 121
123 netif_tx_lock_bh(to); 122 netif_tx_lock_bh(to);
124 da = from->mc_list; 123 err = __dev_addr_sync(&to->mc_list, &to->mc_count,
125 while (da != NULL) { 124 &from->mc_list, &from->mc_count);
126 next = da->next;
127 if (!da->da_synced) {
128 err = __dev_addr_add(&to->mc_list, &to->mc_count,
129 da->da_addr, da->da_addrlen, 0);
130 if (err < 0)
131 break;
132 da->da_synced = 1;
133 da->da_users++;
134 } else if (da->da_users == 1) {
135 __dev_addr_delete(&to->mc_list, &to->mc_count,
136 da->da_addr, da->da_addrlen, 0);
137 __dev_addr_delete(&from->mc_list, &from->mc_count,
138 da->da_addr, da->da_addrlen, 0);
139 }
140 da = next;
141 }
142 if (!err) 125 if (!err)
143 __dev_set_rx_mode(to); 126 __dev_set_rx_mode(to);
144 netif_tx_unlock_bh(to); 127 netif_tx_unlock_bh(to);
@@ -160,23 +143,11 @@ EXPORT_SYMBOL(dev_mc_sync);
160 */ 143 */
161void dev_mc_unsync(struct net_device *to, struct net_device *from) 144void dev_mc_unsync(struct net_device *to, struct net_device *from)
162{ 145{
163 struct dev_addr_list *da, *next;
164
165 netif_tx_lock_bh(from); 146 netif_tx_lock_bh(from);
166 netif_tx_lock_bh(to); 147 netif_tx_lock_bh(to);
167 148
168 da = from->mc_list; 149 __dev_addr_unsync(&to->mc_list, &to->mc_count,
169 while (da != NULL) { 150 &from->mc_list, &from->mc_count);
170 next = da->next;
171 if (da->da_synced) {
172 __dev_addr_delete(&to->mc_list, &to->mc_count,
173 da->da_addr, da->da_addrlen, 0);
174 da->da_synced = 0;
175 __dev_addr_delete(&from->mc_list, &from->mc_count,
176 da->da_addr, da->da_addrlen, 0);
177 }
178 da = next;
179 }
180 __dev_set_rx_mode(to); 151 __dev_set_rx_mode(to);
181 152
182 netif_tx_unlock_bh(to); 153 netif_tx_unlock_bh(to);