diff options
Diffstat (limited to 'net')
-rw-r--r-- | net/batman-adv/main.c | 3 | ||||
-rw-r--r-- | net/batman-adv/soft-interface.c | 393 | ||||
-rw-r--r-- | net/batman-adv/types.h | 15 |
3 files changed, 298 insertions, 113 deletions
diff --git a/net/batman-adv/main.c b/net/batman-adv/main.c index 709b33bbdf43..705e8be07c8d 100644 --- a/net/batman-adv/main.c +++ b/net/batman-adv/main.c | |||
@@ -87,11 +87,12 @@ int mesh_init(struct net_device *soft_iface) | |||
87 | spin_lock_init(&bat_priv->vis_hash_lock); | 87 | spin_lock_init(&bat_priv->vis_hash_lock); |
88 | spin_lock_init(&bat_priv->vis_list_lock); | 88 | spin_lock_init(&bat_priv->vis_list_lock); |
89 | spin_lock_init(&bat_priv->softif_neigh_lock); | 89 | spin_lock_init(&bat_priv->softif_neigh_lock); |
90 | spin_lock_init(&bat_priv->softif_neigh_vid_lock); | ||
90 | 91 | ||
91 | INIT_HLIST_HEAD(&bat_priv->forw_bat_list); | 92 | INIT_HLIST_HEAD(&bat_priv->forw_bat_list); |
92 | INIT_HLIST_HEAD(&bat_priv->forw_bcast_list); | 93 | INIT_HLIST_HEAD(&bat_priv->forw_bcast_list); |
93 | INIT_HLIST_HEAD(&bat_priv->gw_list); | 94 | INIT_HLIST_HEAD(&bat_priv->gw_list); |
94 | INIT_HLIST_HEAD(&bat_priv->softif_neigh_list); | 95 | INIT_HLIST_HEAD(&bat_priv->softif_neigh_vids); |
95 | 96 | ||
96 | if (originator_init(bat_priv) < 1) | 97 | if (originator_init(bat_priv) < 1) |
97 | goto err; | 98 | goto err; |
diff --git a/net/batman-adv/soft-interface.c b/net/batman-adv/soft-interface.c index ea5e58c252f0..8cb13a03b0e1 100644 --- a/net/batman-adv/soft-interface.c +++ b/net/batman-adv/soft-interface.c | |||
@@ -90,135 +90,251 @@ static void softif_neigh_free_ref(struct softif_neigh *softif_neigh) | |||
90 | call_rcu(&softif_neigh->rcu, softif_neigh_free_rcu); | 90 | call_rcu(&softif_neigh->rcu, softif_neigh_free_rcu); |
91 | } | 91 | } |
92 | 92 | ||
93 | static struct softif_neigh *softif_neigh_get_selected(struct bat_priv *bat_priv) | 93 | static void softif_neigh_vid_free_rcu(struct rcu_head *rcu) |
94 | { | 94 | { |
95 | struct softif_neigh *neigh; | 95 | struct softif_neigh_vid *softif_neigh_vid; |
96 | 96 | struct softif_neigh *softif_neigh; | |
97 | rcu_read_lock(); | 97 | struct hlist_node *node, *node_tmp; |
98 | neigh = rcu_dereference(bat_priv->softif_neigh); | 98 | struct bat_priv *bat_priv; |
99 | |||
100 | if (neigh && !atomic_inc_not_zero(&neigh->refcount)) | ||
101 | neigh = NULL; | ||
102 | |||
103 | rcu_read_unlock(); | ||
104 | return neigh; | ||
105 | } | ||
106 | 99 | ||
107 | static void softif_neigh_select(struct bat_priv *bat_priv, | 100 | softif_neigh_vid = container_of(rcu, struct softif_neigh_vid, rcu); |
108 | struct softif_neigh *new_neigh) | 101 | bat_priv = softif_neigh_vid->bat_priv; |
109 | { | ||
110 | struct softif_neigh *curr_neigh; | ||
111 | 102 | ||
112 | spin_lock_bh(&bat_priv->softif_neigh_lock); | 103 | spin_lock_bh(&bat_priv->softif_neigh_lock); |
113 | 104 | hlist_for_each_entry_safe(softif_neigh, node, node_tmp, | |
114 | if (new_neigh && !atomic_inc_not_zero(&new_neigh->refcount)) | 105 | &softif_neigh_vid->softif_neigh_list, list) { |
115 | new_neigh = NULL; | 106 | hlist_del_rcu(&softif_neigh->list); |
116 | 107 | softif_neigh_free_ref(softif_neigh); | |
117 | curr_neigh = bat_priv->softif_neigh; | 108 | } |
118 | rcu_assign_pointer(bat_priv->softif_neigh, new_neigh); | ||
119 | |||
120 | if (curr_neigh) | ||
121 | softif_neigh_free_ref(curr_neigh); | ||
122 | |||
123 | spin_unlock_bh(&bat_priv->softif_neigh_lock); | 109 | spin_unlock_bh(&bat_priv->softif_neigh_lock); |
110 | |||
111 | kfree(softif_neigh_vid); | ||
124 | } | 112 | } |
125 | 113 | ||
126 | static void softif_neigh_deselect(struct bat_priv *bat_priv) | 114 | static void softif_neigh_vid_free_ref(struct softif_neigh_vid *softif_neigh_vid) |
127 | { | 115 | { |
128 | softif_neigh_select(bat_priv, NULL); | 116 | if (atomic_dec_and_test(&softif_neigh_vid->refcount)) |
117 | call_rcu(&softif_neigh_vid->rcu, softif_neigh_vid_free_rcu); | ||
129 | } | 118 | } |
130 | 119 | ||
131 | void softif_neigh_purge(struct bat_priv *bat_priv) | 120 | static struct softif_neigh_vid *softif_neigh_vid_get(struct bat_priv *bat_priv, |
121 | short vid) | ||
132 | { | 122 | { |
133 | struct softif_neigh *softif_neigh, *curr_softif_neigh; | 123 | struct softif_neigh_vid *softif_neigh_vid; |
134 | struct hlist_node *node, *node_tmp; | 124 | struct hlist_node *node; |
135 | char do_deselect = 0; | ||
136 | |||
137 | curr_softif_neigh = softif_neigh_get_selected(bat_priv); | ||
138 | |||
139 | spin_lock_bh(&bat_priv->softif_neigh_lock); | ||
140 | |||
141 | hlist_for_each_entry_safe(softif_neigh, node, node_tmp, | ||
142 | &bat_priv->softif_neigh_list, list) { | ||
143 | 125 | ||
144 | if ((!time_after(jiffies, softif_neigh->last_seen + | 126 | rcu_read_lock(); |
145 | msecs_to_jiffies(SOFTIF_NEIGH_TIMEOUT))) && | 127 | hlist_for_each_entry_rcu(softif_neigh_vid, node, |
146 | (atomic_read(&bat_priv->mesh_state) == MESH_ACTIVE)) | 128 | &bat_priv->softif_neigh_vids, list) { |
129 | if (softif_neigh_vid->vid != vid) | ||
147 | continue; | 130 | continue; |
148 | 131 | ||
149 | if (curr_softif_neigh == softif_neigh) { | 132 | if (!atomic_inc_not_zero(&softif_neigh_vid->refcount)) |
150 | bat_dbg(DBG_ROUTES, bat_priv, | 133 | continue; |
151 | "Current mesh exit point '%pM' vanished " | ||
152 | "(vid: %d).\n", | ||
153 | softif_neigh->addr, softif_neigh->vid); | ||
154 | do_deselect = 1; | ||
155 | } | ||
156 | 134 | ||
157 | hlist_del_rcu(&softif_neigh->list); | 135 | goto out; |
158 | softif_neigh_free_ref(softif_neigh); | ||
159 | } | 136 | } |
160 | 137 | ||
161 | spin_unlock_bh(&bat_priv->softif_neigh_lock); | 138 | softif_neigh_vid = kzalloc(sizeof(struct softif_neigh_vid), |
139 | GFP_ATOMIC); | ||
140 | if (!softif_neigh_vid) | ||
141 | goto out; | ||
162 | 142 | ||
163 | /* soft_neigh_deselect() needs to acquire the softif_neigh_lock */ | 143 | softif_neigh_vid->vid = vid; |
164 | if (do_deselect) | 144 | softif_neigh_vid->bat_priv = bat_priv; |
165 | softif_neigh_deselect(bat_priv); | ||
166 | 145 | ||
167 | if (curr_softif_neigh) | 146 | /* initialize with 2 - caller decrements counter by one */ |
168 | softif_neigh_free_ref(curr_softif_neigh); | 147 | atomic_set(&softif_neigh_vid->refcount, 2); |
148 | INIT_HLIST_HEAD(&softif_neigh_vid->softif_neigh_list); | ||
149 | INIT_HLIST_NODE(&softif_neigh_vid->list); | ||
150 | spin_lock_bh(&bat_priv->softif_neigh_vid_lock); | ||
151 | hlist_add_head_rcu(&softif_neigh_vid->list, | ||
152 | &bat_priv->softif_neigh_vids); | ||
153 | spin_unlock_bh(&bat_priv->softif_neigh_vid_lock); | ||
154 | |||
155 | out: | ||
156 | rcu_read_unlock(); | ||
157 | return softif_neigh_vid; | ||
169 | } | 158 | } |
170 | 159 | ||
171 | static struct softif_neigh *softif_neigh_get(struct bat_priv *bat_priv, | 160 | static struct softif_neigh *softif_neigh_get(struct bat_priv *bat_priv, |
172 | uint8_t *addr, short vid) | 161 | uint8_t *addr, short vid) |
173 | { | 162 | { |
174 | struct softif_neigh *softif_neigh; | 163 | struct softif_neigh_vid *softif_neigh_vid; |
164 | struct softif_neigh *softif_neigh = NULL; | ||
175 | struct hlist_node *node; | 165 | struct hlist_node *node; |
176 | 166 | ||
167 | softif_neigh_vid = softif_neigh_vid_get(bat_priv, vid); | ||
168 | if (!softif_neigh_vid) | ||
169 | goto out; | ||
170 | |||
177 | rcu_read_lock(); | 171 | rcu_read_lock(); |
178 | hlist_for_each_entry_rcu(softif_neigh, node, | 172 | hlist_for_each_entry_rcu(softif_neigh, node, |
179 | &bat_priv->softif_neigh_list, list) { | 173 | &softif_neigh_vid->softif_neigh_list, |
174 | list) { | ||
180 | if (!compare_eth(softif_neigh->addr, addr)) | 175 | if (!compare_eth(softif_neigh->addr, addr)) |
181 | continue; | 176 | continue; |
182 | 177 | ||
183 | if (softif_neigh->vid != vid) | ||
184 | continue; | ||
185 | |||
186 | if (!atomic_inc_not_zero(&softif_neigh->refcount)) | 178 | if (!atomic_inc_not_zero(&softif_neigh->refcount)) |
187 | continue; | 179 | continue; |
188 | 180 | ||
189 | softif_neigh->last_seen = jiffies; | 181 | softif_neigh->last_seen = jiffies; |
190 | goto out; | 182 | goto unlock; |
191 | } | 183 | } |
192 | 184 | ||
193 | softif_neigh = kzalloc(sizeof(struct softif_neigh), GFP_ATOMIC); | 185 | softif_neigh = kzalloc(sizeof(struct softif_neigh), GFP_ATOMIC); |
194 | if (!softif_neigh) | 186 | if (!softif_neigh) |
195 | goto out; | 187 | goto unlock; |
196 | 188 | ||
197 | memcpy(softif_neigh->addr, addr, ETH_ALEN); | 189 | memcpy(softif_neigh->addr, addr, ETH_ALEN); |
198 | softif_neigh->vid = vid; | ||
199 | softif_neigh->last_seen = jiffies; | 190 | softif_neigh->last_seen = jiffies; |
200 | /* initialize with 2 - caller decrements counter by one */ | 191 | /* initialize with 2 - caller decrements counter by one */ |
201 | atomic_set(&softif_neigh->refcount, 2); | 192 | atomic_set(&softif_neigh->refcount, 2); |
202 | 193 | ||
203 | INIT_HLIST_NODE(&softif_neigh->list); | 194 | INIT_HLIST_NODE(&softif_neigh->list); |
204 | spin_lock_bh(&bat_priv->softif_neigh_lock); | 195 | spin_lock_bh(&bat_priv->softif_neigh_lock); |
205 | hlist_add_head_rcu(&softif_neigh->list, &bat_priv->softif_neigh_list); | 196 | hlist_add_head_rcu(&softif_neigh->list, |
197 | &softif_neigh_vid->softif_neigh_list); | ||
206 | spin_unlock_bh(&bat_priv->softif_neigh_lock); | 198 | spin_unlock_bh(&bat_priv->softif_neigh_lock); |
207 | 199 | ||
200 | unlock: | ||
201 | rcu_read_unlock(); | ||
208 | out: | 202 | out: |
203 | if (softif_neigh_vid) | ||
204 | softif_neigh_vid_free_ref(softif_neigh_vid); | ||
205 | return softif_neigh; | ||
206 | } | ||
207 | |||
208 | static struct softif_neigh *softif_neigh_get_selected( | ||
209 | struct softif_neigh_vid *softif_neigh_vid) | ||
210 | { | ||
211 | struct softif_neigh *softif_neigh; | ||
212 | |||
213 | rcu_read_lock(); | ||
214 | softif_neigh = rcu_dereference(softif_neigh_vid->softif_neigh); | ||
215 | |||
216 | if (softif_neigh && !atomic_inc_not_zero(&softif_neigh->refcount)) | ||
217 | softif_neigh = NULL; | ||
218 | |||
209 | rcu_read_unlock(); | 219 | rcu_read_unlock(); |
210 | return softif_neigh; | 220 | return softif_neigh; |
211 | } | 221 | } |
212 | 222 | ||
223 | static struct softif_neigh *softif_neigh_vid_get_selected( | ||
224 | struct bat_priv *bat_priv, | ||
225 | short vid) | ||
226 | { | ||
227 | struct softif_neigh_vid *softif_neigh_vid; | ||
228 | struct softif_neigh *softif_neigh = NULL; | ||
229 | |||
230 | softif_neigh_vid = softif_neigh_vid_get(bat_priv, vid); | ||
231 | if (!softif_neigh_vid) | ||
232 | goto out; | ||
233 | |||
234 | softif_neigh = softif_neigh_get_selected(softif_neigh_vid); | ||
235 | out: | ||
236 | if (softif_neigh_vid) | ||
237 | softif_neigh_vid_free_ref(softif_neigh_vid); | ||
238 | return softif_neigh; | ||
239 | } | ||
240 | |||
241 | static void softif_neigh_vid_select(struct bat_priv *bat_priv, | ||
242 | struct softif_neigh *new_neigh, | ||
243 | short vid) | ||
244 | { | ||
245 | struct softif_neigh_vid *softif_neigh_vid; | ||
246 | struct softif_neigh *curr_neigh; | ||
247 | |||
248 | softif_neigh_vid = softif_neigh_vid_get(bat_priv, vid); | ||
249 | if (!softif_neigh_vid) | ||
250 | goto out; | ||
251 | |||
252 | spin_lock_bh(&bat_priv->softif_neigh_lock); | ||
253 | |||
254 | if (new_neigh && !atomic_inc_not_zero(&new_neigh->refcount)) | ||
255 | new_neigh = NULL; | ||
256 | |||
257 | curr_neigh = softif_neigh_vid->softif_neigh; | ||
258 | rcu_assign_pointer(softif_neigh_vid->softif_neigh, new_neigh); | ||
259 | |||
260 | if ((curr_neigh) && (!new_neigh)) | ||
261 | bat_dbg(DBG_ROUTES, bat_priv, | ||
262 | "Removing mesh exit point on vid: %d (prev: %pM).\n", | ||
263 | vid, curr_neigh->addr); | ||
264 | else if ((curr_neigh) && (new_neigh)) | ||
265 | bat_dbg(DBG_ROUTES, bat_priv, | ||
266 | "Changing mesh exit point on vid: %d from %pM " | ||
267 | "to %pM.\n", vid, curr_neigh->addr, new_neigh->addr); | ||
268 | else if ((!curr_neigh) && (new_neigh)) | ||
269 | bat_dbg(DBG_ROUTES, bat_priv, | ||
270 | "Setting mesh exit point on vid: %d to %pM.\n", | ||
271 | vid, new_neigh->addr); | ||
272 | |||
273 | if (curr_neigh) | ||
274 | softif_neigh_free_ref(curr_neigh); | ||
275 | |||
276 | spin_unlock_bh(&bat_priv->softif_neigh_lock); | ||
277 | |||
278 | out: | ||
279 | if (softif_neigh_vid) | ||
280 | softif_neigh_vid_free_ref(softif_neigh_vid); | ||
281 | } | ||
282 | |||
283 | static void softif_neigh_vid_deselect(struct bat_priv *bat_priv, | ||
284 | struct softif_neigh_vid *softif_neigh_vid) | ||
285 | { | ||
286 | struct softif_neigh *curr_neigh; | ||
287 | struct softif_neigh *softif_neigh = NULL, *softif_neigh_tmp; | ||
288 | struct hard_iface *primary_if = NULL; | ||
289 | struct hlist_node *node; | ||
290 | |||
291 | primary_if = primary_if_get_selected(bat_priv); | ||
292 | if (!primary_if) | ||
293 | goto out; | ||
294 | |||
295 | /* find new softif_neigh immediately to avoid temporary loops */ | ||
296 | rcu_read_lock(); | ||
297 | curr_neigh = rcu_dereference(softif_neigh_vid->softif_neigh); | ||
298 | |||
299 | hlist_for_each_entry_rcu(softif_neigh_tmp, node, | ||
300 | &softif_neigh_vid->softif_neigh_list, | ||
301 | list) { | ||
302 | if (softif_neigh_tmp == curr_neigh) | ||
303 | continue; | ||
304 | |||
305 | /* we got a neighbor but its mac is 'bigger' than ours */ | ||
306 | if (memcmp(primary_if->net_dev->dev_addr, | ||
307 | softif_neigh_tmp->addr, ETH_ALEN) < 0) | ||
308 | continue; | ||
309 | |||
310 | if (!atomic_inc_not_zero(&softif_neigh_tmp->refcount)) | ||
311 | continue; | ||
312 | |||
313 | softif_neigh = softif_neigh_tmp; | ||
314 | goto unlock; | ||
315 | } | ||
316 | |||
317 | unlock: | ||
318 | rcu_read_unlock(); | ||
319 | out: | ||
320 | softif_neigh_vid_select(bat_priv, softif_neigh, softif_neigh_vid->vid); | ||
321 | |||
322 | if (primary_if) | ||
323 | hardif_free_ref(primary_if); | ||
324 | if (softif_neigh) | ||
325 | softif_neigh_free_ref(softif_neigh); | ||
326 | } | ||
327 | |||
213 | int softif_neigh_seq_print_text(struct seq_file *seq, void *offset) | 328 | int softif_neigh_seq_print_text(struct seq_file *seq, void *offset) |
214 | { | 329 | { |
215 | struct net_device *net_dev = (struct net_device *)seq->private; | 330 | struct net_device *net_dev = (struct net_device *)seq->private; |
216 | struct bat_priv *bat_priv = netdev_priv(net_dev); | 331 | struct bat_priv *bat_priv = netdev_priv(net_dev); |
332 | struct softif_neigh_vid *softif_neigh_vid; | ||
217 | struct softif_neigh *softif_neigh; | 333 | struct softif_neigh *softif_neigh; |
218 | struct hard_iface *primary_if; | 334 | struct hard_iface *primary_if; |
219 | struct hlist_node *node; | 335 | struct hlist_node *node, *node_tmp; |
220 | struct softif_neigh *curr_softif_neigh; | 336 | struct softif_neigh *curr_softif_neigh; |
221 | int ret = 0; | 337 | int ret = 0, last_seen_secs, last_seen_msecs; |
222 | 338 | ||
223 | primary_if = primary_if_get_selected(bat_priv); | 339 | primary_if = primary_if_get_selected(bat_priv); |
224 | if (!primary_if) { | 340 | if (!primary_if) { |
@@ -237,17 +353,33 @@ int softif_neigh_seq_print_text(struct seq_file *seq, void *offset) | |||
237 | 353 | ||
238 | seq_printf(seq, "Softif neighbor list (%s)\n", net_dev->name); | 354 | seq_printf(seq, "Softif neighbor list (%s)\n", net_dev->name); |
239 | 355 | ||
240 | curr_softif_neigh = softif_neigh_get_selected(bat_priv); | ||
241 | rcu_read_lock(); | 356 | rcu_read_lock(); |
242 | hlist_for_each_entry_rcu(softif_neigh, node, | 357 | hlist_for_each_entry_rcu(softif_neigh_vid, node, |
243 | &bat_priv->softif_neigh_list, list) | 358 | &bat_priv->softif_neigh_vids, list) { |
244 | seq_printf(seq, "%s %pM (vid: %d)\n", | 359 | seq_printf(seq, " %-15s %s on vid: %d\n", |
245 | curr_softif_neigh == softif_neigh | 360 | "Originator", "last-seen", softif_neigh_vid->vid); |
246 | ? "=>" : " ", softif_neigh->addr, | 361 | |
247 | softif_neigh->vid); | 362 | curr_softif_neigh = softif_neigh_get_selected(softif_neigh_vid); |
363 | |||
364 | hlist_for_each_entry_rcu(softif_neigh, node_tmp, | ||
365 | &softif_neigh_vid->softif_neigh_list, | ||
366 | list) { | ||
367 | last_seen_secs = jiffies_to_msecs(jiffies - | ||
368 | softif_neigh->last_seen) / 1000; | ||
369 | last_seen_msecs = jiffies_to_msecs(jiffies - | ||
370 | softif_neigh->last_seen) % 1000; | ||
371 | seq_printf(seq, "%s %pM %3i.%03is\n", | ||
372 | curr_softif_neigh == softif_neigh | ||
373 | ? "=>" : " ", softif_neigh->addr, | ||
374 | last_seen_secs, last_seen_msecs); | ||
375 | } | ||
376 | |||
377 | if (curr_softif_neigh) | ||
378 | softif_neigh_free_ref(curr_softif_neigh); | ||
379 | |||
380 | seq_printf(seq, "\n"); | ||
381 | } | ||
248 | rcu_read_unlock(); | 382 | rcu_read_unlock(); |
249 | if (curr_softif_neigh) | ||
250 | softif_neigh_free_ref(curr_softif_neigh); | ||
251 | 383 | ||
252 | out: | 384 | out: |
253 | if (primary_if) | 385 | if (primary_if) |
@@ -255,6 +387,70 @@ out: | |||
255 | return ret; | 387 | return ret; |
256 | } | 388 | } |
257 | 389 | ||
390 | void softif_neigh_purge(struct bat_priv *bat_priv) | ||
391 | { | ||
392 | struct softif_neigh *softif_neigh, *curr_softif_neigh; | ||
393 | struct softif_neigh_vid *softif_neigh_vid; | ||
394 | struct hlist_node *node, *node_tmp, *node_tmp2; | ||
395 | char do_deselect; | ||
396 | |||
397 | rcu_read_lock(); | ||
398 | hlist_for_each_entry_rcu(softif_neigh_vid, node, | ||
399 | &bat_priv->softif_neigh_vids, list) { | ||
400 | if (!atomic_inc_not_zero(&softif_neigh_vid->refcount)) | ||
401 | continue; | ||
402 | |||
403 | curr_softif_neigh = softif_neigh_get_selected(softif_neigh_vid); | ||
404 | do_deselect = 0; | ||
405 | |||
406 | spin_lock_bh(&bat_priv->softif_neigh_lock); | ||
407 | hlist_for_each_entry_safe(softif_neigh, node_tmp, node_tmp2, | ||
408 | &softif_neigh_vid->softif_neigh_list, | ||
409 | list) { | ||
410 | if ((!time_after(jiffies, softif_neigh->last_seen + | ||
411 | msecs_to_jiffies(SOFTIF_NEIGH_TIMEOUT))) && | ||
412 | (atomic_read(&bat_priv->mesh_state) == MESH_ACTIVE)) | ||
413 | continue; | ||
414 | |||
415 | if (curr_softif_neigh == softif_neigh) { | ||
416 | bat_dbg(DBG_ROUTES, bat_priv, | ||
417 | "Current mesh exit point on vid: %d " | ||
418 | "'%pM' vanished.\n", | ||
419 | softif_neigh_vid->vid, | ||
420 | softif_neigh->addr); | ||
421 | do_deselect = 1; | ||
422 | } | ||
423 | |||
424 | hlist_del_rcu(&softif_neigh->list); | ||
425 | softif_neigh_free_ref(softif_neigh); | ||
426 | } | ||
427 | spin_unlock_bh(&bat_priv->softif_neigh_lock); | ||
428 | |||
429 | /* soft_neigh_vid_deselect() needs to acquire the | ||
430 | * softif_neigh_lock */ | ||
431 | if (do_deselect) | ||
432 | softif_neigh_vid_deselect(bat_priv, softif_neigh_vid); | ||
433 | |||
434 | if (curr_softif_neigh) | ||
435 | softif_neigh_free_ref(curr_softif_neigh); | ||
436 | |||
437 | softif_neigh_vid_free_ref(softif_neigh_vid); | ||
438 | } | ||
439 | rcu_read_unlock(); | ||
440 | |||
441 | spin_lock_bh(&bat_priv->softif_neigh_vid_lock); | ||
442 | hlist_for_each_entry_safe(softif_neigh_vid, node, node_tmp, | ||
443 | &bat_priv->softif_neigh_vids, list) { | ||
444 | if (!hlist_empty(&softif_neigh_vid->softif_neigh_list)) | ||
445 | continue; | ||
446 | |||
447 | hlist_del_rcu(&softif_neigh_vid->list); | ||
448 | softif_neigh_vid_free_ref(softif_neigh_vid); | ||
449 | } | ||
450 | spin_unlock_bh(&bat_priv->softif_neigh_vid_lock); | ||
451 | |||
452 | } | ||
453 | |||
258 | static void softif_batman_recv(struct sk_buff *skb, struct net_device *dev, | 454 | static void softif_batman_recv(struct sk_buff *skb, struct net_device *dev, |
259 | short vid) | 455 | short vid) |
260 | { | 456 | { |
@@ -287,10 +483,7 @@ static void softif_batman_recv(struct sk_buff *skb, struct net_device *dev, | |||
287 | if (!softif_neigh) | 483 | if (!softif_neigh) |
288 | goto out; | 484 | goto out; |
289 | 485 | ||
290 | curr_softif_neigh = softif_neigh_get_selected(bat_priv); | 486 | curr_softif_neigh = softif_neigh_vid_get_selected(bat_priv, vid); |
291 | if (!curr_softif_neigh) | ||
292 | goto out; | ||
293 | |||
294 | if (curr_softif_neigh == softif_neigh) | 487 | if (curr_softif_neigh == softif_neigh) |
295 | goto out; | 488 | goto out; |
296 | 489 | ||
@@ -303,33 +496,16 @@ static void softif_batman_recv(struct sk_buff *skb, struct net_device *dev, | |||
303 | softif_neigh->addr, ETH_ALEN) < 0) | 496 | softif_neigh->addr, ETH_ALEN) < 0) |
304 | goto out; | 497 | goto out; |
305 | 498 | ||
306 | /* switch to new 'smallest neighbor' */ | ||
307 | if ((curr_softif_neigh) && | ||
308 | (memcmp(softif_neigh->addr, curr_softif_neigh->addr, | ||
309 | ETH_ALEN) < 0)) { | ||
310 | bat_dbg(DBG_ROUTES, bat_priv, | ||
311 | "Changing mesh exit point from %pM (vid: %d) " | ||
312 | "to %pM (vid: %d).\n", | ||
313 | curr_softif_neigh->addr, | ||
314 | curr_softif_neigh->vid, | ||
315 | softif_neigh->addr, softif_neigh->vid); | ||
316 | |||
317 | softif_neigh_select(bat_priv, softif_neigh); | ||
318 | goto out; | ||
319 | } | ||
320 | |||
321 | /* close own batX device and use softif_neigh as exit node */ | 499 | /* close own batX device and use softif_neigh as exit node */ |
322 | if ((!curr_softif_neigh) && | 500 | if (!curr_softif_neigh) { |
323 | (memcmp(softif_neigh->addr, | 501 | softif_neigh_vid_select(bat_priv, softif_neigh, vid); |
324 | primary_if->net_dev->dev_addr, ETH_ALEN) < 0)) { | ||
325 | bat_dbg(DBG_ROUTES, bat_priv, | ||
326 | "Setting mesh exit point to %pM (vid: %d).\n", | ||
327 | softif_neigh->addr, softif_neigh->vid); | ||
328 | |||
329 | softif_neigh_select(bat_priv, softif_neigh); | ||
330 | goto out; | 502 | goto out; |
331 | } | 503 | } |
332 | 504 | ||
505 | /* switch to new 'smallest neighbor' */ | ||
506 | if (memcmp(softif_neigh->addr, curr_softif_neigh->addr, ETH_ALEN) < 0) | ||
507 | softif_neigh_vid_select(bat_priv, softif_neigh, vid); | ||
508 | |||
333 | out: | 509 | out: |
334 | kfree_skb(skb); | 510 | kfree_skb(skb); |
335 | if (softif_neigh) | 511 | if (softif_neigh) |
@@ -424,8 +600,8 @@ int interface_tx(struct sk_buff *skb, struct net_device *soft_iface) | |||
424 | * if we have a another chosen mesh exit node in range | 600 | * if we have a another chosen mesh exit node in range |
425 | * it will transport the packets to the mesh | 601 | * it will transport the packets to the mesh |
426 | */ | 602 | */ |
427 | curr_softif_neigh = softif_neigh_get_selected(bat_priv); | 603 | curr_softif_neigh = softif_neigh_vid_get_selected(bat_priv, vid); |
428 | if ((curr_softif_neigh) && (curr_softif_neigh->vid == vid)) | 604 | if (curr_softif_neigh) |
429 | goto dropped; | 605 | goto dropped; |
430 | 606 | ||
431 | /* TODO: check this for locks */ | 607 | /* TODO: check this for locks */ |
@@ -533,8 +709,8 @@ void interface_rx(struct net_device *soft_iface, | |||
533 | * if we have a another chosen mesh exit node in range | 709 | * if we have a another chosen mesh exit node in range |
534 | * it will transport the packets to the non-mesh network | 710 | * it will transport the packets to the non-mesh network |
535 | */ | 711 | */ |
536 | curr_softif_neigh = softif_neigh_get_selected(bat_priv); | 712 | curr_softif_neigh = softif_neigh_vid_get_selected(bat_priv, vid); |
537 | if (curr_softif_neigh && (curr_softif_neigh->vid == vid)) { | 713 | if (curr_softif_neigh) { |
538 | skb_push(skb, hdr_size); | 714 | skb_push(skb, hdr_size); |
539 | unicast_packet = (struct unicast_packet *)skb->data; | 715 | unicast_packet = (struct unicast_packet *)skb->data; |
540 | 716 | ||
@@ -671,7 +847,6 @@ struct net_device *softif_create(char *name) | |||
671 | 847 | ||
672 | bat_priv->primary_if = NULL; | 848 | bat_priv->primary_if = NULL; |
673 | bat_priv->num_ifaces = 0; | 849 | bat_priv->num_ifaces = 0; |
674 | bat_priv->softif_neigh = NULL; | ||
675 | 850 | ||
676 | ret = sysfs_add_meshif(soft_iface); | 851 | ret = sysfs_add_meshif(soft_iface); |
677 | if (ret < 0) | 852 | if (ret < 0) |
diff --git a/net/batman-adv/types.h b/net/batman-adv/types.h index 947bafc6431a..9ae507ab7bbe 100644 --- a/net/batman-adv/types.h +++ b/net/batman-adv/types.h | |||
@@ -146,14 +146,13 @@ struct bat_priv { | |||
146 | atomic_t bcast_queue_left; | 146 | atomic_t bcast_queue_left; |
147 | atomic_t batman_queue_left; | 147 | atomic_t batman_queue_left; |
148 | char num_ifaces; | 148 | char num_ifaces; |
149 | struct hlist_head softif_neigh_list; | ||
150 | struct softif_neigh __rcu *softif_neigh; | ||
151 | struct debug_log *debug_log; | 149 | struct debug_log *debug_log; |
152 | struct kobject *mesh_obj; | 150 | struct kobject *mesh_obj; |
153 | struct dentry *debug_dir; | 151 | struct dentry *debug_dir; |
154 | struct hlist_head forw_bat_list; | 152 | struct hlist_head forw_bat_list; |
155 | struct hlist_head forw_bcast_list; | 153 | struct hlist_head forw_bcast_list; |
156 | struct hlist_head gw_list; | 154 | struct hlist_head gw_list; |
155 | struct hlist_head softif_neigh_vids; | ||
157 | struct list_head vis_send_list; | 156 | struct list_head vis_send_list; |
158 | struct hashtable_t *orig_hash; | 157 | struct hashtable_t *orig_hash; |
159 | struct hashtable_t *hna_local_hash; | 158 | struct hashtable_t *hna_local_hash; |
@@ -167,6 +166,7 @@ struct bat_priv { | |||
167 | spinlock_t vis_hash_lock; /* protects vis_hash */ | 166 | spinlock_t vis_hash_lock; /* protects vis_hash */ |
168 | spinlock_t vis_list_lock; /* protects vis_info::recv_list */ | 167 | spinlock_t vis_list_lock; /* protects vis_info::recv_list */ |
169 | spinlock_t softif_neigh_lock; /* protects soft-interface neigh list */ | 168 | spinlock_t softif_neigh_lock; /* protects soft-interface neigh list */ |
169 | spinlock_t softif_neigh_vid_lock; /* protects soft-interface vid list */ | ||
170 | int16_t num_local_hna; | 170 | int16_t num_local_hna; |
171 | atomic_t hna_local_changed; | 171 | atomic_t hna_local_changed; |
172 | struct delayed_work hna_work; | 172 | struct delayed_work hna_work; |
@@ -270,11 +270,20 @@ struct recvlist_node { | |||
270 | uint8_t mac[ETH_ALEN]; | 270 | uint8_t mac[ETH_ALEN]; |
271 | }; | 271 | }; |
272 | 272 | ||
273 | struct softif_neigh_vid { | ||
274 | struct hlist_node list; | ||
275 | struct bat_priv *bat_priv; | ||
276 | short vid; | ||
277 | atomic_t refcount; | ||
278 | struct softif_neigh __rcu *softif_neigh; | ||
279 | struct rcu_head rcu; | ||
280 | struct hlist_head softif_neigh_list; | ||
281 | }; | ||
282 | |||
273 | struct softif_neigh { | 283 | struct softif_neigh { |
274 | struct hlist_node list; | 284 | struct hlist_node list; |
275 | uint8_t addr[ETH_ALEN]; | 285 | uint8_t addr[ETH_ALEN]; |
276 | unsigned long last_seen; | 286 | unsigned long last_seen; |
277 | short vid; | ||
278 | atomic_t refcount; | 287 | atomic_t refcount; |
279 | struct rcu_head rcu; | 288 | struct rcu_head rcu; |
280 | }; | 289 | }; |