aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorMarek Lindner <lindner_marek@yahoo.de>2011-04-21 09:52:17 -0400
committerSven Eckelmann <sven@narfation.org>2011-05-08 10:10:41 -0400
commit61906ae86d8989e5bd3bc1f51b2fb8d32ffde2c5 (patch)
treedf71d837c147495099a1411897652154bc26c08e
parent28f8e546e6bc4c2bc6687d7c8dcbe9934cebe639 (diff)
batman-adv: multi vlan support for bridge loop detection
The bridge loop detection for batman-adv allows the bat0 interface to be bridged into an ethernet segment which other batman-adv nodes are connected to. In order to also allow multiple VLANs on top of the bat0 interface to be bridged into the ethernet segment this patch extends the aforementioned bridge loop detection. Signed-off-by: Marek Lindner <lindner_marek@yahoo.de> Signed-off-by: Sven Eckelmann <sven@narfation.org>
-rw-r--r--net/batman-adv/main.c3
-rw-r--r--net/batman-adv/soft-interface.c393
-rw-r--r--net/batman-adv/types.h15
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
93static struct softif_neigh *softif_neigh_get_selected(struct bat_priv *bat_priv) 93static 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
107static 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
126static void softif_neigh_deselect(struct bat_priv *bat_priv) 114static 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
131void softif_neigh_purge(struct bat_priv *bat_priv) 120static 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
155out:
156 rcu_read_unlock();
157 return softif_neigh_vid;
169} 158}
170 159
171static struct softif_neigh *softif_neigh_get(struct bat_priv *bat_priv, 160static 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
200unlock:
201 rcu_read_unlock();
208out: 202out:
203 if (softif_neigh_vid)
204 softif_neigh_vid_free_ref(softif_neigh_vid);
205 return softif_neigh;
206}
207
208static 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
223static 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);
235out:
236 if (softif_neigh_vid)
237 softif_neigh_vid_free_ref(softif_neigh_vid);
238 return softif_neigh;
239}
240
241static 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
278out:
279 if (softif_neigh_vid)
280 softif_neigh_vid_free_ref(softif_neigh_vid);
281}
282
283static 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
317unlock:
318 rcu_read_unlock();
319out:
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
213int softif_neigh_seq_print_text(struct seq_file *seq, void *offset) 328int 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
252out: 384out:
253 if (primary_if) 385 if (primary_if)
@@ -255,6 +387,70 @@ out:
255 return ret; 387 return ret;
256} 388}
257 389
390void 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
258static void softif_batman_recv(struct sk_buff *skb, struct net_device *dev, 454static 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
333out: 509out:
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
273struct 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
273struct softif_neigh { 283struct 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};