diff options
author | Marek Lindner <lindner_marek@yahoo.de> | 2011-04-20 09:40:58 -0400 |
---|---|---|
committer | Sven Eckelmann <sven@narfation.org> | 2011-05-01 16:49:03 -0400 |
commit | 32ae9b221e788413ce68feaae2ca39e406211a0a (patch) | |
tree | d827f989976a28fea5cdcb349c308baa98182c35 /net/batman-adv/soft-interface.c | |
parent | 71e4aa9c465fd66c110667ab5d620fb6a4ef2157 (diff) |
batman-adv: Make bat_priv->primary_if an rcu protected pointer
The rcu protected macros rcu_dereference() and rcu_assign_pointer()
for the bat_priv->primary_if need to be used, as well as spin/rcu locking.
Otherwise we might end up using a primary_if pointer pointing to already
freed memory.
Signed-off-by: Marek Lindner <lindner_marek@yahoo.de>
Signed-off-by: Sven Eckelmann <sven@narfation.org>
Diffstat (limited to 'net/batman-adv/soft-interface.c')
-rw-r--r-- | net/batman-adv/soft-interface.c | 64 |
1 files changed, 45 insertions, 19 deletions
diff --git a/net/batman-adv/soft-interface.c b/net/batman-adv/soft-interface.c index 58ce4400d581..ea5e58c252f0 100644 --- a/net/batman-adv/soft-interface.c +++ b/net/batman-adv/soft-interface.c | |||
@@ -215,13 +215,24 @@ int softif_neigh_seq_print_text(struct seq_file *seq, void *offset) | |||
215 | struct net_device *net_dev = (struct net_device *)seq->private; | 215 | struct net_device *net_dev = (struct net_device *)seq->private; |
216 | struct bat_priv *bat_priv = netdev_priv(net_dev); | 216 | struct bat_priv *bat_priv = netdev_priv(net_dev); |
217 | struct softif_neigh *softif_neigh; | 217 | struct softif_neigh *softif_neigh; |
218 | struct hard_iface *primary_if; | ||
218 | struct hlist_node *node; | 219 | struct hlist_node *node; |
219 | struct softif_neigh *curr_softif_neigh; | 220 | struct softif_neigh *curr_softif_neigh; |
221 | int ret = 0; | ||
220 | 222 | ||
221 | if (!bat_priv->primary_if) { | 223 | primary_if = primary_if_get_selected(bat_priv); |
222 | return seq_printf(seq, "BATMAN mesh %s disabled - " | 224 | if (!primary_if) { |
223 | "please specify interfaces to enable it\n", | 225 | ret = seq_printf(seq, "BATMAN mesh %s disabled - " |
224 | net_dev->name); | 226 | "please specify interfaces to enable it\n", |
227 | net_dev->name); | ||
228 | goto out; | ||
229 | } | ||
230 | |||
231 | if (primary_if->if_status != IF_ACTIVE) { | ||
232 | ret = seq_printf(seq, "BATMAN mesh %s " | ||
233 | "disabled - primary interface not active\n", | ||
234 | net_dev->name); | ||
235 | goto out; | ||
225 | } | 236 | } |
226 | 237 | ||
227 | seq_printf(seq, "Softif neighbor list (%s)\n", net_dev->name); | 238 | seq_printf(seq, "Softif neighbor list (%s)\n", net_dev->name); |
@@ -238,7 +249,10 @@ int softif_neigh_seq_print_text(struct seq_file *seq, void *offset) | |||
238 | if (curr_softif_neigh) | 249 | if (curr_softif_neigh) |
239 | softif_neigh_free_ref(curr_softif_neigh); | 250 | softif_neigh_free_ref(curr_softif_neigh); |
240 | 251 | ||
241 | return 0; | 252 | out: |
253 | if (primary_if) | ||
254 | hardif_free_ref(primary_if); | ||
255 | return ret; | ||
242 | } | 256 | } |
243 | 257 | ||
244 | static void softif_batman_recv(struct sk_buff *skb, struct net_device *dev, | 258 | static void softif_batman_recv(struct sk_buff *skb, struct net_device *dev, |
@@ -247,7 +261,8 @@ static void softif_batman_recv(struct sk_buff *skb, struct net_device *dev, | |||
247 | struct bat_priv *bat_priv = netdev_priv(dev); | 261 | struct bat_priv *bat_priv = netdev_priv(dev); |
248 | struct ethhdr *ethhdr = (struct ethhdr *)skb->data; | 262 | struct ethhdr *ethhdr = (struct ethhdr *)skb->data; |
249 | struct batman_packet *batman_packet; | 263 | struct batman_packet *batman_packet; |
250 | struct softif_neigh *softif_neigh; | 264 | struct softif_neigh *softif_neigh = NULL; |
265 | struct hard_iface *primary_if = NULL; | ||
251 | struct softif_neigh *curr_softif_neigh = NULL; | 266 | struct softif_neigh *curr_softif_neigh = NULL; |
252 | 267 | ||
253 | if (ntohs(ethhdr->h_proto) == ETH_P_8021Q) | 268 | if (ntohs(ethhdr->h_proto) == ETH_P_8021Q) |
@@ -257,28 +272,34 @@ static void softif_batman_recv(struct sk_buff *skb, struct net_device *dev, | |||
257 | batman_packet = (struct batman_packet *)(skb->data + ETH_HLEN); | 272 | batman_packet = (struct batman_packet *)(skb->data + ETH_HLEN); |
258 | 273 | ||
259 | if (batman_packet->version != COMPAT_VERSION) | 274 | if (batman_packet->version != COMPAT_VERSION) |
260 | goto err; | 275 | goto out; |
261 | 276 | ||
262 | if (batman_packet->packet_type != BAT_PACKET) | 277 | if (batman_packet->packet_type != BAT_PACKET) |
263 | goto err; | 278 | goto out; |
264 | 279 | ||
265 | if (!(batman_packet->flags & PRIMARIES_FIRST_HOP)) | 280 | if (!(batman_packet->flags & PRIMARIES_FIRST_HOP)) |
266 | goto err; | 281 | goto out; |
267 | 282 | ||
268 | if (is_my_mac(batman_packet->orig)) | 283 | if (is_my_mac(batman_packet->orig)) |
269 | goto err; | 284 | goto out; |
270 | 285 | ||
271 | softif_neigh = softif_neigh_get(bat_priv, batman_packet->orig, vid); | 286 | softif_neigh = softif_neigh_get(bat_priv, batman_packet->orig, vid); |
272 | |||
273 | if (!softif_neigh) | 287 | if (!softif_neigh) |
274 | goto err; | 288 | goto out; |
275 | 289 | ||
276 | curr_softif_neigh = softif_neigh_get_selected(bat_priv); | 290 | curr_softif_neigh = softif_neigh_get_selected(bat_priv); |
291 | if (!curr_softif_neigh) | ||
292 | goto out; | ||
293 | |||
277 | if (curr_softif_neigh == softif_neigh) | 294 | if (curr_softif_neigh == softif_neigh) |
278 | goto out; | 295 | goto out; |
279 | 296 | ||
297 | primary_if = primary_if_get_selected(bat_priv); | ||
298 | if (!primary_if) | ||
299 | goto out; | ||
300 | |||
280 | /* we got a neighbor but its mac is 'bigger' than ours */ | 301 | /* we got a neighbor but its mac is 'bigger' than ours */ |
281 | if (memcmp(bat_priv->primary_if->net_dev->dev_addr, | 302 | if (memcmp(primary_if->net_dev->dev_addr, |
282 | softif_neigh->addr, ETH_ALEN) < 0) | 303 | softif_neigh->addr, ETH_ALEN) < 0) |
283 | goto out; | 304 | goto out; |
284 | 305 | ||
@@ -300,7 +321,7 @@ static void softif_batman_recv(struct sk_buff *skb, struct net_device *dev, | |||
300 | /* close own batX device and use softif_neigh as exit node */ | 321 | /* close own batX device and use softif_neigh as exit node */ |
301 | if ((!curr_softif_neigh) && | 322 | if ((!curr_softif_neigh) && |
302 | (memcmp(softif_neigh->addr, | 323 | (memcmp(softif_neigh->addr, |
303 | bat_priv->primary_if->net_dev->dev_addr, ETH_ALEN) < 0)) { | 324 | primary_if->net_dev->dev_addr, ETH_ALEN) < 0)) { |
304 | bat_dbg(DBG_ROUTES, bat_priv, | 325 | bat_dbg(DBG_ROUTES, bat_priv, |
305 | "Setting mesh exit point to %pM (vid: %d).\n", | 326 | "Setting mesh exit point to %pM (vid: %d).\n", |
306 | softif_neigh->addr, softif_neigh->vid); | 327 | softif_neigh->addr, softif_neigh->vid); |
@@ -310,12 +331,13 @@ static void softif_batman_recv(struct sk_buff *skb, struct net_device *dev, | |||
310 | } | 331 | } |
311 | 332 | ||
312 | out: | 333 | out: |
313 | softif_neigh_free_ref(softif_neigh); | ||
314 | err: | ||
315 | kfree_skb(skb); | 334 | kfree_skb(skb); |
335 | if (softif_neigh) | ||
336 | softif_neigh_free_ref(softif_neigh); | ||
316 | if (curr_softif_neigh) | 337 | if (curr_softif_neigh) |
317 | softif_neigh_free_ref(curr_softif_neigh); | 338 | softif_neigh_free_ref(curr_softif_neigh); |
318 | 339 | if (primary_if) | |
340 | hardif_free_ref(primary_if); | ||
319 | return; | 341 | return; |
320 | } | 342 | } |
321 | 343 | ||
@@ -371,6 +393,7 @@ int interface_tx(struct sk_buff *skb, struct net_device *soft_iface) | |||
371 | { | 393 | { |
372 | struct ethhdr *ethhdr = (struct ethhdr *)skb->data; | 394 | struct ethhdr *ethhdr = (struct ethhdr *)skb->data; |
373 | struct bat_priv *bat_priv = netdev_priv(soft_iface); | 395 | struct bat_priv *bat_priv = netdev_priv(soft_iface); |
396 | struct hard_iface *primary_if = NULL; | ||
374 | struct bcast_packet *bcast_packet; | 397 | struct bcast_packet *bcast_packet; |
375 | struct vlan_ethhdr *vhdr; | 398 | struct vlan_ethhdr *vhdr; |
376 | struct softif_neigh *curr_softif_neigh = NULL; | 399 | struct softif_neigh *curr_softif_neigh = NULL; |
@@ -420,7 +443,8 @@ int interface_tx(struct sk_buff *skb, struct net_device *soft_iface) | |||
420 | 443 | ||
421 | /* ethernet packet should be broadcasted */ | 444 | /* ethernet packet should be broadcasted */ |
422 | if (do_bcast) { | 445 | if (do_bcast) { |
423 | if (!bat_priv->primary_if) | 446 | primary_if = primary_if_get_selected(bat_priv); |
447 | if (!primary_if) | ||
424 | goto dropped; | 448 | goto dropped; |
425 | 449 | ||
426 | if (my_skb_head_push(skb, sizeof(struct bcast_packet)) < 0) | 450 | if (my_skb_head_push(skb, sizeof(struct bcast_packet)) < 0) |
@@ -436,7 +460,7 @@ int interface_tx(struct sk_buff *skb, struct net_device *soft_iface) | |||
436 | /* hw address of first interface is the orig mac because only | 460 | /* hw address of first interface is the orig mac because only |
437 | * this mac is known throughout the mesh */ | 461 | * this mac is known throughout the mesh */ |
438 | memcpy(bcast_packet->orig, | 462 | memcpy(bcast_packet->orig, |
439 | bat_priv->primary_if->net_dev->dev_addr, ETH_ALEN); | 463 | primary_if->net_dev->dev_addr, ETH_ALEN); |
440 | 464 | ||
441 | /* set broadcast sequence number */ | 465 | /* set broadcast sequence number */ |
442 | bcast_packet->seqno = | 466 | bcast_packet->seqno = |
@@ -466,6 +490,8 @@ dropped_freed: | |||
466 | end: | 490 | end: |
467 | if (curr_softif_neigh) | 491 | if (curr_softif_neigh) |
468 | softif_neigh_free_ref(curr_softif_neigh); | 492 | softif_neigh_free_ref(curr_softif_neigh); |
493 | if (primary_if) | ||
494 | hardif_free_ref(primary_if); | ||
469 | return NETDEV_TX_OK; | 495 | return NETDEV_TX_OK; |
470 | } | 496 | } |
471 | 497 | ||