Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

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>

authored by

Ben Greear and committed by
John W. Linville
62c58fb4 92c68a66

+40 -26
+40 -26
drivers/net/wireless/ath/ath5k/base.c
··· 62 62 #include "reg.h" 63 63 #include "debug.h" 64 64 #include "ani.h" 65 + #include "../debug.h" 65 66 66 67 static int modparam_nohwcrypt; 67 68 module_param_named(nohwcrypt, modparam_nohwcrypt, bool, S_IRUGO); ··· 518 517 bool need_set_hw_addr; 519 518 bool found_active; 520 519 bool any_assoc; 520 + enum nl80211_iftype opmode; 521 521 }; 522 522 523 523 static void ath_vif_iter(void *data, u8 *mac, struct ieee80211_vif *vif) 524 524 { 525 525 struct ath_vif_iter_data *iter_data = data; 526 526 int i; 527 + struct ath5k_vif *avf = (void *)vif->drv_priv; 527 528 528 529 if (iter_data->hw_macaddr) 529 530 for (i = 0; i < ETH_ALEN; i++) ··· 542 539 iter_data->need_set_hw_addr = false; 543 540 544 541 if (!iter_data->any_assoc) { 545 - struct ath5k_vif *avf = (void *)vif->drv_priv; 546 542 if (avf->assoc) 547 543 iter_data->any_assoc = true; 548 544 } 545 + 546 + /* Calculate combined mode - when APs are active, operate in AP mode. 547 + * Otherwise use the mode of the new interface. This can currently 548 + * only deal with combinations of APs and STAs. Only one ad-hoc 549 + * interfaces is allowed above. 550 + */ 551 + if (avf->opmode == NL80211_IFTYPE_AP) 552 + iter_data->opmode = NL80211_IFTYPE_AP; 553 + else 554 + if (iter_data->opmode == NL80211_IFTYPE_UNSPECIFIED) 555 + iter_data->opmode = avf->opmode; 549 556 } 550 557 551 - void ath5k_update_bssid_mask(struct ath5k_softc *sc, struct ieee80211_vif *vif) 558 + static void ath_do_set_opmode(struct ath5k_softc *sc) 559 + { 560 + struct ath5k_hw *ah = sc->ah; 561 + ath5k_hw_set_opmode(ah, sc->opmode); 562 + ATH5K_DBG(sc, ATH5K_DEBUG_MODE, "mode setup opmode %d (%s)\n", 563 + sc->opmode, 564 + ath_opmode_to_string(sc->opmode) ? 565 + ath_opmode_to_string(sc->opmode) : "UKNOWN"); 566 + } 567 + 568 + void ath5k_update_bssid_mask_and_opmode(struct ath5k_softc *sc, 569 + struct ieee80211_vif *vif) 552 570 { 553 571 struct ath_common *common = ath5k_hw_common(sc->ah); 554 572 struct ath_vif_iter_data iter_data; ··· 582 558 memset(&iter_data.mask, 0xff, ETH_ALEN); 583 559 iter_data.found_active = false; 584 560 iter_data.need_set_hw_addr = true; 561 + iter_data.opmode = NL80211_IFTYPE_UNSPECIFIED; 585 562 586 563 if (vif) 587 564 ath_vif_iter(&iter_data, vif->addr, vif); ··· 592 567 &iter_data); 593 568 memcpy(sc->bssidmask, iter_data.mask, ETH_ALEN); 594 569 570 + sc->opmode = iter_data.opmode; 571 + if (sc->opmode == NL80211_IFTYPE_UNSPECIFIED) 572 + /* Nothing active, default to station mode */ 573 + sc->opmode = NL80211_IFTYPE_STATION; 574 + 575 + ath_do_set_opmode(sc); 576 + 595 577 if (iter_data.need_set_hw_addr && iter_data.found_active) 596 578 ath5k_hw_set_lladdr(sc->ah, iter_data.active_mac); 597 579 598 - ath5k_hw_set_bssid_mask(sc->ah, sc->bssidmask); 580 + if (ath5k_hw_hasbssidmask(sc->ah)) 581 + ath5k_hw_set_bssid_mask(sc->ah, sc->bssidmask); 599 582 } 600 583 601 584 static void ··· 615 582 /* configure rx filter */ 616 583 rfilt = sc->filter_flags; 617 584 ath5k_hw_set_rx_filter(ah, rfilt); 618 - 619 - if (ath5k_hw_hasbssidmask(ah)) 620 - ath5k_update_bssid_mask(sc, vif); 621 - 622 - /* configure operational mode */ 623 - ath5k_hw_set_opmode(ah, sc->opmode); 624 - 625 - ATH5K_DBG(sc, ATH5K_DEBUG_MODE, "mode setup opmode %d\n", sc->opmode); 626 585 ATH5K_DBG(sc, ATH5K_DEBUG_MODE, "RX filter 0x%x\n", rfilt); 586 + 587 + ath5k_update_bssid_mask_and_opmode(sc, vif); 627 588 } 628 589 629 590 static inline int ··· 2715 2688 SET_IEEE80211_PERM_ADDR(hw, mac); 2716 2689 memcpy(&sc->lladdr, mac, ETH_ALEN); 2717 2690 /* All MAC address bits matter for ACKs */ 2718 - ath5k_update_bssid_mask(sc, NULL); 2691 + ath5k_update_bssid_mask_and_opmode(sc, NULL); 2719 2692 2720 2693 regulatory->current_rd = ah->ah_capabilities.cap_eeprom.ee_regdomain; 2721 2694 ret = ath_regd_init(regulatory, hw->wiphy, ath5k_reg_notifier); ··· 2813 2786 { 2814 2787 struct ath5k_softc *sc = hw->priv; 2815 2788 int ret; 2816 - struct ath5k_hw *ah = sc->ah; 2817 2789 struct ath5k_vif *avf = (void *)vif->drv_priv; 2818 2790 2819 2791 mutex_lock(&sc->lock); ··· 2876 2850 sc->num_adhoc_vifs++; 2877 2851 } 2878 2852 2879 - /* Set combined mode - when APs are configured, operate in AP mode. 2880 - * Otherwise use the mode of the new interface. This can currently 2881 - * only deal with combinations of APs and STAs. Only one ad-hoc 2882 - * interfaces is allowed above. 2883 - */ 2884 - if (sc->num_ap_vifs) 2885 - sc->opmode = NL80211_IFTYPE_AP; 2886 - else 2887 - sc->opmode = vif->type; 2888 - 2889 - ath5k_hw_set_opmode(ah, sc->opmode); 2890 - 2891 2853 /* Any MAC address is fine, all others are included through the 2892 2854 * filter. 2893 2855 */ ··· 2919 2905 else if (avf->opmode == NL80211_IFTYPE_ADHOC) 2920 2906 sc->num_adhoc_vifs--; 2921 2907 2922 - ath5k_update_bssid_mask(sc, NULL); 2908 + ath5k_update_bssid_mask_and_opmode(sc, NULL); 2923 2909 mutex_unlock(&sc->lock); 2924 2910 } 2925 2911