diff options
author | Linus Torvalds <torvalds@linux-foundation.org> | 2011-05-20 16:43:21 -0400 |
---|---|---|
committer | Linus Torvalds <torvalds@linux-foundation.org> | 2011-05-20 16:43:21 -0400 |
commit | 06f4e926d256d902dd9a53dcb400fd74974ce087 (patch) | |
tree | 0b438b67f5f0eff6fd617bc497a9dace6164a488 /net/batman-adv/gateway_client.c | |
parent | 8e7bfcbab3825d1b404d615cb1b54f44ff81f981 (diff) | |
parent | d93515611bbc70c2fe4db232e5feb448ed8e4cc9 (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.c | 296 |
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 | ||
37 | void *gw_get_selected(struct bat_priv *bat_priv) | 38 | static 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 | ||
54 | out: | 50 | out: |
55 | rcu_read_unlock(); | 51 | rcu_read_unlock(); |
56 | return orig_node; | 52 | return gw_node; |
57 | } | 53 | } |
58 | 54 | ||
59 | void gw_deselect(struct bat_priv *bat_priv) | 55 | struct 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 | ||
72 | unlock: | ||
73 | rcu_read_unlock(); | ||
74 | out: | ||
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 | ||
72 | static void gw_select(struct bat_priv *bat_priv, struct gw_node *new_gw_node) | 80 | static 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 | |||
98 | void gw_deselect(struct bat_priv *bat_priv) | ||
99 | { | ||
100 | gw_select(bat_priv, NULL); | ||
86 | } | 101 | } |
87 | 102 | ||
88 | void gw_election(struct bat_priv *bat_priv) | 103 | void 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 | ||
208 | unlock: | ||
193 | rcu_read_unlock(); | 209 | rcu_read_unlock(); |
210 | out: | ||
211 | if (curr_gw) | ||
212 | gw_node_free_ref(curr_gw); | ||
194 | } | 213 | } |
195 | 214 | ||
196 | void gw_check_election(struct bat_priv *bat_priv, struct orig_node *orig_node) | 215 | void 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 | ||
242 | out_rcu: | ||
243 | rcu_read_unlock(); | ||
244 | goto out; | ||
245 | deselect_rcu: | ||
246 | rcu_read_unlock(); | ||
247 | deselect: | 257 | deselect: |
248 | gw_deselect(bat_priv); | 258 | gw_deselect(bat_priv); |
249 | out: | 259 | out: |
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 | |||
345 | deselect: | ||
346 | gw_deselect(bat_priv); | ||
347 | unlock: | ||
348 | rcu_read_unlock(); | ||
349 | |||
350 | if (curr_gw) | ||
351 | gw_node_free_ref(curr_gw); | ||
323 | } | 352 | } |
324 | 353 | ||
325 | void gw_node_delete(struct bat_priv *bat_priv, struct orig_node *orig_node) | 354 | void 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 | ||
330 | void gw_node_purge(struct bat_priv *bat_priv) | 359 | void 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 | */ | ||
356 | static int _write_buffer_text(struct bat_priv *bat_priv, | 397 | static 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); | ||
426 | out: | ||
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; | 477 | out: |
478 | if (primary_if) | ||
479 | hardif_free_ref(primary_if); | ||
480 | return ret; | ||
429 | } | 481 | } |
430 | 482 | ||
431 | int gw_is_target(struct bat_priv *bat_priv, struct sk_buff *skb) | 483 | int 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 | } |