aboutsummaryrefslogtreecommitdiffstats
path: root/net/batman-adv/hard-interface.c
diff options
context:
space:
mode:
Diffstat (limited to 'net/batman-adv/hard-interface.c')
-rw-r--r--net/batman-adv/hard-interface.c107
1 files changed, 61 insertions, 46 deletions
diff --git a/net/batman-adv/hard-interface.c b/net/batman-adv/hard-interface.c
index b3058e46ee6b..dfbfccc9fe40 100644
--- a/net/batman-adv/hard-interface.c
+++ b/net/batman-adv/hard-interface.c
@@ -31,9 +31,6 @@
31 31
32#include <linux/if_arp.h> 32#include <linux/if_arp.h>
33 33
34/* protect update critical side of hardif_list - but not the content */
35static DEFINE_SPINLOCK(hardif_list_lock);
36
37 34
38static int batman_skb_recv(struct sk_buff *skb, 35static int batman_skb_recv(struct sk_buff *skb,
39 struct net_device *dev, 36 struct net_device *dev,
@@ -110,47 +107,57 @@ out:
110 return hard_iface; 107 return hard_iface;
111} 108}
112 109
113static void update_primary_addr(struct bat_priv *bat_priv) 110static void primary_if_update_addr(struct bat_priv *bat_priv)
114{ 111{
115 struct vis_packet *vis_packet; 112 struct vis_packet *vis_packet;
113 struct hard_iface *primary_if;
114
115 primary_if = primary_if_get_selected(bat_priv);
116 if (!primary_if)
117 goto out;
116 118
117 vis_packet = (struct vis_packet *) 119 vis_packet = (struct vis_packet *)
118 bat_priv->my_vis_info->skb_packet->data; 120 bat_priv->my_vis_info->skb_packet->data;
119 memcpy(vis_packet->vis_orig, 121 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, 122 memcpy(vis_packet->sender_orig,
122 bat_priv->primary_if->net_dev->dev_addr, ETH_ALEN); 123 primary_if->net_dev->dev_addr, ETH_ALEN);
124
125out:
126 if (primary_if)
127 hardif_free_ref(primary_if);
123} 128}
124 129
125static void set_primary_if(struct bat_priv *bat_priv, 130static void primary_if_select(struct bat_priv *bat_priv,
126 struct hard_iface *hard_iface) 131 struct hard_iface *new_hard_iface)
127{ 132{
133 struct hard_iface *curr_hard_iface;
128 struct batman_packet *batman_packet; 134 struct batman_packet *batman_packet;
129 struct hard_iface *old_if;
130 135
131 if (hard_iface && !atomic_inc_not_zero(&hard_iface->refcount)) 136 ASSERT_RTNL();
132 hard_iface = NULL; 137
138 if (new_hard_iface && !atomic_inc_not_zero(&new_hard_iface->refcount))
139 new_hard_iface = NULL;
133 140
134 old_if = bat_priv->primary_if; 141 curr_hard_iface = bat_priv->primary_if;
135 bat_priv->primary_if = hard_iface; 142 rcu_assign_pointer(bat_priv->primary_if, new_hard_iface);
136 143
137 if (old_if) 144 if (curr_hard_iface)
138 hardif_free_ref(old_if); 145 hardif_free_ref(curr_hard_iface);
139 146
140 if (!bat_priv->primary_if) 147 if (!new_hard_iface)
141 return; 148 return;
142 149
143 batman_packet = (struct batman_packet *)(hard_iface->packet_buff); 150 batman_packet = (struct batman_packet *)(new_hard_iface->packet_buff);
144 batman_packet->flags = PRIMARIES_FIRST_HOP; 151 batman_packet->flags = PRIMARIES_FIRST_HOP;
145 batman_packet->ttl = TTL; 152 batman_packet->ttl = TTL;
146 153
147 update_primary_addr(bat_priv); 154 primary_if_update_addr(bat_priv);
148 155
149 /*** 156 /***
150 * hacky trick to make sure that we send the HNA information via 157 * hacky trick to make sure that we send the TT information via
151 * our new primary interface 158 * our new primary interface
152 */ 159 */
153 atomic_set(&bat_priv->hna_local_changed, 1); 160 atomic_set(&bat_priv->tt_local_changed, 1);
154} 161}
155 162
156static bool hardif_is_iface_up(struct hard_iface *hard_iface) 163static bool hardif_is_iface_up(struct hard_iface *hard_iface)
@@ -236,9 +243,10 @@ void update_min_mtu(struct net_device *soft_iface)
236static void hardif_activate_interface(struct hard_iface *hard_iface) 243static void hardif_activate_interface(struct hard_iface *hard_iface)
237{ 244{
238 struct bat_priv *bat_priv; 245 struct bat_priv *bat_priv;
246 struct hard_iface *primary_if = NULL;
239 247
240 if (hard_iface->if_status != IF_INACTIVE) 248 if (hard_iface->if_status != IF_INACTIVE)
241 return; 249 goto out;
242 250
243 bat_priv = netdev_priv(hard_iface->soft_iface); 251 bat_priv = netdev_priv(hard_iface->soft_iface);
244 252
@@ -249,14 +257,18 @@ static void hardif_activate_interface(struct hard_iface *hard_iface)
249 * the first active interface becomes our primary interface or 257 * the first active interface becomes our primary interface or
250 * the next active interface after the old primay interface was removed 258 * the next active interface after the old primay interface was removed
251 */ 259 */
252 if (!bat_priv->primary_if) 260 primary_if = primary_if_get_selected(bat_priv);
253 set_primary_if(bat_priv, hard_iface); 261 if (!primary_if)
262 primary_if_select(bat_priv, hard_iface);
254 263
255 bat_info(hard_iface->soft_iface, "Interface activated: %s\n", 264 bat_info(hard_iface->soft_iface, "Interface activated: %s\n",
256 hard_iface->net_dev->name); 265 hard_iface->net_dev->name);
257 266
258 update_min_mtu(hard_iface->soft_iface); 267 update_min_mtu(hard_iface->soft_iface);
259 return; 268
269out:
270 if (primary_if)
271 hardif_free_ref(primary_if);
260} 272}
261 273
262static void hardif_deactivate_interface(struct hard_iface *hard_iface) 274static void hardif_deactivate_interface(struct hard_iface *hard_iface)
@@ -327,7 +339,7 @@ int hardif_enable_interface(struct hard_iface *hard_iface, char *iface_name)
327 batman_packet->flags = 0; 339 batman_packet->flags = 0;
328 batman_packet->ttl = 2; 340 batman_packet->ttl = 2;
329 batman_packet->tq = TQ_MAX_VALUE; 341 batman_packet->tq = TQ_MAX_VALUE;
330 batman_packet->num_hna = 0; 342 batman_packet->num_tt = 0;
331 343
332 hard_iface->if_num = bat_priv->num_ifaces; 344 hard_iface->if_num = bat_priv->num_ifaces;
333 bat_priv->num_ifaces++; 345 bat_priv->num_ifaces++;
@@ -386,12 +398,13 @@ err:
386void hardif_disable_interface(struct hard_iface *hard_iface) 398void hardif_disable_interface(struct hard_iface *hard_iface)
387{ 399{
388 struct bat_priv *bat_priv = netdev_priv(hard_iface->soft_iface); 400 struct bat_priv *bat_priv = netdev_priv(hard_iface->soft_iface);
401 struct hard_iface *primary_if = NULL;
389 402
390 if (hard_iface->if_status == IF_ACTIVE) 403 if (hard_iface->if_status == IF_ACTIVE)
391 hardif_deactivate_interface(hard_iface); 404 hardif_deactivate_interface(hard_iface);
392 405
393 if (hard_iface->if_status != IF_INACTIVE) 406 if (hard_iface->if_status != IF_INACTIVE)
394 return; 407 goto out;
395 408
396 bat_info(hard_iface->soft_iface, "Removing interface: %s\n", 409 bat_info(hard_iface->soft_iface, "Removing interface: %s\n",
397 hard_iface->net_dev->name); 410 hard_iface->net_dev->name);
@@ -400,11 +413,12 @@ void hardif_disable_interface(struct hard_iface *hard_iface)
400 bat_priv->num_ifaces--; 413 bat_priv->num_ifaces--;
401 orig_hash_del_if(hard_iface, bat_priv->num_ifaces); 414 orig_hash_del_if(hard_iface, bat_priv->num_ifaces);
402 415
403 if (hard_iface == bat_priv->primary_if) { 416 primary_if = primary_if_get_selected(bat_priv);
417 if (hard_iface == primary_if) {
404 struct hard_iface *new_if; 418 struct hard_iface *new_if;
405 419
406 new_if = hardif_get_active(hard_iface->soft_iface); 420 new_if = hardif_get_active(hard_iface->soft_iface);
407 set_primary_if(bat_priv, new_if); 421 primary_if_select(bat_priv, new_if);
408 422
409 if (new_if) 423 if (new_if)
410 hardif_free_ref(new_if); 424 hardif_free_ref(new_if);
@@ -425,6 +439,10 @@ void hardif_disable_interface(struct hard_iface *hard_iface)
425 439
426 hard_iface->soft_iface = NULL; 440 hard_iface->soft_iface = NULL;
427 hardif_free_ref(hard_iface); 441 hardif_free_ref(hard_iface);
442
443out:
444 if (primary_if)
445 hardif_free_ref(primary_if);
428} 446}
429 447
430static struct hard_iface *hardif_add_interface(struct net_device *net_dev) 448static struct hard_iface *hardif_add_interface(struct net_device *net_dev)
@@ -432,6 +450,8 @@ static struct hard_iface *hardif_add_interface(struct net_device *net_dev)
432 struct hard_iface *hard_iface; 450 struct hard_iface *hard_iface;
433 int ret; 451 int ret;
434 452
453 ASSERT_RTNL();
454
435 ret = is_valid_iface(net_dev); 455 ret = is_valid_iface(net_dev);
436 if (ret != 1) 456 if (ret != 1)
437 goto out; 457 goto out;
@@ -458,10 +478,7 @@ static struct hard_iface *hardif_add_interface(struct net_device *net_dev)
458 atomic_set(&hard_iface->refcount, 2); 478 atomic_set(&hard_iface->refcount, 2);
459 479
460 check_known_mac_addr(hard_iface->net_dev); 480 check_known_mac_addr(hard_iface->net_dev);
461
462 spin_lock(&hardif_list_lock);
463 list_add_tail_rcu(&hard_iface->list, &hardif_list); 481 list_add_tail_rcu(&hard_iface->list, &hardif_list);
464 spin_unlock(&hardif_list_lock);
465 482
466 return hard_iface; 483 return hard_iface;
467 484
@@ -475,6 +492,8 @@ out:
475 492
476static void hardif_remove_interface(struct hard_iface *hard_iface) 493static void hardif_remove_interface(struct hard_iface *hard_iface)
477{ 494{
495 ASSERT_RTNL();
496
478 /* first deactivate interface */ 497 /* first deactivate interface */
479 if (hard_iface->if_status != IF_NOT_IN_USE) 498 if (hard_iface->if_status != IF_NOT_IN_USE)
480 hardif_disable_interface(hard_iface); 499 hardif_disable_interface(hard_iface);
@@ -490,20 +509,11 @@ static void hardif_remove_interface(struct hard_iface *hard_iface)
490void hardif_remove_interfaces(void) 509void hardif_remove_interfaces(void)
491{ 510{
492 struct hard_iface *hard_iface, *hard_iface_tmp; 511 struct hard_iface *hard_iface, *hard_iface_tmp;
493 struct list_head if_queue;
494
495 INIT_LIST_HEAD(&if_queue);
496 512
497 spin_lock(&hardif_list_lock); 513 rtnl_lock();
498 list_for_each_entry_safe(hard_iface, hard_iface_tmp, 514 list_for_each_entry_safe(hard_iface, hard_iface_tmp,
499 &hardif_list, list) { 515 &hardif_list, list) {
500 list_del_rcu(&hard_iface->list); 516 list_del_rcu(&hard_iface->list);
501 list_add_tail(&hard_iface->list, &if_queue);
502 }
503 spin_unlock(&hardif_list_lock);
504
505 rtnl_lock();
506 list_for_each_entry_safe(hard_iface, hard_iface_tmp, &if_queue, list) {
507 hardif_remove_interface(hard_iface); 517 hardif_remove_interface(hard_iface);
508 } 518 }
509 rtnl_unlock(); 519 rtnl_unlock();
@@ -514,6 +524,7 @@ static int hard_if_event(struct notifier_block *this,
514{ 524{
515 struct net_device *net_dev = (struct net_device *)ptr; 525 struct net_device *net_dev = (struct net_device *)ptr;
516 struct hard_iface *hard_iface = hardif_get_by_netdev(net_dev); 526 struct hard_iface *hard_iface = hardif_get_by_netdev(net_dev);
527 struct hard_iface *primary_if = NULL;
517 struct bat_priv *bat_priv; 528 struct bat_priv *bat_priv;
518 529
519 if (!hard_iface && event == NETDEV_REGISTER) 530 if (!hard_iface && event == NETDEV_REGISTER)
@@ -531,9 +542,7 @@ static int hard_if_event(struct notifier_block *this,
531 hardif_deactivate_interface(hard_iface); 542 hardif_deactivate_interface(hard_iface);
532 break; 543 break;
533 case NETDEV_UNREGISTER: 544 case NETDEV_UNREGISTER:
534 spin_lock(&hardif_list_lock);
535 list_del_rcu(&hard_iface->list); 545 list_del_rcu(&hard_iface->list);
536 spin_unlock(&hardif_list_lock);
537 546
538 hardif_remove_interface(hard_iface); 547 hardif_remove_interface(hard_iface);
539 break; 548 break;
@@ -549,8 +558,12 @@ static int hard_if_event(struct notifier_block *this,
549 update_mac_addresses(hard_iface); 558 update_mac_addresses(hard_iface);
550 559
551 bat_priv = netdev_priv(hard_iface->soft_iface); 560 bat_priv = netdev_priv(hard_iface->soft_iface);
552 if (hard_iface == bat_priv->primary_if) 561 primary_if = primary_if_get_selected(bat_priv);
553 update_primary_addr(bat_priv); 562 if (!primary_if)
563 goto hardif_put;
564
565 if (hard_iface == primary_if)
566 primary_if_update_addr(bat_priv);
554 break; 567 break;
555 default: 568 default:
556 break; 569 break;
@@ -559,6 +572,8 @@ static int hard_if_event(struct notifier_block *this,
559hardif_put: 572hardif_put:
560 hardif_free_ref(hard_iface); 573 hardif_free_ref(hard_iface);
561out: 574out:
575 if (primary_if)
576 hardif_free_ref(primary_if);
562 return NOTIFY_DONE; 577 return NOTIFY_DONE;
563} 578}
564 579