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 | /** |
