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/hard-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/hard-interface.c')
-rw-r--r-- | net/batman-adv/hard-interface.c | 83 |
1 files changed, 57 insertions, 26 deletions
diff --git a/net/batman-adv/hard-interface.c b/net/batman-adv/hard-interface.c index b3058e46ee6b..3e888f133d75 100644 --- a/net/batman-adv/hard-interface.c +++ b/net/batman-adv/hard-interface.c | |||
@@ -110,47 +110,60 @@ out: | |||
110 | return hard_iface; | 110 | return hard_iface; |
111 | } | 111 | } |
112 | 112 | ||
113 | static void update_primary_addr(struct bat_priv *bat_priv) | 113 | static void primary_if_update_addr(struct bat_priv *bat_priv) |
114 | { | 114 | { |
115 | struct vis_packet *vis_packet; | 115 | struct vis_packet *vis_packet; |
116 | struct hard_iface *primary_if; | ||
117 | |||
118 | primary_if = primary_if_get_selected(bat_priv); | ||
119 | if (!primary_if) | ||
120 | goto out; | ||
116 | 121 | ||
117 | vis_packet = (struct vis_packet *) | 122 | vis_packet = (struct vis_packet *) |
118 | bat_priv->my_vis_info->skb_packet->data; | 123 | bat_priv->my_vis_info->skb_packet->data; |
119 | memcpy(vis_packet->vis_orig, | 124 | memcpy(vis_packet->vis_orig, primary_if->net_dev->dev_addr, ETH_ALEN); |
120 | bat_priv->primary_if->net_dev->dev_addr, ETH_ALEN); | ||
121 | memcpy(vis_packet->sender_orig, | 125 | memcpy(vis_packet->sender_orig, |
122 | bat_priv->primary_if->net_dev->dev_addr, ETH_ALEN); | 126 | primary_if->net_dev->dev_addr, ETH_ALEN); |
127 | |||
128 | out: | ||
129 | if (primary_if) | ||
130 | hardif_free_ref(primary_if); | ||
123 | } | 131 | } |
124 | 132 | ||
125 | static void set_primary_if(struct bat_priv *bat_priv, | 133 | static void primary_if_select(struct bat_priv *bat_priv, |
126 | struct hard_iface *hard_iface) | 134 | struct hard_iface *new_hard_iface) |
127 | { | 135 | { |
136 | struct hard_iface *curr_hard_iface; | ||
128 | struct batman_packet *batman_packet; | 137 | struct batman_packet *batman_packet; |
129 | struct hard_iface *old_if; | ||
130 | 138 | ||
131 | if (hard_iface && !atomic_inc_not_zero(&hard_iface->refcount)) | 139 | spin_lock_bh(&hardif_list_lock); |
132 | hard_iface = NULL; | ||
133 | 140 | ||
134 | old_if = bat_priv->primary_if; | 141 | if (new_hard_iface && !atomic_inc_not_zero(&new_hard_iface->refcount)) |
135 | bat_priv->primary_if = hard_iface; | 142 | new_hard_iface = NULL; |
136 | 143 | ||
137 | if (old_if) | 144 | curr_hard_iface = bat_priv->primary_if; |
138 | hardif_free_ref(old_if); | 145 | rcu_assign_pointer(bat_priv->primary_if, new_hard_iface); |
139 | 146 | ||
140 | if (!bat_priv->primary_if) | 147 | if (curr_hard_iface) |
141 | return; | 148 | hardif_free_ref(curr_hard_iface); |
142 | 149 | ||
143 | batman_packet = (struct batman_packet *)(hard_iface->packet_buff); | 150 | if (!new_hard_iface) |
151 | goto out; | ||
152 | |||
153 | batman_packet = (struct batman_packet *)(new_hard_iface->packet_buff); | ||
144 | batman_packet->flags = PRIMARIES_FIRST_HOP; | 154 | batman_packet->flags = PRIMARIES_FIRST_HOP; |
145 | batman_packet->ttl = TTL; | 155 | batman_packet->ttl = TTL; |
146 | 156 | ||
147 | update_primary_addr(bat_priv); | 157 | primary_if_update_addr(bat_priv); |
148 | 158 | ||
149 | /*** | 159 | /*** |
150 | * hacky trick to make sure that we send the HNA information via | 160 | * hacky trick to make sure that we send the HNA information via |
151 | * our new primary interface | 161 | * our new primary interface |
152 | */ | 162 | */ |
153 | atomic_set(&bat_priv->hna_local_changed, 1); | 163 | atomic_set(&bat_priv->hna_local_changed, 1); |
164 | |||
165 | out: | ||
166 | spin_unlock_bh(&hardif_list_lock); | ||
154 | } | 167 | } |
155 | 168 | ||
156 | static bool hardif_is_iface_up(struct hard_iface *hard_iface) | 169 | static bool hardif_is_iface_up(struct hard_iface *hard_iface) |
@@ -236,9 +249,10 @@ void update_min_mtu(struct net_device *soft_iface) | |||
236 | static void hardif_activate_interface(struct hard_iface *hard_iface) | 249 | static void hardif_activate_interface(struct hard_iface *hard_iface) |
237 | { | 250 | { |
238 | struct bat_priv *bat_priv; | 251 | struct bat_priv *bat_priv; |
252 | struct hard_iface *primary_if = NULL; | ||
239 | 253 | ||
240 | if (hard_iface->if_status != IF_INACTIVE) | 254 | if (hard_iface->if_status != IF_INACTIVE) |
241 | return; | 255 | goto out; |
242 | 256 | ||
243 | bat_priv = netdev_priv(hard_iface->soft_iface); | 257 | bat_priv = netdev_priv(hard_iface->soft_iface); |
244 | 258 | ||
@@ -249,14 +263,18 @@ static void hardif_activate_interface(struct hard_iface *hard_iface) | |||
249 | * the first active interface becomes our primary interface or | 263 | * the first active interface becomes our primary interface or |
250 | * the next active interface after the old primay interface was removed | 264 | * the next active interface after the old primay interface was removed |
251 | */ | 265 | */ |
252 | if (!bat_priv->primary_if) | 266 | primary_if = primary_if_get_selected(bat_priv); |
253 | set_primary_if(bat_priv, hard_iface); | 267 | if (!primary_if) |
268 | primary_if_select(bat_priv, hard_iface); | ||
254 | 269 | ||
255 | bat_info(hard_iface->soft_iface, "Interface activated: %s\n", | 270 | bat_info(hard_iface->soft_iface, "Interface activated: %s\n", |
256 | hard_iface->net_dev->name); | 271 | hard_iface->net_dev->name); |
257 | 272 | ||
258 | update_min_mtu(hard_iface->soft_iface); | 273 | update_min_mtu(hard_iface->soft_iface); |
259 | return; | 274 | |
275 | out: | ||
276 | if (primary_if) | ||
277 | hardif_free_ref(primary_if); | ||
260 | } | 278 | } |
261 | 279 | ||
262 | static void hardif_deactivate_interface(struct hard_iface *hard_iface) | 280 | static void hardif_deactivate_interface(struct hard_iface *hard_iface) |
@@ -386,12 +404,13 @@ err: | |||
386 | void hardif_disable_interface(struct hard_iface *hard_iface) | 404 | void hardif_disable_interface(struct hard_iface *hard_iface) |
387 | { | 405 | { |
388 | struct bat_priv *bat_priv = netdev_priv(hard_iface->soft_iface); | 406 | struct bat_priv *bat_priv = netdev_priv(hard_iface->soft_iface); |
407 | struct hard_iface *primary_if = NULL; | ||
389 | 408 | ||
390 | if (hard_iface->if_status == IF_ACTIVE) | 409 | if (hard_iface->if_status == IF_ACTIVE) |
391 | hardif_deactivate_interface(hard_iface); | 410 | hardif_deactivate_interface(hard_iface); |
392 | 411 | ||
393 | if (hard_iface->if_status != IF_INACTIVE) | 412 | if (hard_iface->if_status != IF_INACTIVE) |
394 | return; | 413 | goto out; |
395 | 414 | ||
396 | bat_info(hard_iface->soft_iface, "Removing interface: %s\n", | 415 | bat_info(hard_iface->soft_iface, "Removing interface: %s\n", |
397 | hard_iface->net_dev->name); | 416 | hard_iface->net_dev->name); |
@@ -400,11 +419,12 @@ void hardif_disable_interface(struct hard_iface *hard_iface) | |||
400 | bat_priv->num_ifaces--; | 419 | bat_priv->num_ifaces--; |
401 | orig_hash_del_if(hard_iface, bat_priv->num_ifaces); | 420 | orig_hash_del_if(hard_iface, bat_priv->num_ifaces); |
402 | 421 | ||
403 | if (hard_iface == bat_priv->primary_if) { | 422 | primary_if = primary_if_get_selected(bat_priv); |
423 | if (hard_iface == primary_if) { | ||
404 | struct hard_iface *new_if; | 424 | struct hard_iface *new_if; |
405 | 425 | ||
406 | new_if = hardif_get_active(hard_iface->soft_iface); | 426 | new_if = hardif_get_active(hard_iface->soft_iface); |
407 | set_primary_if(bat_priv, new_if); | 427 | primary_if_select(bat_priv, new_if); |
408 | 428 | ||
409 | if (new_if) | 429 | if (new_if) |
410 | hardif_free_ref(new_if); | 430 | hardif_free_ref(new_if); |
@@ -425,6 +445,10 @@ void hardif_disable_interface(struct hard_iface *hard_iface) | |||
425 | 445 | ||
426 | hard_iface->soft_iface = NULL; | 446 | hard_iface->soft_iface = NULL; |
427 | hardif_free_ref(hard_iface); | 447 | hardif_free_ref(hard_iface); |
448 | |||
449 | out: | ||
450 | if (primary_if) | ||
451 | hardif_free_ref(primary_if); | ||
428 | } | 452 | } |
429 | 453 | ||
430 | static struct hard_iface *hardif_add_interface(struct net_device *net_dev) | 454 | static struct hard_iface *hardif_add_interface(struct net_device *net_dev) |
@@ -514,6 +538,7 @@ static int hard_if_event(struct notifier_block *this, | |||
514 | { | 538 | { |
515 | struct net_device *net_dev = (struct net_device *)ptr; | 539 | struct net_device *net_dev = (struct net_device *)ptr; |
516 | struct hard_iface *hard_iface = hardif_get_by_netdev(net_dev); | 540 | struct hard_iface *hard_iface = hardif_get_by_netdev(net_dev); |
541 | struct hard_iface *primary_if = NULL; | ||
517 | struct bat_priv *bat_priv; | 542 | struct bat_priv *bat_priv; |
518 | 543 | ||
519 | if (!hard_iface && event == NETDEV_REGISTER) | 544 | if (!hard_iface && event == NETDEV_REGISTER) |
@@ -549,8 +574,12 @@ static int hard_if_event(struct notifier_block *this, | |||
549 | update_mac_addresses(hard_iface); | 574 | update_mac_addresses(hard_iface); |
550 | 575 | ||
551 | bat_priv = netdev_priv(hard_iface->soft_iface); | 576 | bat_priv = netdev_priv(hard_iface->soft_iface); |
552 | if (hard_iface == bat_priv->primary_if) | 577 | primary_if = primary_if_get_selected(bat_priv); |
553 | update_primary_addr(bat_priv); | 578 | if (!primary_if) |
579 | goto hardif_put; | ||
580 | |||
581 | if (hard_iface == primary_if) | ||
582 | primary_if_update_addr(bat_priv); | ||
554 | break; | 583 | break; |
555 | default: | 584 | default: |
556 | break; | 585 | break; |
@@ -559,6 +588,8 @@ static int hard_if_event(struct notifier_block *this, | |||
559 | hardif_put: | 588 | hardif_put: |
560 | hardif_free_ref(hard_iface); | 589 | hardif_free_ref(hard_iface); |
561 | out: | 590 | out: |
591 | if (primary_if) | ||
592 | hardif_free_ref(primary_if); | ||
562 | return NOTIFY_DONE; | 593 | return NOTIFY_DONE; |
563 | } | 594 | } |
564 | 595 | ||