Use the negotiated SCS descriptor-to-TID mapping when selecting the transmit queue for packets carrying QoS Management metadata. The low 16 bits of skb->mark are used as private QoS Management metadata. Bits 0-7 carry the IEEE Std 802.11-2024 element ID for the respective QoS Management descriptor: WLAN_EID_SCS_DESCRIPTOR (185, 0xB9) for SCS and WLAN_EID_EXT_MSCS_DESCRIPTOR (88, 0x58) for MSCS. Bits 8-15 carry the negotiated SCS identifier. During transmit queue selection, look up the negotiated SCS state for the station and apply the corresponding TID mapping. SCS identifier zero is reserved and is rejected before accessing the RCU-protected per-station QoS state. hostapd programs nftables rules on the netdev egress hook to maintain QoS Management metadata in the conntrack mark and to copy it into skb->mark before packets reach mac80211 transmit queue selection, for example: nft add rule netdev qos wlan0_wifi_qos meta mark set ct mark This nftables rule copies the conntrack mark (ct mark) into skb->mark on egress, allowing the negotiated SCS state to be applied during transmit queue selection. The conntrack mark is restored into skb->mark at the final egress hook, after earlier L3 policy-routing decisions have completed. mac80211 first checks the QoS Management tag and then validates it against the per-station state, so SCS metadata is used only when SCS is enabled and the marked SCS ID is active. Packets without a matching tag or active descriptor, including ordinary non-SCS traffic, are ignored by this path. Intra-BSS forwarding requires per-station peer isolation to ensure the SCS mark is preserved at transmit queue selection. This implementation depends on the corresponding hostapd and nftables configuration that populates the conntrack mark with the QoS Management metadata. Signed-off-by: Aishwarya R --- include/linux/ieee80211.h | 1 + net/mac80211/ieee80211_i.h | 14 ++++++++++++++ net/mac80211/wme.c | 36 ++++++++++++++++++++++++++++++++++++ 3 files changed, 51 insertions(+) diff --git a/include/linux/ieee80211.h b/include/linux/ieee80211.h index 66f9ebe79c61..f235059cbebd 100644 --- a/include/linux/ieee80211.h +++ b/include/linux/ieee80211.h @@ -1821,6 +1821,7 @@ enum ieee80211_eid_ext { WLAN_EID_EXT_SHORT_SSID_LIST = 58, WLAN_EID_EXT_HE_6GHZ_CAPA = 59, WLAN_EID_EXT_UL_MU_POWER_CAPA = 60, + WLAN_EID_EXT_MSCS_DESCRIPTOR = 88, WLAN_EID_EXT_EHT_OPERATION = 106, WLAN_EID_EXT_EHT_MULTI_LINK = 107, WLAN_EID_EXT_EHT_CAPABILITY = 108, diff --git a/net/mac80211/ieee80211_i.h b/net/mac80211/ieee80211_i.h index 63391a1fd9c6..aa36289b3ae4 100644 --- a/net/mac80211/ieee80211_i.h +++ b/net/mac80211/ieee80211_i.h @@ -80,6 +80,20 @@ struct ieee80211_mesh_fast_tx; #define IEEE80211_DEFAULT_MAX_SP_LEN \ IEEE80211_WMM_IE_STA_QOSINFO_SP_ALL +/* + * TODO: Synchronize this skb->mark encoding with the userspace application + * (hostapd). These values reuse IEEE element IDs, but their use in skb->mark + * is an implementation contract between hostapd/nftables and mac80211. + */ +/* skb->mark bits [7:0] carry a QoS Management protocol tag. The values + * match the IEEE Std 802.11-2024 element IDs for the respective descriptors: + * WLAN_EID_SCS_DESCRIPTOR (185) and WLAN_EID_EXT_MSCS_DESCRIPTOR (88). + */ +#define IEEE80211_QOS_MGMT_TAG_MASK GENMASK(7, 0) +#define IEEE80211_QOS_MGMT_SCS_TAG WLAN_EID_SCS_DESCRIPTOR +#define IEEE80211_QOS_MGMT_MSCS_TAG WLAN_EID_EXT_MSCS_DESCRIPTOR +#define IEEE80211_QOS_MGMT_ID_MASK GENMASK(15, 8) + extern const u8 ieee80211_ac_to_qos_mask[IEEE80211_NUM_ACS]; #define IEEE80211_DEAUTH_FRAME_LEN (24 /* hdr */ + 2 /* reason */) diff --git a/net/mac80211/wme.c b/net/mac80211/wme.c index 1601be576414..4d1bad27a8d6 100644 --- a/net/mac80211/wme.c +++ b/net/mac80211/wme.c @@ -113,6 +113,41 @@ static u16 ieee80211_downgrade_queue(struct ieee80211_sub_if_data *sdata, return ieee802_1d_to_ac[skb->priority]; } +static void +ieee80211_qos_mgmt_set_priority(struct sta_info *sta, struct sk_buff *skb) +{ + struct ieee80211_sta_qos_rcu *qos; + u8 qos_tag; + u8 qos_id; + u8 tid; + + if (!sta) + return; + + qos_tag = u32_get_bits(skb->mark, IEEE80211_QOS_MGMT_TAG_MASK); + qos_id = u32_get_bits(skb->mark, IEEE80211_QOS_MGMT_ID_MASK); + if (qos_tag != IEEE80211_QOS_MGMT_SCS_TAG) + return; + + if (!qos_id) + return; + + guard(rcu)(); + qos = rcu_dereference(sta->qos); + + if (!qos) + return; + + if (!qos->data.scs_enabled || + !test_bit(qos_id, qos->data.active_scs_id)) + return; + + tid = qos->data.scs_id_tid_mapping[qos_id]; + + if (tid < IEEE80211_QOS_MGMT_MAX_TID) + skb->priority = tid; +} + /* Indicate which queue to use for this fully formed 802.11 frame */ u16 ieee80211_select_queue_80211(struct ieee80211_sub_if_data *sdata, struct sk_buff *skb, @@ -179,6 +214,7 @@ u16 ieee80211_select_queue(struct ieee80211_sub_if_data *sdata, qos_map = rcu_dereference(sdata->qos_map); skb->priority = cfg80211_classify8021d(skb, qos_map ? &qos_map->qos_map : NULL); + ieee80211_qos_mgmt_set_priority(sta, skb); downgrade: return ieee80211_downgrade_queue(sdata, sta, skb); -- 2.34.1