diff options
author | Ben Greear <greearb@candelatech.com> | 2010-10-08 15:01:15 -0400 |
---|---|---|
committer | John W. Linville <linville@tuxdriver.com> | 2010-10-11 15:04:19 -0400 |
commit | 62c58fb4316905cd9c1dbf01967935ed5610b45d (patch) | |
tree | 088cea1c12ac3ad53bd7b75275bcbef4666ce3ba /drivers/net/wireless/ath/ath5k/base.c | |
parent | 92c68a66a8f73c51f062ae8cae958c86a21fea78 (diff) |
ath5k: Adjust opmode when interfaces are removed.
Otherwise, if there is an AP and a STATION, and AP
is removed, the NIC will not revert back to STATION mode.
Reported-by: Eliad Peller <eliad@wizery.com>
Signed-off-by: Ben Greear <greearb@candelatech.com>
Signed-off-by: John W. Linville <linville@tuxdriver.com>
Diffstat (limited to 'drivers/net/wireless/ath/ath5k/base.c')
-rw-r--r-- | drivers/net/wireless/ath/ath5k/base.c | 66 |
1 files changed, 40 insertions, 26 deletions
diff --git a/drivers/net/wireless/ath/ath5k/base.c b/drivers/net/wireless/ath/ath5k/base.c index dad726585637..c9732a6ce87f 100644 --- a/drivers/net/wireless/ath/ath5k/base.c +++ b/drivers/net/wireless/ath/ath5k/base.c | |||
@@ -62,6 +62,7 @@ | |||
62 | #include "reg.h" | 62 | #include "reg.h" |
63 | #include "debug.h" | 63 | #include "debug.h" |
64 | #include "ani.h" | 64 | #include "ani.h" |
65 | #include "../debug.h" | ||
65 | 66 | ||
66 | static int modparam_nohwcrypt; | 67 | static int modparam_nohwcrypt; |
67 | module_param_named(nohwcrypt, modparam_nohwcrypt, bool, S_IRUGO); | 68 | module_param_named(nohwcrypt, modparam_nohwcrypt, bool, S_IRUGO); |
@@ -517,12 +518,14 @@ struct ath_vif_iter_data { | |||
517 | bool need_set_hw_addr; | 518 | bool need_set_hw_addr; |
518 | bool found_active; | 519 | bool found_active; |
519 | bool any_assoc; | 520 | bool any_assoc; |
521 | enum nl80211_iftype opmode; | ||
520 | }; | 522 | }; |
521 | 523 | ||
522 | static void ath_vif_iter(void *data, u8 *mac, struct ieee80211_vif *vif) | 524 | static void ath_vif_iter(void *data, u8 *mac, struct ieee80211_vif *vif) |
523 | { | 525 | { |
524 | struct ath_vif_iter_data *iter_data = data; | 526 | struct ath_vif_iter_data *iter_data = data; |
525 | int i; | 527 | int i; |
528 | struct ath5k_vif *avf = (void *)vif->drv_priv; | ||
526 | 529 | ||
527 | if (iter_data->hw_macaddr) | 530 | if (iter_data->hw_macaddr) |
528 | for (i = 0; i < ETH_ALEN; i++) | 531 | for (i = 0; i < ETH_ALEN; i++) |
@@ -539,13 +542,34 @@ static void ath_vif_iter(void *data, u8 *mac, struct ieee80211_vif *vif) | |||
539 | iter_data->need_set_hw_addr = false; | 542 | iter_data->need_set_hw_addr = false; |
540 | 543 | ||
541 | if (!iter_data->any_assoc) { | 544 | if (!iter_data->any_assoc) { |
542 | struct ath5k_vif *avf = (void *)vif->drv_priv; | ||
543 | if (avf->assoc) | 545 | if (avf->assoc) |
544 | iter_data->any_assoc = true; | 546 | iter_data->any_assoc = true; |
545 | } | 547 | } |
548 | |||
549 | /* Calculate combined mode - when APs are active, operate in AP mode. | ||
550 | * Otherwise use the mode of the new interface. This can currently | ||
551 | * only deal with combinations of APs and STAs. Only one ad-hoc | ||
552 | * interfaces is allowed above. | ||
553 | */ | ||
554 | if (avf->opmode == NL80211_IFTYPE_AP) | ||
555 | iter_data->opmode = NL80211_IFTYPE_AP; | ||
556 | else | ||
557 | if (iter_data->opmode == NL80211_IFTYPE_UNSPECIFIED) | ||
558 | iter_data->opmode = avf->opmode; | ||
546 | } | 559 | } |
547 | 560 | ||
548 | void ath5k_update_bssid_mask(struct ath5k_softc *sc, struct ieee80211_vif *vif) | 561 | static void ath_do_set_opmode(struct ath5k_softc *sc) |
562 | { | ||
563 | struct ath5k_hw *ah = sc->ah; | ||
564 | ath5k_hw_set_opmode(ah, sc->opmode); | ||
565 | ATH5K_DBG(sc, ATH5K_DEBUG_MODE, "mode setup opmode %d (%s)\n", | ||
566 | sc->opmode, | ||
567 | ath_opmode_to_string(sc->opmode) ? | ||
568 | ath_opmode_to_string(sc->opmode) : "UKNOWN"); | ||
569 | } | ||
570 | |||
571 | void ath5k_update_bssid_mask_and_opmode(struct ath5k_softc *sc, | ||
572 | struct ieee80211_vif *vif) | ||
549 | { | 573 | { |
550 | struct ath_common *common = ath5k_hw_common(sc->ah); | 574 | struct ath_common *common = ath5k_hw_common(sc->ah); |
551 | struct ath_vif_iter_data iter_data; | 575 | struct ath_vif_iter_data iter_data; |
@@ -558,6 +582,7 @@ void ath5k_update_bssid_mask(struct ath5k_softc *sc, struct ieee80211_vif *vif) | |||
558 | memset(&iter_data.mask, 0xff, ETH_ALEN); | 582 | memset(&iter_data.mask, 0xff, ETH_ALEN); |
559 | iter_data.found_active = false; | 583 | iter_data.found_active = false; |
560 | iter_data.need_set_hw_addr = true; | 584 | iter_data.need_set_hw_addr = true; |
585 | iter_data.opmode = NL80211_IFTYPE_UNSPECIFIED; | ||
561 | 586 | ||
562 | if (vif) | 587 | if (vif) |
563 | ath_vif_iter(&iter_data, vif->addr, vif); | 588 | ath_vif_iter(&iter_data, vif->addr, vif); |
@@ -567,10 +592,18 @@ void ath5k_update_bssid_mask(struct ath5k_softc *sc, struct ieee80211_vif *vif) | |||
567 | &iter_data); | 592 | &iter_data); |
568 | memcpy(sc->bssidmask, iter_data.mask, ETH_ALEN); | 593 | memcpy(sc->bssidmask, iter_data.mask, ETH_ALEN); |
569 | 594 | ||
595 | sc->opmode = iter_data.opmode; | ||
596 | if (sc->opmode == NL80211_IFTYPE_UNSPECIFIED) | ||
597 | /* Nothing active, default to station mode */ | ||
598 | sc->opmode = NL80211_IFTYPE_STATION; | ||
599 | |||
600 | ath_do_set_opmode(sc); | ||
601 | |||
570 | if (iter_data.need_set_hw_addr && iter_data.found_active) | 602 | if (iter_data.need_set_hw_addr && iter_data.found_active) |
571 | ath5k_hw_set_lladdr(sc->ah, iter_data.active_mac); | 603 | ath5k_hw_set_lladdr(sc->ah, iter_data.active_mac); |
572 | 604 | ||
573 | ath5k_hw_set_bssid_mask(sc->ah, sc->bssidmask); | 605 | if (ath5k_hw_hasbssidmask(sc->ah)) |
606 | ath5k_hw_set_bssid_mask(sc->ah, sc->bssidmask); | ||
574 | } | 607 | } |
575 | 608 | ||
576 | static void | 609 | static void |
@@ -582,15 +615,9 @@ ath5k_mode_setup(struct ath5k_softc *sc, struct ieee80211_vif *vif) | |||
582 | /* configure rx filter */ | 615 | /* configure rx filter */ |
583 | rfilt = sc->filter_flags; | 616 | rfilt = sc->filter_flags; |
584 | ath5k_hw_set_rx_filter(ah, rfilt); | 617 | ath5k_hw_set_rx_filter(ah, rfilt); |
585 | |||
586 | if (ath5k_hw_hasbssidmask(ah)) | ||
587 | ath5k_update_bssid_mask(sc, vif); | ||
588 | |||
589 | /* configure operational mode */ | ||
590 | ath5k_hw_set_opmode(ah, sc->opmode); | ||
591 | |||
592 | ATH5K_DBG(sc, ATH5K_DEBUG_MODE, "mode setup opmode %d\n", sc->opmode); | ||
593 | ATH5K_DBG(sc, ATH5K_DEBUG_MODE, "RX filter 0x%x\n", rfilt); | 618 | ATH5K_DBG(sc, ATH5K_DEBUG_MODE, "RX filter 0x%x\n", rfilt); |
619 | |||
620 | ath5k_update_bssid_mask_and_opmode(sc, vif); | ||
594 | } | 621 | } |
595 | 622 | ||
596 | static inline int | 623 | static inline int |
@@ -2688,7 +2715,7 @@ ath5k_attach(struct pci_dev *pdev, struct ieee80211_hw *hw) | |||
2688 | SET_IEEE80211_PERM_ADDR(hw, mac); | 2715 | SET_IEEE80211_PERM_ADDR(hw, mac); |
2689 | memcpy(&sc->lladdr, mac, ETH_ALEN); | 2716 | memcpy(&sc->lladdr, mac, ETH_ALEN); |
2690 | /* All MAC address bits matter for ACKs */ | 2717 | /* All MAC address bits matter for ACKs */ |
2691 | ath5k_update_bssid_mask(sc, NULL); | 2718 | ath5k_update_bssid_mask_and_opmode(sc, NULL); |
2692 | 2719 | ||
2693 | regulatory->current_rd = ah->ah_capabilities.cap_eeprom.ee_regdomain; | 2720 | regulatory->current_rd = ah->ah_capabilities.cap_eeprom.ee_regdomain; |
2694 | ret = ath_regd_init(regulatory, hw->wiphy, ath5k_reg_notifier); | 2721 | ret = ath_regd_init(regulatory, hw->wiphy, ath5k_reg_notifier); |
@@ -2786,7 +2813,6 @@ static int ath5k_add_interface(struct ieee80211_hw *hw, | |||
2786 | { | 2813 | { |
2787 | struct ath5k_softc *sc = hw->priv; | 2814 | struct ath5k_softc *sc = hw->priv; |
2788 | int ret; | 2815 | int ret; |
2789 | struct ath5k_hw *ah = sc->ah; | ||
2790 | struct ath5k_vif *avf = (void *)vif->drv_priv; | 2816 | struct ath5k_vif *avf = (void *)vif->drv_priv; |
2791 | 2817 | ||
2792 | mutex_lock(&sc->lock); | 2818 | mutex_lock(&sc->lock); |
@@ -2850,18 +2876,6 @@ static int ath5k_add_interface(struct ieee80211_hw *hw, | |||
2850 | sc->num_adhoc_vifs++; | 2876 | sc->num_adhoc_vifs++; |
2851 | } | 2877 | } |
2852 | 2878 | ||
2853 | /* Set combined mode - when APs are configured, operate in AP mode. | ||
2854 | * Otherwise use the mode of the new interface. This can currently | ||
2855 | * only deal with combinations of APs and STAs. Only one ad-hoc | ||
2856 | * interfaces is allowed above. | ||
2857 | */ | ||
2858 | if (sc->num_ap_vifs) | ||
2859 | sc->opmode = NL80211_IFTYPE_AP; | ||
2860 | else | ||
2861 | sc->opmode = vif->type; | ||
2862 | |||
2863 | ath5k_hw_set_opmode(ah, sc->opmode); | ||
2864 | |||
2865 | /* Any MAC address is fine, all others are included through the | 2879 | /* Any MAC address is fine, all others are included through the |
2866 | * filter. | 2880 | * filter. |
2867 | */ | 2881 | */ |
@@ -2905,7 +2919,7 @@ ath5k_remove_interface(struct ieee80211_hw *hw, | |||
2905 | else if (avf->opmode == NL80211_IFTYPE_ADHOC) | 2919 | else if (avf->opmode == NL80211_IFTYPE_ADHOC) |
2906 | sc->num_adhoc_vifs--; | 2920 | sc->num_adhoc_vifs--; |
2907 | 2921 | ||
2908 | ath5k_update_bssid_mask(sc, NULL); | 2922 | ath5k_update_bssid_mask_and_opmode(sc, NULL); |
2909 | mutex_unlock(&sc->lock); | 2923 | mutex_unlock(&sc->lock); |
2910 | } | 2924 | } |
2911 | 2925 | ||