diff options
Diffstat (limited to 'drivers/net/wireless')
-rw-r--r-- | drivers/net/wireless/ath/ath11k/mac.c | 116 | ||||
-rw-r--r-- | drivers/net/wireless/ath/ath11k/wmi.c | 1 |
2 files changed, 112 insertions, 5 deletions
diff --git a/drivers/net/wireless/ath/ath11k/mac.c b/drivers/net/wireless/ath/ath11k/mac.c index adb2122fe340..3229f65fc6d2 100644 --- a/drivers/net/wireless/ath/ath11k/mac.c +++ b/drivers/net/wireless/ath/ath11k/mac.c @@ -1351,6 +1351,84 @@ err_mon_del: return ret; } +static void ath11k_mac_setup_nontx_vif_rsnie(struct ath11k_vif *arvif, + bool tx_arvif_rsnie_present, + const u8 *profile, u8 profile_len) +{ + if (cfg80211_find_ie(WLAN_EID_RSN, profile, profile_len)) { + arvif->rsnie_present = true; + } else if (tx_arvif_rsnie_present) { + int i; + u8 nie_len; + const u8 *nie = cfg80211_find_ext_ie(WLAN_EID_EXT_NON_INHERITANCE, + profile, profile_len); + if (!nie) + return; + + nie_len = nie[1]; + nie += 2; + for (i = 0; i < nie_len; i++) { + if (nie[i] == WLAN_EID_RSN) { + arvif->rsnie_present = false; + break; + } + } + } +} + +static bool ath11k_mac_set_nontx_vif_params(struct ath11k_vif *tx_arvif, + struct ath11k_vif *arvif, + struct sk_buff *bcn) +{ + struct ieee80211_mgmt *mgmt; + const u8 *ies, *profile, *next_profile; + int ies_len; + + ies = bcn->data + ieee80211_get_hdrlen_from_skb(bcn); + mgmt = (struct ieee80211_mgmt *)bcn->data; + ies += sizeof(mgmt->u.beacon); + ies_len = skb_tail_pointer(bcn) - ies; + + ies = cfg80211_find_ie(WLAN_EID_MULTIPLE_BSSID, ies, ies_len); + arvif->rsnie_present = tx_arvif->rsnie_present; + + while (ies) { + u8 mbssid_len; + + ies_len -= (2 + ies[1]); + mbssid_len = ies[1] - 1; + profile = &ies[3]; + + while (mbssid_len) { + u8 profile_len; + + profile_len = profile[1]; + next_profile = profile + (2 + profile_len); + mbssid_len -= (2 + profile_len); + + profile += 2; + profile_len -= (2 + profile[1]); + profile += (2 + profile[1]); /* nontx capabilities */ + profile_len -= (2 + profile[1]); + profile += (2 + profile[1]); /* SSID */ + if (profile[2] == arvif->vif->bss_conf.bssid_index) { + profile_len -= 5; + profile = profile + 5; + ath11k_mac_setup_nontx_vif_rsnie(arvif, + tx_arvif->rsnie_present, + profile, + profile_len); + return true; + } + profile = next_profile; + } + ies = cfg80211_find_ie(WLAN_EID_MULTIPLE_BSSID, profile, + ies_len); + } + + return false; +} + static void ath11k_mac_set_vif_params(struct ath11k_vif *arvif, struct sk_buff *bcn) { @@ -1374,18 +1452,26 @@ static void ath11k_mac_set_vif_params(struct ath11k_vif *arvif, arvif->wpaie_present = false; } -static int ath11k_mac_setup_bcn_tmpl(struct ath11k_vif *arvif) +static int ath11k_mac_setup_bcn_tmpl_mbssid(struct ath11k_vif *arvif) { struct ath11k *ar = arvif->ar; struct ath11k_base *ab = ar->ab; + struct ath11k_vif *tx_arvif = arvif; struct ieee80211_hw *hw = ar->hw; struct ieee80211_vif *vif = arvif->vif; struct ieee80211_mutable_offsets offs = {}; struct sk_buff *bcn; int ret; - if (arvif->vdev_type != WMI_VDEV_TYPE_AP) - return 0; + if (arvif->vif->mbssid_tx_vif) { + tx_arvif = (void *)arvif->vif->mbssid_tx_vif->drv_priv; + if (tx_arvif != arvif) { + ar = tx_arvif->ar; + ab = ar->ab; + hw = ar->hw; + vif = tx_arvif->vif; + } + } bcn = ieee80211_beacon_get_template(hw, vif, &offs, 0); if (!bcn) { @@ -1393,9 +1479,12 @@ static int ath11k_mac_setup_bcn_tmpl(struct ath11k_vif *arvif) return -EPERM; } - ath11k_mac_set_vif_params(arvif, bcn); - ret = ath11k_wmi_bcn_tmpl(ar, arvif->vdev_id, &offs, bcn); + if (tx_arvif == arvif) + ath11k_mac_set_vif_params(tx_arvif, bcn); + else if (!ath11k_mac_set_nontx_vif_params(tx_arvif, arvif, bcn)) + return -EINVAL; + ret = ath11k_wmi_bcn_tmpl(ar, arvif->vdev_id, &offs, bcn); kfree_skb(bcn); if (ret) @@ -1405,6 +1494,23 @@ static int ath11k_mac_setup_bcn_tmpl(struct ath11k_vif *arvif) return ret; } +static int ath11k_mac_setup_bcn_tmpl(struct ath11k_vif *arvif) +{ + struct ieee80211_vif *vif = arvif->vif; + + if (arvif->vdev_type != WMI_VDEV_TYPE_AP) + return 0; + + /* Target does not expect beacon templates for the already up + * non-transmitting interfaces, and results in a crash if sent. + */ + if (vif->mbssid_tx_vif && + arvif != (void *)vif->mbssid_tx_vif->drv_priv && arvif->is_up) + return 0; + + return ath11k_mac_setup_bcn_tmpl_mbssid(arvif); +} + void ath11k_mac_bcn_tx_event(struct ath11k_vif *arvif) { struct ieee80211_vif *vif = arvif->vif; diff --git a/drivers/net/wireless/ath/ath11k/wmi.c b/drivers/net/wireless/ath/ath11k/wmi.c index 12b31f389318..30364dfe12be 100644 --- a/drivers/net/wireless/ath/ath11k/wmi.c +++ b/drivers/net/wireless/ath/ath11k/wmi.c @@ -1737,6 +1737,7 @@ int ath11k_wmi_bcn_tmpl(struct ath11k *ar, u32 vdev_id, } cmd->buf_len = bcn->len; + cmd->mbssid_ie_offset = offs->mbssid_off; ptr = skb->data + sizeof(*cmd); |