mirror of
https://github.com/Telecominfraproject/wlan-ap.git
synced 2025-12-21 11:22:50 +00:00
414 lines
12 KiB
Diff
414 lines
12 KiB
Diff
From 3fe2ac33f0d0f7a9c305943f127eb11c6f871ba8 Mon Sep 17 00:00:00 2001
|
|
From: Muna Sinada <quic_msinada@quicinc.com>
|
|
Date: Tue, 7 Feb 2023 07:38:58 -0800
|
|
Subject: [PATCH] wifi: ath12k: Add Dynamic VLAN support
|
|
|
|
Add support for dynamic VLAN. VLAN group traffic is encrypted in
|
|
mac80211 and driver needs to add metadata for the SW encrypted vlan group
|
|
traffic.
|
|
|
|
Signed-off-by: Muna Sinada <quic_msinada@quicinc.com>
|
|
---
|
|
drivers/net/wireless/ath/ath12k/dp_tx.c | 71 +++++++++++-
|
|
drivers/net/wireless/ath/ath12k/dp_tx.h | 198 ++++++++++++++++++++++++++++++++
|
|
drivers/net/wireless/ath/ath12k/mac.c | 3 +
|
|
3 files changed, 270 insertions(+), 2 deletions(-)
|
|
|
|
--- a/drivers/net/wireless/ath/ath12k/dp_tx.c
|
|
+++ b/drivers/net/wireless/ath/ath12k/dp_tx.c
|
|
@@ -117,6 +117,43 @@ static void ath12k_hal_tx_cmd_ext_desc_s
|
|
HAL_TX_MSDU_EXT_INFO1_ENCRYPT_TYPE);
|
|
}
|
|
|
|
+#define HTT_META_DATA_ALIGNMENT 0x8
|
|
+
|
|
+static int ath12k_dp_metadata_align_skb(struct sk_buff *skb, u8 align_len)
|
|
+{
|
|
+ if (unlikely(skb_cow_head(skb, align_len)))
|
|
+ return -ENOMEM;
|
|
+
|
|
+ skb_push(skb, align_len);
|
|
+ memset(skb->data, 0, align_len);
|
|
+ return 0;
|
|
+}
|
|
+
|
|
+static int ath12k_dp_prepare_htt_metadata(struct sk_buff *skb,
|
|
+ u8 *htt_metadata_size)
|
|
+{
|
|
+ u8 htt_desc_size;
|
|
+ /* Size rounded of multiple of 8 bytes */
|
|
+ u8 htt_desc_size_aligned;
|
|
+ int ret;
|
|
+ struct htt_tx_msdu_desc_ext *desc_ext;
|
|
+
|
|
+ htt_desc_size = sizeof(struct htt_tx_msdu_desc_ext);
|
|
+ htt_desc_size_aligned = ALIGN(htt_desc_size, HTT_META_DATA_ALIGNMENT);
|
|
+
|
|
+ ret = ath12k_dp_metadata_align_skb(skb, htt_desc_size_aligned);
|
|
+ if (unlikely(ret))
|
|
+ return ret;
|
|
+
|
|
+ desc_ext = (struct htt_tx_msdu_desc_ext *)skb->data;
|
|
+ desc_ext->valid_encrypt_type = 1;
|
|
+ desc_ext->encrypt_type = HAL_ENCRYPT_TYPE_WEP_40;
|
|
+ desc_ext->host_tx_desc_pool = 1;
|
|
+ *htt_metadata_size = htt_desc_size_aligned;
|
|
+
|
|
+ return 0;
|
|
+}
|
|
+
|
|
int ath12k_dp_tx(struct ath12k *ar, struct ath12k_link_vif *arvif,
|
|
struct ath12k_sta *ahsta, struct sk_buff *skb)
|
|
{
|
|
@@ -141,6 +178,8 @@ int ath12k_dp_tx(struct ath12k *ar, stru
|
|
bool tcl_ring_retry;
|
|
u16 peer_id;
|
|
bool msdu_ext_desc = false;
|
|
+ bool is_diff_encap = false;
|
|
+ u8 align_pad, htt_meta_size = 0;
|
|
|
|
if (unlikely(test_bit(ATH12K_FLAG_CRASH_FLUSH, &ar->ab->dev_flags)))
|
|
return -ESHUTDOWN;
|
|
@@ -224,7 +263,11 @@ tcl_ring_sel:
|
|
|
|
switch (ti.encap_type) {
|
|
case HAL_TCL_ENCAP_TYPE_NATIVE_WIFI:
|
|
- ath12k_dp_tx_encap_nwifi(skb);
|
|
+ if ((ahvif->vif->offload_flags & IEEE80211_OFFLOAD_ENCAP_ENABLED) &&
|
|
+ skb->protocol == cpu_to_be16(ETH_P_PAE))
|
|
+ is_diff_encap = true;
|
|
+ else
|
|
+ ath12k_dp_tx_encap_nwifi(skb);
|
|
break;
|
|
case HAL_TCL_ENCAP_TYPE_RAW:
|
|
if (!test_bit(ATH12K_FLAG_RAW_MODE, &ag->dev_flags)) {
|
|
@@ -243,14 +286,6 @@ tcl_ring_sel:
|
|
goto fail_remove_tx_buf;
|
|
}
|
|
|
|
- ti.paddr = dma_map_single(ab->dev, skb->data, skb->len, DMA_TO_DEVICE);
|
|
- if (unlikely(dma_mapping_error(ab->dev, ti.paddr))) {
|
|
- atomic_inc(&ab->soc_stats.tx_err.misc_fail);
|
|
- ath12k_warn(ab, "failed to DMA map data Tx buffer\n");
|
|
- ret = -ENOMEM;
|
|
- goto fail_remove_tx_buf;
|
|
- }
|
|
-
|
|
if (unlikely((ahvif->tx_encap_type == HAL_TCL_ENCAP_TYPE_ETHERNET &&
|
|
!(info->flags & IEEE80211_TX_CTL_HW_80211_ENCAP)))) {
|
|
msdu_ext_desc = true;
|
|
@@ -279,10 +314,40 @@ tcl_ring_sel:
|
|
}
|
|
}
|
|
|
|
+ /* Add metadata for sw encrypted vlan group traffic */
|
|
+ if ((!test_bit(ATH12K_FLAG_HW_CRYPTO_DISABLED, &ar->ab->ag->dev_flags) &&
|
|
+ !(info->control.flags & IEEE80211_TX_CTL_HW_80211_ENCAP) &&
|
|
+ !info->control.hw_key && ieee80211_has_protected(hdr->frame_control)) ||
|
|
+ is_diff_encap) {
|
|
+ align_pad = ((unsigned long)skb->data) & (HTT_META_DATA_ALIGNMENT - 1);
|
|
+ ret = ath12k_dp_metadata_align_skb(skb, align_pad);
|
|
+ if (unlikely(ret))
|
|
+ goto fail_remove_tx_buf;
|
|
+
|
|
+ ti.pkt_offset += align_pad;
|
|
+ ret = ath12k_dp_prepare_htt_metadata(skb, &htt_meta_size);
|
|
+ if (unlikely(ret))
|
|
+ goto fail_remove_tx_buf;
|
|
+
|
|
+ ti.pkt_offset += htt_meta_size;
|
|
+ ti.meta_data_flags |= HTT_TCL_META_DATA_VALID_HTT;
|
|
+ ti.flags0 |= FIELD_PREP(HAL_TCL_DATA_CMD_INFO2_TO_FW, 1);
|
|
+ ti.encap_type = HAL_TCL_ENCAP_TYPE_RAW;
|
|
+ ti.encrypt_type = HAL_ENCRYPT_TYPE_OPEN;
|
|
+ }
|
|
+
|
|
+ ti.paddr = dma_map_single(ab->dev, skb->data, skb->len, DMA_TO_DEVICE);
|
|
+ if (unlikely(dma_mapping_error(ab->dev, ti.paddr))) {
|
|
+ atomic_inc(&ab->soc_stats.tx_err.misc_fail);
|
|
+ ath12k_warn(ab, "failed to DMA map data Tx buffer\n");
|
|
+ ret = -ENOMEM;
|
|
+ goto fail_remove_tx_buf;
|
|
+ }
|
|
+
|
|
tx_desc->skb = skb;
|
|
tx_desc->mac_id = ar->pdev_idx;
|
|
ti.desc_id = tx_desc->desc_id;
|
|
- ti.data_len = skb->len;
|
|
+ ti.data_len = skb->len - ti.pkt_offset;
|
|
skb_cb->paddr = ti.paddr;
|
|
skb_cb->vif = ahvif->vif;
|
|
skb_cb->ar = ar;
|
|
@@ -373,6 +438,9 @@ fail_unmap_dma:
|
|
|
|
fail_remove_tx_buf:
|
|
ath12k_dp_tx_release_txbuf(dp, tx_desc, ti.ring_id);
|
|
+ if (ti.pkt_offset)
|
|
+ skb_pull(skb, ti.pkt_offset);
|
|
+
|
|
if (tcl_ring_retry)
|
|
goto tcl_ring_sel;
|
|
|
|
--- a/drivers/net/wireless/ath/ath12k/dp_tx.h
|
|
+++ b/drivers/net/wireless/ath/ath12k/dp_tx.h
|
|
@@ -15,6 +15,204 @@ struct ath12k_dp_htt_wbm_tx_status {
|
|
int ack_rssi;
|
|
};
|
|
|
|
+/* htt_tx_msdu_desc_ext
|
|
+ *
|
|
+ * valid_pwr
|
|
+ * if set, tx pwr spec is valid
|
|
+ *
|
|
+ * valid_mcs_mask
|
|
+ * if set, tx MCS mask is valid
|
|
+ *
|
|
+ * valid_nss_mask
|
|
+ * if set, tx Nss mask is valid
|
|
+ *
|
|
+ * valid_preamble_type
|
|
+ * if set, tx preamble spec is valid
|
|
+ *
|
|
+ * valid_retries
|
|
+ * if set, tx retries spec is valid
|
|
+ *
|
|
+ * valid_bw_info
|
|
+ * if set, tx dyn_bw and bw_mask are valid
|
|
+ *
|
|
+ * valid_guard_interval
|
|
+ * if set, tx guard intv spec is valid
|
|
+ *
|
|
+ * valid_chainmask
|
|
+ * if set, tx chainmask is valid
|
|
+ *
|
|
+ * valid_encrypt_type
|
|
+ * if set, encrypt type is valid
|
|
+ *
|
|
+ * valid_key_flags
|
|
+ * if set, key flags is valid
|
|
+ *
|
|
+ * valid_expire_tsf
|
|
+ * if set, tx expire TSF spec is valid
|
|
+ *
|
|
+ * valid_chanfreq
|
|
+ * if set, chanfreq is valid
|
|
+ *
|
|
+ * is_dsrc
|
|
+ * if set, MSDU is a DSRC frame
|
|
+ *
|
|
+ * guard_interval
|
|
+ * 0.4us, 0.8us, 1.6us, 3.2us
|
|
+ *
|
|
+ * encrypt_type
|
|
+ * 0 = NO_ENCRYPT,
|
|
+ * 1 = ENCRYPT,
|
|
+ * 2 ~ 3 - Reserved
|
|
+ *
|
|
+ * retry_limit
|
|
+ * Specify the maximum number of transmissions, including the
|
|
+ * initial transmission, to attempt before giving up if no ack
|
|
+ * is received.
|
|
+ * If the tx rate is specified, then all retries shall use the
|
|
+ * same rate as the initial transmission.
|
|
+ * If no tx rate is specified, the target can choose whether to
|
|
+ * retain the original rate during the retransmissions, or to
|
|
+ * fall back to a more robust rate.
|
|
+ *
|
|
+ * use_dcm_11ax
|
|
+ * If set, Use Dual subcarrier modulation.
|
|
+ * Valid only for 11ax preamble types HE_SU
|
|
+ * and HE_EXT_SU
|
|
+ *
|
|
+ * ltf_subtype_11ax
|
|
+ * Takes enum values of htt_11ax_ltf_subtype_t
|
|
+ * Valid only for 11ax preamble types HE_SU
|
|
+ * and HE_EXT_SU
|
|
+ *
|
|
+ * dyn_bw
|
|
+ * 0 = static bw, 1 = dynamic bw
|
|
+ *
|
|
+ * bw_mask
|
|
+ * Valid only if dyn_bw == 0 (static bw).
|
|
+ *
|
|
+ * host_tx_desc_pool
|
|
+ * If set, Firmware allocates tx_descriptors
|
|
+ * in WAL_BUFFERID_TX_HOST_DATA_EXP,instead
|
|
+ * of WAL_BUFFERID_TX_TCL_DATA_EXP.
|
|
+ * Use cases:
|
|
+ * Any time firmware uses TQM-BYPASS for Data
|
|
+ * TID, firmware expect host to set this bit.
|
|
+ *
|
|
+ * power
|
|
+ * unit of the power field is 0.5 dbm
|
|
+ * signed value ranging from -64dbm to 63.5 dbm
|
|
+ *
|
|
+ * mcs_mask
|
|
+ * mcs bit mask of 0 ~ 11
|
|
+ * Setting more than one MCS isn't currently
|
|
+ * supported by the target (but is supported
|
|
+ * in the interface in case in the future
|
|
+ * the target supports specifications of
|
|
+ * a limited set of MCS values.
|
|
+ *
|
|
+ * nss_mask
|
|
+ * Nss bit mask 0 ~ 7
|
|
+ * Setting more than one Nss isn't currently
|
|
+ * supported by the target (but is supported
|
|
+ * in the interface in case in the future
|
|
+ * the target supports specifications of
|
|
+ * a limited set of Nss values.
|
|
+ *
|
|
+ * pream_type
|
|
+ * Preamble types
|
|
+ *
|
|
+ * update_peer_cache
|
|
+ * When set these custom values will be
|
|
+ * used for all packets, until the next
|
|
+ * update via this ext header.
|
|
+ * This is to make sure not all packets
|
|
+ * need to include this header.
|
|
+ *
|
|
+ * chain_mask
|
|
+ * specify which chains to transmit from
|
|
+ *
|
|
+ * key_flags
|
|
+ * Key Index and related flags - used in mesh mode
|
|
+ *
|
|
+ * chanfreq
|
|
+ * Channel frequency: This identifies the desired channel
|
|
+ * frequency (in MHz) for tx frames. This is used by FW to help
|
|
+ * determine when it is safe to transmit or drop frames for
|
|
+ * off-channel operation.
|
|
+ * The default value of zero indicates to FW that the corresponding
|
|
+ * VDEV's home channel (if there is one) is the desired channel
|
|
+ * frequency.
|
|
+ *
|
|
+ * expire_tsf_lo
|
|
+ * tx expiry time (TSF) LSBs
|
|
+ *
|
|
+ * expire_tsf_hi
|
|
+ * tx expiry time (TSF) MSBs
|
|
+ *
|
|
+ * learning_frame
|
|
+ * When this flag is set, this frame will be dropped by FW
|
|
+ * rather than being enqueued to the Transmit Queue Manager (TQM) HW.
|
|
+ *
|
|
+ * send_as_standalone
|
|
+ * This will indicate if the msdu needs to be sent as a singleton PPDU,
|
|
+ * i.e. with no A-MSDU or A-MPDU aggregation.
|
|
+ * The scope is extended to other use-cases.
|
|
+ *
|
|
+ * is_host_opaque_valid
|
|
+ * set this bit to 1 if the host_opaque_cookie is populated
|
|
+ * with valid information.
|
|
+ *
|
|
+ * host_opaque_cookie
|
|
+ * Host opaque cookie for special frames
|
|
+ */
|
|
+
|
|
+struct htt_tx_msdu_desc_ext {
|
|
+ u32
|
|
+ valid_pwr : 1,
|
|
+ valid_mcs_mask : 1,
|
|
+ valid_nss_mask : 1,
|
|
+ valid_preamble_type : 1,
|
|
+ valid_retries : 1,
|
|
+ valid_bw_info : 1,
|
|
+ valid_guard_interval : 1,
|
|
+ valid_chainmask : 1,
|
|
+ valid_encrypt_type : 1,
|
|
+ valid_key_flags : 1,
|
|
+ valid_expire_tsf : 1,
|
|
+ valid_chanfreq : 1,
|
|
+ is_dsrc : 1,
|
|
+ guard_interval : 2,
|
|
+ encrypt_type : 2,
|
|
+ retry_limit : 4,
|
|
+ use_dcm_11ax : 1,
|
|
+ ltf_subtype_11ax : 2,
|
|
+ dyn_bw : 1,
|
|
+ bw_mask : 6,
|
|
+ host_tx_desc_pool : 1;
|
|
+ u32
|
|
+ power : 8,
|
|
+ mcs_mask : 12,
|
|
+ nss_mask : 8,
|
|
+ pream_type : 3,
|
|
+ update_peer_cache : 1;
|
|
+ u32
|
|
+ chain_mask : 8,
|
|
+ key_flags : 8,
|
|
+ chanfreq : 16;
|
|
+
|
|
+ u32 expire_tsf_lo;
|
|
+ u32 expire_tsf_hi;
|
|
+
|
|
+ u32
|
|
+ learning_frame : 1,
|
|
+ send_as_standalone : 1,
|
|
+ is_host_opaque_valid : 1,
|
|
+ rsvd0 : 29;
|
|
+ u32
|
|
+ host_opaque_cookie : 16,
|
|
+ rsvd1 : 16;
|
|
+} __packed;
|
|
+
|
|
void ath12k_dp_tx_update_txcompl(struct ath12k *ar, struct hal_tx_status *ts);
|
|
int ath12k_dp_tx_htt_h2t_ver_req_msg(struct ath12k_base *ab);
|
|
int ath12k_dp_tx(struct ath12k *ar, struct ath12k_link_vif *arvif,
|
|
--- a/drivers/net/wireless/ath/ath12k/mac.c
|
|
+++ b/drivers/net/wireless/ath/ath12k/mac.c
|
|
@@ -14266,6 +14266,9 @@ static int __ath12k_mac_register(struct
|
|
ar->max_num_stations = TARGET_NUM_STATIONS;
|
|
ar->max_num_peers = TARGET_NUM_PEERS_PDEV;
|
|
|
|
+ hw->wiphy->interface_modes |= BIT(NL80211_IFTYPE_AP_VLAN);
|
|
+ hw->wiphy->software_iftypes |= BIT(NL80211_IFTYPE_AP_VLAN);
|
|
+
|
|
if (cap->nss_ratio_enabled)
|
|
ieee80211_hw_set(hw, SUPPORTS_VHT_EXT_NSS_BW);
|
|
|
|
--- a/net/mac80211/chan.c
|
|
+++ b/net/mac80211/chan.c
|
|
@@ -2049,6 +2049,9 @@ void ieee80211_link_vlan_copy_chanctx(st
|
|
conf = rcu_dereference_protected(ap_conf->chanctx_conf,
|
|
lockdep_is_held(&local->chanctx_mtx));
|
|
rcu_assign_pointer(link_conf->chanctx_conf, conf);
|
|
+ memcpy(&sdata->vif.link_conf[link_id]->chandef,
|
|
+ &ap->vif.link_conf[link_id]->chandef,
|
|
+ sizeof(struct cfg80211_chan_def));
|
|
rcu_read_unlock();
|
|
mutex_unlock(&local->chanctx_mtx);
|
|
}
|
|
--- a/net/mac80211/tx.c
|
|
+++ b/net/mac80211/tx.c
|
|
@@ -2692,8 +2692,15 @@ static struct sk_buff *ieee80211_build_h
|
|
ap_sdata = container_of(sdata->bss,
|
|
struct ieee80211_sub_if_data,
|
|
u.ap);
|
|
- chanctx_conf =
|
|
- rcu_dereference(ap_sdata->vif.bss_conf.chanctx_conf);
|
|
+
|
|
+ /* TODO: change index of link_conf[] to link id of corresponding
|
|
+ * AP for MLO cases */
|
|
+ if (ap_sdata->vif.valid_links)
|
|
+ chanctx_conf =
|
|
+ rcu_dereference(ap_sdata->vif.link_conf[0]->chanctx_conf);
|
|
+ else
|
|
+ chanctx_conf =
|
|
+ rcu_dereference(ap_sdata->vif.bss_conf.chanctx_conf);
|
|
}
|
|
if (sdata->wdev.use_4addr)
|
|
break;
|
|
--- a/net/wireless/nl80211.c
|
|
+++ b/net/wireless/nl80211.c
|
|
@@ -4737,7 +4737,7 @@ static int nl80211_validate_key_link_id(
|
|
GENL_SET_ERR_MSG(info, "invalid link ID for MLO group key");
|
|
return -EINVAL;
|
|
}
|
|
- } else if (link_id != -1) {
|
|
+ } else if (link_id != -1 && wdev->iftype != NL80211_IFTYPE_AP_VLAN) {
|
|
GENL_SET_ERR_MSG(info, "link ID not allowed for non-MLO group key");
|
|
return -EINVAL;
|
|
}
|