[PATCH v3 RESEND] ath11k: add support for dynamic vlan (ap/vlan)
Vasanthakumar Thiagarajan
quic_vthiagar at quicinc.com
Thu Jun 12 00:25:41 PDT 2025
On 6/5/2025 4:52 AM, David Rapaň wrote:
> ath11k currently lacks support for dynamic vlan (AP/VLAN), so make
> '__ath11k_mac_register' in dp_tx to register 'NL80211_IFTYPE_AP_VLAN'
> as available interface mode.
>
> Make 'ath11k_dp_tx' in dp_tx to add metadata info to notify firmware
> that the multicast/broadcast packets are encrypted in software.
>
> Make '__ieee80211_subif_start_xmit' in tx to offload encapsulation
> for VLAN unicast packets using 8023 xmit path instead of current
> 80211 xmit path.
>
> Tested, long-term in production environment using OpenWrt platform
> installed on multiple AX3600 with FT:
> Tested-on: IPQ8074 hw2.0 AHB WLAN.HK.2.9.0.1-01385-QCAHKSWPL_SILICONZ-1
> Tested-on: IPQ8074 hw2.0 AHB WLAN.HK.2.9.0.1-01977-QCAHKSWPL_SILICONZ-1
>
> Co-developed-by: Seevalamuthu Mariappan <seevalam at codeaurora.org>
> Signed-off-by: Seevalamuthu Mariappan <seevalam at codeaurora.org>
> Signed-off-by: David Rapan <david at rapan.cz>
> ---
> v1 -> v2: Move 'cpu_to_be16(ETH_P_PAE)' to earlier condition and add
> 'ieee80211_is_qos_nullfunc' check so QoS NULL Data frames are
> properly send as open type frames with TID 7 in ethernet encap
> instead of QoS Data with TID 0.
> v2 -> v3: Make 'hal_tx_msdu_metadata' struct to comply with current
> coding standard (no use of bit masks in '__packed').
> Make key retrieval in 8023 xmit path from
> '__ieee80211_subif_start_xmit' to be on pair with the standard flow in
> 'ieee80211_subif_start_xmit_8023' where it also falls back to
> 'default_unicast_key'.
>
> drivers/net/wireless/ath/ath11k/core.h | 1 +
> drivers/net/wireless/ath/ath11k/dp_tx.c | 83 +++++++++-
> drivers/net/wireless/ath/ath11k/hal_desc.h | 160 ++++++++++++++++++++
> drivers/net/wireless/ath/ath11k/mac.c | 3 +
> net/mac80211/tx.c | 15 +++
> 5 files changed, 260 insertions(+), 2 deletions(-)
>
> base-commit: ff8069c7cf3eb0fcd53adebdf341b6aaa98bdd3b
>
> --- a/drivers/net/wireless/ath/ath11k/core.h
> +++ b/drivers/net/wireless/ath/ath11k/core.h
> @@ -120,6 +120,7 @@ struct ath11k_skb_cb {
> u32 cipher;
> struct ath11k *ar;
> struct ieee80211_vif *vif;
> + u32 pkt_offset;
> } __packed;
>
> struct ath11k_skb_rxcb {
> --- a/drivers/net/wireless/ath/ath11k/dp_tx.c
> +++ b/drivers/net/wireless/ath/ath11k/dp_tx.c
> @@ -79,6 +79,43 @@ enum hal_encrypt_type ath11k_dp_tx_get_e
> }
> }
>
> +#define HTT_META_DATA_ALIGNMENT 0x8
> +
> +static int ath11k_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 ath11k_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 hal_tx_msdu_metadata *desc_ext;
> +
> + htt_desc_size = sizeof(struct hal_tx_msdu_metadata);
> + htt_desc_size_aligned = ALIGN(htt_desc_size, HTT_META_DATA_ALIGNMENT);
> +
> + ret = ath11k_dp_metadata_align_skb(skb, htt_desc_size_aligned);
> + if (unlikely(ret))
> + return ret;
> +
> + desc_ext = (struct hal_tx_msdu_metadata *)skb->data;
> + desc_ext->info0 = le32_encode_bits(1, HAL_TX_MSDU_METADATA_INFO0_ENCRYPT_FLAG) |
> + le32_encode_bits(0, HAL_TX_MSDU_METADATA_INFO0_ENCRYPT_TYPE) |
> + le32_encode_bits(1,
> + HAL_TX_MSDU_METADATA_INFO0_HOST_TX_DESC_POOL);
> + *htt_metadata_size = htt_desc_size_aligned;
> + return 0;
> +}
> +
> int ath11k_dp_tx(struct ath11k *ar, struct ath11k_vif *arvif,
> struct ath11k_sta *arsta, struct sk_buff *skb)
> {
> @@ -97,6 +134,9 @@ int ath11k_dp_tx(struct ath11k *ar, stru
> u32 ring_selector = 0;
> u8 ring_map = 0;
> bool tcl_ring_retry;
> + bool is_diff_encap = false;
> + u8 align_pad;
> + u8 htt_meta_size = 0;
>
> if (unlikely(test_bit(ATH11K_FLAG_CRASH_FLUSH, &ar->ab->dev_flags)))
> return -ESHUTDOWN;
> @@ -189,7 +229,12 @@ tcl_ring_sel:
>
> switch (ti.encap_type) {
> case HAL_TCL_ENCAP_TYPE_NATIVE_WIFI:
> - ath11k_dp_tx_encap_nwifi(skb);
> + if ((arvif->vif->offload_flags & IEEE80211_OFFLOAD_ENCAP_ENABLED) &&
> + (skb->protocol == cpu_to_be16(ETH_P_PAE) ||
> + ieee80211_is_qos_nullfunc(hdr->frame_control)))
> + is_diff_encap = true;
> + else
> + ath11k_dp_tx_encap_nwifi(skb);
I dont think this is related to dynamic AP_VLAN
> break;
> case HAL_TCL_ENCAP_TYPE_RAW:
> if (!test_bit(ATH11K_FLAG_RAW_MODE, &ab->dev_flags)) {
> @@ -208,6 +253,33 @@ tcl_ring_sel:
> goto fail_remove_idr;
> }
>
> + /* Add metadata for software encryption of vlan group traffic */
> + if ((!test_bit(ATH11K_FLAG_HW_CRYPTO_DISABLED, &ar->ab->dev_flags) &&
> + !(info->control.flags & IEEE80211_TX_CTL_HW_80211_ENCAP) &&
> + !info->control.hw_key && ieee80211_has_protected(hdr->frame_control)) ||
> + is_diff_encap) {
> + /* HW requirement is that metadata should always point to a
> + * 8-byte aligned address. So we add alignment pad to start of
> + * buffer. HTT Metadata should be ensured to be multiple of 8-bytes
> + * to get 8-byte aligned start address along with align_pad added
> + */
> + align_pad = ((unsigned long)skb->data) & (HTT_META_DATA_ALIGNMENT - 1);
> + ret = ath11k_dp_metadata_align_skb(skb, align_pad);
> + if (unlikely(ret))
> + goto fail_remove_idr;
> +
> + ti.pkt_offset += align_pad;
> + ret = ath11k_dp_prepare_htt_metadata(skb, &htt_meta_size);
> + if (unlikely(ret))
> + goto fail_remove_idr;
> +
> + ti.pkt_offset += htt_meta_size;
> + ti.meta_data_flags |= HTT_TCL_META_DATA_VALID_HTT;
> + ti.flags0 |= FIELD_PREP(HAL_TCL_DATA_CMD_INFO1_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);
> @@ -216,7 +288,8 @@ tcl_ring_sel:
> goto fail_remove_idr;
> }
>
> - ti.data_len = skb->len;
> + ti.data_len = skb->len - ti.pkt_offset;
> + skb_cb->pkt_offset = ti.pkt_offset;
> skb_cb->paddr = ti.paddr;
> skb_cb->vif = arvif->vif;
> skb_cb->ar = ar;
> @@ -272,6 +345,8 @@ fail_unmap_dma:
> dma_unmap_single(ab->dev, ti.paddr, ti.data_len, DMA_TO_DEVICE);
>
> fail_remove_idr:
> + if (ti.pkt_offset)
> + skb_pull(skb, ti.pkt_offset);
> spin_lock_bh(&tx_ring->tx_idr_lock);
> idr_remove(&tx_ring->txbuf_idr,
> FIELD_GET(DP_TX_DESC_ID_MSDU_ID, ti.desc_id));
> @@ -348,6 +423,10 @@ ath11k_dp_tx_htt_tx_complete_buf(struct
> return;
> }
>
> + if (skb_cb->pkt_offset)
> + /* Removing the alignment and htt meta data */
> + skb_pull(msdu, skb_cb->pkt_offset);
> +
> memset(&info->status, 0, sizeof(info->status));
>
> if (ts->acked) {
> --- a/drivers/net/wireless/ath/ath11k/hal_desc.h
> +++ b/drivers/net/wireless/ath/ath11k/hal_desc.h
> @@ -2490,5 +2490,165 @@
> * A count value that indicates the number of times the producer of
> * entries into this Ring has looped around the ring.
> */
> +
> +#define HAL_TX_MSDU_METADATA_INFO0_ENCRYPT_FLAG BIT(8)
> +#define HAL_TX_MSDU_METADATA_INFO0_ENCRYPT_TYPE GENMASK(16, 15)
> +#define HAL_TX_MSDU_METADATA_INFO0_HOST_TX_DESC_POOL BIT(31)
> +
> +struct hal_tx_msdu_metadata {
> + __le32 info0;
> + __le32 rsvd0[6];
> +} __packed;
> +
> +/* hal_tx_msdu_metadata
> + *
> + * 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
> + */
With bit fields removed, may be this doc is not of much help?
>
> #endif /* ATH11K_HAL_DESC_H */
> --- a/drivers/net/wireless/ath/ath11k/mac.c
> +++ b/drivers/net/wireless/ath/ath11k/mac.c
> @@ -10324,6 +10324,9 @@ static int __ath11k_mac_register(struct
> goto err_free_if_combs;
> }
>
> + ar->hw->wiphy->interface_modes |= BIT(NL80211_IFTYPE_AP_VLAN);
> + ar->hw->wiphy->software_iftypes |= BIT(NL80211_IFTYPE_AP_VLAN);
> +
> if (!ab->hw_params.supports_monitor)
> /* There's a race between calling ieee80211_register_hw()
> * and here where the monitor mode is enabled for a little
> --- a/net/mac80211/tx.c
> +++ b/net/mac80211/tx.c
> @@ -40,6 +40,10 @@
>
> /* misc utils */
>
> +static void ieee80211_8023_xmit(struct ieee80211_sub_if_data *sdata,
> + struct net_device *dev, struct sta_info *sta,
> + struct ieee80211_key *key, struct sk_buff *skb);
> +
> static __le16 ieee80211_duration(struct ieee80211_tx_data *tx,
> struct sk_buff *skb, int group_addr,
> int next_frag_len)
> @@ -4281,5 +4285,16 @@ void __ieee80211_subif_start_xmit(struct
> if (IS_ERR(sta))
> sta = NULL;
>
> + if (sta && sdata->vif.type == NL80211_IFTYPE_AP_VLAN &&
> + get_bss_sdata(sdata)->vif.offload_flags & IEEE80211_OFFLOAD_ENCAP_ENABLED &&
> + !is_multicast_ether_addr(skb->data)) {
> + struct ieee80211_key *key = rcu_dereference(sta->ptk[sta->ptk_idx]);
> + if (!key)
> + key = rcu_dereference(get_bss_sdata(sdata)->default_unicast_key);
> + ieee80211_8023_xmit(sdata, dev, sta, key, skb);
> + rcu_read_unlock();
> + return;
> + }
> +
In general, have mac80211 changes in a separate patch. I dont think this particular change
is really required as AP_VLAN xmit will also be 8023 if the master interface supports it.
Vasanth
More information about the ath11k
mailing list