diff options
-rw-r--r-- | include/linux/netdevice.h | 4 | ||||
-rw-r--r-- | net/8021q/vlan_dev.c | 7 | ||||
-rw-r--r-- | net/core/dev.c | 96 | ||||
-rw-r--r-- | net/core/dev_mcast.c | 39 |
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); | |||
1414 | extern void __dev_set_rx_mode(struct net_device *dev); | 1414 | extern void __dev_set_rx_mode(struct net_device *dev); |
1415 | extern int dev_unicast_delete(struct net_device *dev, void *addr, int alen); | 1415 | extern int dev_unicast_delete(struct net_device *dev, void *addr, int alen); |
1416 | extern int dev_unicast_add(struct net_device *dev, void *addr, int alen); | 1416 | extern int dev_unicast_add(struct net_device *dev, void *addr, int alen); |
1417 | extern int dev_unicast_sync(struct net_device *to, struct net_device *from); | ||
1418 | extern void dev_unicast_unsync(struct net_device *to, struct net_device *from); | ||
1417 | extern int dev_mc_delete(struct net_device *dev, void *addr, int alen, int all); | 1419 | extern int dev_mc_delete(struct net_device *dev, void *addr, int alen, int all); |
1418 | extern int dev_mc_add(struct net_device *dev, void *addr, int alen, int newonly); | 1420 | extern int dev_mc_add(struct net_device *dev, void *addr, int alen, int newonly); |
1419 | extern int dev_mc_sync(struct net_device *to, struct net_device *from); | 1421 | extern int dev_mc_sync(struct net_device *to, struct net_device *from); |
1420 | extern void dev_mc_unsync(struct net_device *to, struct net_device *from); | 1422 | extern void dev_mc_unsync(struct net_device *to, struct net_device *from); |
1421 | extern int __dev_addr_delete(struct dev_addr_list **list, int *count, void *addr, int alen, int all); | 1423 | extern int __dev_addr_delete(struct dev_addr_list **list, int *count, void *addr, int alen, int all); |
1422 | extern int __dev_addr_add(struct dev_addr_list **list, int *count, void *addr, int alen, int newonly); | 1424 | extern int __dev_addr_add(struct dev_addr_list **list, int *count, void *addr, int alen, int newonly); |
1425 | extern int __dev_addr_sync(struct dev_addr_list **to, int *to_count, struct dev_addr_list **from, int *from_count); | ||
1426 | extern void __dev_addr_unsync(struct dev_addr_list **to, int *to_count, struct dev_addr_list **from, int *from_count); | ||
1423 | extern void dev_set_promiscuity(struct net_device *dev, int inc); | 1427 | extern void dev_set_promiscuity(struct net_device *dev, int inc); |
1424 | extern void dev_set_allmulti(struct net_device *dev, int inc); | 1428 | extern void dev_set_allmulti(struct net_device *dev, int inc); |
1425 | extern void netdev_state_change(struct net_device *dev); | 1429 | extern 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 | ||
637 | static void vlan_dev_set_multicast_list(struct net_device *vlan_dev) | 638 | static 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 | } |
2963 | EXPORT_SYMBOL(dev_unicast_add); | 2963 | EXPORT_SYMBOL(dev_unicast_add); |
2964 | 2964 | ||
2965 | int __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 | |||
2992 | void __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 | */ | ||
3023 | int 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 | } | ||
3035 | EXPORT_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 | */ | ||
3047 | void 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 | } | ||
3059 | EXPORT_SYMBOL(dev_unicast_unsync); | ||
3060 | |||
2965 | static void __dev_addr_discard(struct dev_addr_list **list) | 3061 | static 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 | */ |
118 | int dev_mc_sync(struct net_device *to, struct net_device *from) | 118 | int 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 | */ |
161 | void dev_mc_unsync(struct net_device *to, struct net_device *from) | 144 | void 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); |