wifi: ath11k: MBSSID beacon support
authorAloka Dixit <quic_alokad@quicinc.com>
Fri, 5 May 2023 13:11:28 +0000 (16:11 +0300)
committerKalle Valo <quic_kvalo@quicinc.com>
Tue, 9 May 2023 16:58:57 +0000 (19:58 +0300)
- Split ath11k_mac_setup_bcn_tmpl() to move the beacon retrieval and
  WMI command to a new function, ath11k_mac_setup_bcn_tmpl_legacy().
  In the original function add checks to use the transmitting interface
  when MBSSID is enabled.
- Set rsnie_present and wpaie_present fields for the non-transmitting
  interfaces when MBSSID is enabled.

Tested-on: IPQ8074 hw2.0 AHB WLAN.HK.2.7.0.1-01744-QCAHKSWPL_SILICONZ-1

Signed-off-by: Aloka Dixit <quic_alokad@quicinc.com>
Co-developed-by: John Crispin <john@phrozen.org>
Signed-off-by: John Crispin <john@phrozen.org>
Signed-off-by: Kalle Valo <quic_kvalo@quicinc.com>
Link: https://lore.kernel.org/r/20230405221648.17950-7-quic_alokad@quicinc.com
drivers/net/wireless/ath/ath11k/mac.c
drivers/net/wireless/ath/ath11k/wmi.c

index adb2122..3229f65 100644 (file)
@@ -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;
index 12b31f3..30364df 100644 (file)
@@ -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);