openwrt-ipq-breeze303/package/kernel/mac80211/patches/nss/ath11k/236-003-ath11k-add-dynamic-VLAN-support-in-NSS-offload.patch
Sean Khan 6590c095a7 ath11k_nss: Refresh patches for backports 6.11.2
Signed-off-by: Sean Khan <datapronix@protonmail.com>
2024-10-12 00:24:14 -04:00

558 lines
17 KiB
Diff

From da432fe6dda831c867416d338def3e277c989287 Mon Sep 17 00:00:00 2001
From: Sathishkumar Muruganandam <murugana@codeaurora.org>
Date: Fri, 8 Jan 2021 00:39:47 +0530
Subject: [PATCH 3/3] ath11k: add dynamic VLAN support in NSS offload
Driver should advertise NL80211_EXT_FEATURE_VLAN_OFFLOAD to enable
vlan offload in hostapd.
Group Key for multiple vlan interfaces are configured with the help
of group key index as NSS uses this index to get the corresponding
group key during transmission.
Each dynamic AP-VLAN interface choose unique group key index which
will be sent to NSS along with VLAN ID for dynamic VLAN ext vdev
configuration.
ath11k_mac_op_set_key() does the NSS ext vdev config upon receiving
VLAN ID on group key.
ath11k_mac_op_sta_state() does the STA assignment from AP vif to
AP_VLAN vif in NSS after mac80211.
Currently, the firmware supports upto 128 group keys for an AP
interface. The multiple group key support can be enabled during
resource config.
Co-Developed-by: Seevalamuthu Mariappan <seevalam@codeaurora.org>
Signed-off-by: Seevalamuthu Mariappan <seevalam@codeaurora.org>
Signed-off-by: Sathishkumar Muruganandam <murugana@codeaurora.org>
---
drivers/net/wireless/ath/ath11k/core.h | 8 ++
drivers/net/wireless/ath/ath11k/mac.c | 237 ++++++++++++++++++++++++++++++---
drivers/net/wireless/ath/ath11k/wmi.c | 5 +
drivers/net/wireless/ath/ath11k/wmi.h | 2 +
4 files changed, 233 insertions(+), 19 deletions(-)
--- a/drivers/net/wireless/ath/ath11k/core.h
+++ b/drivers/net/wireless/ath/ath11k/core.h
@@ -102,6 +102,11 @@ enum ath11k_crypt_mode {
ATH11K_CRYPT_MODE_SW,
};
+#define ATH11K_GROUP_KEYS_NUM_MAX 128
+#define ATH11K_FREE_GROUP_IDX_MAP_BITS (BITS_PER_BYTE * (sizeof(long)))
+#define ATH11K_FREE_GROUP_IDX_MAP_MAX (ATH11K_GROUP_KEYS_NUM_MAX / \
+ ATH11K_FREE_GROUP_IDX_MAP_BITS)
+
static inline enum wme_ac ath11k_tid_to_ac(u32 tid)
{
return (((tid == 0) || (tid == 3)) ? WME_AC_BE :
@@ -370,6 +375,20 @@ struct ath11k_mgmt_frame_stats {
u32 tx_compl_fail[ATH11K_STATS_MGMT_FRM_TYPE_MAX];
};
+/**
+ *struct ath11k_dyn_vlan_cfg - dynamic vlan config state info container.
+ * will be used during ieee80211_reconfig
+ * nss offload case
+ *@arvif: driver's data for the corresponding AP_VLAN ieee80211_vif
+ *@sta: ieee80211_sta which is getting associated to AP_VLAN
+ *@cfg_list: list to hold all associated sta's state
+ */
+struct ath11k_dyn_vlan_cfg {
+ struct ath11k_vif *arvif;
+ struct ieee80211_sta *sta;
+ struct list_head cfg_list;
+};
+
struct ath11k_vif {
u32 vdev_id;
enum wmi_vdev_type vdev_type;
@@ -432,6 +451,11 @@ struct ath11k_vif {
struct arvif_nss nss;
#endif
struct list_head ap_vlan_arvifs;
+ /* list required by Dynamic VLAN during fw_recovery */
+ struct list_head dyn_vlan_cfg;
+ /* VLAN keyidx map required for Dynamic VLAN */
+ u16 *vlan_keyid_map;
+ DECLARE_BITMAP(free_groupidx_map, ATH11K_GROUP_KEYS_NUM_MAX);
};
struct ath11k_vif_iter {
--- a/drivers/net/wireless/ath/ath11k/mac.c
+++ b/drivers/net/wireless/ath/ath11k/mac.c
@@ -343,6 +343,10 @@ enum nl80211_he_gi ath11k_mac_he_gi_to_n
return ret;
}
+static int ath11k_mac_cfg_dyn_vlan(struct ath11k_base *ab,
+ struct ath11k_vif *ap_vlan_arvif,
+ struct ieee80211_sta *sta);
+
u8 ath11k_mac_bw_to_mac80211_bw(u8 bw)
{
u8 ret = 0;
@@ -715,6 +719,33 @@ u8 ath11k_mac_get_target_pdev_id(struct
return ar->ab->target_pdev_ids[0].pdev_id;
}
+struct ath11k_vif *ath11k_mac_get_ap_arvif_by_addr(struct ath11k_base *ab,
+ const u8 *addr)
+{
+ int i;
+ struct ath11k_pdev *pdev;
+ struct ath11k_vif *arvif;
+ struct ath11k *ar;
+
+ for (i = 0; i < ab->num_radios; i++) {
+ pdev = rcu_dereference(ab->pdevs_active[i]);
+ if (pdev && pdev->ar) {
+ ar = pdev->ar;
+
+ spin_lock_bh(&ar->data_lock);
+ list_for_each_entry(arvif, &ar->arvifs, list) {
+ if (arvif->vif->type == NL80211_IFTYPE_AP &&
+ ether_addr_equal(arvif->vif->addr, addr)) {
+ spin_unlock_bh(&ar->data_lock);
+ return arvif;
+ }
+ }
+ spin_unlock_bh(&ar->data_lock);
+ }
+ }
+ return NULL;
+}
+
static void ath11k_pdev_caps_update(struct ath11k *ar)
{
struct ath11k_base *ab = ar->ab;
@@ -4265,6 +4296,9 @@ static int ath11k_install_key(struct ath
if (test_bit(ATH11K_FLAG_HW_CRYPTO_DISABLED, &ar->ab->dev_flags))
return 0;
+ if (key->vlan_id)
+ arg.group_key_idx = key->hw_key_idx;
+
if (cmd == DISABLE_KEY) {
arg.key_cipher = WMI_CIPHER_NONE;
arg.key_data = NULL;
@@ -4353,15 +4387,40 @@ static int ath11k_clear_peer_keys(struct
return first_errno;
}
+static int ath11k_get_vlan_groupkey_index(struct ath11k_vif *arvif,
+ struct ieee80211_key_conf *key)
+{
+ struct ath11k *ar = arvif->ar;
+ int map_idx = 0;
+ int free_bit;
+
+ for (map_idx = 0; map_idx < ATH11K_FREE_GROUP_IDX_MAP_MAX; map_idx++)
+ if (arvif->free_groupidx_map[map_idx] != 0)
+ break;
+
+ if (map_idx == ATH11K_FREE_GROUP_IDX_MAP_MAX)
+ return -ENOSPC;
+
+ spin_lock_bh(&ar->data_lock);
+ /* select the first free key index */
+ free_bit = __ffs64(arvif->free_groupidx_map[map_idx]);
+ key->hw_key_idx = (map_idx * ATH11K_FREE_GROUP_IDX_MAP_BITS) + free_bit;
+ /* clear the selected bit from free index map */
+ clear_bit(key->hw_key_idx, arvif->free_groupidx_map);
+ spin_unlock_bh(&ar->data_lock);
+
+ return 0;
+}
+
static int ath11k_mac_op_set_key(struct ieee80211_hw *hw, enum set_key_cmd cmd,
struct ieee80211_vif *vif, struct ieee80211_sta *sta,
struct ieee80211_key_conf *key)
{
struct ath11k *ar = hw->priv;
struct ath11k_base *ab = ar->ab;
- struct ath11k_vif *arvif = ath11k_vif_to_arvif(vif);
+ struct ath11k_vif *arvif, *ap_vlan_arvif = NULL;
struct ath11k_peer *peer;
- struct ath11k_sta *arsta;
+ struct ath11k_sta *arsta = NULL;
const u8 *peer_addr;
int ret = 0;
u32 flags = 0;
@@ -4379,17 +4438,38 @@ static int ath11k_mac_op_set_key(struct
if (key->keyidx > WMI_MAX_KEY_INDEX)
return -ENOSPC;
- mutex_lock(&ar->conf_mutex);
+ arvif = ath11k_vif_to_arvif(vif);
- if (sta)
+ mutex_lock(&ar->conf_mutex);
+ if (sta) {
peer_addr = sta->addr;
- else if (arvif->vdev_type == WMI_VDEV_TYPE_STA)
+ arsta = (struct ath11k_sta *)sta->drv_priv;
+ } else if (arvif->vdev_type == WMI_VDEV_TYPE_STA) {
peer_addr = vif->bss_conf.bssid;
- else
+ } else {
peer_addr = vif->addr;
+ }
key->hw_key_idx = key->keyidx;
+ if (ab->nss.enabled && vif->type == NL80211_IFTYPE_AP_VLAN) {
+ ap_vlan_arvif = arvif;
+ if (arsta) {
+ ap_vlan_arvif->nss.ap_vif = arsta->arvif;
+ arvif = arsta->arvif;
+ } else {
+ rcu_read_lock();
+ arvif = ath11k_mac_get_ap_arvif_by_addr(ab, peer_addr);
+ if (!arvif) {
+ rcu_read_unlock();
+ ret = -EINVAL;
+ goto exit;
+ }
+ ap_vlan_arvif->nss.ap_vif = arvif;
+ rcu_read_unlock();
+ }
+ }
+
/* the peer should not disappear in mid-way (unless FW goes awry) since
* we already hold conf_mutex. we just make sure its there now.
*/
@@ -4434,6 +4514,74 @@ static int ath11k_mac_op_set_key(struct
goto exit;
}
+ /* VLAN ID is updated non-zero only for AP_VLAN vif */
+ if (key->vlan_id && !(key->flags & IEEE80211_KEY_FLAG_PAIRWISE) &&
+ ap_vlan_arvif) {
+ if (arvif->vlan_keyid_map)
+ key->hw_key_idx = arvif->vlan_keyid_map[key->vlan_id];
+ else
+ key->hw_key_idx = 0;
+ switch (cmd) {
+ case SET_KEY:
+ /* If the group key idx is already available,
+ * no need to find the free index again.
+ * This happens during GTK rekey. It uses
+ * the same index after rekey also.
+ */
+ if (!key->hw_key_idx)
+ ret = ath11k_get_vlan_groupkey_index(arvif, key);
+ break;
+ case DISABLE_KEY:
+ /* If the group key idx is already 0,
+ * no need of freeing the index.
+ */
+ if (key->hw_key_idx) {
+ spin_lock_bh(&ar->data_lock);
+ /* make the group index as available */
+ set_bit(key->hw_key_idx, arvif->free_groupidx_map);
+ spin_unlock_bh(&ar->data_lock);
+ }
+ break;
+ default:
+ ret = -EINVAL;
+ }
+
+ if (ret) {
+ ath11k_warn(ab, "failed to set group key index for vlan %u : %d\n",
+ key->vlan_id, ret);
+ goto exit;
+ }
+
+ ret = ath11k_nss_ext_vdev_configure(ap_vlan_arvif);
+ if (ret) {
+ ath11k_warn(ab, "failed to nss cfg ext vdev %pM: %d\n",
+ ap_vlan_arvif->vif->addr, ret);
+ goto exit;
+ }
+
+ ret = ath11k_nss_ext_vdev_cfg_dyn_vlan(ap_vlan_arvif,
+ key->vlan_id);
+ if (ret) {
+ ath11k_warn(ab, "failed to cfg dynamic vlan %d\n", ret);
+ goto exit;
+ }
+
+ ret = ath11k_nss_dyn_vlan_set_group_key(ap_vlan_arvif->nss.ap_vif,
+ key->vlan_id,
+ key->hw_key_idx);
+ if (ret) {
+ ath11k_warn(ab, "failed to set dynamic vlan group key %d\n",
+ ret);
+ goto exit;
+ }
+
+ ret = ath11k_nss_ext_vdev_up(ap_vlan_arvif);
+ if (ret) {
+ ath11k_warn(ab, "failed to set dyn vlan UP %d\n", ret);
+ goto exit;
+ }
+ }
+
spin_lock_bh(&ab->base_lock);
peer = ath11k_peer_find(ab, arvif->vdev_id, peer_addr);
@@ -4456,6 +4604,27 @@ static int ath11k_mac_op_set_key(struct
goto unlock;
}
+ spin_unlock_bh(&ar->ab->base_lock);
+ if (ap_vlan_arvif && ar->state == ATH11K_STATE_RESTARTED) {
+ /* Keys are getting installed during ieee80211_reconfig(). Configuring
+ * dynamic vlan is pending and the state is saved in the ap_vlan
+ * arvif dyn_vlan_cfg list. We will configure it now since nss peer is authorised */
+ struct ath11k_dyn_vlan_cfg *dyn_vlan_cfg, *tmp;
+
+ list_for_each_entry_safe(dyn_vlan_cfg, tmp, &ap_vlan_arvif->dyn_vlan_cfg, cfg_list) {
+ struct ieee80211_sta *vlan_sta = dyn_vlan_cfg->sta;
+
+ ret = ath11k_mac_cfg_dyn_vlan(ar->ab, ap_vlan_arvif, vlan_sta);
+ if (ret)
+ ath11k_warn(ar->ab, "failed to cfg dyn vlan for peer %pM: %d\n",
+ vlan_sta->addr, ret);
+ /* Configuration is used. Free up space */
+ list_del(&dyn_vlan_cfg->cfg_list);
+ kfree(dyn_vlan_cfg);
+ }
+ }
+
+ spin_lock_bh(&ar->ab->base_lock);
if (peer && cmd == SET_KEY) {
peer->keys[key->keyidx] = key;
if (key->flags & IEEE80211_KEY_FLAG_PAIRWISE) {
@@ -4465,18 +4634,23 @@ static int ath11k_mac_op_set_key(struct
peer->mcast_keyidx = key->keyidx;
peer->sec_type_grp = ath11k_dp_tx_get_encrypt_type(key->cipher);
}
+ /* storing group key idx which will be used during rekey */
+ if (key->vlan_id)
+ arvif->vlan_keyid_map[key->vlan_id] = key->hw_key_idx;
} else if (peer && cmd == DISABLE_KEY) {
peer->keys[key->keyidx] = NULL;
if (key->flags & IEEE80211_KEY_FLAG_PAIRWISE)
peer->ucast_keyidx = 0;
else
peer->mcast_keyidx = 0;
- } else if (!peer)
+ if (key->vlan_id)
+ arvif->vlan_keyid_map[key->vlan_id] = 0;
+ } else if (!peer) {
/* impossible unless FW goes crazy */
ath11k_warn(ab, "peer %pM disappeared!\n", peer_addr);
+ }
- if (sta) {
- arsta = ath11k_sta_to_arsta(sta);
+ if (arsta) {
switch (key->cipher) {
case WLAN_CIPHER_SUITE_TKIP:
@@ -6899,7 +7073,7 @@ static int ath11k_mac_op_add_interface(s
if ((vif->type == NL80211_IFTYPE_AP_VLAN ||
vif->type == NL80211_IFTYPE_STATION) && ab->nss.enabled) {
if (ath11k_frame_mode == ATH11K_HW_TXRX_ETHERNET &&
- ieee80211_set_hw_80211_encap(vif, true)) {
+ (vif->offload_flags & IEEE80211_OFFLOAD_ENCAP_ENABLED)) {
vif->offload_flags |= IEEE80211_OFFLOAD_ENCAP_4ADDR;
arvif->nss.encap = ATH11K_HW_TXRX_ETHERNET;
arvif->nss.decap = ATH11K_HW_TXRX_ETHERNET;
@@ -6912,6 +7086,7 @@ static int ath11k_mac_op_add_interface(s
vif->addr, ret);
goto err;
}
+ INIT_LIST_HEAD(&arvif->dyn_vlan_cfg);
mutex_unlock(&ar->conf_mutex);
return ret;
}
@@ -6937,6 +7112,20 @@ static int ath11k_mac_op_add_interface(s
arvif->vdev_id = bit;
arvif->vdev_subtype = WMI_VDEV_SUBTYPE_NONE;
+ spin_lock_bh(&ar->data_lock);
+ /* Configure vlan specific parameters */
+ for (i = 0; i < ATH11K_FREE_GROUP_IDX_MAP_MAX; i++)
+ arvif->free_groupidx_map[i] = 0xFFFFFFFFL;
+ /* Group idx 0 is not valid for VLAN*/
+ arvif->free_groupidx_map[0] &= ~(1L);
+ spin_unlock_bh(&ar->data_lock);
+
+ arvif->vlan_keyid_map = kzalloc(4096, GFP_KERNEL);
+ if (!arvif->vlan_keyid_map) {
+ ret = -ENOMEM;
+ goto err;
+ }
+
switch (vif->type) {
case NL80211_IFTYPE_UNSPECIFIED:
case NL80211_IFTYPE_STATION:
@@ -6986,7 +7175,7 @@ static int ath11k_mac_op_add_interface(s
if (ret) {
ath11k_warn(ab, "failed to create WMI vdev %d: %d\n",
arvif->vdev_id, ret);
- goto err;
+ goto err_keyid;
}
ar->num_created_vdevs++;
@@ -7151,7 +7340,7 @@ err_peer_del:
if (fbret) {
ath11k_warn(ar->ab, "fallback fail to delete peer addr %pM vdev_id %d ret %d\n",
vif->addr, arvif->vdev_id, fbret);
- goto err;
+ goto err_keyid;
}
}
@@ -7162,6 +7351,8 @@ err_vdev_del:
list_del(&arvif->list);
spin_unlock_bh(&ar->data_lock);
+err_keyid:
+ kfree(arvif->vlan_keyid_map);
err:
mutex_unlock(&ar->conf_mutex);
@@ -7260,6 +7451,7 @@ err_vdev_del:
list_del(&arvif->list);
spin_unlock_bh(&ar->data_lock);
+ kfree(arvif->vlan_keyid_map);
ath11k_peer_cleanup(ar, arvif->vdev_id);
idr_for_each(&ar->txmgmt_idr,
@@ -9884,6 +10076,33 @@ static int ath11k_mac_station_remove(str
return ret;
}
+static int ath11k_mac_cfg_dyn_vlan(struct ath11k_base *ab,
+ struct ath11k_vif *ap_vlan_arvif,
+ struct ieee80211_sta *sta)
+{
+ struct ath11k_peer *peer;
+ int peer_id, ret;
+
+ spin_lock_bh(&ab->base_lock);
+ peer = ath11k_peer_find_by_addr(ab, sta->addr);
+ if (!peer) {
+ ath11k_warn(ab, "failed to find peer for %pM\n", sta->addr);
+ spin_unlock_bh(&ab->base_lock);
+ return -EINVAL;
+ }
+ peer_id = peer->peer_id;
+ spin_unlock_bh(&ab->base_lock);
+
+ ret = ath11k_nss_ext_vdev_wds_4addr_allow(ap_vlan_arvif, peer_id);
+ if (ret) {
+ ath11k_warn(ab, "failed to set 4addr allow for %pM:%d\n",
+ sta->addr, ret);
+ return ret;
+ }
+
+ return ret;
+}
+
static int ath11k_mac_op_sta_state(struct ieee80211_hw *hw,
struct ieee80211_vif *vif,
struct ieee80211_sta *sta,
@@ -9973,6 +10192,34 @@ static int ath11k_mac_op_sta_state(struc
if (ret)
ath11k_warn(ar->ab, "Unable to authorize peer %pM vdev %d: %d\n",
sta->addr, arvif->vdev_id, ret);
+ } else if (ar->ab->nss.enabled &&
+ vif->type == NL80211_IFTYPE_AP_VLAN &&
+ !arsta->use_4addr_set) {
+
+ if (ar->state == ATH11K_STATE_RESTARTED) {
+ /* During ieee80211_reconfig(), at this point, nss ext vdev peer is not
+ * authorized. Hence ath11k_mac_cfg_dyn_vlan() will return error. We save
+ * the state vars here and use it later once nss ext vdev is authorized
+ * in ath11k_mac_op_set_key() */
+ struct ath11k_dyn_vlan_cfg *ar_dyn_vlan_cfg;
+ ar_dyn_vlan_cfg = kzalloc(sizeof(*ar_dyn_vlan_cfg), GFP_ATOMIC);
+
+ if (!ar_dyn_vlan_cfg) {
+ ath11k_warn(ar->ab, "failed to save state for dynamic AP_VLAN configuration (%d)",
+ -ENOSPC);
+ } else {
+ INIT_LIST_HEAD(&ar_dyn_vlan_cfg->cfg_list);
+ ar_dyn_vlan_cfg->arvif = arvif;
+ ar_dyn_vlan_cfg->sta = sta;
+ /* save it to arvif (AP_VLAN) list */
+ list_add_tail(&ar_dyn_vlan_cfg->cfg_list, &arvif->dyn_vlan_cfg);
+ }
+ } else {
+ ret = ath11k_mac_cfg_dyn_vlan(ar->ab, arvif, sta);
+ if (ret)
+ ath11k_warn(ar->ab, "failed to cfg dyn vlan for peer %pM: %d\n",
+ sta->addr, ret);
+ }
}
if (!ret &&
@@ -10587,8 +10834,11 @@ static int __ath11k_mac_register(struct
ab->hw_params.bios_sar_capa)
ar->hw->wiphy->sar_capa = ab->hw_params.bios_sar_capa;
- if (ab->nss.enabled)
+ if (ab->nss.enabled) {
ieee80211_hw_set(ar->hw, SUPPORTS_NSS_OFFLOAD);
+ wiphy_ext_feature_set(ar->hw->wiphy,
+ NL80211_EXT_FEATURE_VLAN_OFFLOAD);
+ }
ret = ieee80211_register_hw(ar->hw);
if (ret) {
--- a/drivers/net/wireless/ath/ath11k/wmi.c
+++ b/drivers/net/wireless/ath/ath11k/wmi.c
@@ -1982,6 +1982,7 @@ int ath11k_wmi_vdev_install_key(struct a
cmd->key_len = arg->key_len;
cmd->key_txmic_len = arg->key_txmic_len;
cmd->key_rxmic_len = arg->key_rxmic_len;
+ cmd->group_key_id = arg->group_key_idx;
if (arg->key_rsc_counter)
memcpy(&cmd->key_rsc_counter, &arg->key_rsc_counter,
@@ -4321,6 +4322,7 @@ ath11k_wmi_copy_resource_config(struct w
wmi_cfg->flags2 = WMI_RSRC_CFG_FLAG2_CALC_NEXT_DTIM_COUNT_SET;
wmi_cfg->ema_max_vap_cnt = tg_cfg->ema_max_vap_cnt;
wmi_cfg->ema_max_profile_period = tg_cfg->ema_max_profile_period;
+ wmi_cfg->max_num_group_keys = tg_cfg->max_num_group_keys;
}
static int ath11k_init_cmd_send(struct ath11k_pdev_wmi *wmi,
@@ -4543,6 +4545,9 @@ int ath11k_wmi_cmd_init(struct ath11k_ba
memset(&init_param, 0, sizeof(init_param));
memset(&config, 0, sizeof(config));
+ if (ab->nss.enabled)
+ config.max_num_group_keys = ATH11K_GROUP_KEYS_NUM_MAX;
+
ab->hw_params.hw_ops->wmi_init_config(ab, &config);
if (test_bit(WMI_TLV_SERVICE_REG_CC_EXT_EVENT_SUPPORT,
--- a/drivers/net/wireless/ath/ath11k/wmi.h
+++ b/drivers/net/wireless/ath/ath11k/wmi.h
@@ -3755,6 +3755,7 @@ struct wmi_vdev_install_key_arg {
u32 vdev_id;
const u8 *macaddr;
u32 key_idx;
+ u32 group_key_idx;
u32 key_flags;
u32 key_cipher;
u32 key_len;
@@ -5815,6 +5816,7 @@ struct target_resource_config {
u32 bpf_instruction_size;
u32 max_bssid_rx_filters;
u32 use_pdev_id;
+ u32 max_num_group_keys;
u32 peer_map_unmap_v2_support;
u32 sched_params;
u32 twt_ap_pdev_count;