aboutsummaryrefslogtreecommitdiffstats
path: root/net/batman-adv/hard-interface.c
diff options
context:
space:
mode:
authorMarek Lindner <lindner_marek@yahoo.de>2011-04-20 09:40:58 -0400
committerSven Eckelmann <sven@narfation.org>2011-05-01 16:49:03 -0400
commit32ae9b221e788413ce68feaae2ca39e406211a0a (patch)
treed827f989976a28fea5cdcb349c308baa98182c35 /net/batman-adv/hard-interface.c
parent71e4aa9c465fd66c110667ab5d620fb6a4ef2157 (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.c83
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
113static void update_primary_addr(struct bat_priv *bat_priv) 113static 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
128out:
129 if (primary_if)
130 hardif_free_ref(primary_if);
123} 131}
124 132
125static void set_primary_if(struct bat_priv *bat_priv, 133static 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
165out:
166 spin_unlock_bh(&hardif_list_lock);
154} 167}
155 168
156static bool hardif_is_iface_up(struct hard_iface *hard_iface) 169static bool hardif_is_iface_up(struct hard_iface *hard_iface)
@@ -236,9 +249,10 @@ void update_min_mtu(struct net_device *soft_iface)
236static void hardif_activate_interface(struct hard_iface *hard_iface) 249static 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
275out:
276 if (primary_if)
277 hardif_free_ref(primary_if);
260} 278}
261 279
262static void hardif_deactivate_interface(struct hard_iface *hard_iface) 280static void hardif_deactivate_interface(struct hard_iface *hard_iface)
@@ -386,12 +404,13 @@ err:
386void hardif_disable_interface(struct hard_iface *hard_iface) 404void 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
449out:
450 if (primary_if)
451 hardif_free_ref(primary_if);
428} 452}
429 453
430static struct hard_iface *hardif_add_interface(struct net_device *net_dev) 454static 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,
559hardif_put: 588hardif_put:
560 hardif_free_ref(hard_iface); 589 hardif_free_ref(hard_iface);
561out: 590out:
591 if (primary_if)
592 hardif_free_ref(primary_if);
562 return NOTIFY_DONE; 593 return NOTIFY_DONE;
563} 594}
564 595