diff options
Diffstat (limited to 'net/batman-adv/soft-interface.c')
-rw-r--r-- | net/batman-adv/soft-interface.c | 60 |
1 files changed, 46 insertions, 14 deletions
diff --git a/net/batman-adv/soft-interface.c b/net/batman-adv/soft-interface.c index e7ee65dc20bf..cbd677f48c00 100644 --- a/net/batman-adv/soft-interface.c +++ b/net/batman-adv/soft-interface.c | |||
@@ -448,10 +448,15 @@ out: | |||
448 | * possibly free it | 448 | * possibly free it |
449 | * @softif_vlan: the vlan object to release | 449 | * @softif_vlan: the vlan object to release |
450 | */ | 450 | */ |
451 | void batadv_softif_vlan_free_ref(struct batadv_softif_vlan *softif_vlan) | 451 | void batadv_softif_vlan_free_ref(struct batadv_softif_vlan *vlan) |
452 | { | 452 | { |
453 | if (atomic_dec_and_test(&softif_vlan->refcount)) | 453 | if (atomic_dec_and_test(&vlan->refcount)) { |
454 | kfree_rcu(softif_vlan, rcu); | 454 | spin_lock_bh(&vlan->bat_priv->softif_vlan_list_lock); |
455 | hlist_del_rcu(&vlan->list); | ||
456 | spin_unlock_bh(&vlan->bat_priv->softif_vlan_list_lock); | ||
457 | |||
458 | kfree_rcu(vlan, rcu); | ||
459 | } | ||
455 | } | 460 | } |
456 | 461 | ||
457 | /** | 462 | /** |
@@ -505,6 +510,7 @@ int batadv_softif_create_vlan(struct batadv_priv *bat_priv, unsigned short vid) | |||
505 | if (!vlan) | 510 | if (!vlan) |
506 | return -ENOMEM; | 511 | return -ENOMEM; |
507 | 512 | ||
513 | vlan->bat_priv = bat_priv; | ||
508 | vlan->vid = vid; | 514 | vlan->vid = vid; |
509 | atomic_set(&vlan->refcount, 1); | 515 | atomic_set(&vlan->refcount, 1); |
510 | 516 | ||
@@ -516,6 +522,10 @@ int batadv_softif_create_vlan(struct batadv_priv *bat_priv, unsigned short vid) | |||
516 | return err; | 522 | return err; |
517 | } | 523 | } |
518 | 524 | ||
525 | spin_lock_bh(&bat_priv->softif_vlan_list_lock); | ||
526 | hlist_add_head_rcu(&vlan->list, &bat_priv->softif_vlan_list); | ||
527 | spin_unlock_bh(&bat_priv->softif_vlan_list_lock); | ||
528 | |||
519 | /* add a new TT local entry. This one will be marked with the NOPURGE | 529 | /* add a new TT local entry. This one will be marked with the NOPURGE |
520 | * flag | 530 | * flag |
521 | */ | 531 | */ |
@@ -523,10 +533,6 @@ int batadv_softif_create_vlan(struct batadv_priv *bat_priv, unsigned short vid) | |||
523 | bat_priv->soft_iface->dev_addr, vid, | 533 | bat_priv->soft_iface->dev_addr, vid, |
524 | BATADV_NULL_IFINDEX, BATADV_NO_MARK); | 534 | BATADV_NULL_IFINDEX, BATADV_NO_MARK); |
525 | 535 | ||
526 | spin_lock_bh(&bat_priv->softif_vlan_list_lock); | ||
527 | hlist_add_head_rcu(&vlan->list, &bat_priv->softif_vlan_list); | ||
528 | spin_unlock_bh(&bat_priv->softif_vlan_list_lock); | ||
529 | |||
530 | return 0; | 536 | return 0; |
531 | } | 537 | } |
532 | 538 | ||
@@ -538,18 +544,13 @@ int batadv_softif_create_vlan(struct batadv_priv *bat_priv, unsigned short vid) | |||
538 | static void batadv_softif_destroy_vlan(struct batadv_priv *bat_priv, | 544 | static void batadv_softif_destroy_vlan(struct batadv_priv *bat_priv, |
539 | struct batadv_softif_vlan *vlan) | 545 | struct batadv_softif_vlan *vlan) |
540 | { | 546 | { |
541 | spin_lock_bh(&bat_priv->softif_vlan_list_lock); | ||
542 | hlist_del_rcu(&vlan->list); | ||
543 | spin_unlock_bh(&bat_priv->softif_vlan_list_lock); | ||
544 | |||
545 | batadv_sysfs_del_vlan(bat_priv, vlan); | ||
546 | |||
547 | /* explicitly remove the associated TT local entry because it is marked | 547 | /* explicitly remove the associated TT local entry because it is marked |
548 | * with the NOPURGE flag | 548 | * with the NOPURGE flag |
549 | */ | 549 | */ |
550 | batadv_tt_local_remove(bat_priv, bat_priv->soft_iface->dev_addr, | 550 | batadv_tt_local_remove(bat_priv, bat_priv->soft_iface->dev_addr, |
551 | vlan->vid, "vlan interface destroyed", false); | 551 | vlan->vid, "vlan interface destroyed", false); |
552 | 552 | ||
553 | batadv_sysfs_del_vlan(bat_priv, vlan); | ||
553 | batadv_softif_vlan_free_ref(vlan); | 554 | batadv_softif_vlan_free_ref(vlan); |
554 | } | 555 | } |
555 | 556 | ||
@@ -567,6 +568,8 @@ static int batadv_interface_add_vid(struct net_device *dev, __be16 proto, | |||
567 | unsigned short vid) | 568 | unsigned short vid) |
568 | { | 569 | { |
569 | struct batadv_priv *bat_priv = netdev_priv(dev); | 570 | struct batadv_priv *bat_priv = netdev_priv(dev); |
571 | struct batadv_softif_vlan *vlan; | ||
572 | int ret; | ||
570 | 573 | ||
571 | /* only 802.1Q vlans are supported. | 574 | /* only 802.1Q vlans are supported. |
572 | * batman-adv does not know how to handle other types | 575 | * batman-adv does not know how to handle other types |
@@ -576,7 +579,36 @@ static int batadv_interface_add_vid(struct net_device *dev, __be16 proto, | |||
576 | 579 | ||
577 | vid |= BATADV_VLAN_HAS_TAG; | 580 | vid |= BATADV_VLAN_HAS_TAG; |
578 | 581 | ||
579 | return batadv_softif_create_vlan(bat_priv, vid); | 582 | /* if a new vlan is getting created and it already exists, it means that |
583 | * it was not deleted yet. batadv_softif_vlan_get() increases the | ||
584 | * refcount in order to revive the object. | ||
585 | * | ||
586 | * if it does not exist then create it. | ||
587 | */ | ||
588 | vlan = batadv_softif_vlan_get(bat_priv, vid); | ||
589 | if (!vlan) | ||
590 | return batadv_softif_create_vlan(bat_priv, vid); | ||
591 | |||
592 | /* recreate the sysfs object if it was already destroyed (and it should | ||
593 | * be since we received a kill_vid() for this vlan | ||
594 | */ | ||
595 | if (!vlan->kobj) { | ||
596 | ret = batadv_sysfs_add_vlan(bat_priv->soft_iface, vlan); | ||
597 | if (ret) { | ||
598 | batadv_softif_vlan_free_ref(vlan); | ||
599 | return ret; | ||
600 | } | ||
601 | } | ||
602 | |||
603 | /* add a new TT local entry. This one will be marked with the NOPURGE | ||
604 | * flag. This must be added again, even if the vlan object already | ||
605 | * exists, because the entry was deleted by kill_vid() | ||
606 | */ | ||
607 | batadv_tt_local_add(bat_priv->soft_iface, | ||
608 | bat_priv->soft_iface->dev_addr, vid, | ||
609 | BATADV_NULL_IFINDEX, BATADV_NO_MARK); | ||
610 | |||
611 | return 0; | ||
580 | } | 612 | } |
581 | 613 | ||
582 | /** | 614 | /** |