diff options
-rw-r--r-- | net/batman-adv/routing.c | 40 |
1 files changed, 31 insertions, 9 deletions
diff --git a/net/batman-adv/routing.c b/net/batman-adv/routing.c index 97f321615686..c15e6c1c20b5 100644 --- a/net/batman-adv/routing.c +++ b/net/batman-adv/routing.c | |||
@@ -151,6 +151,7 @@ static int is_bidirectional_neigh(struct orig_node *orig_node, | |||
151 | struct neigh_node *neigh_node = NULL, *tmp_neigh_node = NULL; | 151 | struct neigh_node *neigh_node = NULL, *tmp_neigh_node = NULL; |
152 | struct hlist_node *node; | 152 | struct hlist_node *node; |
153 | unsigned char total_count; | 153 | unsigned char total_count; |
154 | int ret = 0; | ||
154 | 155 | ||
155 | if (orig_node == orig_neigh_node) { | 156 | if (orig_node == orig_neigh_node) { |
156 | rcu_read_lock(); | 157 | rcu_read_lock(); |
@@ -162,7 +163,6 @@ static int is_bidirectional_neigh(struct orig_node *orig_node, | |||
162 | (tmp_neigh_node->if_incoming == if_incoming)) | 163 | (tmp_neigh_node->if_incoming == if_incoming)) |
163 | neigh_node = tmp_neigh_node; | 164 | neigh_node = tmp_neigh_node; |
164 | } | 165 | } |
165 | rcu_read_unlock(); | ||
166 | 166 | ||
167 | if (!neigh_node) | 167 | if (!neigh_node) |
168 | neigh_node = create_neighbor(orig_node, | 168 | neigh_node = create_neighbor(orig_node, |
@@ -171,7 +171,10 @@ static int is_bidirectional_neigh(struct orig_node *orig_node, | |||
171 | if_incoming); | 171 | if_incoming); |
172 | /* create_neighbor failed, return 0 */ | 172 | /* create_neighbor failed, return 0 */ |
173 | if (!neigh_node) | 173 | if (!neigh_node) |
174 | return 0; | 174 | goto unlock; |
175 | |||
176 | kref_get(&neigh_node->refcount); | ||
177 | rcu_read_unlock(); | ||
175 | 178 | ||
176 | neigh_node->last_valid = jiffies; | 179 | neigh_node->last_valid = jiffies; |
177 | } else { | 180 | } else { |
@@ -185,7 +188,6 @@ static int is_bidirectional_neigh(struct orig_node *orig_node, | |||
185 | (tmp_neigh_node->if_incoming == if_incoming)) | 188 | (tmp_neigh_node->if_incoming == if_incoming)) |
186 | neigh_node = tmp_neigh_node; | 189 | neigh_node = tmp_neigh_node; |
187 | } | 190 | } |
188 | rcu_read_unlock(); | ||
189 | 191 | ||
190 | if (!neigh_node) | 192 | if (!neigh_node) |
191 | neigh_node = create_neighbor(orig_neigh_node, | 193 | neigh_node = create_neighbor(orig_neigh_node, |
@@ -194,7 +196,10 @@ static int is_bidirectional_neigh(struct orig_node *orig_node, | |||
194 | if_incoming); | 196 | if_incoming); |
195 | /* create_neighbor failed, return 0 */ | 197 | /* create_neighbor failed, return 0 */ |
196 | if (!neigh_node) | 198 | if (!neigh_node) |
197 | return 0; | 199 | goto unlock; |
200 | |||
201 | kref_get(&neigh_node->refcount); | ||
202 | rcu_read_unlock(); | ||
198 | } | 203 | } |
199 | 204 | ||
200 | orig_node->last_valid = jiffies; | 205 | orig_node->last_valid = jiffies; |
@@ -250,9 +255,16 @@ static int is_bidirectional_neigh(struct orig_node *orig_node, | |||
250 | /* if link has the minimum required transmission quality | 255 | /* if link has the minimum required transmission quality |
251 | * consider it bidirectional */ | 256 | * consider it bidirectional */ |
252 | if (batman_packet->tq >= TQ_TOTAL_BIDRECT_LIMIT) | 257 | if (batman_packet->tq >= TQ_TOTAL_BIDRECT_LIMIT) |
253 | return 1; | 258 | ret = 1; |
254 | 259 | ||
255 | return 0; | 260 | goto out; |
261 | |||
262 | unlock: | ||
263 | rcu_read_unlock(); | ||
264 | out: | ||
265 | if (neigh_node) | ||
266 | kref_put(&neigh_node->refcount, neigh_node_free_ref); | ||
267 | return ret; | ||
256 | } | 268 | } |
257 | 269 | ||
258 | static void update_orig(struct bat_priv *bat_priv, | 270 | static void update_orig(struct bat_priv *bat_priv, |
@@ -287,23 +299,25 @@ static void update_orig(struct bat_priv *bat_priv, | |||
287 | tmp_neigh_node->tq_avg = | 299 | tmp_neigh_node->tq_avg = |
288 | ring_buffer_avg(tmp_neigh_node->tq_recv); | 300 | ring_buffer_avg(tmp_neigh_node->tq_recv); |
289 | } | 301 | } |
290 | rcu_read_unlock(); | ||
291 | 302 | ||
292 | if (!neigh_node) { | 303 | if (!neigh_node) { |
293 | struct orig_node *orig_tmp; | 304 | struct orig_node *orig_tmp; |
294 | 305 | ||
295 | orig_tmp = get_orig_node(bat_priv, ethhdr->h_source); | 306 | orig_tmp = get_orig_node(bat_priv, ethhdr->h_source); |
296 | if (!orig_tmp) | 307 | if (!orig_tmp) |
297 | return; | 308 | goto unlock; |
298 | 309 | ||
299 | neigh_node = create_neighbor(orig_node, orig_tmp, | 310 | neigh_node = create_neighbor(orig_node, orig_tmp, |
300 | ethhdr->h_source, if_incoming); | 311 | ethhdr->h_source, if_incoming); |
301 | if (!neigh_node) | 312 | if (!neigh_node) |
302 | return; | 313 | goto unlock; |
303 | } else | 314 | } else |
304 | bat_dbg(DBG_BATMAN, bat_priv, | 315 | bat_dbg(DBG_BATMAN, bat_priv, |
305 | "Updating existing last-hop neighbor of originator\n"); | 316 | "Updating existing last-hop neighbor of originator\n"); |
306 | 317 | ||
318 | kref_get(&neigh_node->refcount); | ||
319 | rcu_read_unlock(); | ||
320 | |||
307 | orig_node->flags = batman_packet->flags; | 321 | orig_node->flags = batman_packet->flags; |
308 | neigh_node->last_valid = jiffies; | 322 | neigh_node->last_valid = jiffies; |
309 | 323 | ||
@@ -357,6 +371,14 @@ update_gw: | |||
357 | (atomic_read(&bat_priv->gw_mode) == GW_MODE_CLIENT) && | 371 | (atomic_read(&bat_priv->gw_mode) == GW_MODE_CLIENT) && |
358 | (atomic_read(&bat_priv->gw_sel_class) > 2)) | 372 | (atomic_read(&bat_priv->gw_sel_class) > 2)) |
359 | gw_check_election(bat_priv, orig_node); | 373 | gw_check_election(bat_priv, orig_node); |
374 | |||
375 | goto out; | ||
376 | |||
377 | unlock: | ||
378 | rcu_read_unlock(); | ||
379 | out: | ||
380 | if (neigh_node) | ||
381 | kref_put(&neigh_node->refcount, neigh_node_free_ref); | ||
360 | } | 382 | } |
361 | 383 | ||
362 | /* checks whether the host restarted and is in the protection time. | 384 | /* checks whether the host restarted and is in the protection time. |