aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorLinus Lüssing <linus.luessing@web.de>2011-03-14 18:43:37 -0400
committerSven Eckelmann <sven@narfation.org>2011-04-17 15:11:01 -0400
commite1a5382f978b67b5cc36eec65e6046730ce07714 (patch)
treef7ca07cde3a49858d0cfa33e0189a659a1fcc95d
parent57f0c07c4d0da8bcc23e21c330fe9c7c5cf776b5 (diff)
batman-adv: Make orig_node->router an rcu protected pointer
The rcu protected macros rcu_dereference() and rcu_assign_pointer() for the orig_node->router need to be used, as well as spin/rcu locking. Otherwise we might end up using a router pointer pointing to already freed memory. Therefore this commit introduces the safe getter method orig_node_get_router(). Signed-off-by: Linus Lüssing <linus.luessing@web.de> Signed-off-by: Marek Lindner <lindner_marek@yahoo.de> Signed-off-by: Sven Eckelmann <sven@narfation.org>
-rw-r--r--net/batman-adv/gateway_client.c80
-rw-r--r--net/batman-adv/icmp_socket.c18
-rw-r--r--net/batman-adv/originator.c37
-rw-r--r--net/batman-adv/originator.h1
-rw-r--r--net/batman-adv/routing.c194
-rw-r--r--net/batman-adv/send.c19
-rw-r--r--net/batman-adv/types.h4
-rw-r--r--net/batman-adv/vis.c91
8 files changed, 232 insertions, 212 deletions
diff --git a/net/batman-adv/gateway_client.c b/net/batman-adv/gateway_client.c
index 879ac1594869..42a8a7ba06e6 100644
--- a/net/batman-adv/gateway_client.c
+++ b/net/batman-adv/gateway_client.c
@@ -98,6 +98,7 @@ void gw_election(struct bat_priv *bat_priv)
98{ 98{
99 struct hlist_node *node; 99 struct hlist_node *node;
100 struct gw_node *gw_node, *curr_gw, *curr_gw_tmp = NULL; 100 struct gw_node *gw_node, *curr_gw, *curr_gw_tmp = NULL;
101 struct neigh_node *router;
101 uint8_t max_tq = 0; 102 uint8_t max_tq = 0;
102 uint32_t max_gw_factor = 0, tmp_gw_factor = 0; 103 uint32_t max_gw_factor = 0, tmp_gw_factor = 0;
103 int down, up; 104 int down, up;
@@ -133,10 +134,11 @@ void gw_election(struct bat_priv *bat_priv)
133 } 134 }
134 135
135 hlist_for_each_entry_rcu(gw_node, node, &bat_priv->gw_list, list) { 136 hlist_for_each_entry_rcu(gw_node, node, &bat_priv->gw_list, list) {
136 if (!gw_node->orig_node->router) 137 if (gw_node->deleted)
137 continue; 138 continue;
138 139
139 if (gw_node->deleted) 140 router = orig_node_get_router(gw_node->orig_node);
141 if (!router)
140 continue; 142 continue;
141 143
142 switch (atomic_read(&bat_priv->gw_sel_class)) { 144 switch (atomic_read(&bat_priv->gw_sel_class)) {
@@ -144,15 +146,14 @@ void gw_election(struct bat_priv *bat_priv)
144 gw_bandwidth_to_kbit(gw_node->orig_node->gw_flags, 146 gw_bandwidth_to_kbit(gw_node->orig_node->gw_flags,
145 &down, &up); 147 &down, &up);
146 148
147 tmp_gw_factor = (gw_node->orig_node->router->tq_avg * 149 tmp_gw_factor = (router->tq_avg * router->tq_avg *
148 gw_node->orig_node->router->tq_avg *
149 down * 100 * 100) / 150 down * 100 * 100) /
150 (TQ_LOCAL_WINDOW_SIZE * 151 (TQ_LOCAL_WINDOW_SIZE *
151 TQ_LOCAL_WINDOW_SIZE * 64); 152 TQ_LOCAL_WINDOW_SIZE * 64);
152 153
153 if ((tmp_gw_factor > max_gw_factor) || 154 if ((tmp_gw_factor > max_gw_factor) ||
154 ((tmp_gw_factor == max_gw_factor) && 155 ((tmp_gw_factor == max_gw_factor) &&
155 (gw_node->orig_node->router->tq_avg > max_tq))) 156 (router->tq_avg > max_tq)))
156 curr_gw_tmp = gw_node; 157 curr_gw_tmp = gw_node;
157 break; 158 break;
158 159
@@ -164,19 +165,25 @@ void gw_election(struct bat_priv *bat_priv)
164 * soon as a better gateway appears which has 165 * soon as a better gateway appears which has
165 * $routing_class more tq points) 166 * $routing_class more tq points)
166 **/ 167 **/
167 if (gw_node->orig_node->router->tq_avg > max_tq) 168 if (router->tq_avg > max_tq)
168 curr_gw_tmp = gw_node; 169 curr_gw_tmp = gw_node;
169 break; 170 break;
170 } 171 }
171 172
172 if (gw_node->orig_node->router->tq_avg > max_tq) 173 if (router->tq_avg > max_tq)
173 max_tq = gw_node->orig_node->router->tq_avg; 174 max_tq = router->tq_avg;
174 175
175 if (tmp_gw_factor > max_gw_factor) 176 if (tmp_gw_factor > max_gw_factor)
176 max_gw_factor = tmp_gw_factor; 177 max_gw_factor = tmp_gw_factor;
178
179 neigh_node_free_ref(router);
177 } 180 }
178 181
179 if (curr_gw != curr_gw_tmp) { 182 if (curr_gw != curr_gw_tmp) {
183 router = orig_node_get_router(curr_gw_tmp->orig_node);
184 if (!router)
185 goto out;
186
180 if ((curr_gw) && (!curr_gw_tmp)) 187 if ((curr_gw) && (!curr_gw_tmp))
181 bat_dbg(DBG_BATMAN, bat_priv, 188 bat_dbg(DBG_BATMAN, bat_priv,
182 "Removing selected gateway - " 189 "Removing selected gateway - "
@@ -187,45 +194,47 @@ void gw_election(struct bat_priv *bat_priv)
187 "(gw_flags: %i, tq: %i)\n", 194 "(gw_flags: %i, tq: %i)\n",
188 curr_gw_tmp->orig_node->orig, 195 curr_gw_tmp->orig_node->orig,
189 curr_gw_tmp->orig_node->gw_flags, 196 curr_gw_tmp->orig_node->gw_flags,
190 curr_gw_tmp->orig_node->router->tq_avg); 197 router->tq_avg);
191 else 198 else
192 bat_dbg(DBG_BATMAN, bat_priv, 199 bat_dbg(DBG_BATMAN, bat_priv,
193 "Changing route to gateway %pM " 200 "Changing route to gateway %pM "
194 "(gw_flags: %i, tq: %i)\n", 201 "(gw_flags: %i, tq: %i)\n",
195 curr_gw_tmp->orig_node->orig, 202 curr_gw_tmp->orig_node->orig,
196 curr_gw_tmp->orig_node->gw_flags, 203 curr_gw_tmp->orig_node->gw_flags,
197 curr_gw_tmp->orig_node->router->tq_avg); 204 router->tq_avg);
198 205
206 neigh_node_free_ref(router);
199 gw_select(bat_priv, curr_gw_tmp); 207 gw_select(bat_priv, curr_gw_tmp);
200 } 208 }
201 209
210out:
202 rcu_read_unlock(); 211 rcu_read_unlock();
203} 212}
204 213
205void gw_check_election(struct bat_priv *bat_priv, struct orig_node *orig_node) 214void gw_check_election(struct bat_priv *bat_priv, struct orig_node *orig_node)
206{ 215{
207 struct orig_node *curr_gw_orig; 216 struct orig_node *curr_gw_orig;
217 struct neigh_node *router_gw = NULL, *router_orig = NULL;
208 uint8_t gw_tq_avg, orig_tq_avg; 218 uint8_t gw_tq_avg, orig_tq_avg;
209 219
210 curr_gw_orig = gw_get_selected(bat_priv); 220 curr_gw_orig = gw_get_selected(bat_priv);
211 if (!curr_gw_orig) 221 if (!curr_gw_orig)
212 goto deselect; 222 goto deselect;
213 223
214 rcu_read_lock(); 224 router_gw = orig_node_get_router(curr_gw_orig);
215 if (!curr_gw_orig->router) 225 if (!router_gw)
216 goto deselect_rcu; 226 goto deselect;
217 227
218 /* this node already is the gateway */ 228 /* this node already is the gateway */
219 if (curr_gw_orig == orig_node) 229 if (curr_gw_orig == orig_node)
220 goto out_rcu; 230 goto out;
221
222 if (!orig_node->router)
223 goto out_rcu;
224 231
225 gw_tq_avg = curr_gw_orig->router->tq_avg; 232 router_orig = orig_node_get_router(orig_node);
226 rcu_read_unlock(); 233 if (!router_orig)
234 goto out;
227 235
228 orig_tq_avg = orig_node->router->tq_avg; 236 gw_tq_avg = router_gw->tq_avg;
237 orig_tq_avg = router_orig->tq_avg;
229 238
230 /* the TQ value has to be better */ 239 /* the TQ value has to be better */
231 if (orig_tq_avg < gw_tq_avg) 240 if (orig_tq_avg < gw_tq_avg)
@@ -243,18 +252,16 @@ void gw_check_election(struct bat_priv *bat_priv, struct orig_node *orig_node)
243 "Restarting gateway selection: better gateway found (tq curr: " 252 "Restarting gateway selection: better gateway found (tq curr: "
244 "%i, tq new: %i)\n", 253 "%i, tq new: %i)\n",
245 gw_tq_avg, orig_tq_avg); 254 gw_tq_avg, orig_tq_avg);
246 goto deselect;
247 255
248out_rcu:
249 rcu_read_unlock();
250 goto out;
251deselect_rcu:
252 rcu_read_unlock();
253deselect: 256deselect:
254 gw_deselect(bat_priv); 257 gw_deselect(bat_priv);
255out: 258out:
256 if (curr_gw_orig) 259 if (curr_gw_orig)
257 orig_node_free_ref(curr_gw_orig); 260 orig_node_free_ref(curr_gw_orig);
261 if (router_gw)
262 neigh_node_free_ref(router_gw);
263 if (router_orig)
264 neigh_node_free_ref(router_orig);
258 265
259 return; 266 return;
260} 267}
@@ -362,23 +369,30 @@ void gw_node_purge(struct bat_priv *bat_priv)
362 spin_unlock_bh(&bat_priv->gw_list_lock); 369 spin_unlock_bh(&bat_priv->gw_list_lock);
363} 370}
364 371
372/**
373 * fails if orig_node has no router
374 */
365static int _write_buffer_text(struct bat_priv *bat_priv, 375static int _write_buffer_text(struct bat_priv *bat_priv,
366 struct seq_file *seq, struct gw_node *gw_node) 376 struct seq_file *seq, struct gw_node *gw_node)
367{ 377{
368 struct gw_node *curr_gw; 378 struct gw_node *curr_gw;
369 int down, up, ret; 379 struct neigh_node *router;
380 int down, up, ret = -1;
370 381
371 gw_bandwidth_to_kbit(gw_node->orig_node->gw_flags, &down, &up); 382 gw_bandwidth_to_kbit(gw_node->orig_node->gw_flags, &down, &up);
372 383
384 router = orig_node_get_router(gw_node->orig_node);
385 if (!router)
386 goto out;
387
373 rcu_read_lock(); 388 rcu_read_lock();
374 curr_gw = rcu_dereference(bat_priv->curr_gw); 389 curr_gw = rcu_dereference(bat_priv->curr_gw);
375 390
376 ret = seq_printf(seq, "%s %pM (%3i) %pM [%10s]: %3i - %i%s/%i%s\n", 391 ret = seq_printf(seq, "%s %pM (%3i) %pM [%10s]: %3i - %i%s/%i%s\n",
377 (curr_gw == gw_node ? "=>" : " "), 392 (curr_gw == gw_node ? "=>" : " "),
378 gw_node->orig_node->orig, 393 gw_node->orig_node->orig,
379 gw_node->orig_node->router->tq_avg, 394 router->tq_avg, router->addr,
380 gw_node->orig_node->router->addr, 395 router->if_incoming->net_dev->name,
381 gw_node->orig_node->router->if_incoming->net_dev->name,
382 gw_node->orig_node->gw_flags, 396 gw_node->orig_node->gw_flags,
383 (down > 2048 ? down / 1024 : down), 397 (down > 2048 ? down / 1024 : down),
384 (down > 2048 ? "MBit" : "KBit"), 398 (down > 2048 ? "MBit" : "KBit"),
@@ -386,6 +400,8 @@ static int _write_buffer_text(struct bat_priv *bat_priv,
386 (up > 2048 ? "MBit" : "KBit")); 400 (up > 2048 ? "MBit" : "KBit"));
387 401
388 rcu_read_unlock(); 402 rcu_read_unlock();
403 neigh_node_free_ref(router);
404out:
389 return ret; 405 return ret;
390} 406}
391 407
@@ -423,10 +439,10 @@ int gw_client_seq_print_text(struct seq_file *seq, void *offset)
423 if (gw_node->deleted) 439 if (gw_node->deleted)
424 continue; 440 continue;
425 441
426 if (!gw_node->orig_node->router) 442 /* fails if orig_node has no router */
443 if (_write_buffer_text(bat_priv, seq, gw_node) < 0)
427 continue; 444 continue;
428 445
429 _write_buffer_text(bat_priv, seq, gw_node);
430 gw_count++; 446 gw_count++;
431 } 447 }
432 rcu_read_unlock(); 448 rcu_read_unlock();
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..b4cfe3686155 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,
@@ -390,7 +405,7 @@ int orig_seq_print_text(struct seq_file *seq, void *offset)
390 struct hlist_node *node, *node_tmp; 405 struct hlist_node *node, *node_tmp;
391 struct hlist_head *head; 406 struct hlist_head *head;
392 struct orig_node *orig_node; 407 struct orig_node *orig_node;
393 struct neigh_node *neigh_node; 408 struct neigh_node *neigh_node, *neigh_node_tmp;
394 int batman_count = 0; 409 int batman_count = 0;
395 int last_seen_secs; 410 int last_seen_secs;
396 int last_seen_msecs; 411 int last_seen_msecs;
@@ -421,37 +436,41 @@ int orig_seq_print_text(struct seq_file *seq, void *offset)
421 436
422 rcu_read_lock(); 437 rcu_read_lock();
423 hlist_for_each_entry_rcu(orig_node, node, head, hash_entry) { 438 hlist_for_each_entry_rcu(orig_node, node, head, hash_entry) {
424 if (!orig_node->router) 439 neigh_node = orig_node_get_router(orig_node);
440 if (!neigh_node)
425 continue; 441 continue;
426 442
427 if (orig_node->router->tq_avg == 0) 443 if (neigh_node->tq_avg == 0)
428 continue; 444 goto next;
429 445
430 last_seen_secs = jiffies_to_msecs(jiffies - 446 last_seen_secs = jiffies_to_msecs(jiffies -
431 orig_node->last_valid) / 1000; 447 orig_node->last_valid) / 1000;
432 last_seen_msecs = jiffies_to_msecs(jiffies - 448 last_seen_msecs = jiffies_to_msecs(jiffies -
433 orig_node->last_valid) % 1000; 449 orig_node->last_valid) % 1000;
434 450
435 neigh_node = orig_node->router;
436 seq_printf(seq, "%pM %4i.%03is (%3i) %pM [%10s]:", 451 seq_printf(seq, "%pM %4i.%03is (%3i) %pM [%10s]:",
437 orig_node->orig, last_seen_secs, 452 orig_node->orig, last_seen_secs,
438 last_seen_msecs, neigh_node->tq_avg, 453 last_seen_msecs, neigh_node->tq_avg,
439 neigh_node->addr, 454 neigh_node->addr,
440 neigh_node->if_incoming->net_dev->name); 455 neigh_node->if_incoming->net_dev->name);
441 456
442 hlist_for_each_entry_rcu(neigh_node, node_tmp, 457 hlist_for_each_entry_rcu(neigh_node_tmp, node_tmp,
443 &orig_node->neigh_list, list) { 458 &orig_node->neigh_list, list) {
444 seq_printf(seq, " %pM (%3i)", neigh_node->addr, 459 seq_printf(seq, " %pM (%3i)",
445 neigh_node->tq_avg); 460 neigh_node_tmp->addr,
461 neigh_node_tmp->tq_avg);
446 } 462 }
447 463
448 seq_printf(seq, "\n"); 464 seq_printf(seq, "\n");
449 batman_count++; 465 batman_count++;
466
467next:
468 neigh_node_free_ref(neigh_node);
450 } 469 }
451 rcu_read_unlock(); 470 rcu_read_unlock();
452 } 471 }
453 472
454 if ((batman_count == 0)) 473 if (batman_count == 0)
455 seq_printf(seq, "No batman nodes in range ...\n"); 474 seq_printf(seq, "No batman nodes in range ...\n");
456 475
457 return 0; 476 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 f212abe745bc..b7d43caaa9c8 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;
@@ -441,19 +460,18 @@ static void update_orig(struct bat_priv *bat_priv,
441 460
442 /* if this neighbor already is our next hop there is nothing 461 /* if this neighbor already is our next hop there is nothing
443 * to change */ 462 * to change */
444 if (orig_node->router == neigh_node) 463 router = orig_node_get_router(orig_node);
464 if (router == neigh_node)
445 goto update_hna; 465 goto update_hna;
446 466
447 /* if this neighbor does not offer a better TQ we won't consider it */ 467 /* if this neighbor does not offer a better TQ we won't consider it */
448 if ((orig_node->router) && 468 if (router && (router->tq_avg > neigh_node->tq_avg))
449 (orig_node->router->tq_avg > neigh_node->tq_avg))
450 goto update_hna; 469 goto update_hna;
451 470
452 /* if the TQ is the same and the link not more symetric we 471 /* if the TQ is the same and the link not more symetric we
453 * won't consider it either */ 472 * won't consider it either */
454 if ((orig_node->router) && 473 if (router && (neigh_node->tq_avg == router->tq_avg)) {
455 (neigh_node->tq_avg == orig_node->router->tq_avg)) { 474 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); 475 spin_lock_bh(&orig_node_tmp->ogm_cnt_lock);
458 bcast_own_sum_orig = 476 bcast_own_sum_orig =
459 orig_node_tmp->bcast_own_sum[if_incoming->if_num]; 477 orig_node_tmp->bcast_own_sum[if_incoming->if_num];
@@ -474,7 +492,7 @@ static void update_orig(struct bat_priv *bat_priv,
474 goto update_gw; 492 goto update_gw;
475 493
476update_hna: 494update_hna:
477 update_routes(bat_priv, orig_node, orig_node->router, 495 update_routes(bat_priv, orig_node, router,
478 hna_buff, tmp_hna_buff_len); 496 hna_buff, tmp_hna_buff_len);
479 497
480update_gw: 498update_gw:
@@ -496,6 +514,8 @@ unlock:
496out: 514out:
497 if (neigh_node) 515 if (neigh_node)
498 neigh_node_free_ref(neigh_node); 516 neigh_node_free_ref(neigh_node);
517 if (router)
518 neigh_node_free_ref(router);
499} 519}
500 520
501/* checks whether the host restarted and is in the protection time. 521/* checks whether the host restarted and is in the protection time.
@@ -603,6 +623,8 @@ void receive_bat_packet(struct ethhdr *ethhdr,
603 struct bat_priv *bat_priv = netdev_priv(if_incoming->soft_iface); 623 struct bat_priv *bat_priv = netdev_priv(if_incoming->soft_iface);
604 struct hard_iface *hard_iface; 624 struct hard_iface *hard_iface;
605 struct orig_node *orig_neigh_node, *orig_node; 625 struct orig_node *orig_neigh_node, *orig_node;
626 struct neigh_node *router = NULL, *router_router = NULL;
627 struct neigh_node *orig_neigh_router = NULL;
606 char has_directlink_flag; 628 char has_directlink_flag;
607 char is_my_addr = 0, is_my_orig = 0, is_my_oldorig = 0; 629 char is_my_addr = 0, is_my_orig = 0, is_my_oldorig = 0;
608 char is_broadcast = 0, is_bidirectional, is_single_hop_neigh; 630 char is_broadcast = 0, is_bidirectional, is_single_hop_neigh;
@@ -747,14 +769,15 @@ void receive_bat_packet(struct ethhdr *ethhdr,
747 goto out; 769 goto out;
748 } 770 }
749 771
772 router = orig_node_get_router(orig_node);
773 if (router)
774 router_router = orig_node_get_router(router->orig_node);
775
750 /* avoid temporary routing loops */ 776 /* avoid temporary routing loops */
751 if ((orig_node->router) && 777 if (router && router_router &&
752 (orig_node->router->orig_node->router) && 778 (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)) && 779 !(compare_eth(batman_packet->orig, batman_packet->prev_sender)) &&
756 (compare_eth(orig_node->router->addr, 780 (compare_eth(router->addr, router_router->addr))) {
757 orig_node->router->orig_node->router->addr))) {
758 bat_dbg(DBG_BATMAN, bat_priv, 781 bat_dbg(DBG_BATMAN, bat_priv,
759 "Drop packet: ignoring all rebroadcast packets that " 782 "Drop packet: ignoring all rebroadcast packets that "
760 "may make me loop (sender: %pM)\n", ethhdr->h_source); 783 "may make me loop (sender: %pM)\n", ethhdr->h_source);
@@ -769,9 +792,11 @@ void receive_bat_packet(struct ethhdr *ethhdr,
769 if (!orig_neigh_node) 792 if (!orig_neigh_node)
770 goto out; 793 goto out;
771 794
795 orig_neigh_router = orig_node_get_router(orig_neigh_node);
796
772 /* drop packet if sender is not a direct neighbor and if we 797 /* drop packet if sender is not a direct neighbor and if we
773 * don't route towards it */ 798 * don't route towards it */
774 if (!is_single_hop_neigh && (!orig_neigh_node->router)) { 799 if (!is_single_hop_neigh && (!orig_neigh_router)) {
775 bat_dbg(DBG_BATMAN, bat_priv, 800 bat_dbg(DBG_BATMAN, bat_priv,
776 "Drop packet: OGM via unknown neighbor!\n"); 801 "Drop packet: OGM via unknown neighbor!\n");
777 goto out_neigh; 802 goto out_neigh;
@@ -825,6 +850,13 @@ out_neigh:
825 if ((orig_neigh_node) && (!is_single_hop_neigh)) 850 if ((orig_neigh_node) && (!is_single_hop_neigh))
826 orig_node_free_ref(orig_neigh_node); 851 orig_node_free_ref(orig_neigh_node);
827out: 852out:
853 if (router)
854 neigh_node_free_ref(router);
855 if (router_router)
856 neigh_node_free_ref(router_router);
857 if (orig_neigh_router)
858 neigh_node_free_ref(orig_neigh_router);
859
828 orig_node_free_ref(orig_node); 860 orig_node_free_ref(orig_node);
829} 861}
830 862
@@ -869,7 +901,7 @@ static int recv_my_icmp_packet(struct bat_priv *bat_priv,
869 struct sk_buff *skb, size_t icmp_len) 901 struct sk_buff *skb, size_t icmp_len)
870{ 902{
871 struct orig_node *orig_node = NULL; 903 struct orig_node *orig_node = NULL;
872 struct neigh_node *neigh_node = NULL; 904 struct neigh_node *router = NULL;
873 struct icmp_packet_rr *icmp_packet; 905 struct icmp_packet_rr *icmp_packet;
874 int ret = NET_RX_DROP; 906 int ret = NET_RX_DROP;
875 907
@@ -886,23 +918,13 @@ static int recv_my_icmp_packet(struct bat_priv *bat_priv,
886 918
887 /* answer echo request (ping) */ 919 /* answer echo request (ping) */
888 /* get routing information */ 920 /* get routing information */
889 rcu_read_lock();
890 orig_node = orig_hash_find(bat_priv, icmp_packet->orig); 921 orig_node = orig_hash_find(bat_priv, icmp_packet->orig);
891
892 if (!orig_node) 922 if (!orig_node)
893 goto unlock; 923 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 924
905 rcu_read_unlock(); 925 router = orig_node_get_router(orig_node);
926 if (!router)
927 goto out;
906 928
907 /* create a copy of the skb, if needed, to modify it. */ 929 /* create a copy of the skb, if needed, to modify it. */
908 if (skb_cow(skb, sizeof(struct ethhdr)) < 0) 930 if (skb_cow(skb, sizeof(struct ethhdr)) < 0)
@@ -916,15 +938,12 @@ static int recv_my_icmp_packet(struct bat_priv *bat_priv,
916 icmp_packet->msg_type = ECHO_REPLY; 938 icmp_packet->msg_type = ECHO_REPLY;
917 icmp_packet->ttl = TTL; 939 icmp_packet->ttl = TTL;
918 940
919 send_skb_packet(skb, neigh_node->if_incoming, neigh_node->addr); 941 send_skb_packet(skb, router->if_incoming, router->addr);
920 ret = NET_RX_SUCCESS; 942 ret = NET_RX_SUCCESS;
921 goto out;
922 943
923unlock:
924 rcu_read_unlock();
925out: 944out:
926 if (neigh_node) 945 if (router)
927 neigh_node_free_ref(neigh_node); 946 neigh_node_free_ref(router);
928 if (orig_node) 947 if (orig_node)
929 orig_node_free_ref(orig_node); 948 orig_node_free_ref(orig_node);
930 return ret; 949 return ret;
@@ -934,7 +953,7 @@ static int recv_icmp_ttl_exceeded(struct bat_priv *bat_priv,
934 struct sk_buff *skb) 953 struct sk_buff *skb)
935{ 954{
936 struct orig_node *orig_node = NULL; 955 struct orig_node *orig_node = NULL;
937 struct neigh_node *neigh_node = NULL; 956 struct neigh_node *router = NULL;
938 struct icmp_packet *icmp_packet; 957 struct icmp_packet *icmp_packet;
939 int ret = NET_RX_DROP; 958 int ret = NET_RX_DROP;
940 959
@@ -952,23 +971,13 @@ static int recv_icmp_ttl_exceeded(struct bat_priv *bat_priv,
952 goto out; 971 goto out;
953 972
954 /* get routing information */ 973 /* get routing information */
955 rcu_read_lock();
956 orig_node = orig_hash_find(bat_priv, icmp_packet->orig); 974 orig_node = orig_hash_find(bat_priv, icmp_packet->orig);
957
958 if (!orig_node) 975 if (!orig_node)
959 goto unlock; 976 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 977
971 rcu_read_unlock(); 978 router = orig_node_get_router(orig_node);
979 if (!router)
980 goto out;
972 981
973 /* create a copy of the skb, if needed, to modify it. */ 982 /* create a copy of the skb, if needed, to modify it. */
974 if (skb_cow(skb, sizeof(struct ethhdr)) < 0) 983 if (skb_cow(skb, sizeof(struct ethhdr)) < 0)
@@ -982,15 +991,12 @@ static int recv_icmp_ttl_exceeded(struct bat_priv *bat_priv,
982 icmp_packet->msg_type = TTL_EXCEEDED; 991 icmp_packet->msg_type = TTL_EXCEEDED;
983 icmp_packet->ttl = TTL; 992 icmp_packet->ttl = TTL;
984 993
985 send_skb_packet(skb, neigh_node->if_incoming, neigh_node->addr); 994 send_skb_packet(skb, router->if_incoming, router->addr);
986 ret = NET_RX_SUCCESS; 995 ret = NET_RX_SUCCESS;
987 goto out;
988 996
989unlock:
990 rcu_read_unlock();
991out: 997out:
992 if (neigh_node) 998 if (router)
993 neigh_node_free_ref(neigh_node); 999 neigh_node_free_ref(router);
994 if (orig_node) 1000 if (orig_node)
995 orig_node_free_ref(orig_node); 1001 orig_node_free_ref(orig_node);
996 return ret; 1002 return ret;
@@ -1003,7 +1009,7 @@ int recv_icmp_packet(struct sk_buff *skb, struct hard_iface *recv_if)
1003 struct icmp_packet_rr *icmp_packet; 1009 struct icmp_packet_rr *icmp_packet;
1004 struct ethhdr *ethhdr; 1010 struct ethhdr *ethhdr;
1005 struct orig_node *orig_node = NULL; 1011 struct orig_node *orig_node = NULL;
1006 struct neigh_node *neigh_node = NULL; 1012 struct neigh_node *router = NULL;
1007 int hdr_size = sizeof(struct icmp_packet); 1013 int hdr_size = sizeof(struct icmp_packet);
1008 int ret = NET_RX_DROP; 1014 int ret = NET_RX_DROP;
1009 1015
@@ -1050,23 +1056,13 @@ int recv_icmp_packet(struct sk_buff *skb, struct hard_iface *recv_if)
1050 return recv_icmp_ttl_exceeded(bat_priv, skb); 1056 return recv_icmp_ttl_exceeded(bat_priv, skb);
1051 1057
1052 /* get routing information */ 1058 /* get routing information */
1053 rcu_read_lock();
1054 orig_node = orig_hash_find(bat_priv, icmp_packet->dst); 1059 orig_node = orig_hash_find(bat_priv, icmp_packet->dst);
1055
1056 if (!orig_node) 1060 if (!orig_node)
1057 goto unlock; 1061 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 1062
1069 rcu_read_unlock(); 1063 router = orig_node_get_router(orig_node);
1064 if (!router)
1065 goto out;
1070 1066
1071 /* create a copy of the skb, if needed, to modify it. */ 1067 /* create a copy of the skb, if needed, to modify it. */
1072 if (skb_cow(skb, sizeof(struct ethhdr)) < 0) 1068 if (skb_cow(skb, sizeof(struct ethhdr)) < 0)
@@ -1078,15 +1074,12 @@ int recv_icmp_packet(struct sk_buff *skb, struct hard_iface *recv_if)
1078 icmp_packet->ttl--; 1074 icmp_packet->ttl--;
1079 1075
1080 /* route it */ 1076 /* route it */
1081 send_skb_packet(skb, neigh_node->if_incoming, neigh_node->addr); 1077 send_skb_packet(skb, router->if_incoming, router->addr);
1082 ret = NET_RX_SUCCESS; 1078 ret = NET_RX_SUCCESS;
1083 goto out;
1084 1079
1085unlock:
1086 rcu_read_unlock();
1087out: 1080out:
1088 if (neigh_node) 1081 if (router)
1089 neigh_node_free_ref(neigh_node); 1082 neigh_node_free_ref(router);
1090 if (orig_node) 1083 if (orig_node)
1091 orig_node_free_ref(orig_node); 1084 orig_node_free_ref(orig_node);
1092 return ret; 1085 return ret;
@@ -1208,7 +1201,8 @@ struct neigh_node *find_router(struct bat_priv *bat_priv,
1208 if (!orig_node) 1201 if (!orig_node)
1209 return NULL; 1202 return NULL;
1210 1203
1211 if (!orig_node->router) 1204 router = orig_node_get_router(orig_node);
1205 if (!router)
1212 return NULL; 1206 return NULL;
1213 1207
1214 /* without bonding, the first node should 1208 /* without bonding, the first node should
@@ -1217,9 +1211,8 @@ struct neigh_node *find_router(struct bat_priv *bat_priv,
1217 1211
1218 rcu_read_lock(); 1212 rcu_read_lock();
1219 /* select default router to output */ 1213 /* select default router to output */
1220 router = orig_node->router; 1214 router_orig = router->orig_node;
1221 router_orig = orig_node->router->orig_node; 1215 if (!router_orig) {
1222 if (!router_orig || !atomic_inc_not_zero(&router->refcount)) {
1223 rcu_read_unlock(); 1216 rcu_read_unlock();
1224 return NULL; 1217 return NULL;
1225 } 1218 }
@@ -1251,7 +1244,6 @@ struct neigh_node *find_router(struct bat_priv *bat_priv,
1251 if (atomic_read(&primary_orig_node->bond_candidates) < 2) 1244 if (atomic_read(&primary_orig_node->bond_candidates) < 2)
1252 goto return_router; 1245 goto return_router;
1253 1246
1254
1255 /* all nodes between should choose a candidate which 1247 /* all nodes between should choose a candidate which
1256 * is is not on the interface where the packet came 1248 * is is not on the interface where the packet came
1257 * in. */ 1249 * in. */
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/types.h b/net/batman-adv/types.h
index 83445cf0cc9f..1854cbb4c1b6 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;
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() */