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