aboutsummaryrefslogtreecommitdiffstats
path: root/net
diff options
context:
space:
mode:
Diffstat (limited to 'net')
-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};