aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--net/batman-adv/routing.c40
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
262unlock:
263 rcu_read_unlock();
264out:
265 if (neigh_node)
266 kref_put(&neigh_node->refcount, neigh_node_free_ref);
267 return ret;
256} 268}
257 269
258static void update_orig(struct bat_priv *bat_priv, 270static 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
377unlock:
378 rcu_read_unlock();
379out:
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.