aboutsummaryrefslogtreecommitdiffstats
path: root/net/batman-adv
diff options
context:
space:
mode:
Diffstat (limited to 'net/batman-adv')
-rw-r--r--net/batman-adv/gateway_client.c259
-rw-r--r--net/batman-adv/gateway_client.h2
-rw-r--r--net/batman-adv/icmp_socket.c18
-rw-r--r--net/batman-adv/originator.c38
-rw-r--r--net/batman-adv/originator.h1
-rw-r--r--net/batman-adv/routing.c378
-rw-r--r--net/batman-adv/send.c19
-rw-r--r--net/batman-adv/soft-interface.c115
-rw-r--r--net/batman-adv/types.h7
-rw-r--r--net/batman-adv/unicast.c2
-rw-r--r--net/batman-adv/vis.c91
11 files changed, 537 insertions, 393 deletions
diff --git a/net/batman-adv/gateway_client.c b/net/batman-adv/gateway_client.c
index 3cc43558cf9c..2acd7a666bda 100644
--- a/net/batman-adv/gateway_client.c
+++ b/net/batman-adv/gateway_client.c
@@ -23,6 +23,7 @@
23#include "gateway_client.h" 23#include "gateway_client.h"
24#include "gateway_common.h" 24#include "gateway_common.h"
25#include "hard-interface.h" 25#include "hard-interface.h"
26#include "originator.h"
26#include <linux/ip.h> 27#include <linux/ip.h>
27#include <linux/ipv6.h> 28#include <linux/ipv6.h>
28#include <linux/udp.h> 29#include <linux/udp.h>
@@ -42,61 +43,76 @@ static void gw_node_free_ref(struct gw_node *gw_node)
42 call_rcu(&gw_node->rcu, gw_node_free_rcu); 43 call_rcu(&gw_node->rcu, gw_node_free_rcu);
43} 44}
44 45
45void *gw_get_selected(struct bat_priv *bat_priv) 46static struct gw_node *gw_get_selected_gw_node(struct bat_priv *bat_priv)
46{ 47{
47 struct gw_node *curr_gateway_tmp; 48 struct gw_node *gw_node;
48 struct orig_node *orig_node = NULL;
49 49
50 rcu_read_lock(); 50 rcu_read_lock();
51 curr_gateway_tmp = rcu_dereference(bat_priv->curr_gw); 51 gw_node = rcu_dereference(bat_priv->curr_gw);
52 if (!curr_gateway_tmp) 52 if (!gw_node)
53 goto out;
54
55 orig_node = curr_gateway_tmp->orig_node;
56 if (!orig_node)
57 goto out; 53 goto out;
58 54
59 if (!atomic_inc_not_zero(&orig_node->refcount)) 55 if (!atomic_inc_not_zero(&gw_node->refcount))
60 orig_node = NULL; 56 gw_node = NULL;
61 57
62out: 58out:
63 rcu_read_unlock(); 59 rcu_read_unlock();
64 return orig_node; 60 return gw_node;
65} 61}
66 62
67void gw_deselect(struct bat_priv *bat_priv) 63struct orig_node *gw_get_selected_orig(struct bat_priv *bat_priv)
68{ 64{
69 struct gw_node *gw_node; 65 struct gw_node *gw_node;
66 struct orig_node *orig_node = NULL;
70 67
71 spin_lock_bh(&bat_priv->gw_list_lock); 68 gw_node = gw_get_selected_gw_node(bat_priv);
72 gw_node = rcu_dereference(bat_priv->curr_gw); 69 if (!gw_node)
73 rcu_assign_pointer(bat_priv->curr_gw, NULL); 70 goto out;
74 spin_unlock_bh(&bat_priv->gw_list_lock); 71
72 rcu_read_lock();
73 orig_node = gw_node->orig_node;
74 if (!orig_node)
75 goto unlock;
76
77 if (!atomic_inc_not_zero(&orig_node->refcount))
78 orig_node = NULL;
75 79
80unlock:
81 rcu_read_unlock();
82out:
76 if (gw_node) 83 if (gw_node)
77 gw_node_free_ref(gw_node); 84 gw_node_free_ref(gw_node);
85 return orig_node;
78} 86}
79 87
80static void gw_select(struct bat_priv *bat_priv, struct gw_node *new_gw_node) 88static void gw_select(struct bat_priv *bat_priv, struct gw_node *new_gw_node)
81{ 89{
82 struct gw_node *curr_gw_node; 90 struct gw_node *curr_gw_node;
83 91
92 spin_lock_bh(&bat_priv->gw_list_lock);
93
84 if (new_gw_node && !atomic_inc_not_zero(&new_gw_node->refcount)) 94 if (new_gw_node && !atomic_inc_not_zero(&new_gw_node->refcount))
85 new_gw_node = NULL; 95 new_gw_node = NULL;
86 96
87 spin_lock_bh(&bat_priv->gw_list_lock); 97 curr_gw_node = bat_priv->curr_gw;
88 curr_gw_node = rcu_dereference(bat_priv->curr_gw);
89 rcu_assign_pointer(bat_priv->curr_gw, new_gw_node); 98 rcu_assign_pointer(bat_priv->curr_gw, new_gw_node);
90 spin_unlock_bh(&bat_priv->gw_list_lock);
91 99
92 if (curr_gw_node) 100 if (curr_gw_node)
93 gw_node_free_ref(curr_gw_node); 101 gw_node_free_ref(curr_gw_node);
102
103 spin_unlock_bh(&bat_priv->gw_list_lock);
104}
105
106void gw_deselect(struct bat_priv *bat_priv)
107{
108 gw_select(bat_priv, NULL);
94} 109}
95 110
96void gw_election(struct bat_priv *bat_priv) 111void gw_election(struct bat_priv *bat_priv)
97{ 112{
98 struct hlist_node *node; 113 struct hlist_node *node;
99 struct gw_node *gw_node, *curr_gw, *curr_gw_tmp = NULL; 114 struct gw_node *gw_node, *curr_gw = NULL, *curr_gw_tmp = NULL;
115 struct neigh_node *router;
100 uint8_t max_tq = 0; 116 uint8_t max_tq = 0;
101 uint32_t max_gw_factor = 0, tmp_gw_factor = 0; 117 uint32_t max_gw_factor = 0, tmp_gw_factor = 0;
102 int down, up; 118 int down, up;
@@ -110,32 +126,25 @@ void gw_election(struct bat_priv *bat_priv)
110 if (atomic_read(&bat_priv->gw_mode) != GW_MODE_CLIENT) 126 if (atomic_read(&bat_priv->gw_mode) != GW_MODE_CLIENT)
111 return; 127 return;
112 128
113 rcu_read_lock(); 129 curr_gw = gw_get_selected_gw_node(bat_priv);
114 curr_gw = rcu_dereference(bat_priv->curr_gw); 130 if (!curr_gw)
115 if (curr_gw) { 131 goto out;
116 rcu_read_unlock();
117 return;
118 }
119 132
133 rcu_read_lock();
120 if (hlist_empty(&bat_priv->gw_list)) { 134 if (hlist_empty(&bat_priv->gw_list)) {
121 135 bat_dbg(DBG_BATMAN, bat_priv,
122 if (curr_gw) { 136 "Removing selected gateway - "
123 rcu_read_unlock(); 137 "no gateway in range\n");
124 bat_dbg(DBG_BATMAN, bat_priv, 138 gw_deselect(bat_priv);
125 "Removing selected gateway - " 139 goto unlock;
126 "no gateway in range\n");
127 gw_deselect(bat_priv);
128 } else
129 rcu_read_unlock();
130
131 return;
132 } 140 }
133 141
134 hlist_for_each_entry_rcu(gw_node, node, &bat_priv->gw_list, list) { 142 hlist_for_each_entry_rcu(gw_node, node, &bat_priv->gw_list, list) {
135 if (!gw_node->orig_node->router) 143 if (gw_node->deleted)
136 continue; 144 continue;
137 145
138 if (gw_node->deleted) 146 router = orig_node_get_router(gw_node->orig_node);
147 if (!router)
139 continue; 148 continue;
140 149
141 switch (atomic_read(&bat_priv->gw_sel_class)) { 150 switch (atomic_read(&bat_priv->gw_sel_class)) {
@@ -143,15 +152,14 @@ void gw_election(struct bat_priv *bat_priv)
143 gw_bandwidth_to_kbit(gw_node->orig_node->gw_flags, 152 gw_bandwidth_to_kbit(gw_node->orig_node->gw_flags,
144 &down, &up); 153 &down, &up);
145 154
146 tmp_gw_factor = (gw_node->orig_node->router->tq_avg * 155 tmp_gw_factor = (router->tq_avg * router->tq_avg *
147 gw_node->orig_node->router->tq_avg *
148 down * 100 * 100) / 156 down * 100 * 100) /
149 (TQ_LOCAL_WINDOW_SIZE * 157 (TQ_LOCAL_WINDOW_SIZE *
150 TQ_LOCAL_WINDOW_SIZE * 64); 158 TQ_LOCAL_WINDOW_SIZE * 64);
151 159
152 if ((tmp_gw_factor > max_gw_factor) || 160 if ((tmp_gw_factor > max_gw_factor) ||
153 ((tmp_gw_factor == max_gw_factor) && 161 ((tmp_gw_factor == max_gw_factor) &&
154 (gw_node->orig_node->router->tq_avg > max_tq))) 162 (router->tq_avg > max_tq)))
155 curr_gw_tmp = gw_node; 163 curr_gw_tmp = gw_node;
156 break; 164 break;
157 165
@@ -163,19 +171,25 @@ void gw_election(struct bat_priv *bat_priv)
163 * soon as a better gateway appears which has 171 * soon as a better gateway appears which has
164 * $routing_class more tq points) 172 * $routing_class more tq points)
165 **/ 173 **/
166 if (gw_node->orig_node->router->tq_avg > max_tq) 174 if (router->tq_avg > max_tq)
167 curr_gw_tmp = gw_node; 175 curr_gw_tmp = gw_node;
168 break; 176 break;
169 } 177 }
170 178
171 if (gw_node->orig_node->router->tq_avg > max_tq) 179 if (router->tq_avg > max_tq)
172 max_tq = gw_node->orig_node->router->tq_avg; 180 max_tq = router->tq_avg;
173 181
174 if (tmp_gw_factor > max_gw_factor) 182 if (tmp_gw_factor > max_gw_factor)
175 max_gw_factor = tmp_gw_factor; 183 max_gw_factor = tmp_gw_factor;
184
185 neigh_node_free_ref(router);
176 } 186 }
177 187
178 if (curr_gw != curr_gw_tmp) { 188 if (curr_gw != curr_gw_tmp) {
189 router = orig_node_get_router(curr_gw_tmp->orig_node);
190 if (!router)
191 goto unlock;
192
179 if ((curr_gw) && (!curr_gw_tmp)) 193 if ((curr_gw) && (!curr_gw_tmp))
180 bat_dbg(DBG_BATMAN, bat_priv, 194 bat_dbg(DBG_BATMAN, bat_priv,
181 "Removing selected gateway - " 195 "Removing selected gateway - "
@@ -186,48 +200,50 @@ void gw_election(struct bat_priv *bat_priv)
186 "(gw_flags: %i, tq: %i)\n", 200 "(gw_flags: %i, tq: %i)\n",
187 curr_gw_tmp->orig_node->orig, 201 curr_gw_tmp->orig_node->orig,
188 curr_gw_tmp->orig_node->gw_flags, 202 curr_gw_tmp->orig_node->gw_flags,
189 curr_gw_tmp->orig_node->router->tq_avg); 203 router->tq_avg);
190 else 204 else
191 bat_dbg(DBG_BATMAN, bat_priv, 205 bat_dbg(DBG_BATMAN, bat_priv,
192 "Changing route to gateway %pM " 206 "Changing route to gateway %pM "
193 "(gw_flags: %i, tq: %i)\n", 207 "(gw_flags: %i, tq: %i)\n",
194 curr_gw_tmp->orig_node->orig, 208 curr_gw_tmp->orig_node->orig,
195 curr_gw_tmp->orig_node->gw_flags, 209 curr_gw_tmp->orig_node->gw_flags,
196 curr_gw_tmp->orig_node->router->tq_avg); 210 router->tq_avg);
197 211
212 neigh_node_free_ref(router);
198 gw_select(bat_priv, curr_gw_tmp); 213 gw_select(bat_priv, curr_gw_tmp);
199 } 214 }
200 215
216unlock:
201 rcu_read_unlock(); 217 rcu_read_unlock();
218out:
219 if (curr_gw)
220 gw_node_free_ref(curr_gw);
202} 221}
203 222
204void gw_check_election(struct bat_priv *bat_priv, struct orig_node *orig_node) 223void gw_check_election(struct bat_priv *bat_priv, struct orig_node *orig_node)
205{ 224{
206 struct gw_node *curr_gateway_tmp; 225 struct orig_node *curr_gw_orig;
226 struct neigh_node *router_gw = NULL, *router_orig = NULL;
207 uint8_t gw_tq_avg, orig_tq_avg; 227 uint8_t gw_tq_avg, orig_tq_avg;
208 228
209 rcu_read_lock(); 229 curr_gw_orig = gw_get_selected_orig(bat_priv);
210 curr_gateway_tmp = rcu_dereference(bat_priv->curr_gw); 230 if (!curr_gw_orig)
211 if (!curr_gateway_tmp) 231 goto deselect;
212 goto out_rcu;
213 232
214 if (!curr_gateway_tmp->orig_node) 233 router_gw = orig_node_get_router(curr_gw_orig);
215 goto deselect_rcu; 234 if (!router_gw)
216 235 goto deselect;
217 if (!curr_gateway_tmp->orig_node->router)
218 goto deselect_rcu;
219 236
220 /* this node already is the gateway */ 237 /* this node already is the gateway */
221 if (curr_gateway_tmp->orig_node == orig_node) 238 if (curr_gw_orig == orig_node)
222 goto out_rcu; 239 goto out;
223
224 if (!orig_node->router)
225 goto out_rcu;
226 240
227 gw_tq_avg = curr_gateway_tmp->orig_node->router->tq_avg; 241 router_orig = orig_node_get_router(orig_node);
228 rcu_read_unlock(); 242 if (!router_orig)
243 goto out;
229 244
230 orig_tq_avg = orig_node->router->tq_avg; 245 gw_tq_avg = router_gw->tq_avg;
246 orig_tq_avg = router_orig->tq_avg;
231 247
232 /* the TQ value has to be better */ 248 /* the TQ value has to be better */
233 if (orig_tq_avg < gw_tq_avg) 249 if (orig_tq_avg < gw_tq_avg)
@@ -245,16 +261,17 @@ void gw_check_election(struct bat_priv *bat_priv, struct orig_node *orig_node)
245 "Restarting gateway selection: better gateway found (tq curr: " 261 "Restarting gateway selection: better gateway found (tq curr: "
246 "%i, tq new: %i)\n", 262 "%i, tq new: %i)\n",
247 gw_tq_avg, orig_tq_avg); 263 gw_tq_avg, orig_tq_avg);
248 goto deselect;
249 264
250out_rcu:
251 rcu_read_unlock();
252 goto out;
253deselect_rcu:
254 rcu_read_unlock();
255deselect: 265deselect:
256 gw_deselect(bat_priv); 266 gw_deselect(bat_priv);
257out: 267out:
268 if (curr_gw_orig)
269 orig_node_free_ref(curr_gw_orig);
270 if (router_gw)
271 neigh_node_free_ref(router_gw);
272 if (router_orig)
273 neigh_node_free_ref(router_orig);
274
258 return; 275 return;
259} 276}
260 277
@@ -291,7 +308,11 @@ void gw_node_update(struct bat_priv *bat_priv,
291 struct orig_node *orig_node, uint8_t new_gwflags) 308 struct orig_node *orig_node, uint8_t new_gwflags)
292{ 309{
293 struct hlist_node *node; 310 struct hlist_node *node;
294 struct gw_node *gw_node; 311 struct gw_node *gw_node, *curr_gw;
312
313 curr_gw = gw_get_selected_gw_node(bat_priv);
314 if (!curr_gw)
315 goto out;
295 316
296 rcu_read_lock(); 317 rcu_read_lock();
297 hlist_for_each_entry_rcu(gw_node, node, &bat_priv->gw_list, list) { 318 hlist_for_each_entry_rcu(gw_node, node, &bat_priv->gw_list, list) {
@@ -312,22 +333,26 @@ void gw_node_update(struct bat_priv *bat_priv,
312 "Gateway %pM removed from gateway list\n", 333 "Gateway %pM removed from gateway list\n",
313 orig_node->orig); 334 orig_node->orig);
314 335
315 if (gw_node == rcu_dereference(bat_priv->curr_gw)) { 336 if (gw_node == curr_gw)
316 rcu_read_unlock(); 337 goto deselect;
317 gw_deselect(bat_priv);
318 return;
319 }
320 } 338 }
321 339
322 rcu_read_unlock(); 340 goto unlock;
323 return;
324 } 341 }
325 rcu_read_unlock();
326 342
327 if (new_gwflags == 0) 343 if (new_gwflags == 0)
328 return; 344 goto unlock;
329 345
330 gw_node_add(bat_priv, orig_node, new_gwflags); 346 gw_node_add(bat_priv, orig_node, new_gwflags);
347 goto unlock;
348
349deselect:
350 gw_deselect(bat_priv);
351unlock:
352 rcu_read_unlock();
353out:
354 if (curr_gw)
355 gw_node_free_ref(curr_gw);
331} 356}
332 357
333void gw_node_delete(struct bat_priv *bat_priv, struct orig_node *orig_node) 358void gw_node_delete(struct bat_priv *bat_priv, struct orig_node *orig_node)
@@ -337,9 +362,12 @@ void gw_node_delete(struct bat_priv *bat_priv, struct orig_node *orig_node)
337 362
338void gw_node_purge(struct bat_priv *bat_priv) 363void gw_node_purge(struct bat_priv *bat_priv)
339{ 364{
340 struct gw_node *gw_node; 365 struct gw_node *gw_node, *curr_gw;
341 struct hlist_node *node, *node_tmp; 366 struct hlist_node *node, *node_tmp;
342 unsigned long timeout = 2 * PURGE_TIMEOUT * HZ; 367 unsigned long timeout = 2 * PURGE_TIMEOUT * HZ;
368 char do_deselect = 0;
369
370 curr_gw = gw_get_selected_gw_node(bat_priv);
343 371
344 spin_lock_bh(&bat_priv->gw_list_lock); 372 spin_lock_bh(&bat_priv->gw_list_lock);
345 373
@@ -350,41 +378,56 @@ void gw_node_purge(struct bat_priv *bat_priv)
350 atomic_read(&bat_priv->mesh_state) == MESH_ACTIVE) 378 atomic_read(&bat_priv->mesh_state) == MESH_ACTIVE)
351 continue; 379 continue;
352 380
353 if (rcu_dereference(bat_priv->curr_gw) == gw_node) 381 if (curr_gw == gw_node)
354 gw_deselect(bat_priv); 382 do_deselect = 1;
355 383
356 hlist_del_rcu(&gw_node->list); 384 hlist_del_rcu(&gw_node->list);
357 gw_node_free_ref(gw_node); 385 gw_node_free_ref(gw_node);
358 } 386 }
359 387
360
361 spin_unlock_bh(&bat_priv->gw_list_lock); 388 spin_unlock_bh(&bat_priv->gw_list_lock);
389
390 /* gw_deselect() needs to acquire the gw_list_lock */
391 if (do_deselect)
392 gw_deselect(bat_priv);
393
394 if (curr_gw)
395 gw_node_free_ref(curr_gw);
362} 396}
363 397
398/**
399 * fails if orig_node has no router
400 */
364static int _write_buffer_text(struct bat_priv *bat_priv, 401static int _write_buffer_text(struct bat_priv *bat_priv,
365 struct seq_file *seq, struct gw_node *gw_node) 402 struct seq_file *seq, struct gw_node *gw_node)
366{ 403{
367 struct gw_node *curr_gw; 404 struct gw_node *curr_gw;
368 int down, up, ret; 405 struct neigh_node *router;
406 int down, up, ret = -1;
369 407
370 gw_bandwidth_to_kbit(gw_node->orig_node->gw_flags, &down, &up); 408 gw_bandwidth_to_kbit(gw_node->orig_node->gw_flags, &down, &up);
371 409
372 rcu_read_lock(); 410 router = orig_node_get_router(gw_node->orig_node);
373 curr_gw = rcu_dereference(bat_priv->curr_gw); 411 if (!router)
412 goto out;
374 413
375 ret = seq_printf(seq, "%s %pM (%3i) %pM [%10s]: %3i - %i%s/%i%s\n", 414 curr_gw = gw_get_selected_gw_node(bat_priv);
376 (curr_gw == gw_node ? "=>" : " "),
377 gw_node->orig_node->orig,
378 gw_node->orig_node->router->tq_avg,
379 gw_node->orig_node->router->addr,
380 gw_node->orig_node->router->if_incoming->net_dev->name,
381 gw_node->orig_node->gw_flags,
382 (down > 2048 ? down / 1024 : down),
383 (down > 2048 ? "MBit" : "KBit"),
384 (up > 2048 ? up / 1024 : up),
385 (up > 2048 ? "MBit" : "KBit"));
386 415
387 rcu_read_unlock(); 416 ret = seq_printf(seq, "%s %pM (%3i) %pM [%10s]: %3i - %i%s/%i%s\n",
417 (curr_gw == gw_node ? "=>" : " "),
418 gw_node->orig_node->orig,
419 router->tq_avg, router->addr,
420 router->if_incoming->net_dev->name,
421 gw_node->orig_node->gw_flags,
422 (down > 2048 ? down / 1024 : down),
423 (down > 2048 ? "MBit" : "KBit"),
424 (up > 2048 ? up / 1024 : up),
425 (up > 2048 ? "MBit" : "KBit"));
426
427 neigh_node_free_ref(router);
428 if (curr_gw)
429 gw_node_free_ref(curr_gw);
430out:
388 return ret; 431 return ret;
389} 432}
390 433
@@ -422,10 +465,10 @@ int gw_client_seq_print_text(struct seq_file *seq, void *offset)
422 if (gw_node->deleted) 465 if (gw_node->deleted)
423 continue; 466 continue;
424 467
425 if (!gw_node->orig_node->router) 468 /* fails if orig_node has no router */
469 if (_write_buffer_text(bat_priv, seq, gw_node) < 0)
426 continue; 470 continue;
427 471
428 _write_buffer_text(bat_priv, seq, gw_node);
429 gw_count++; 472 gw_count++;
430 } 473 }
431 rcu_read_unlock(); 474 rcu_read_unlock();
@@ -442,6 +485,7 @@ int gw_is_target(struct bat_priv *bat_priv, struct sk_buff *skb)
442 struct iphdr *iphdr; 485 struct iphdr *iphdr;
443 struct ipv6hdr *ipv6hdr; 486 struct ipv6hdr *ipv6hdr;
444 struct udphdr *udphdr; 487 struct udphdr *udphdr;
488 struct gw_node *curr_gw;
445 unsigned int header_len = 0; 489 unsigned int header_len = 0;
446 490
447 if (atomic_read(&bat_priv->gw_mode) == GW_MODE_OFF) 491 if (atomic_read(&bat_priv->gw_mode) == GW_MODE_OFF)
@@ -506,12 +550,11 @@ int gw_is_target(struct bat_priv *bat_priv, struct sk_buff *skb)
506 if (atomic_read(&bat_priv->gw_mode) == GW_MODE_SERVER) 550 if (atomic_read(&bat_priv->gw_mode) == GW_MODE_SERVER)
507 return -1; 551 return -1;
508 552
509 rcu_read_lock(); 553 curr_gw = gw_get_selected_gw_node(bat_priv);
510 if (!rcu_dereference(bat_priv->curr_gw)) { 554 if (!curr_gw)
511 rcu_read_unlock();
512 return 0; 555 return 0;
513 }
514 rcu_read_unlock();
515 556
557 if (curr_gw)
558 gw_node_free_ref(curr_gw);
516 return 1; 559 return 1;
517} 560}
diff --git a/net/batman-adv/gateway_client.h b/net/batman-adv/gateway_client.h
index 2aa439124ee3..1ce8c6066da1 100644
--- a/net/batman-adv/gateway_client.h
+++ b/net/batman-adv/gateway_client.h
@@ -24,7 +24,7 @@
24 24
25void gw_deselect(struct bat_priv *bat_priv); 25void gw_deselect(struct bat_priv *bat_priv);
26void gw_election(struct bat_priv *bat_priv); 26void gw_election(struct bat_priv *bat_priv);
27void *gw_get_selected(struct bat_priv *bat_priv); 27struct orig_node *gw_get_selected_orig(struct bat_priv *bat_priv);
28void gw_check_election(struct bat_priv *bat_priv, struct orig_node *orig_node); 28void gw_check_election(struct bat_priv *bat_priv, struct orig_node *orig_node);
29void gw_node_update(struct bat_priv *bat_priv, 29void gw_node_update(struct bat_priv *bat_priv,
30 struct orig_node *orig_node, uint8_t new_gwflags); 30 struct orig_node *orig_node, uint8_t new_gwflags);
diff --git a/net/batman-adv/icmp_socket.c b/net/batman-adv/icmp_socket.c
index 34ce56c358e5..49079c254476 100644
--- a/net/batman-adv/icmp_socket.c
+++ b/net/batman-adv/icmp_socket.c
@@ -218,23 +218,13 @@ static ssize_t bat_socket_write(struct file *file, const char __user *buff,
218 if (atomic_read(&bat_priv->mesh_state) != MESH_ACTIVE) 218 if (atomic_read(&bat_priv->mesh_state) != MESH_ACTIVE)
219 goto dst_unreach; 219 goto dst_unreach;
220 220
221 rcu_read_lock();
222 orig_node = orig_hash_find(bat_priv, icmp_packet->dst); 221 orig_node = orig_hash_find(bat_priv, icmp_packet->dst);
223
224 if (!orig_node) 222 if (!orig_node)
225 goto unlock; 223 goto dst_unreach;
226
227 neigh_node = orig_node->router;
228 224
225 neigh_node = orig_node_get_router(orig_node);
229 if (!neigh_node) 226 if (!neigh_node)
230 goto unlock; 227 goto dst_unreach;
231
232 if (!atomic_inc_not_zero(&neigh_node->refcount)) {
233 neigh_node = NULL;
234 goto unlock;
235 }
236
237 rcu_read_unlock();
238 228
239 if (!neigh_node->if_incoming) 229 if (!neigh_node->if_incoming)
240 goto dst_unreach; 230 goto dst_unreach;
@@ -252,8 +242,6 @@ static ssize_t bat_socket_write(struct file *file, const char __user *buff,
252 send_skb_packet(skb, neigh_node->if_incoming, neigh_node->addr); 242 send_skb_packet(skb, neigh_node->if_incoming, neigh_node->addr);
253 goto out; 243 goto out;
254 244
255unlock:
256 rcu_read_unlock();
257dst_unreach: 245dst_unreach:
258 icmp_packet->msg_type = DESTINATION_UNREACHABLE; 246 icmp_packet->msg_type = DESTINATION_UNREACHABLE;
259 bat_socket_add_packet(socket_client, icmp_packet, packet_len); 247 bat_socket_add_packet(socket_client, icmp_packet, packet_len);
diff --git a/net/batman-adv/originator.c b/net/batman-adv/originator.c
index 0b9133022d2d..5b8fe32043da 100644
--- a/net/batman-adv/originator.c
+++ b/net/batman-adv/originator.c
@@ -70,6 +70,21 @@ void neigh_node_free_ref(struct neigh_node *neigh_node)
70 call_rcu(&neigh_node->rcu, neigh_node_free_rcu); 70 call_rcu(&neigh_node->rcu, neigh_node_free_rcu);
71} 71}
72 72
73/* increases the refcounter of a found router */
74struct neigh_node *orig_node_get_router(struct orig_node *orig_node)
75{
76 struct neigh_node *router;
77
78 rcu_read_lock();
79 router = rcu_dereference(orig_node->router);
80
81 if (router && !atomic_inc_not_zero(&router->refcount))
82 router = NULL;
83
84 rcu_read_unlock();
85 return router;
86}
87
73struct neigh_node *create_neighbor(struct orig_node *orig_node, 88struct neigh_node *create_neighbor(struct orig_node *orig_node,
74 struct orig_node *orig_neigh_node, 89 struct orig_node *orig_neigh_node,
75 uint8_t *neigh, 90 uint8_t *neigh,
@@ -87,6 +102,7 @@ struct neigh_node *create_neighbor(struct orig_node *orig_node,
87 102
88 INIT_HLIST_NODE(&neigh_node->list); 103 INIT_HLIST_NODE(&neigh_node->list);
89 INIT_LIST_HEAD(&neigh_node->bonding_list); 104 INIT_LIST_HEAD(&neigh_node->bonding_list);
105 spin_lock_init(&neigh_node->tq_lock);
90 106
91 memcpy(neigh_node->addr, neigh, ETH_ALEN); 107 memcpy(neigh_node->addr, neigh, ETH_ALEN);
92 neigh_node->orig_node = orig_neigh_node; 108 neigh_node->orig_node = orig_neigh_node;
@@ -390,7 +406,7 @@ int orig_seq_print_text(struct seq_file *seq, void *offset)
390 struct hlist_node *node, *node_tmp; 406 struct hlist_node *node, *node_tmp;
391 struct hlist_head *head; 407 struct hlist_head *head;
392 struct orig_node *orig_node; 408 struct orig_node *orig_node;
393 struct neigh_node *neigh_node; 409 struct neigh_node *neigh_node, *neigh_node_tmp;
394 int batman_count = 0; 410 int batman_count = 0;
395 int last_seen_secs; 411 int last_seen_secs;
396 int last_seen_msecs; 412 int last_seen_msecs;
@@ -421,37 +437,41 @@ int orig_seq_print_text(struct seq_file *seq, void *offset)
421 437
422 rcu_read_lock(); 438 rcu_read_lock();
423 hlist_for_each_entry_rcu(orig_node, node, head, hash_entry) { 439 hlist_for_each_entry_rcu(orig_node, node, head, hash_entry) {
424 if (!orig_node->router) 440 neigh_node = orig_node_get_router(orig_node);
441 if (!neigh_node)
425 continue; 442 continue;
426 443
427 if (orig_node->router->tq_avg == 0) 444 if (neigh_node->tq_avg == 0)
428 continue; 445 goto next;
429 446
430 last_seen_secs = jiffies_to_msecs(jiffies - 447 last_seen_secs = jiffies_to_msecs(jiffies -
431 orig_node->last_valid) / 1000; 448 orig_node->last_valid) / 1000;
432 last_seen_msecs = jiffies_to_msecs(jiffies - 449 last_seen_msecs = jiffies_to_msecs(jiffies -
433 orig_node->last_valid) % 1000; 450 orig_node->last_valid) % 1000;
434 451
435 neigh_node = orig_node->router;
436 seq_printf(seq, "%pM %4i.%03is (%3i) %pM [%10s]:", 452 seq_printf(seq, "%pM %4i.%03is (%3i) %pM [%10s]:",
437 orig_node->orig, last_seen_secs, 453 orig_node->orig, last_seen_secs,
438 last_seen_msecs, neigh_node->tq_avg, 454 last_seen_msecs, neigh_node->tq_avg,
439 neigh_node->addr, 455 neigh_node->addr,
440 neigh_node->if_incoming->net_dev->name); 456 neigh_node->if_incoming->net_dev->name);
441 457
442 hlist_for_each_entry_rcu(neigh_node, node_tmp, 458 hlist_for_each_entry_rcu(neigh_node_tmp, node_tmp,
443 &orig_node->neigh_list, list) { 459 &orig_node->neigh_list, list) {
444 seq_printf(seq, " %pM (%3i)", neigh_node->addr, 460 seq_printf(seq, " %pM (%3i)",
445 neigh_node->tq_avg); 461 neigh_node_tmp->addr,
462 neigh_node_tmp->tq_avg);
446 } 463 }
447 464
448 seq_printf(seq, "\n"); 465 seq_printf(seq, "\n");
449 batman_count++; 466 batman_count++;
467
468next:
469 neigh_node_free_ref(neigh_node);
450 } 470 }
451 rcu_read_unlock(); 471 rcu_read_unlock();
452 } 472 }
453 473
454 if ((batman_count == 0)) 474 if (batman_count == 0)
455 seq_printf(seq, "No batman nodes in range ...\n"); 475 seq_printf(seq, "No batman nodes in range ...\n");
456 476
457 return 0; 477 return 0;
diff --git a/net/batman-adv/originator.h b/net/batman-adv/originator.h
index 5cc011057da1..e1d641f27aa9 100644
--- a/net/batman-adv/originator.h
+++ b/net/batman-adv/originator.h
@@ -34,6 +34,7 @@ struct neigh_node *create_neighbor(struct orig_node *orig_node,
34 uint8_t *neigh, 34 uint8_t *neigh,
35 struct hard_iface *if_incoming); 35 struct hard_iface *if_incoming);
36void neigh_node_free_ref(struct neigh_node *neigh_node); 36void neigh_node_free_ref(struct neigh_node *neigh_node);
37struct neigh_node *orig_node_get_router(struct orig_node *orig_node);
37int orig_seq_print_text(struct seq_file *seq, void *offset); 38int orig_seq_print_text(struct seq_file *seq, void *offset);
38int orig_hash_add_if(struct hard_iface *hard_iface, int max_if_num); 39int orig_hash_add_if(struct hard_iface *hard_iface, int max_if_num);
39int orig_hash_del_if(struct hard_iface *hard_iface, int max_if_num); 40int orig_hash_del_if(struct hard_iface *hard_iface, int max_if_num);
diff --git a/net/batman-adv/routing.c b/net/batman-adv/routing.c
index c172f5d0e05a..f6c642246972 100644
--- a/net/batman-adv/routing.c
+++ b/net/batman-adv/routing.c
@@ -87,18 +87,20 @@ static void update_route(struct bat_priv *bat_priv,
87 struct neigh_node *neigh_node, 87 struct neigh_node *neigh_node,
88 unsigned char *hna_buff, int hna_buff_len) 88 unsigned char *hna_buff, int hna_buff_len)
89{ 89{
90 struct neigh_node *neigh_node_tmp; 90 struct neigh_node *curr_router;
91
92 curr_router = orig_node_get_router(orig_node);
91 93
92 /* route deleted */ 94 /* route deleted */
93 if ((orig_node->router) && (!neigh_node)) { 95 if ((curr_router) && (!neigh_node)) {
94 96
95 bat_dbg(DBG_ROUTES, bat_priv, "Deleting route towards: %pM\n", 97 bat_dbg(DBG_ROUTES, bat_priv, "Deleting route towards: %pM\n",
96 orig_node->orig); 98 orig_node->orig);
97 hna_global_del_orig(bat_priv, orig_node, 99 hna_global_del_orig(bat_priv, orig_node,
98 "originator timed out"); 100 "originator timed out");
99 101
100 /* route added */ 102 /* route added */
101 } else if ((!orig_node->router) && (neigh_node)) { 103 } else if ((!curr_router) && (neigh_node)) {
102 104
103 bat_dbg(DBG_ROUTES, bat_priv, 105 bat_dbg(DBG_ROUTES, bat_priv,
104 "Adding route towards: %pM (via %pM)\n", 106 "Adding route towards: %pM (via %pM)\n",
@@ -106,21 +108,29 @@ static void update_route(struct bat_priv *bat_priv,
106 hna_global_add_orig(bat_priv, orig_node, 108 hna_global_add_orig(bat_priv, orig_node,
107 hna_buff, hna_buff_len); 109 hna_buff, hna_buff_len);
108 110
109 /* route changed */ 111 /* route changed */
110 } else { 112 } else {
111 bat_dbg(DBG_ROUTES, bat_priv, 113 bat_dbg(DBG_ROUTES, bat_priv,
112 "Changing route towards: %pM " 114 "Changing route towards: %pM "
113 "(now via %pM - was via %pM)\n", 115 "(now via %pM - was via %pM)\n",
114 orig_node->orig, neigh_node->addr, 116 orig_node->orig, neigh_node->addr,
115 orig_node->router->addr); 117 curr_router->addr);
116 } 118 }
117 119
120 if (curr_router)
121 neigh_node_free_ref(curr_router);
122
123 /* increase refcount of new best neighbor */
118 if (neigh_node && !atomic_inc_not_zero(&neigh_node->refcount)) 124 if (neigh_node && !atomic_inc_not_zero(&neigh_node->refcount))
119 neigh_node = NULL; 125 neigh_node = NULL;
120 neigh_node_tmp = orig_node->router; 126
121 orig_node->router = neigh_node; 127 spin_lock_bh(&orig_node->neigh_list_lock);
122 if (neigh_node_tmp) 128 rcu_assign_pointer(orig_node->router, neigh_node);
123 neigh_node_free_ref(neigh_node_tmp); 129 spin_unlock_bh(&orig_node->neigh_list_lock);
130
131 /* decrease refcount of previous best neighbor */
132 if (curr_router)
133 neigh_node_free_ref(curr_router);
124} 134}
125 135
126 136
@@ -128,16 +138,23 @@ void update_routes(struct bat_priv *bat_priv, struct orig_node *orig_node,
128 struct neigh_node *neigh_node, unsigned char *hna_buff, 138 struct neigh_node *neigh_node, unsigned char *hna_buff,
129 int hna_buff_len) 139 int hna_buff_len)
130{ 140{
141 struct neigh_node *router = NULL;
131 142
132 if (!orig_node) 143 if (!orig_node)
133 return; 144 goto out;
145
146 router = orig_node_get_router(orig_node);
134 147
135 if (orig_node->router != neigh_node) 148 if (router != neigh_node)
136 update_route(bat_priv, orig_node, neigh_node, 149 update_route(bat_priv, orig_node, neigh_node,
137 hna_buff, hna_buff_len); 150 hna_buff, hna_buff_len);
138 /* may be just HNA changed */ 151 /* may be just HNA changed */
139 else 152 else
140 update_HNA(bat_priv, orig_node, hna_buff, hna_buff_len); 153 update_HNA(bat_priv, orig_node, hna_buff, hna_buff_len);
154
155out:
156 if (router)
157 neigh_node_free_ref(router);
141} 158}
142 159
143static int is_bidirectional_neigh(struct orig_node *orig_node, 160static int is_bidirectional_neigh(struct orig_node *orig_node,
@@ -288,8 +305,8 @@ static void bonding_candidate_add(struct orig_node *orig_node,
288 struct neigh_node *neigh_node) 305 struct neigh_node *neigh_node)
289{ 306{
290 struct hlist_node *node; 307 struct hlist_node *node;
291 struct neigh_node *tmp_neigh_node; 308 struct neigh_node *tmp_neigh_node, *router = NULL;
292 uint8_t best_tq, interference_candidate = 0; 309 uint8_t interference_candidate = 0;
293 310
294 spin_lock_bh(&orig_node->neigh_list_lock); 311 spin_lock_bh(&orig_node->neigh_list_lock);
295 312
@@ -298,13 +315,12 @@ static void bonding_candidate_add(struct orig_node *orig_node,
298 neigh_node->orig_node->primary_addr)) 315 neigh_node->orig_node->primary_addr))
299 goto candidate_del; 316 goto candidate_del;
300 317
301 if (!orig_node->router) 318 router = orig_node_get_router(orig_node);
319 if (!router)
302 goto candidate_del; 320 goto candidate_del;
303 321
304 best_tq = orig_node->router->tq_avg;
305
306 /* ... and is good enough to be considered */ 322 /* ... and is good enough to be considered */
307 if (neigh_node->tq_avg < best_tq - BONDING_TQ_THRESHOLD) 323 if (neigh_node->tq_avg < router->tq_avg - BONDING_TQ_THRESHOLD)
308 goto candidate_del; 324 goto candidate_del;
309 325
310 /** 326 /**
@@ -350,7 +366,9 @@ candidate_del:
350 366
351out: 367out:
352 spin_unlock_bh(&orig_node->neigh_list_lock); 368 spin_unlock_bh(&orig_node->neigh_list_lock);
353 return; 369
370 if (router)
371 neigh_node_free_ref(router);
354} 372}
355 373
356/* copy primary address for bonding */ 374/* copy primary address for bonding */
@@ -373,6 +391,7 @@ static void update_orig(struct bat_priv *bat_priv,
373 char is_duplicate) 391 char is_duplicate)
374{ 392{
375 struct neigh_node *neigh_node = NULL, *tmp_neigh_node = NULL; 393 struct neigh_node *neigh_node = NULL, *tmp_neigh_node = NULL;
394 struct neigh_node *router = NULL;
376 struct orig_node *orig_node_tmp; 395 struct orig_node *orig_node_tmp;
377 struct hlist_node *node; 396 struct hlist_node *node;
378 int tmp_hna_buff_len; 397 int tmp_hna_buff_len;
@@ -396,10 +415,12 @@ static void update_orig(struct bat_priv *bat_priv,
396 if (is_duplicate) 415 if (is_duplicate)
397 continue; 416 continue;
398 417
418 spin_lock_bh(&tmp_neigh_node->tq_lock);
399 ring_buffer_set(tmp_neigh_node->tq_recv, 419 ring_buffer_set(tmp_neigh_node->tq_recv,
400 &tmp_neigh_node->tq_index, 0); 420 &tmp_neigh_node->tq_index, 0);
401 tmp_neigh_node->tq_avg = 421 tmp_neigh_node->tq_avg =
402 ring_buffer_avg(tmp_neigh_node->tq_recv); 422 ring_buffer_avg(tmp_neigh_node->tq_recv);
423 spin_unlock_bh(&tmp_neigh_node->tq_lock);
403 } 424 }
404 425
405 if (!neigh_node) { 426 if (!neigh_node) {
@@ -424,10 +445,12 @@ static void update_orig(struct bat_priv *bat_priv,
424 orig_node->flags = batman_packet->flags; 445 orig_node->flags = batman_packet->flags;
425 neigh_node->last_valid = jiffies; 446 neigh_node->last_valid = jiffies;
426 447
448 spin_lock_bh(&neigh_node->tq_lock);
427 ring_buffer_set(neigh_node->tq_recv, 449 ring_buffer_set(neigh_node->tq_recv,
428 &neigh_node->tq_index, 450 &neigh_node->tq_index,
429 batman_packet->tq); 451 batman_packet->tq);
430 neigh_node->tq_avg = ring_buffer_avg(neigh_node->tq_recv); 452 neigh_node->tq_avg = ring_buffer_avg(neigh_node->tq_recv);
453 spin_unlock_bh(&neigh_node->tq_lock);
431 454
432 if (!is_duplicate) { 455 if (!is_duplicate) {
433 orig_node->last_ttl = batman_packet->ttl; 456 orig_node->last_ttl = batman_packet->ttl;
@@ -441,19 +464,18 @@ static void update_orig(struct bat_priv *bat_priv,
441 464
442 /* if this neighbor already is our next hop there is nothing 465 /* if this neighbor already is our next hop there is nothing
443 * to change */ 466 * to change */
444 if (orig_node->router == neigh_node) 467 router = orig_node_get_router(orig_node);
468 if (router == neigh_node)
445 goto update_hna; 469 goto update_hna;
446 470
447 /* if this neighbor does not offer a better TQ we won't consider it */ 471 /* if this neighbor does not offer a better TQ we won't consider it */
448 if ((orig_node->router) && 472 if (router && (router->tq_avg > neigh_node->tq_avg))
449 (orig_node->router->tq_avg > neigh_node->tq_avg))
450 goto update_hna; 473 goto update_hna;
451 474
452 /* if the TQ is the same and the link not more symetric we 475 /* if the TQ is the same and the link not more symetric we
453 * won't consider it either */ 476 * won't consider it either */
454 if ((orig_node->router) && 477 if (router && (neigh_node->tq_avg == router->tq_avg)) {
455 (neigh_node->tq_avg == orig_node->router->tq_avg)) { 478 orig_node_tmp = router->orig_node;
456 orig_node_tmp = orig_node->router->orig_node;
457 spin_lock_bh(&orig_node_tmp->ogm_cnt_lock); 479 spin_lock_bh(&orig_node_tmp->ogm_cnt_lock);
458 bcast_own_sum_orig = 480 bcast_own_sum_orig =
459 orig_node_tmp->bcast_own_sum[if_incoming->if_num]; 481 orig_node_tmp->bcast_own_sum[if_incoming->if_num];
@@ -474,7 +496,7 @@ static void update_orig(struct bat_priv *bat_priv,
474 goto update_gw; 496 goto update_gw;
475 497
476update_hna: 498update_hna:
477 update_routes(bat_priv, orig_node, orig_node->router, 499 update_routes(bat_priv, orig_node, router,
478 hna_buff, tmp_hna_buff_len); 500 hna_buff, tmp_hna_buff_len);
479 501
480update_gw: 502update_gw:
@@ -496,6 +518,8 @@ unlock:
496out: 518out:
497 if (neigh_node) 519 if (neigh_node)
498 neigh_node_free_ref(neigh_node); 520 neigh_node_free_ref(neigh_node);
521 if (router)
522 neigh_node_free_ref(router);
499} 523}
500 524
501/* checks whether the host restarted and is in the protection time. 525/* checks whether the host restarted and is in the protection time.
@@ -603,6 +627,8 @@ void receive_bat_packet(struct ethhdr *ethhdr,
603 struct bat_priv *bat_priv = netdev_priv(if_incoming->soft_iface); 627 struct bat_priv *bat_priv = netdev_priv(if_incoming->soft_iface);
604 struct hard_iface *hard_iface; 628 struct hard_iface *hard_iface;
605 struct orig_node *orig_neigh_node, *orig_node; 629 struct orig_node *orig_neigh_node, *orig_node;
630 struct neigh_node *router = NULL, *router_router = NULL;
631 struct neigh_node *orig_neigh_router = NULL;
606 char has_directlink_flag; 632 char has_directlink_flag;
607 char is_my_addr = 0, is_my_orig = 0, is_my_oldorig = 0; 633 char is_my_addr = 0, is_my_orig = 0, is_my_oldorig = 0;
608 char is_broadcast = 0, is_bidirectional, is_single_hop_neigh; 634 char is_broadcast = 0, is_bidirectional, is_single_hop_neigh;
@@ -747,14 +773,15 @@ void receive_bat_packet(struct ethhdr *ethhdr,
747 goto out; 773 goto out;
748 } 774 }
749 775
776 router = orig_node_get_router(orig_node);
777 if (router)
778 router_router = orig_node_get_router(router->orig_node);
779
750 /* avoid temporary routing loops */ 780 /* avoid temporary routing loops */
751 if ((orig_node->router) && 781 if (router && router_router &&
752 (orig_node->router->orig_node->router) && 782 (compare_eth(router->addr, batman_packet->prev_sender)) &&
753 (compare_eth(orig_node->router->addr,
754 batman_packet->prev_sender)) &&
755 !(compare_eth(batman_packet->orig, batman_packet->prev_sender)) && 783 !(compare_eth(batman_packet->orig, batman_packet->prev_sender)) &&
756 (compare_eth(orig_node->router->addr, 784 (compare_eth(router->addr, router_router->addr))) {
757 orig_node->router->orig_node->router->addr))) {
758 bat_dbg(DBG_BATMAN, bat_priv, 785 bat_dbg(DBG_BATMAN, bat_priv,
759 "Drop packet: ignoring all rebroadcast packets that " 786 "Drop packet: ignoring all rebroadcast packets that "
760 "may make me loop (sender: %pM)\n", ethhdr->h_source); 787 "may make me loop (sender: %pM)\n", ethhdr->h_source);
@@ -769,9 +796,11 @@ void receive_bat_packet(struct ethhdr *ethhdr,
769 if (!orig_neigh_node) 796 if (!orig_neigh_node)
770 goto out; 797 goto out;
771 798
799 orig_neigh_router = orig_node_get_router(orig_neigh_node);
800
772 /* drop packet if sender is not a direct neighbor and if we 801 /* drop packet if sender is not a direct neighbor and if we
773 * don't route towards it */ 802 * don't route towards it */
774 if (!is_single_hop_neigh && (!orig_neigh_node->router)) { 803 if (!is_single_hop_neigh && (!orig_neigh_router)) {
775 bat_dbg(DBG_BATMAN, bat_priv, 804 bat_dbg(DBG_BATMAN, bat_priv,
776 "Drop packet: OGM via unknown neighbor!\n"); 805 "Drop packet: OGM via unknown neighbor!\n");
777 goto out_neigh; 806 goto out_neigh;
@@ -825,6 +854,13 @@ out_neigh:
825 if ((orig_neigh_node) && (!is_single_hop_neigh)) 854 if ((orig_neigh_node) && (!is_single_hop_neigh))
826 orig_node_free_ref(orig_neigh_node); 855 orig_node_free_ref(orig_neigh_node);
827out: 856out:
857 if (router)
858 neigh_node_free_ref(router);
859 if (router_router)
860 neigh_node_free_ref(router_router);
861 if (orig_neigh_router)
862 neigh_node_free_ref(orig_neigh_router);
863
828 orig_node_free_ref(orig_node); 864 orig_node_free_ref(orig_node);
829} 865}
830 866
@@ -869,7 +905,7 @@ static int recv_my_icmp_packet(struct bat_priv *bat_priv,
869 struct sk_buff *skb, size_t icmp_len) 905 struct sk_buff *skb, size_t icmp_len)
870{ 906{
871 struct orig_node *orig_node = NULL; 907 struct orig_node *orig_node = NULL;
872 struct neigh_node *neigh_node = NULL; 908 struct neigh_node *router = NULL;
873 struct icmp_packet_rr *icmp_packet; 909 struct icmp_packet_rr *icmp_packet;
874 int ret = NET_RX_DROP; 910 int ret = NET_RX_DROP;
875 911
@@ -886,23 +922,13 @@ static int recv_my_icmp_packet(struct bat_priv *bat_priv,
886 922
887 /* answer echo request (ping) */ 923 /* answer echo request (ping) */
888 /* get routing information */ 924 /* get routing information */
889 rcu_read_lock();
890 orig_node = orig_hash_find(bat_priv, icmp_packet->orig); 925 orig_node = orig_hash_find(bat_priv, icmp_packet->orig);
891
892 if (!orig_node) 926 if (!orig_node)
893 goto unlock; 927 goto out;
894
895 neigh_node = orig_node->router;
896
897 if (!neigh_node)
898 goto unlock;
899
900 if (!atomic_inc_not_zero(&neigh_node->refcount)) {
901 neigh_node = NULL;
902 goto unlock;
903 }
904 928
905 rcu_read_unlock(); 929 router = orig_node_get_router(orig_node);
930 if (!router)
931 goto out;
906 932
907 /* create a copy of the skb, if needed, to modify it. */ 933 /* create a copy of the skb, if needed, to modify it. */
908 if (skb_cow(skb, sizeof(struct ethhdr)) < 0) 934 if (skb_cow(skb, sizeof(struct ethhdr)) < 0)
@@ -916,15 +942,12 @@ static int recv_my_icmp_packet(struct bat_priv *bat_priv,
916 icmp_packet->msg_type = ECHO_REPLY; 942 icmp_packet->msg_type = ECHO_REPLY;
917 icmp_packet->ttl = TTL; 943 icmp_packet->ttl = TTL;
918 944
919 send_skb_packet(skb, neigh_node->if_incoming, neigh_node->addr); 945 send_skb_packet(skb, router->if_incoming, router->addr);
920 ret = NET_RX_SUCCESS; 946 ret = NET_RX_SUCCESS;
921 goto out;
922 947
923unlock:
924 rcu_read_unlock();
925out: 948out:
926 if (neigh_node) 949 if (router)
927 neigh_node_free_ref(neigh_node); 950 neigh_node_free_ref(router);
928 if (orig_node) 951 if (orig_node)
929 orig_node_free_ref(orig_node); 952 orig_node_free_ref(orig_node);
930 return ret; 953 return ret;
@@ -934,7 +957,7 @@ static int recv_icmp_ttl_exceeded(struct bat_priv *bat_priv,
934 struct sk_buff *skb) 957 struct sk_buff *skb)
935{ 958{
936 struct orig_node *orig_node = NULL; 959 struct orig_node *orig_node = NULL;
937 struct neigh_node *neigh_node = NULL; 960 struct neigh_node *router = NULL;
938 struct icmp_packet *icmp_packet; 961 struct icmp_packet *icmp_packet;
939 int ret = NET_RX_DROP; 962 int ret = NET_RX_DROP;
940 963
@@ -952,23 +975,13 @@ static int recv_icmp_ttl_exceeded(struct bat_priv *bat_priv,
952 goto out; 975 goto out;
953 976
954 /* get routing information */ 977 /* get routing information */
955 rcu_read_lock();
956 orig_node = orig_hash_find(bat_priv, icmp_packet->orig); 978 orig_node = orig_hash_find(bat_priv, icmp_packet->orig);
957
958 if (!orig_node) 979 if (!orig_node)
959 goto unlock; 980 goto out;
960
961 neigh_node = orig_node->router;
962
963 if (!neigh_node)
964 goto unlock;
965
966 if (!atomic_inc_not_zero(&neigh_node->refcount)) {
967 neigh_node = NULL;
968 goto unlock;
969 }
970 981
971 rcu_read_unlock(); 982 router = orig_node_get_router(orig_node);
983 if (!router)
984 goto out;
972 985
973 /* create a copy of the skb, if needed, to modify it. */ 986 /* create a copy of the skb, if needed, to modify it. */
974 if (skb_cow(skb, sizeof(struct ethhdr)) < 0) 987 if (skb_cow(skb, sizeof(struct ethhdr)) < 0)
@@ -982,15 +995,12 @@ static int recv_icmp_ttl_exceeded(struct bat_priv *bat_priv,
982 icmp_packet->msg_type = TTL_EXCEEDED; 995 icmp_packet->msg_type = TTL_EXCEEDED;
983 icmp_packet->ttl = TTL; 996 icmp_packet->ttl = TTL;
984 997
985 send_skb_packet(skb, neigh_node->if_incoming, neigh_node->addr); 998 send_skb_packet(skb, router->if_incoming, router->addr);
986 ret = NET_RX_SUCCESS; 999 ret = NET_RX_SUCCESS;
987 goto out;
988 1000
989unlock:
990 rcu_read_unlock();
991out: 1001out:
992 if (neigh_node) 1002 if (router)
993 neigh_node_free_ref(neigh_node); 1003 neigh_node_free_ref(router);
994 if (orig_node) 1004 if (orig_node)
995 orig_node_free_ref(orig_node); 1005 orig_node_free_ref(orig_node);
996 return ret; 1006 return ret;
@@ -1003,7 +1013,7 @@ int recv_icmp_packet(struct sk_buff *skb, struct hard_iface *recv_if)
1003 struct icmp_packet_rr *icmp_packet; 1013 struct icmp_packet_rr *icmp_packet;
1004 struct ethhdr *ethhdr; 1014 struct ethhdr *ethhdr;
1005 struct orig_node *orig_node = NULL; 1015 struct orig_node *orig_node = NULL;
1006 struct neigh_node *neigh_node = NULL; 1016 struct neigh_node *router = NULL;
1007 int hdr_size = sizeof(struct icmp_packet); 1017 int hdr_size = sizeof(struct icmp_packet);
1008 int ret = NET_RX_DROP; 1018 int ret = NET_RX_DROP;
1009 1019
@@ -1050,23 +1060,13 @@ int recv_icmp_packet(struct sk_buff *skb, struct hard_iface *recv_if)
1050 return recv_icmp_ttl_exceeded(bat_priv, skb); 1060 return recv_icmp_ttl_exceeded(bat_priv, skb);
1051 1061
1052 /* get routing information */ 1062 /* get routing information */
1053 rcu_read_lock();
1054 orig_node = orig_hash_find(bat_priv, icmp_packet->dst); 1063 orig_node = orig_hash_find(bat_priv, icmp_packet->dst);
1055
1056 if (!orig_node) 1064 if (!orig_node)
1057 goto unlock; 1065 goto out;
1058
1059 neigh_node = orig_node->router;
1060
1061 if (!neigh_node)
1062 goto unlock;
1063
1064 if (!atomic_inc_not_zero(&neigh_node->refcount)) {
1065 neigh_node = NULL;
1066 goto unlock;
1067 }
1068 1066
1069 rcu_read_unlock(); 1067 router = orig_node_get_router(orig_node);
1068 if (!router)
1069 goto out;
1070 1070
1071 /* create a copy of the skb, if needed, to modify it. */ 1071 /* create a copy of the skb, if needed, to modify it. */
1072 if (skb_cow(skb, sizeof(struct ethhdr)) < 0) 1072 if (skb_cow(skb, sizeof(struct ethhdr)) < 0)
@@ -1078,20 +1078,117 @@ int recv_icmp_packet(struct sk_buff *skb, struct hard_iface *recv_if)
1078 icmp_packet->ttl--; 1078 icmp_packet->ttl--;
1079 1079
1080 /* route it */ 1080 /* route it */
1081 send_skb_packet(skb, neigh_node->if_incoming, neigh_node->addr); 1081 send_skb_packet(skb, router->if_incoming, router->addr);
1082 ret = NET_RX_SUCCESS; 1082 ret = NET_RX_SUCCESS;
1083 goto out;
1084 1083
1085unlock:
1086 rcu_read_unlock();
1087out: 1084out:
1088 if (neigh_node) 1085 if (router)
1089 neigh_node_free_ref(neigh_node); 1086 neigh_node_free_ref(router);
1090 if (orig_node) 1087 if (orig_node)
1091 orig_node_free_ref(orig_node); 1088 orig_node_free_ref(orig_node);
1092 return ret; 1089 return ret;
1093} 1090}
1094 1091
1092/* In the bonding case, send the packets in a round
1093 * robin fashion over the remaining interfaces.
1094 *
1095 * This method rotates the bonding list and increases the
1096 * returned router's refcount. */
1097static struct neigh_node *find_bond_router(struct orig_node *primary_orig,
1098 struct hard_iface *recv_if)
1099{
1100 struct neigh_node *tmp_neigh_node;
1101 struct neigh_node *router = NULL, *first_candidate = NULL;
1102
1103 rcu_read_lock();
1104 list_for_each_entry_rcu(tmp_neigh_node, &primary_orig->bond_list,
1105 bonding_list) {
1106 if (!first_candidate)
1107 first_candidate = tmp_neigh_node;
1108
1109 /* recv_if == NULL on the first node. */
1110 if (tmp_neigh_node->if_incoming == recv_if)
1111 continue;
1112
1113 if (!atomic_inc_not_zero(&tmp_neigh_node->refcount))
1114 continue;
1115
1116 router = tmp_neigh_node;
1117 break;
1118 }
1119
1120 /* use the first candidate if nothing was found. */
1121 if (!router && first_candidate &&
1122 atomic_inc_not_zero(&first_candidate->refcount))
1123 router = first_candidate;
1124
1125 if (!router)
1126 goto out;
1127
1128 /* selected should point to the next element
1129 * after the current router */
1130 spin_lock_bh(&primary_orig->neigh_list_lock);
1131 /* this is a list_move(), which unfortunately
1132 * does not exist as rcu version */
1133 list_del_rcu(&primary_orig->bond_list);
1134 list_add_rcu(&primary_orig->bond_list,
1135 &router->bonding_list);
1136 spin_unlock_bh(&primary_orig->neigh_list_lock);
1137
1138out:
1139 rcu_read_unlock();
1140 return router;
1141}
1142
1143/* Interface Alternating: Use the best of the
1144 * remaining candidates which are not using
1145 * this interface.
1146 *
1147 * Increases the returned router's refcount */
1148static struct neigh_node *find_ifalter_router(struct orig_node *primary_orig,
1149 struct hard_iface *recv_if)
1150{
1151 struct neigh_node *tmp_neigh_node;
1152 struct neigh_node *router = NULL, *first_candidate = NULL;
1153
1154 rcu_read_lock();
1155 list_for_each_entry_rcu(tmp_neigh_node, &primary_orig->bond_list,
1156 bonding_list) {
1157 if (!first_candidate)
1158 first_candidate = tmp_neigh_node;
1159
1160 /* recv_if == NULL on the first node. */
1161 if (tmp_neigh_node->if_incoming == recv_if)
1162 continue;
1163
1164 if (!atomic_inc_not_zero(&tmp_neigh_node->refcount))
1165 continue;
1166
1167 /* if we don't have a router yet
1168 * or this one is better, choose it. */
1169 if ((!router) ||
1170 (tmp_neigh_node->tq_avg > router->tq_avg)) {
1171 /* decrement refcount of
1172 * previously selected router */
1173 if (router)
1174 neigh_node_free_ref(router);
1175
1176 router = tmp_neigh_node;
1177 atomic_inc_not_zero(&router->refcount);
1178 }
1179
1180 neigh_node_free_ref(tmp_neigh_node);
1181 }
1182
1183 /* use the first candidate if nothing was found. */
1184 if (!router && first_candidate &&
1185 atomic_inc_not_zero(&first_candidate->refcount))
1186 router = first_candidate;
1187
1188 rcu_read_unlock();
1189 return router;
1190}
1191
1095/* find a suitable router for this originator, and use 1192/* find a suitable router for this originator, and use
1096 * bonding if possible. increases the found neighbors 1193 * bonding if possible. increases the found neighbors
1097 * refcount.*/ 1194 * refcount.*/
@@ -1101,14 +1198,15 @@ struct neigh_node *find_router(struct bat_priv *bat_priv,
1101{ 1198{
1102 struct orig_node *primary_orig_node; 1199 struct orig_node *primary_orig_node;
1103 struct orig_node *router_orig; 1200 struct orig_node *router_orig;
1104 struct neigh_node *router, *first_candidate, *tmp_neigh_node; 1201 struct neigh_node *router;
1105 static uint8_t zero_mac[ETH_ALEN] = {0, 0, 0, 0, 0, 0}; 1202 static uint8_t zero_mac[ETH_ALEN] = {0, 0, 0, 0, 0, 0};
1106 int bonding_enabled; 1203 int bonding_enabled;
1107 1204
1108 if (!orig_node) 1205 if (!orig_node)
1109 return NULL; 1206 return NULL;
1110 1207
1111 if (!orig_node->router) 1208 router = orig_node_get_router(orig_node);
1209 if (!router)
1112 return NULL; 1210 return NULL;
1113 1211
1114 /* without bonding, the first node should 1212 /* without bonding, the first node should
@@ -1117,9 +1215,8 @@ struct neigh_node *find_router(struct bat_priv *bat_priv,
1117 1215
1118 rcu_read_lock(); 1216 rcu_read_lock();
1119 /* select default router to output */ 1217 /* select default router to output */
1120 router = orig_node->router; 1218 router_orig = router->orig_node;
1121 router_orig = orig_node->router->orig_node; 1219 if (!router_orig) {
1122 if (!router_orig || !atomic_inc_not_zero(&router->refcount)) {
1123 rcu_read_unlock(); 1220 rcu_read_unlock();
1124 return NULL; 1221 return NULL;
1125 } 1222 }
@@ -1151,88 +1248,17 @@ struct neigh_node *find_router(struct bat_priv *bat_priv,
1151 if (atomic_read(&primary_orig_node->bond_candidates) < 2) 1248 if (atomic_read(&primary_orig_node->bond_candidates) < 2)
1152 goto return_router; 1249 goto return_router;
1153 1250
1154
1155 /* all nodes between should choose a candidate which 1251 /* all nodes between should choose a candidate which
1156 * is is not on the interface where the packet came 1252 * is is not on the interface where the packet came
1157 * in. */ 1253 * in. */
1158 1254
1159 neigh_node_free_ref(router); 1255 neigh_node_free_ref(router);
1160 first_candidate = NULL;
1161 router = NULL;
1162
1163 if (bonding_enabled) {
1164 /* in the bonding case, send the packets in a round
1165 * robin fashion over the remaining interfaces. */
1166
1167 list_for_each_entry_rcu(tmp_neigh_node,
1168 &primary_orig_node->bond_list, bonding_list) {
1169 if (!first_candidate)
1170 first_candidate = tmp_neigh_node;
1171 /* recv_if == NULL on the first node. */
1172 if (tmp_neigh_node->if_incoming != recv_if &&
1173 atomic_inc_not_zero(&tmp_neigh_node->refcount)) {
1174 router = tmp_neigh_node;
1175 break;
1176 }
1177 }
1178
1179 /* use the first candidate if nothing was found. */
1180 if (!router && first_candidate &&
1181 atomic_inc_not_zero(&first_candidate->refcount))
1182 router = first_candidate;
1183
1184 if (!router) {
1185 rcu_read_unlock();
1186 return NULL;
1187 }
1188
1189 /* selected should point to the next element
1190 * after the current router */
1191 spin_lock_bh(&primary_orig_node->neigh_list_lock);
1192 /* this is a list_move(), which unfortunately
1193 * does not exist as rcu version */
1194 list_del_rcu(&primary_orig_node->bond_list);
1195 list_add_rcu(&primary_orig_node->bond_list,
1196 &router->bonding_list);
1197 spin_unlock_bh(&primary_orig_node->neigh_list_lock);
1198
1199 } else {
1200 /* if bonding is disabled, use the best of the
1201 * remaining candidates which are not using
1202 * this interface. */
1203 list_for_each_entry_rcu(tmp_neigh_node,
1204 &primary_orig_node->bond_list, bonding_list) {
1205 if (!first_candidate)
1206 first_candidate = tmp_neigh_node;
1207
1208 /* recv_if == NULL on the first node. */
1209 if (tmp_neigh_node->if_incoming == recv_if)
1210 continue;
1211 1256
1212 if (!atomic_inc_not_zero(&tmp_neigh_node->refcount)) 1257 if (bonding_enabled)
1213 continue; 1258 router = find_bond_router(primary_orig_node, recv_if);
1214 1259 else
1215 /* if we don't have a router yet 1260 router = find_ifalter_router(primary_orig_node, recv_if);
1216 * or this one is better, choose it. */
1217 if ((!router) ||
1218 (tmp_neigh_node->tq_avg > router->tq_avg)) {
1219 /* decrement refcount of
1220 * previously selected router */
1221 if (router)
1222 neigh_node_free_ref(router);
1223
1224 router = tmp_neigh_node;
1225 atomic_inc_not_zero(&router->refcount);
1226 }
1227
1228 neigh_node_free_ref(tmp_neigh_node);
1229 }
1230 1261
1231 /* use the first candidate if nothing was found. */
1232 if (!router && first_candidate &&
1233 atomic_inc_not_zero(&first_candidate->refcount))
1234 router = first_candidate;
1235 }
1236return_router: 1262return_router:
1237 rcu_read_unlock(); 1263 rcu_read_unlock();
1238 return router; 1264 return router;
diff --git a/net/batman-adv/send.c b/net/batman-adv/send.c
index d49e54d932af..e78670c3c4b7 100644
--- a/net/batman-adv/send.c
+++ b/net/batman-adv/send.c
@@ -308,6 +308,7 @@ void schedule_forward_packet(struct orig_node *orig_node,
308 struct hard_iface *if_incoming) 308 struct hard_iface *if_incoming)
309{ 309{
310 struct bat_priv *bat_priv = netdev_priv(if_incoming->soft_iface); 310 struct bat_priv *bat_priv = netdev_priv(if_incoming->soft_iface);
311 struct neigh_node *router;
311 unsigned char in_tq, in_ttl, tq_avg = 0; 312 unsigned char in_tq, in_ttl, tq_avg = 0;
312 unsigned long send_time; 313 unsigned long send_time;
313 314
@@ -316,6 +317,8 @@ void schedule_forward_packet(struct orig_node *orig_node,
316 return; 317 return;
317 } 318 }
318 319
320 router = orig_node_get_router(orig_node);
321
319 in_tq = batman_packet->tq; 322 in_tq = batman_packet->tq;
320 in_ttl = batman_packet->ttl; 323 in_ttl = batman_packet->ttl;
321 324
@@ -324,20 +327,22 @@ void schedule_forward_packet(struct orig_node *orig_node,
324 327
325 /* rebroadcast tq of our best ranking neighbor to ensure the rebroadcast 328 /* rebroadcast tq of our best ranking neighbor to ensure the rebroadcast
326 * of our best tq value */ 329 * of our best tq value */
327 if ((orig_node->router) && (orig_node->router->tq_avg != 0)) { 330 if (router && router->tq_avg != 0) {
328 331
329 /* rebroadcast ogm of best ranking neighbor as is */ 332 /* rebroadcast ogm of best ranking neighbor as is */
330 if (!compare_eth(orig_node->router->addr, ethhdr->h_source)) { 333 if (!compare_eth(router->addr, ethhdr->h_source)) {
331 batman_packet->tq = orig_node->router->tq_avg; 334 batman_packet->tq = router->tq_avg;
332 335
333 if (orig_node->router->last_ttl) 336 if (router->last_ttl)
334 batman_packet->ttl = orig_node->router->last_ttl 337 batman_packet->ttl = router->last_ttl - 1;
335 - 1;
336 } 338 }
337 339
338 tq_avg = orig_node->router->tq_avg; 340 tq_avg = router->tq_avg;
339 } 341 }
340 342
343 if (router)
344 neigh_node_free_ref(router);
345
341 /* apply hop penalty */ 346 /* apply hop penalty */
342 batman_packet->tq = hop_penalty(batman_packet->tq, bat_priv); 347 batman_packet->tq = hop_penalty(batman_packet->tq, bat_priv);
343 348
diff --git a/net/batman-adv/soft-interface.c b/net/batman-adv/soft-interface.c
index 824e1f6e50f2..1f6f756bc584 100644
--- a/net/batman-adv/soft-interface.c
+++ b/net/batman-adv/soft-interface.c
@@ -90,10 +90,51 @@ 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)
94{
95 struct softif_neigh *neigh;
96
97 rcu_read_lock();
98 neigh = rcu_dereference(bat_priv->softif_neigh);
99
100 if (neigh && !atomic_inc_not_zero(&neigh->refcount))
101 neigh = NULL;
102
103 rcu_read_unlock();
104 return neigh;
105}
106
107static void softif_neigh_select(struct bat_priv *bat_priv,
108 struct softif_neigh *new_neigh)
109{
110 struct softif_neigh *curr_neigh;
111
112 spin_lock_bh(&bat_priv->softif_neigh_lock);
113
114 if (new_neigh && !atomic_inc_not_zero(&new_neigh->refcount))
115 new_neigh = NULL;
116
117 curr_neigh = bat_priv->softif_neigh;
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);
124}
125
126static void softif_neigh_deselect(struct bat_priv *bat_priv)
127{
128 softif_neigh_select(bat_priv, NULL);
129}
130
93void softif_neigh_purge(struct bat_priv *bat_priv) 131void softif_neigh_purge(struct bat_priv *bat_priv)
94{ 132{
95 struct softif_neigh *softif_neigh, *softif_neigh_tmp; 133 struct softif_neigh *softif_neigh, *curr_softif_neigh;
96 struct hlist_node *node, *node_tmp; 134 struct hlist_node *node, *node_tmp;
135 char do_deselect = 0;
136
137 curr_softif_neigh = softif_neigh_get_selected(bat_priv);
97 138
98 spin_lock_bh(&bat_priv->softif_neigh_lock); 139 spin_lock_bh(&bat_priv->softif_neigh_lock);
99 140
@@ -105,22 +146,26 @@ void softif_neigh_purge(struct bat_priv *bat_priv)
105 (atomic_read(&bat_priv->mesh_state) == MESH_ACTIVE)) 146 (atomic_read(&bat_priv->mesh_state) == MESH_ACTIVE))
106 continue; 147 continue;
107 148
108 hlist_del_rcu(&softif_neigh->list); 149 if (curr_softif_neigh == softif_neigh) {
109
110 if (bat_priv->softif_neigh == softif_neigh) {
111 bat_dbg(DBG_ROUTES, bat_priv, 150 bat_dbg(DBG_ROUTES, bat_priv,
112 "Current mesh exit point '%pM' vanished " 151 "Current mesh exit point '%pM' vanished "
113 "(vid: %d).\n", 152 "(vid: %d).\n",
114 softif_neigh->addr, softif_neigh->vid); 153 softif_neigh->addr, softif_neigh->vid);
115 softif_neigh_tmp = bat_priv->softif_neigh; 154 do_deselect = 1;
116 bat_priv->softif_neigh = NULL;
117 softif_neigh_free_ref(softif_neigh_tmp);
118 } 155 }
119 156
157 hlist_del_rcu(&softif_neigh->list);
120 softif_neigh_free_ref(softif_neigh); 158 softif_neigh_free_ref(softif_neigh);
121 } 159 }
122 160
123 spin_unlock_bh(&bat_priv->softif_neigh_lock); 161 spin_unlock_bh(&bat_priv->softif_neigh_lock);
162
163 /* soft_neigh_deselect() needs to acquire the softif_neigh_lock */
164 if (do_deselect)
165 softif_neigh_deselect(bat_priv);
166
167 if (curr_softif_neigh)
168 softif_neigh_free_ref(curr_softif_neigh);
124} 169}
125 170
126static struct softif_neigh *softif_neigh_get(struct bat_priv *bat_priv, 171static struct softif_neigh *softif_neigh_get(struct bat_priv *bat_priv,
@@ -171,6 +216,7 @@ int softif_neigh_seq_print_text(struct seq_file *seq, void *offset)
171 struct bat_priv *bat_priv = netdev_priv(net_dev); 216 struct bat_priv *bat_priv = netdev_priv(net_dev);
172 struct softif_neigh *softif_neigh; 217 struct softif_neigh *softif_neigh;
173 struct hlist_node *node; 218 struct hlist_node *node;
219 struct softif_neigh *curr_softif_neigh;
174 220
175 if (!bat_priv->primary_if) { 221 if (!bat_priv->primary_if) {
176 return seq_printf(seq, "BATMAN mesh %s disabled - " 222 return seq_printf(seq, "BATMAN mesh %s disabled - "
@@ -180,14 +226,17 @@ int softif_neigh_seq_print_text(struct seq_file *seq, void *offset)
180 226
181 seq_printf(seq, "Softif neighbor list (%s)\n", net_dev->name); 227 seq_printf(seq, "Softif neighbor list (%s)\n", net_dev->name);
182 228
229 curr_softif_neigh = softif_neigh_get_selected(bat_priv);
183 rcu_read_lock(); 230 rcu_read_lock();
184 hlist_for_each_entry_rcu(softif_neigh, node, 231 hlist_for_each_entry_rcu(softif_neigh, node,
185 &bat_priv->softif_neigh_list, list) 232 &bat_priv->softif_neigh_list, list)
186 seq_printf(seq, "%s %pM (vid: %d)\n", 233 seq_printf(seq, "%s %pM (vid: %d)\n",
187 bat_priv->softif_neigh == softif_neigh 234 curr_softif_neigh == softif_neigh
188 ? "=>" : " ", softif_neigh->addr, 235 ? "=>" : " ", softif_neigh->addr,
189 softif_neigh->vid); 236 softif_neigh->vid);
190 rcu_read_unlock(); 237 rcu_read_unlock();
238 if (curr_softif_neigh)
239 softif_neigh_free_ref(curr_softif_neigh);
191 240
192 return 0; 241 return 0;
193} 242}
@@ -198,7 +247,8 @@ static void softif_batman_recv(struct sk_buff *skb, struct net_device *dev,
198 struct bat_priv *bat_priv = netdev_priv(dev); 247 struct bat_priv *bat_priv = netdev_priv(dev);
199 struct ethhdr *ethhdr = (struct ethhdr *)skb->data; 248 struct ethhdr *ethhdr = (struct ethhdr *)skb->data;
200 struct batman_packet *batman_packet; 249 struct batman_packet *batman_packet;
201 struct softif_neigh *softif_neigh, *softif_neigh_tmp; 250 struct softif_neigh *softif_neigh;
251 struct softif_neigh *curr_softif_neigh = NULL;
202 252
203 if (ntohs(ethhdr->h_proto) == ETH_P_8021Q) 253 if (ntohs(ethhdr->h_proto) == ETH_P_8021Q)
204 batman_packet = (struct batman_packet *) 254 batman_packet = (struct batman_packet *)
@@ -223,7 +273,8 @@ static void softif_batman_recv(struct sk_buff *skb, struct net_device *dev,
223 if (!softif_neigh) 273 if (!softif_neigh)
224 goto err; 274 goto err;
225 275
226 if (bat_priv->softif_neigh == softif_neigh) 276 curr_softif_neigh = softif_neigh_get_selected(bat_priv);
277 if (curr_softif_neigh == softif_neigh)
227 goto out; 278 goto out;
228 279
229 /* we got a neighbor but its mac is 'bigger' than ours */ 280 /* we got a neighbor but its mac is 'bigger' than ours */
@@ -232,38 +283,39 @@ static void softif_batman_recv(struct sk_buff *skb, struct net_device *dev,
232 goto out; 283 goto out;
233 284
234 /* switch to new 'smallest neighbor' */ 285 /* switch to new 'smallest neighbor' */
235 if ((bat_priv->softif_neigh) && 286 if ((curr_softif_neigh) &&
236 (memcmp(softif_neigh->addr, bat_priv->softif_neigh->addr, 287 (memcmp(softif_neigh->addr, curr_softif_neigh->addr,
237 ETH_ALEN) < 0)) { 288 ETH_ALEN) < 0)) {
238 bat_dbg(DBG_ROUTES, bat_priv, 289 bat_dbg(DBG_ROUTES, bat_priv,
239 "Changing mesh exit point from %pM (vid: %d) " 290 "Changing mesh exit point from %pM (vid: %d) "
240 "to %pM (vid: %d).\n", 291 "to %pM (vid: %d).\n",
241 bat_priv->softif_neigh->addr, 292 curr_softif_neigh->addr,
242 bat_priv->softif_neigh->vid, 293 curr_softif_neigh->vid,
243 softif_neigh->addr, softif_neigh->vid); 294 softif_neigh->addr, softif_neigh->vid);
244 softif_neigh_tmp = bat_priv->softif_neigh; 295
245 bat_priv->softif_neigh = softif_neigh; 296 softif_neigh_select(bat_priv, softif_neigh);
246 softif_neigh_free_ref(softif_neigh_tmp); 297 goto out;
247 /* we need to hold the additional reference */
248 goto err;
249 } 298 }
250 299
251 /* close own batX device and use softif_neigh as exit node */ 300 /* close own batX device and use softif_neigh as exit node */
252 if ((!bat_priv->softif_neigh) && 301 if ((!curr_softif_neigh) &&
253 (memcmp(softif_neigh->addr, 302 (memcmp(softif_neigh->addr,
254 bat_priv->primary_if->net_dev->dev_addr, ETH_ALEN) < 0)) { 303 bat_priv->primary_if->net_dev->dev_addr, ETH_ALEN) < 0)) {
255 bat_dbg(DBG_ROUTES, bat_priv, 304 bat_dbg(DBG_ROUTES, bat_priv,
256 "Setting mesh exit point to %pM (vid: %d).\n", 305 "Setting mesh exit point to %pM (vid: %d).\n",
257 softif_neigh->addr, softif_neigh->vid); 306 softif_neigh->addr, softif_neigh->vid);
258 bat_priv->softif_neigh = softif_neigh; 307
259 /* we need to hold the additional reference */ 308 softif_neigh_select(bat_priv, softif_neigh);
260 goto err; 309 goto out;
261 } 310 }
262 311
263out: 312out:
264 softif_neigh_free_ref(softif_neigh); 313 softif_neigh_free_ref(softif_neigh);
265err: 314err:
266 kfree_skb(skb); 315 kfree_skb(skb);
316 if (curr_softif_neigh)
317 softif_neigh_free_ref(curr_softif_neigh);
318
267 return; 319 return;
268} 320}
269 321
@@ -321,6 +373,7 @@ int interface_tx(struct sk_buff *skb, struct net_device *soft_iface)
321 struct bat_priv *bat_priv = netdev_priv(soft_iface); 373 struct bat_priv *bat_priv = netdev_priv(soft_iface);
322 struct bcast_packet *bcast_packet; 374 struct bcast_packet *bcast_packet;
323 struct vlan_ethhdr *vhdr; 375 struct vlan_ethhdr *vhdr;
376 struct softif_neigh *curr_softif_neigh = NULL;
324 int data_len = skb->len, ret; 377 int data_len = skb->len, ret;
325 short vid = -1; 378 short vid = -1;
326 bool do_bcast = false; 379 bool do_bcast = false;
@@ -348,7 +401,8 @@ int interface_tx(struct sk_buff *skb, struct net_device *soft_iface)
348 * if we have a another chosen mesh exit node in range 401 * if we have a another chosen mesh exit node in range
349 * it will transport the packets to the mesh 402 * it will transport the packets to the mesh
350 */ 403 */
351 if ((bat_priv->softif_neigh) && (bat_priv->softif_neigh->vid == vid)) 404 curr_softif_neigh = softif_neigh_get_selected(bat_priv);
405 if ((curr_softif_neigh) && (curr_softif_neigh->vid == vid))
352 goto dropped; 406 goto dropped;
353 407
354 /* TODO: check this for locks */ 408 /* TODO: check this for locks */
@@ -410,6 +464,8 @@ dropped:
410dropped_freed: 464dropped_freed:
411 bat_priv->stats.tx_dropped++; 465 bat_priv->stats.tx_dropped++;
412end: 466end:
467 if (curr_softif_neigh)
468 softif_neigh_free_ref(curr_softif_neigh);
413 return NETDEV_TX_OK; 469 return NETDEV_TX_OK;
414} 470}
415 471
@@ -421,6 +477,7 @@ void interface_rx(struct net_device *soft_iface,
421 struct unicast_packet *unicast_packet; 477 struct unicast_packet *unicast_packet;
422 struct ethhdr *ethhdr; 478 struct ethhdr *ethhdr;
423 struct vlan_ethhdr *vhdr; 479 struct vlan_ethhdr *vhdr;
480 struct softif_neigh *curr_softif_neigh = NULL;
424 short vid = -1; 481 short vid = -1;
425 int ret; 482 int ret;
426 483
@@ -450,7 +507,8 @@ void interface_rx(struct net_device *soft_iface,
450 * if we have a another chosen mesh exit node in range 507 * if we have a another chosen mesh exit node in range
451 * it will transport the packets to the non-mesh network 508 * it will transport the packets to the non-mesh network
452 */ 509 */
453 if ((bat_priv->softif_neigh) && (bat_priv->softif_neigh->vid == vid)) { 510 curr_softif_neigh = softif_neigh_get_selected(bat_priv);
511 if (curr_softif_neigh && (curr_softif_neigh->vid == vid)) {
454 skb_push(skb, hdr_size); 512 skb_push(skb, hdr_size);
455 unicast_packet = (struct unicast_packet *)skb->data; 513 unicast_packet = (struct unicast_packet *)skb->data;
456 514
@@ -461,7 +519,7 @@ void interface_rx(struct net_device *soft_iface,
461 skb_reset_mac_header(skb); 519 skb_reset_mac_header(skb);
462 520
463 memcpy(unicast_packet->dest, 521 memcpy(unicast_packet->dest,
464 bat_priv->softif_neigh->addr, ETH_ALEN); 522 curr_softif_neigh->addr, ETH_ALEN);
465 ret = route_unicast_packet(skb, recv_if); 523 ret = route_unicast_packet(skb, recv_if);
466 if (ret == NET_RX_DROP) 524 if (ret == NET_RX_DROP)
467 goto dropped; 525 goto dropped;
@@ -486,11 +544,13 @@ void interface_rx(struct net_device *soft_iface,
486 soft_iface->last_rx = jiffies; 544 soft_iface->last_rx = jiffies;
487 545
488 netif_rx(skb); 546 netif_rx(skb);
489 return; 547 goto out;
490 548
491dropped: 549dropped:
492 kfree_skb(skb); 550 kfree_skb(skb);
493out: 551out:
552 if (curr_softif_neigh)
553 softif_neigh_free_ref(curr_softif_neigh);
494 return; 554 return;
495} 555}
496 556
@@ -524,6 +584,7 @@ static void interface_setup(struct net_device *dev)
524 dev->hard_start_xmit = interface_tx; 584 dev->hard_start_xmit = interface_tx;
525#endif 585#endif
526 dev->destructor = free_netdev; 586 dev->destructor = free_netdev;
587 dev->tx_queue_len = 0;
527 588
528 /** 589 /**
529 * can't call min_mtu, because the needed variables 590 * can't call min_mtu, because the needed variables
diff --git a/net/batman-adv/types.h b/net/batman-adv/types.h
index 83445cf0cc9f..75123b1ae0de 100644
--- a/net/batman-adv/types.h
+++ b/net/batman-adv/types.h
@@ -67,7 +67,7 @@ struct hard_iface {
67struct orig_node { 67struct orig_node {
68 uint8_t orig[ETH_ALEN]; 68 uint8_t orig[ETH_ALEN];
69 uint8_t primary_addr[ETH_ALEN]; 69 uint8_t primary_addr[ETH_ALEN];
70 struct neigh_node *router; 70 struct neigh_node __rcu *router; /* rcu protected pointer */
71 unsigned long *bcast_own; 71 unsigned long *bcast_own;
72 uint8_t *bcast_own_sum; 72 uint8_t *bcast_own_sum;
73 unsigned long last_valid; 73 unsigned long last_valid;
@@ -83,7 +83,7 @@ struct orig_node {
83 uint32_t last_bcast_seqno; 83 uint32_t last_bcast_seqno;
84 struct hlist_head neigh_list; 84 struct hlist_head neigh_list;
85 struct list_head frag_list; 85 struct list_head frag_list;
86 spinlock_t neigh_list_lock; /* protects neighbor list */ 86 spinlock_t neigh_list_lock; /* protects neigh_list and router */
87 atomic_t refcount; 87 atomic_t refcount;
88 struct rcu_head rcu; 88 struct rcu_head rcu;
89 struct hlist_node hash_entry; 89 struct hlist_node hash_entry;
@@ -125,6 +125,7 @@ struct neigh_node {
125 struct rcu_head rcu; 125 struct rcu_head rcu;
126 struct orig_node *orig_node; 126 struct orig_node *orig_node;
127 struct hard_iface *if_incoming; 127 struct hard_iface *if_incoming;
128 spinlock_t tq_lock; /* protects: tq_recv, tq_index */
128}; 129};
129 130
130 131
@@ -146,7 +147,7 @@ struct bat_priv {
146 atomic_t batman_queue_left; 147 atomic_t batman_queue_left;
147 char num_ifaces; 148 char num_ifaces;
148 struct hlist_head softif_neigh_list; 149 struct hlist_head softif_neigh_list;
149 struct softif_neigh *softif_neigh; 150 struct softif_neigh __rcu *softif_neigh;
150 struct debug_log *debug_log; 151 struct debug_log *debug_log;
151 struct hard_iface *primary_if; 152 struct hard_iface *primary_if;
152 struct kobject *mesh_obj; 153 struct kobject *mesh_obj;
diff --git a/net/batman-adv/unicast.c b/net/batman-adv/unicast.c
index 19f84bd443af..d46acc815138 100644
--- a/net/batman-adv/unicast.c
+++ b/net/batman-adv/unicast.c
@@ -289,7 +289,7 @@ int unicast_send_skb(struct sk_buff *skb, struct bat_priv *bat_priv)
289 289
290 /* get routing information */ 290 /* get routing information */
291 if (is_multicast_ether_addr(ethhdr->h_dest)) { 291 if (is_multicast_ether_addr(ethhdr->h_dest)) {
292 orig_node = (struct orig_node *)gw_get_selected(bat_priv); 292 orig_node = (struct orig_node *)gw_get_selected_orig(bat_priv);
293 if (orig_node) 293 if (orig_node)
294 goto find_router; 294 goto find_router;
295 } 295 }
diff --git a/net/batman-adv/vis.c b/net/batman-adv/vis.c
index f90212f42082..d4cc4f5399f4 100644
--- a/net/batman-adv/vis.c
+++ b/net/batman-adv/vis.c
@@ -558,6 +558,7 @@ static int find_best_vis_server(struct bat_priv *bat_priv,
558 struct vis_info *info) 558 struct vis_info *info)
559{ 559{
560 struct hashtable_t *hash = bat_priv->orig_hash; 560 struct hashtable_t *hash = bat_priv->orig_hash;
561 struct neigh_node *router;
561 struct hlist_node *node; 562 struct hlist_node *node;
562 struct hlist_head *head; 563 struct hlist_head *head;
563 struct orig_node *orig_node; 564 struct orig_node *orig_node;
@@ -571,13 +572,17 @@ static int find_best_vis_server(struct bat_priv *bat_priv,
571 572
572 rcu_read_lock(); 573 rcu_read_lock();
573 hlist_for_each_entry_rcu(orig_node, node, head, hash_entry) { 574 hlist_for_each_entry_rcu(orig_node, node, head, hash_entry) {
574 if ((orig_node) && (orig_node->router) && 575 router = orig_node_get_router(orig_node);
575 (orig_node->flags & VIS_SERVER) && 576 if (!router)
576 (orig_node->router->tq_avg > best_tq)) { 577 continue;
577 best_tq = orig_node->router->tq_avg; 578
579 if ((orig_node->flags & VIS_SERVER) &&
580 (router->tq_avg > best_tq)) {
581 best_tq = router->tq_avg;
578 memcpy(packet->target_orig, orig_node->orig, 582 memcpy(packet->target_orig, orig_node->orig,
579 ETH_ALEN); 583 ETH_ALEN);
580 } 584 }
585 neigh_node_free_ref(router);
581 } 586 }
582 rcu_read_unlock(); 587 rcu_read_unlock();
583 } 588 }
@@ -605,7 +610,7 @@ static int generate_vis_packet(struct bat_priv *bat_priv)
605 struct hlist_node *node; 610 struct hlist_node *node;
606 struct hlist_head *head; 611 struct hlist_head *head;
607 struct orig_node *orig_node; 612 struct orig_node *orig_node;
608 struct neigh_node *neigh_node; 613 struct neigh_node *router;
609 struct vis_info *info = (struct vis_info *)bat_priv->my_vis_info; 614 struct vis_info *info = (struct vis_info *)bat_priv->my_vis_info;
610 struct vis_packet *packet = (struct vis_packet *)info->skb_packet->data; 615 struct vis_packet *packet = (struct vis_packet *)info->skb_packet->data;
611 struct vis_info_entry *entry; 616 struct vis_info_entry *entry;
@@ -633,30 +638,32 @@ static int generate_vis_packet(struct bat_priv *bat_priv)
633 638
634 rcu_read_lock(); 639 rcu_read_lock();
635 hlist_for_each_entry_rcu(orig_node, node, head, hash_entry) { 640 hlist_for_each_entry_rcu(orig_node, node, head, hash_entry) {
636 neigh_node = orig_node->router; 641 router = orig_node_get_router(orig_node);
637 642 if (!router)
638 if (!neigh_node)
639 continue; 643 continue;
640 644
641 if (!compare_eth(neigh_node->addr, orig_node->orig)) 645 if (!compare_eth(router->addr, orig_node->orig))
642 continue; 646 goto next;
643 647
644 if (neigh_node->if_incoming->if_status != IF_ACTIVE) 648 if (router->if_incoming->if_status != IF_ACTIVE)
645 continue; 649 goto next;
646 650
647 if (neigh_node->tq_avg < 1) 651 if (router->tq_avg < 1)
648 continue; 652 goto next;
649 653
650 /* fill one entry into buffer. */ 654 /* fill one entry into buffer. */
651 entry = (struct vis_info_entry *) 655 entry = (struct vis_info_entry *)
652 skb_put(info->skb_packet, sizeof(*entry)); 656 skb_put(info->skb_packet, sizeof(*entry));
653 memcpy(entry->src, 657 memcpy(entry->src,
654 neigh_node->if_incoming->net_dev->dev_addr, 658 router->if_incoming->net_dev->dev_addr,
655 ETH_ALEN); 659 ETH_ALEN);
656 memcpy(entry->dest, orig_node->orig, ETH_ALEN); 660 memcpy(entry->dest, orig_node->orig, ETH_ALEN);
657 entry->quality = neigh_node->tq_avg; 661 entry->quality = router->tq_avg;
658 packet->entries++; 662 packet->entries++;
659 663
664next:
665 neigh_node_free_ref(router);
666
660 if (vis_packet_full(info)) 667 if (vis_packet_full(info))
661 goto unlock; 668 goto unlock;
662 } 669 }
@@ -725,6 +732,7 @@ static void purge_vis_packets(struct bat_priv *bat_priv)
725static void broadcast_vis_packet(struct bat_priv *bat_priv, 732static void broadcast_vis_packet(struct bat_priv *bat_priv,
726 struct vis_info *info) 733 struct vis_info *info)
727{ 734{
735 struct neigh_node *router;
728 struct hashtable_t *hash = bat_priv->orig_hash; 736 struct hashtable_t *hash = bat_priv->orig_hash;
729 struct hlist_node *node; 737 struct hlist_node *node;
730 struct hlist_head *head; 738 struct hlist_head *head;
@@ -745,19 +753,26 @@ static void broadcast_vis_packet(struct bat_priv *bat_priv,
745 rcu_read_lock(); 753 rcu_read_lock();
746 hlist_for_each_entry_rcu(orig_node, node, head, hash_entry) { 754 hlist_for_each_entry_rcu(orig_node, node, head, hash_entry) {
747 /* if it's a vis server and reachable, send it. */ 755 /* if it's a vis server and reachable, send it. */
748 if ((!orig_node) || (!orig_node->router))
749 continue;
750 if (!(orig_node->flags & VIS_SERVER)) 756 if (!(orig_node->flags & VIS_SERVER))
751 continue; 757 continue;
758
759 router = orig_node_get_router(orig_node);
760 if (!router)
761 continue;
762
752 /* don't send it if we already received the packet from 763 /* don't send it if we already received the packet from
753 * this node. */ 764 * this node. */
754 if (recv_list_is_in(bat_priv, &info->recv_list, 765 if (recv_list_is_in(bat_priv, &info->recv_list,
755 orig_node->orig)) 766 orig_node->orig)) {
767 neigh_node_free_ref(router);
756 continue; 768 continue;
769 }
757 770
758 memcpy(packet->target_orig, orig_node->orig, ETH_ALEN); 771 memcpy(packet->target_orig, orig_node->orig, ETH_ALEN);
759 hard_iface = orig_node->router->if_incoming; 772 hard_iface = router->if_incoming;
760 memcpy(dstaddr, orig_node->router->addr, ETH_ALEN); 773 memcpy(dstaddr, router->addr, ETH_ALEN);
774
775 neigh_node_free_ref(router);
761 776
762 skb = skb_clone(info->skb_packet, GFP_ATOMIC); 777 skb = skb_clone(info->skb_packet, GFP_ATOMIC);
763 if (skb) 778 if (skb)
@@ -772,45 +787,29 @@ static void unicast_vis_packet(struct bat_priv *bat_priv,
772 struct vis_info *info) 787 struct vis_info *info)
773{ 788{
774 struct orig_node *orig_node; 789 struct orig_node *orig_node;
775 struct neigh_node *neigh_node = NULL; 790 struct neigh_node *router = NULL;
776 struct sk_buff *skb; 791 struct sk_buff *skb;
777 struct vis_packet *packet; 792 struct vis_packet *packet;
778 793
779 packet = (struct vis_packet *)info->skb_packet->data; 794 packet = (struct vis_packet *)info->skb_packet->data;
780 795
781 rcu_read_lock();
782 orig_node = orig_hash_find(bat_priv, packet->target_orig); 796 orig_node = orig_hash_find(bat_priv, packet->target_orig);
783
784 if (!orig_node) 797 if (!orig_node)
785 goto unlock; 798 goto out;
786 799
787 neigh_node = orig_node->router; 800 router = orig_node_get_router(orig_node);
788 801 if (!router)
789 if (!neigh_node) 802 goto out;
790 goto unlock;
791
792 if (!atomic_inc_not_zero(&neigh_node->refcount)) {
793 neigh_node = NULL;
794 goto unlock;
795 }
796
797 rcu_read_unlock();
798 803
799 skb = skb_clone(info->skb_packet, GFP_ATOMIC); 804 skb = skb_clone(info->skb_packet, GFP_ATOMIC);
800 if (skb) 805 if (skb)
801 send_skb_packet(skb, neigh_node->if_incoming, 806 send_skb_packet(skb, router->if_incoming, router->addr);
802 neigh_node->addr);
803
804 goto out;
805 807
806unlock:
807 rcu_read_unlock();
808out: 808out:
809 if (neigh_node) 809 if (router)
810 neigh_node_free_ref(neigh_node); 810 neigh_node_free_ref(router);
811 if (orig_node) 811 if (orig_node)
812 orig_node_free_ref(orig_node); 812 orig_node_free_ref(orig_node);
813 return;
814} 813}
815 814
816/* only send one vis packet. called from send_vis_packets() */ 815/* only send one vis packet. called from send_vis_packets() */