aboutsummaryrefslogtreecommitdiffstats
path: root/net/batman-adv/gateway_client.c
diff options
context:
space:
mode:
authorLinus Torvalds <torvalds@linux-foundation.org>2011-05-20 16:43:21 -0400
committerLinus Torvalds <torvalds@linux-foundation.org>2011-05-20 16:43:21 -0400
commit06f4e926d256d902dd9a53dcb400fd74974ce087 (patch)
tree0b438b67f5f0eff6fd617bc497a9dace6164a488 /net/batman-adv/gateway_client.c
parent8e7bfcbab3825d1b404d615cb1b54f44ff81f981 (diff)
parentd93515611bbc70c2fe4db232e5feb448ed8e4cc9 (diff)
Merge git://git.kernel.org/pub/scm/linux/kernel/git/davem/net-next-2.6
* git://git.kernel.org/pub/scm/linux/kernel/git/davem/net-next-2.6: (1446 commits) macvlan: fix panic if lowerdev in a bond tg3: Add braces around 5906 workaround. tg3: Fix NETIF_F_LOOPBACK error macvlan: remove one synchronize_rcu() call networking: NET_CLS_ROUTE4 depends on INET irda: Fix error propagation in ircomm_lmp_connect_response() irda: Kill set but unused variable 'bytes' in irlan_check_command_param() irda: Kill set but unused variable 'clen' in ircomm_connect_indication() rxrpc: Fix set but unused variable 'usage' in rxrpc_get_transport() be2net: Kill set but unused variable 'req' in lancer_fw_download() irda: Kill set but unused vars 'saddr' and 'daddr' in irlan_provider_connect_indication() atl1c: atl1c_resume() is only used when CONFIG_PM_SLEEP is defined. rxrpc: Fix set but unused variable 'usage' in rxrpc_get_peer(). rxrpc: Kill set but unused variable 'local' in rxrpc_UDP_error_handler() rxrpc: Kill set but unused variable 'sp' in rxrpc_process_connection() rxrpc: Kill set but unused variable 'sp' in rxrpc_rotate_tx_window() pkt_sched: Kill set but unused variable 'protocol' in tc_classify() isdn: capi: Use pr_debug() instead of ifdefs. tg3: Update version to 3.119 tg3: Apply rx_discards fix to 5719/5720 ... Fix up trivial conflicts in arch/x86/Kconfig and net/mac80211/agg-tx.c as per Davem.
Diffstat (limited to 'net/batman-adv/gateway_client.c')
-rw-r--r--net/batman-adv/gateway_client.c296
1 files changed, 174 insertions, 122 deletions
diff --git a/net/batman-adv/gateway_client.c b/net/batman-adv/gateway_client.c
index 150b6ce23df3..61605a0f3f39 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>
@@ -34,61 +35,76 @@ static void gw_node_free_ref(struct gw_node *gw_node)
34 kfree_rcu(gw_node, rcu); 35 kfree_rcu(gw_node, rcu);
35} 36}
36 37
37void *gw_get_selected(struct bat_priv *bat_priv) 38static struct gw_node *gw_get_selected_gw_node(struct bat_priv *bat_priv)
38{ 39{
39 struct gw_node *curr_gateway_tmp; 40 struct gw_node *gw_node;
40 struct orig_node *orig_node = NULL;
41 41
42 rcu_read_lock(); 42 rcu_read_lock();
43 curr_gateway_tmp = rcu_dereference(bat_priv->curr_gw); 43 gw_node = rcu_dereference(bat_priv->curr_gw);
44 if (!curr_gateway_tmp) 44 if (!gw_node)
45 goto out;
46
47 orig_node = curr_gateway_tmp->orig_node;
48 if (!orig_node)
49 goto out; 45 goto out;
50 46
51 if (!atomic_inc_not_zero(&orig_node->refcount)) 47 if (!atomic_inc_not_zero(&gw_node->refcount))
52 orig_node = NULL; 48 gw_node = NULL;
53 49
54out: 50out:
55 rcu_read_unlock(); 51 rcu_read_unlock();
56 return orig_node; 52 return gw_node;
57} 53}
58 54
59void gw_deselect(struct bat_priv *bat_priv) 55struct orig_node *gw_get_selected_orig(struct bat_priv *bat_priv)
60{ 56{
61 struct gw_node *gw_node; 57 struct gw_node *gw_node;
58 struct orig_node *orig_node = NULL;
62 59
63 spin_lock_bh(&bat_priv->gw_list_lock); 60 gw_node = gw_get_selected_gw_node(bat_priv);
64 gw_node = rcu_dereference(bat_priv->curr_gw); 61 if (!gw_node)
65 rcu_assign_pointer(bat_priv->curr_gw, NULL); 62 goto out;
66 spin_unlock_bh(&bat_priv->gw_list_lock); 63
64 rcu_read_lock();
65 orig_node = gw_node->orig_node;
66 if (!orig_node)
67 goto unlock;
68
69 if (!atomic_inc_not_zero(&orig_node->refcount))
70 orig_node = NULL;
67 71
72unlock:
73 rcu_read_unlock();
74out:
68 if (gw_node) 75 if (gw_node)
69 gw_node_free_ref(gw_node); 76 gw_node_free_ref(gw_node);
77 return orig_node;
70} 78}
71 79
72static void gw_select(struct bat_priv *bat_priv, struct gw_node *new_gw_node) 80static void gw_select(struct bat_priv *bat_priv, struct gw_node *new_gw_node)
73{ 81{
74 struct gw_node *curr_gw_node; 82 struct gw_node *curr_gw_node;
75 83
84 spin_lock_bh(&bat_priv->gw_list_lock);
85
76 if (new_gw_node && !atomic_inc_not_zero(&new_gw_node->refcount)) 86 if (new_gw_node && !atomic_inc_not_zero(&new_gw_node->refcount))
77 new_gw_node = NULL; 87 new_gw_node = NULL;
78 88
79 spin_lock_bh(&bat_priv->gw_list_lock); 89 curr_gw_node = bat_priv->curr_gw;
80 curr_gw_node = rcu_dereference(bat_priv->curr_gw);
81 rcu_assign_pointer(bat_priv->curr_gw, new_gw_node); 90 rcu_assign_pointer(bat_priv->curr_gw, new_gw_node);
82 spin_unlock_bh(&bat_priv->gw_list_lock);
83 91
84 if (curr_gw_node) 92 if (curr_gw_node)
85 gw_node_free_ref(curr_gw_node); 93 gw_node_free_ref(curr_gw_node);
94
95 spin_unlock_bh(&bat_priv->gw_list_lock);
96}
97
98void gw_deselect(struct bat_priv *bat_priv)
99{
100 gw_select(bat_priv, NULL);
86} 101}
87 102
88void gw_election(struct bat_priv *bat_priv) 103void gw_election(struct bat_priv *bat_priv)
89{ 104{
90 struct hlist_node *node; 105 struct hlist_node *node;
91 struct gw_node *gw_node, *curr_gw, *curr_gw_tmp = NULL; 106 struct gw_node *gw_node, *curr_gw = NULL, *curr_gw_tmp = NULL;
107 struct neigh_node *router;
92 uint8_t max_tq = 0; 108 uint8_t max_tq = 0;
93 uint32_t max_gw_factor = 0, tmp_gw_factor = 0; 109 uint32_t max_gw_factor = 0, tmp_gw_factor = 0;
94 int down, up; 110 int down, up;
@@ -102,32 +118,25 @@ void gw_election(struct bat_priv *bat_priv)
102 if (atomic_read(&bat_priv->gw_mode) != GW_MODE_CLIENT) 118 if (atomic_read(&bat_priv->gw_mode) != GW_MODE_CLIENT)
103 return; 119 return;
104 120
105 rcu_read_lock(); 121 curr_gw = gw_get_selected_gw_node(bat_priv);
106 curr_gw = rcu_dereference(bat_priv->curr_gw); 122 if (curr_gw)
107 if (curr_gw) { 123 goto out;
108 rcu_read_unlock();
109 return;
110 }
111 124
125 rcu_read_lock();
112 if (hlist_empty(&bat_priv->gw_list)) { 126 if (hlist_empty(&bat_priv->gw_list)) {
113 127 bat_dbg(DBG_BATMAN, bat_priv,
114 if (curr_gw) { 128 "Removing selected gateway - "
115 rcu_read_unlock(); 129 "no gateway in range\n");
116 bat_dbg(DBG_BATMAN, bat_priv, 130 gw_deselect(bat_priv);
117 "Removing selected gateway - " 131 goto unlock;
118 "no gateway in range\n");
119 gw_deselect(bat_priv);
120 } else
121 rcu_read_unlock();
122
123 return;
124 } 132 }
125 133
126 hlist_for_each_entry_rcu(gw_node, node, &bat_priv->gw_list, list) { 134 hlist_for_each_entry_rcu(gw_node, node, &bat_priv->gw_list, list) {
127 if (!gw_node->orig_node->router) 135 if (gw_node->deleted)
128 continue; 136 continue;
129 137
130 if (gw_node->deleted) 138 router = orig_node_get_router(gw_node->orig_node);
139 if (!router)
131 continue; 140 continue;
132 141
133 switch (atomic_read(&bat_priv->gw_sel_class)) { 142 switch (atomic_read(&bat_priv->gw_sel_class)) {
@@ -135,15 +144,14 @@ void gw_election(struct bat_priv *bat_priv)
135 gw_bandwidth_to_kbit(gw_node->orig_node->gw_flags, 144 gw_bandwidth_to_kbit(gw_node->orig_node->gw_flags,
136 &down, &up); 145 &down, &up);
137 146
138 tmp_gw_factor = (gw_node->orig_node->router->tq_avg * 147 tmp_gw_factor = (router->tq_avg * router->tq_avg *
139 gw_node->orig_node->router->tq_avg *
140 down * 100 * 100) / 148 down * 100 * 100) /
141 (TQ_LOCAL_WINDOW_SIZE * 149 (TQ_LOCAL_WINDOW_SIZE *
142 TQ_LOCAL_WINDOW_SIZE * 64); 150 TQ_LOCAL_WINDOW_SIZE * 64);
143 151
144 if ((tmp_gw_factor > max_gw_factor) || 152 if ((tmp_gw_factor > max_gw_factor) ||
145 ((tmp_gw_factor == max_gw_factor) && 153 ((tmp_gw_factor == max_gw_factor) &&
146 (gw_node->orig_node->router->tq_avg > max_tq))) 154 (router->tq_avg > max_tq)))
147 curr_gw_tmp = gw_node; 155 curr_gw_tmp = gw_node;
148 break; 156 break;
149 157
@@ -155,19 +163,25 @@ void gw_election(struct bat_priv *bat_priv)
155 * soon as a better gateway appears which has 163 * soon as a better gateway appears which has
156 * $routing_class more tq points) 164 * $routing_class more tq points)
157 **/ 165 **/
158 if (gw_node->orig_node->router->tq_avg > max_tq) 166 if (router->tq_avg > max_tq)
159 curr_gw_tmp = gw_node; 167 curr_gw_tmp = gw_node;
160 break; 168 break;
161 } 169 }
162 170
163 if (gw_node->orig_node->router->tq_avg > max_tq) 171 if (router->tq_avg > max_tq)
164 max_tq = gw_node->orig_node->router->tq_avg; 172 max_tq = router->tq_avg;
165 173
166 if (tmp_gw_factor > max_gw_factor) 174 if (tmp_gw_factor > max_gw_factor)
167 max_gw_factor = tmp_gw_factor; 175 max_gw_factor = tmp_gw_factor;
176
177 neigh_node_free_ref(router);
168 } 178 }
169 179
170 if (curr_gw != curr_gw_tmp) { 180 if (curr_gw != curr_gw_tmp) {
181 router = orig_node_get_router(curr_gw_tmp->orig_node);
182 if (!router)
183 goto unlock;
184
171 if ((curr_gw) && (!curr_gw_tmp)) 185 if ((curr_gw) && (!curr_gw_tmp))
172 bat_dbg(DBG_BATMAN, bat_priv, 186 bat_dbg(DBG_BATMAN, bat_priv,
173 "Removing selected gateway - " 187 "Removing selected gateway - "
@@ -178,48 +192,50 @@ void gw_election(struct bat_priv *bat_priv)
178 "(gw_flags: %i, tq: %i)\n", 192 "(gw_flags: %i, tq: %i)\n",
179 curr_gw_tmp->orig_node->orig, 193 curr_gw_tmp->orig_node->orig,
180 curr_gw_tmp->orig_node->gw_flags, 194 curr_gw_tmp->orig_node->gw_flags,
181 curr_gw_tmp->orig_node->router->tq_avg); 195 router->tq_avg);
182 else 196 else
183 bat_dbg(DBG_BATMAN, bat_priv, 197 bat_dbg(DBG_BATMAN, bat_priv,
184 "Changing route to gateway %pM " 198 "Changing route to gateway %pM "
185 "(gw_flags: %i, tq: %i)\n", 199 "(gw_flags: %i, tq: %i)\n",
186 curr_gw_tmp->orig_node->orig, 200 curr_gw_tmp->orig_node->orig,
187 curr_gw_tmp->orig_node->gw_flags, 201 curr_gw_tmp->orig_node->gw_flags,
188 curr_gw_tmp->orig_node->router->tq_avg); 202 router->tq_avg);
189 203
204 neigh_node_free_ref(router);
190 gw_select(bat_priv, curr_gw_tmp); 205 gw_select(bat_priv, curr_gw_tmp);
191 } 206 }
192 207
208unlock:
193 rcu_read_unlock(); 209 rcu_read_unlock();
210out:
211 if (curr_gw)
212 gw_node_free_ref(curr_gw);
194} 213}
195 214
196void gw_check_election(struct bat_priv *bat_priv, struct orig_node *orig_node) 215void gw_check_election(struct bat_priv *bat_priv, struct orig_node *orig_node)
197{ 216{
198 struct gw_node *curr_gateway_tmp; 217 struct orig_node *curr_gw_orig;
218 struct neigh_node *router_gw = NULL, *router_orig = NULL;
199 uint8_t gw_tq_avg, orig_tq_avg; 219 uint8_t gw_tq_avg, orig_tq_avg;
200 220
201 rcu_read_lock(); 221 curr_gw_orig = gw_get_selected_orig(bat_priv);
202 curr_gateway_tmp = rcu_dereference(bat_priv->curr_gw); 222 if (!curr_gw_orig)
203 if (!curr_gateway_tmp) 223 goto deselect;
204 goto out_rcu;
205
206 if (!curr_gateway_tmp->orig_node)
207 goto deselect_rcu;
208 224
209 if (!curr_gateway_tmp->orig_node->router) 225 router_gw = orig_node_get_router(curr_gw_orig);
210 goto deselect_rcu; 226 if (!router_gw)
227 goto deselect;
211 228
212 /* this node already is the gateway */ 229 /* this node already is the gateway */
213 if (curr_gateway_tmp->orig_node == orig_node) 230 if (curr_gw_orig == orig_node)
214 goto out_rcu; 231 goto out;
215
216 if (!orig_node->router)
217 goto out_rcu;
218 232
219 gw_tq_avg = curr_gateway_tmp->orig_node->router->tq_avg; 233 router_orig = orig_node_get_router(orig_node);
220 rcu_read_unlock(); 234 if (!router_orig)
235 goto out;
221 236
222 orig_tq_avg = orig_node->router->tq_avg; 237 gw_tq_avg = router_gw->tq_avg;
238 orig_tq_avg = router_orig->tq_avg;
223 239
224 /* the TQ value has to be better */ 240 /* the TQ value has to be better */
225 if (orig_tq_avg < gw_tq_avg) 241 if (orig_tq_avg < gw_tq_avg)
@@ -237,16 +253,17 @@ void gw_check_election(struct bat_priv *bat_priv, struct orig_node *orig_node)
237 "Restarting gateway selection: better gateway found (tq curr: " 253 "Restarting gateway selection: better gateway found (tq curr: "
238 "%i, tq new: %i)\n", 254 "%i, tq new: %i)\n",
239 gw_tq_avg, orig_tq_avg); 255 gw_tq_avg, orig_tq_avg);
240 goto deselect;
241 256
242out_rcu:
243 rcu_read_unlock();
244 goto out;
245deselect_rcu:
246 rcu_read_unlock();
247deselect: 257deselect:
248 gw_deselect(bat_priv); 258 gw_deselect(bat_priv);
249out: 259out:
260 if (curr_gw_orig)
261 orig_node_free_ref(curr_gw_orig);
262 if (router_gw)
263 neigh_node_free_ref(router_gw);
264 if (router_orig)
265 neigh_node_free_ref(router_orig);
266
250 return; 267 return;
251} 268}
252 269
@@ -283,7 +300,15 @@ void gw_node_update(struct bat_priv *bat_priv,
283 struct orig_node *orig_node, uint8_t new_gwflags) 300 struct orig_node *orig_node, uint8_t new_gwflags)
284{ 301{
285 struct hlist_node *node; 302 struct hlist_node *node;
286 struct gw_node *gw_node; 303 struct gw_node *gw_node, *curr_gw;
304
305 /**
306 * Note: We don't need a NULL check here, since curr_gw never gets
307 * dereferenced. If curr_gw is NULL we also should not exit as we may
308 * have this gateway in our list (duplication check!) even though we
309 * have no currently selected gateway.
310 */
311 curr_gw = gw_get_selected_gw_node(bat_priv);
287 312
288 rcu_read_lock(); 313 rcu_read_lock();
289 hlist_for_each_entry_rcu(gw_node, node, &bat_priv->gw_list, list) { 314 hlist_for_each_entry_rcu(gw_node, node, &bat_priv->gw_list, list) {
@@ -304,22 +329,26 @@ void gw_node_update(struct bat_priv *bat_priv,
304 "Gateway %pM removed from gateway list\n", 329 "Gateway %pM removed from gateway list\n",
305 orig_node->orig); 330 orig_node->orig);
306 331
307 if (gw_node == rcu_dereference(bat_priv->curr_gw)) { 332 if (gw_node == curr_gw)
308 rcu_read_unlock(); 333 goto deselect;
309 gw_deselect(bat_priv);
310 return;
311 }
312 } 334 }
313 335
314 rcu_read_unlock(); 336 goto unlock;
315 return;
316 } 337 }
317 rcu_read_unlock();
318 338
319 if (new_gwflags == 0) 339 if (new_gwflags == 0)
320 return; 340 goto unlock;
321 341
322 gw_node_add(bat_priv, orig_node, new_gwflags); 342 gw_node_add(bat_priv, orig_node, new_gwflags);
343 goto unlock;
344
345deselect:
346 gw_deselect(bat_priv);
347unlock:
348 rcu_read_unlock();
349
350 if (curr_gw)
351 gw_node_free_ref(curr_gw);
323} 352}
324 353
325void gw_node_delete(struct bat_priv *bat_priv, struct orig_node *orig_node) 354void gw_node_delete(struct bat_priv *bat_priv, struct orig_node *orig_node)
@@ -329,9 +358,12 @@ void gw_node_delete(struct bat_priv *bat_priv, struct orig_node *orig_node)
329 358
330void gw_node_purge(struct bat_priv *bat_priv) 359void gw_node_purge(struct bat_priv *bat_priv)
331{ 360{
332 struct gw_node *gw_node; 361 struct gw_node *gw_node, *curr_gw;
333 struct hlist_node *node, *node_tmp; 362 struct hlist_node *node, *node_tmp;
334 unsigned long timeout = 2 * PURGE_TIMEOUT * HZ; 363 unsigned long timeout = 2 * PURGE_TIMEOUT * HZ;
364 char do_deselect = 0;
365
366 curr_gw = gw_get_selected_gw_node(bat_priv);
335 367
336 spin_lock_bh(&bat_priv->gw_list_lock); 368 spin_lock_bh(&bat_priv->gw_list_lock);
337 369
@@ -342,41 +374,56 @@ void gw_node_purge(struct bat_priv *bat_priv)
342 atomic_read(&bat_priv->mesh_state) == MESH_ACTIVE) 374 atomic_read(&bat_priv->mesh_state) == MESH_ACTIVE)
343 continue; 375 continue;
344 376
345 if (rcu_dereference(bat_priv->curr_gw) == gw_node) 377 if (curr_gw == gw_node)
346 gw_deselect(bat_priv); 378 do_deselect = 1;
347 379
348 hlist_del_rcu(&gw_node->list); 380 hlist_del_rcu(&gw_node->list);
349 gw_node_free_ref(gw_node); 381 gw_node_free_ref(gw_node);
350 } 382 }
351 383
352
353 spin_unlock_bh(&bat_priv->gw_list_lock); 384 spin_unlock_bh(&bat_priv->gw_list_lock);
385
386 /* gw_deselect() needs to acquire the gw_list_lock */
387 if (do_deselect)
388 gw_deselect(bat_priv);
389
390 if (curr_gw)
391 gw_node_free_ref(curr_gw);
354} 392}
355 393
394/**
395 * fails if orig_node has no router
396 */
356static int _write_buffer_text(struct bat_priv *bat_priv, 397static int _write_buffer_text(struct bat_priv *bat_priv,
357 struct seq_file *seq, struct gw_node *gw_node) 398 struct seq_file *seq, struct gw_node *gw_node)
358{ 399{
359 struct gw_node *curr_gw; 400 struct gw_node *curr_gw;
360 int down, up, ret; 401 struct neigh_node *router;
402 int down, up, ret = -1;
361 403
362 gw_bandwidth_to_kbit(gw_node->orig_node->gw_flags, &down, &up); 404 gw_bandwidth_to_kbit(gw_node->orig_node->gw_flags, &down, &up);
363 405
364 rcu_read_lock(); 406 router = orig_node_get_router(gw_node->orig_node);
365 curr_gw = rcu_dereference(bat_priv->curr_gw); 407 if (!router)
408 goto out;
366 409
367 ret = seq_printf(seq, "%s %pM (%3i) %pM [%10s]: %3i - %i%s/%i%s\n", 410 curr_gw = gw_get_selected_gw_node(bat_priv);
368 (curr_gw == gw_node ? "=>" : " "),
369 gw_node->orig_node->orig,
370 gw_node->orig_node->router->tq_avg,
371 gw_node->orig_node->router->addr,
372 gw_node->orig_node->router->if_incoming->net_dev->name,
373 gw_node->orig_node->gw_flags,
374 (down > 2048 ? down / 1024 : down),
375 (down > 2048 ? "MBit" : "KBit"),
376 (up > 2048 ? up / 1024 : up),
377 (up > 2048 ? "MBit" : "KBit"));
378 411
379 rcu_read_unlock(); 412 ret = seq_printf(seq, "%s %pM (%3i) %pM [%10s]: %3i - %i%s/%i%s\n",
413 (curr_gw == gw_node ? "=>" : " "),
414 gw_node->orig_node->orig,
415 router->tq_avg, router->addr,
416 router->if_incoming->net_dev->name,
417 gw_node->orig_node->gw_flags,
418 (down > 2048 ? down / 1024 : down),
419 (down > 2048 ? "MBit" : "KBit"),
420 (up > 2048 ? up / 1024 : up),
421 (up > 2048 ? "MBit" : "KBit"));
422
423 neigh_node_free_ref(router);
424 if (curr_gw)
425 gw_node_free_ref(curr_gw);
426out:
380 return ret; 427 return ret;
381} 428}
382 429
@@ -384,40 +431,42 @@ int gw_client_seq_print_text(struct seq_file *seq, void *offset)
384{ 431{
385 struct net_device *net_dev = (struct net_device *)seq->private; 432 struct net_device *net_dev = (struct net_device *)seq->private;
386 struct bat_priv *bat_priv = netdev_priv(net_dev); 433 struct bat_priv *bat_priv = netdev_priv(net_dev);
434 struct hard_iface *primary_if;
387 struct gw_node *gw_node; 435 struct gw_node *gw_node;
388 struct hlist_node *node; 436 struct hlist_node *node;
389 int gw_count = 0; 437 int gw_count = 0, ret = 0;
390
391 if (!bat_priv->primary_if) {
392 438
393 return seq_printf(seq, "BATMAN mesh %s disabled - please " 439 primary_if = primary_if_get_selected(bat_priv);
394 "specify interfaces to enable it\n", 440 if (!primary_if) {
395 net_dev->name); 441 ret = seq_printf(seq, "BATMAN mesh %s disabled - please "
442 "specify interfaces to enable it\n",
443 net_dev->name);
444 goto out;
396 } 445 }
397 446
398 if (bat_priv->primary_if->if_status != IF_ACTIVE) { 447 if (primary_if->if_status != IF_ACTIVE) {
399 448 ret = seq_printf(seq, "BATMAN mesh %s disabled - "
400 return seq_printf(seq, "BATMAN mesh %s disabled - " 449 "primary interface not active\n",
401 "primary interface not active\n", 450 net_dev->name);
402 net_dev->name); 451 goto out;
403 } 452 }
404 453
405 seq_printf(seq, " %-12s (%s/%i) %17s [%10s]: gw_class ... " 454 seq_printf(seq, " %-12s (%s/%i) %17s [%10s]: gw_class ... "
406 "[B.A.T.M.A.N. adv %s%s, MainIF/MAC: %s/%pM (%s)]\n", 455 "[B.A.T.M.A.N. adv %s%s, MainIF/MAC: %s/%pM (%s)]\n",
407 "Gateway", "#", TQ_MAX_VALUE, "Nexthop", 456 "Gateway", "#", TQ_MAX_VALUE, "Nexthop",
408 "outgoingIF", SOURCE_VERSION, REVISION_VERSION_STR, 457 "outgoingIF", SOURCE_VERSION, REVISION_VERSION_STR,
409 bat_priv->primary_if->net_dev->name, 458 primary_if->net_dev->name,
410 bat_priv->primary_if->net_dev->dev_addr, net_dev->name); 459 primary_if->net_dev->dev_addr, net_dev->name);
411 460
412 rcu_read_lock(); 461 rcu_read_lock();
413 hlist_for_each_entry_rcu(gw_node, node, &bat_priv->gw_list, list) { 462 hlist_for_each_entry_rcu(gw_node, node, &bat_priv->gw_list, list) {
414 if (gw_node->deleted) 463 if (gw_node->deleted)
415 continue; 464 continue;
416 465
417 if (!gw_node->orig_node->router) 466 /* fails if orig_node has no router */
467 if (_write_buffer_text(bat_priv, seq, gw_node) < 0)
418 continue; 468 continue;
419 469
420 _write_buffer_text(bat_priv, seq, gw_node);
421 gw_count++; 470 gw_count++;
422 } 471 }
423 rcu_read_unlock(); 472 rcu_read_unlock();
@@ -425,7 +474,10 @@ int gw_client_seq_print_text(struct seq_file *seq, void *offset)
425 if (gw_count == 0) 474 if (gw_count == 0)
426 seq_printf(seq, "No gateways in range ...\n"); 475 seq_printf(seq, "No gateways in range ...\n");
427 476
428 return 0; 477out:
478 if (primary_if)
479 hardif_free_ref(primary_if);
480 return ret;
429} 481}
430 482
431int gw_is_target(struct bat_priv *bat_priv, struct sk_buff *skb) 483int gw_is_target(struct bat_priv *bat_priv, struct sk_buff *skb)
@@ -434,6 +486,7 @@ int gw_is_target(struct bat_priv *bat_priv, struct sk_buff *skb)
434 struct iphdr *iphdr; 486 struct iphdr *iphdr;
435 struct ipv6hdr *ipv6hdr; 487 struct ipv6hdr *ipv6hdr;
436 struct udphdr *udphdr; 488 struct udphdr *udphdr;
489 struct gw_node *curr_gw;
437 unsigned int header_len = 0; 490 unsigned int header_len = 0;
438 491
439 if (atomic_read(&bat_priv->gw_mode) == GW_MODE_OFF) 492 if (atomic_read(&bat_priv->gw_mode) == GW_MODE_OFF)
@@ -498,12 +551,11 @@ int gw_is_target(struct bat_priv *bat_priv, struct sk_buff *skb)
498 if (atomic_read(&bat_priv->gw_mode) == GW_MODE_SERVER) 551 if (atomic_read(&bat_priv->gw_mode) == GW_MODE_SERVER)
499 return -1; 552 return -1;
500 553
501 rcu_read_lock(); 554 curr_gw = gw_get_selected_gw_node(bat_priv);
502 if (!rcu_dereference(bat_priv->curr_gw)) { 555 if (!curr_gw)
503 rcu_read_unlock();
504 return 0; 556 return 0;
505 }
506 rcu_read_unlock();
507 557
558 if (curr_gw)
559 gw_node_free_ref(curr_gw);
508 return 1; 560 return 1;
509} 561}