diff options
-rw-r--r-- | include/linux/netdevice.h | 3 | ||||
-rw-r--r-- | net/core/dev_mcast.c | 75 |
2 files changed, 78 insertions, 0 deletions
diff --git a/include/linux/netdevice.h b/include/linux/netdevice.h index f193aba30384..e5af458ab04b 100644 --- a/include/linux/netdevice.h +++ b/include/linux/netdevice.h | |||
@@ -190,6 +190,7 @@ struct dev_addr_list | |||
190 | struct dev_addr_list *next; | 190 | struct dev_addr_list *next; |
191 | u8 da_addr[MAX_ADDR_LEN]; | 191 | u8 da_addr[MAX_ADDR_LEN]; |
192 | u8 da_addrlen; | 192 | u8 da_addrlen; |
193 | u8 da_synced; | ||
193 | int da_users; | 194 | int da_users; |
194 | int da_gusers; | 195 | int da_gusers; |
195 | }; | 196 | }; |
@@ -1103,6 +1104,8 @@ extern int dev_unicast_delete(struct net_device *dev, void *addr, int alen); | |||
1103 | extern int dev_unicast_add(struct net_device *dev, void *addr, int alen); | 1104 | extern int dev_unicast_add(struct net_device *dev, void *addr, int alen); |
1104 | extern int dev_mc_delete(struct net_device *dev, void *addr, int alen, int all); | 1105 | extern int dev_mc_delete(struct net_device *dev, void *addr, int alen, int all); |
1105 | extern int dev_mc_add(struct net_device *dev, void *addr, int alen, int newonly); | 1106 | extern int dev_mc_add(struct net_device *dev, void *addr, int alen, int newonly); |
1107 | extern int dev_mc_sync(struct net_device *to, struct net_device *from); | ||
1108 | extern void dev_mc_unsync(struct net_device *to, struct net_device *from); | ||
1106 | extern void dev_mc_discard(struct net_device *dev); | 1109 | extern void dev_mc_discard(struct net_device *dev); |
1107 | extern int __dev_addr_delete(struct dev_addr_list **list, int *count, void *addr, int alen, int all); | 1110 | extern int __dev_addr_delete(struct dev_addr_list **list, int *count, void *addr, int alen, int all); |
1108 | extern int __dev_addr_add(struct dev_addr_list **list, int *count, void *addr, int alen, int newonly); | 1111 | extern int __dev_addr_add(struct dev_addr_list **list, int *count, void *addr, int alen, int newonly); |
diff --git a/net/core/dev_mcast.c b/net/core/dev_mcast.c index aa38100601fb..235a2a8a0d05 100644 --- a/net/core/dev_mcast.c +++ b/net/core/dev_mcast.c | |||
@@ -102,6 +102,81 @@ int dev_mc_add(struct net_device *dev, void *addr, int alen, int glbl) | |||
102 | return err; | 102 | return err; |
103 | } | 103 | } |
104 | 104 | ||
105 | /** | ||
106 | * dev_mc_sync - Synchronize device's multicast list to another device | ||
107 | * @to: destination device | ||
108 | * @from: source device | ||
109 | * | ||
110 | * Add newly added addresses to the destination device and release | ||
111 | * addresses that have no users left. The source device must be | ||
112 | * locked by netif_tx_lock_bh. | ||
113 | * | ||
114 | * This function is intended to be called from the dev->set_multicast_list | ||
115 | * function of layered software devices. | ||
116 | */ | ||
117 | int dev_mc_sync(struct net_device *to, struct net_device *from) | ||
118 | { | ||
119 | struct dev_addr_list *da; | ||
120 | int err = 0; | ||
121 | |||
122 | netif_tx_lock_bh(to); | ||
123 | for (da = from->mc_list; da != NULL; da = da->next) { | ||
124 | if (!da->da_synced) { | ||
125 | err = __dev_addr_add(&to->mc_list, &to->mc_count, | ||
126 | da->da_addr, da->da_addrlen, 0); | ||
127 | if (err < 0) | ||
128 | break; | ||
129 | da->da_synced = 1; | ||
130 | da->da_users++; | ||
131 | } else if (da->da_users == 1) { | ||
132 | __dev_addr_delete(&to->mc_list, &to->mc_count, | ||
133 | da->da_addr, da->da_addrlen, 0); | ||
134 | __dev_addr_delete(&from->mc_list, &from->mc_count, | ||
135 | da->da_addr, da->da_addrlen, 0); | ||
136 | } | ||
137 | } | ||
138 | if (!err) | ||
139 | __dev_set_rx_mode(to); | ||
140 | netif_tx_unlock_bh(to); | ||
141 | |||
142 | return err; | ||
143 | } | ||
144 | EXPORT_SYMBOL(dev_mc_sync); | ||
145 | |||
146 | |||
147 | /** | ||
148 | * dev_mc_unsync - Remove synchronized addresses from the destination | ||
149 | * device | ||
150 | * @to: destination device | ||
151 | * @from: source device | ||
152 | * | ||
153 | * Remove all addresses that were added to the destination device by | ||
154 | * dev_mc_sync(). This function is intended to be called from the | ||
155 | * dev->stop function of layered software devices. | ||
156 | */ | ||
157 | void dev_mc_unsync(struct net_device *to, struct net_device *from) | ||
158 | { | ||
159 | struct dev_addr_list *da; | ||
160 | |||
161 | netif_tx_lock_bh(from); | ||
162 | netif_tx_lock_bh(to); | ||
163 | |||
164 | for (da = from->mc_list; da != NULL; da = da->next) { | ||
165 | if (!da->da_synced) | ||
166 | continue; | ||
167 | __dev_addr_delete(&to->mc_list, &to->mc_count, | ||
168 | da->da_addr, da->da_addrlen, 0); | ||
169 | da->da_synced = 0; | ||
170 | __dev_addr_delete(&from->mc_list, &from->mc_count, | ||
171 | da->da_addr, da->da_addrlen, 0); | ||
172 | } | ||
173 | __dev_set_rx_mode(to); | ||
174 | |||
175 | netif_tx_unlock_bh(to); | ||
176 | netif_tx_unlock_bh(from); | ||
177 | } | ||
178 | EXPORT_SYMBOL(dev_mc_unsync); | ||
179 | |||
105 | /* | 180 | /* |
106 | * Discard multicast list when a device is downed | 181 | * Discard multicast list when a device is downed |
107 | */ | 182 | */ |