diff options
author | Christian Lamparter <chunkeey@googlemail.com> | 2012-12-15 19:41:37 -0500 |
---|---|---|
committer | John W. Linville <linville@tuxdriver.com> | 2013-01-07 15:16:52 -0500 |
commit | 7f878b0d96e6b3bd27d736fb2fb7e3cc94b16b26 (patch) | |
tree | 29a67f378d034766d7c7b4ac52a4df4d5f282ac9 /drivers/net | |
parent | 5ae994d0984ddc2f1e79c4f8de7189faecfc0af9 (diff) |
carl9170: allow P2P_GO interface creation after P2P_CLIENT
Janusz Dziedzic reported that after a change in wpa_supplicant
["nl80211: Automatically use concurrent P2P if possible"],
carl9170 was no longer able to host a P2P network.
This patch tackles the problem by allowing GO interfaces to be
registered, long after the P2P_CLIENT interface is brought up.
Reported-by: Janusz Dziedzic <janusz.dziedzic@gmail.com>
Signed-off-by: Christian Lamparter <chunkeey@googlemail.com>
Signed-off-by: John W. Linville <linville@tuxdriver.com>
Diffstat (limited to 'drivers/net')
-rw-r--r-- | drivers/net/wireless/ath/carl9170/main.c | 54 |
1 files changed, 51 insertions, 3 deletions
diff --git a/drivers/net/wireless/ath/carl9170/main.c b/drivers/net/wireless/ath/carl9170/main.c index ce8ae1e6bd3b..95e4bf05e559 100644 --- a/drivers/net/wireless/ath/carl9170/main.c +++ b/drivers/net/wireless/ath/carl9170/main.c | |||
@@ -580,7 +580,7 @@ static int carl9170_op_add_interface(struct ieee80211_hw *hw, | |||
580 | struct ieee80211_vif *vif) | 580 | struct ieee80211_vif *vif) |
581 | { | 581 | { |
582 | struct carl9170_vif_info *vif_priv = (void *) vif->drv_priv; | 582 | struct carl9170_vif_info *vif_priv = (void *) vif->drv_priv; |
583 | struct ieee80211_vif *main_vif; | 583 | struct ieee80211_vif *main_vif, *old_main = NULL; |
584 | struct ar9170 *ar = hw->priv; | 584 | struct ar9170 *ar = hw->priv; |
585 | int vif_id = -1, err = 0; | 585 | int vif_id = -1, err = 0; |
586 | 586 | ||
@@ -602,6 +602,15 @@ static int carl9170_op_add_interface(struct ieee80211_hw *hw, | |||
602 | goto init; | 602 | goto init; |
603 | } | 603 | } |
604 | 604 | ||
605 | /* Because the AR9170 HW's MAC doesn't provide full support for | ||
606 | * multiple, independent interfaces [of different operation modes]. | ||
607 | * We have to select ONE main interface [main mode of HW], but we | ||
608 | * can have multiple slaves [AKA: entry in the ACK-table]. | ||
609 | * | ||
610 | * The first (from HEAD/TOP) interface in the ar->vif_list is | ||
611 | * always the main intf. All following intfs in this list | ||
612 | * are considered to be slave intfs. | ||
613 | */ | ||
605 | main_vif = carl9170_get_main_vif(ar); | 614 | main_vif = carl9170_get_main_vif(ar); |
606 | 615 | ||
607 | if (main_vif) { | 616 | if (main_vif) { |
@@ -610,6 +619,18 @@ static int carl9170_op_add_interface(struct ieee80211_hw *hw, | |||
610 | if (vif->type == NL80211_IFTYPE_STATION) | 619 | if (vif->type == NL80211_IFTYPE_STATION) |
611 | break; | 620 | break; |
612 | 621 | ||
622 | /* P2P GO [master] use-case | ||
623 | * Because the P2P GO station is selected dynamically | ||
624 | * by all participating peers of a WIFI Direct network, | ||
625 | * the driver has be able to change the main interface | ||
626 | * operating mode on the fly. | ||
627 | */ | ||
628 | if (main_vif->p2p && vif->p2p && | ||
629 | vif->type == NL80211_IFTYPE_AP) { | ||
630 | old_main = main_vif; | ||
631 | break; | ||
632 | } | ||
633 | |||
613 | err = -EBUSY; | 634 | err = -EBUSY; |
614 | rcu_read_unlock(); | 635 | rcu_read_unlock(); |
615 | 636 | ||
@@ -648,14 +669,41 @@ static int carl9170_op_add_interface(struct ieee80211_hw *hw, | |||
648 | vif_priv->id = vif_id; | 669 | vif_priv->id = vif_id; |
649 | vif_priv->enable_beacon = false; | 670 | vif_priv->enable_beacon = false; |
650 | ar->vifs++; | 671 | ar->vifs++; |
651 | list_add_tail_rcu(&vif_priv->list, &ar->vif_list); | 672 | if (old_main) { |
673 | /* We end up in here, if the main interface is being replaced. | ||
674 | * Put the new main interface at the HEAD of the list and the | ||
675 | * previous inteface will automatically become second in line. | ||
676 | */ | ||
677 | list_add_rcu(&vif_priv->list, &ar->vif_list); | ||
678 | } else { | ||
679 | /* Add new inteface. If the list is empty, it will become the | ||
680 | * main inteface, otherwise it will be slave. | ||
681 | */ | ||
682 | list_add_tail_rcu(&vif_priv->list, &ar->vif_list); | ||
683 | } | ||
652 | rcu_assign_pointer(ar->vif_priv[vif_id].vif, vif); | 684 | rcu_assign_pointer(ar->vif_priv[vif_id].vif, vif); |
653 | 685 | ||
654 | init: | 686 | init: |
655 | if (carl9170_get_main_vif(ar) == vif) { | 687 | main_vif = carl9170_get_main_vif(ar); |
688 | |||
689 | if (main_vif == vif) { | ||
656 | rcu_assign_pointer(ar->beacon_iter, vif_priv); | 690 | rcu_assign_pointer(ar->beacon_iter, vif_priv); |
657 | rcu_read_unlock(); | 691 | rcu_read_unlock(); |
658 | 692 | ||
693 | if (old_main) { | ||
694 | struct carl9170_vif_info *old_main_priv = | ||
695 | (void *) old_main->drv_priv; | ||
696 | /* downgrade old main intf to slave intf. | ||
697 | * NOTE: We are no longer under rcu_read_lock. | ||
698 | * But we are still holding ar->mutex, so the | ||
699 | * vif data [id, addr] is safe. | ||
700 | */ | ||
701 | err = carl9170_mod_virtual_mac(ar, old_main_priv->id, | ||
702 | old_main->addr); | ||
703 | if (err) | ||
704 | goto unlock; | ||
705 | } | ||
706 | |||
659 | err = carl9170_init_interface(ar, vif); | 707 | err = carl9170_init_interface(ar, vif); |
660 | if (err) | 708 | if (err) |
661 | goto unlock; | 709 | goto unlock; |