[PATCH RFC wireless-next 7/7] wifi: mac80211: add MSCS packet classification

Aishwarya R aishwarya.r at oss.qualcomm.com
Wed Oct 14 22:54:41 PDT 2026


Use the negotiated MSCS configuration to classify uplink traffic and
enforce the configured user priority limit during transmit queue
selection for AP-forwarded packets.

For packets received from an associated non-AP STA, the RX path checks
the received user priority against the negotiated MSCS user-priority
bitmap. When a match is found, mac80211 records an MSCS tag together
with the received user priority in skb->mark.

The received user priority can be associated with a connection by
copying skb->mark to the conntrack mark using nftables. Since the
conntrack entry is shared by both directions of the connection, the
stored metadata can later be restored into skb->mark for corresponding
downlink packets. When such a packet is forwarded to mac80211,
ieee80211_select_queue() consumes the metadata from skb->mark, applies
the negotiated MSCS user-priority limit, updates skb->priority, and
normal queue selection maps it to the transmit TID.

Intra-BSS forwarding requires per-station peer isolation to ensure the
MSCS mark is preserved at transmit queue selection.

Signed-off-by: Aishwarya R <aishwarya.r at oss.qualcomm.com>
---
 net/mac80211/rx.c  | 29 +++++++++++++++++++++++++++++
 net/mac80211/wme.c | 23 +++++++++++++++++------
 2 files changed, 46 insertions(+), 6 deletions(-)

diff --git a/net/mac80211/rx.c b/net/mac80211/rx.c
index ecee9348c70d..930de5b412c5 100644
--- a/net/mac80211/rx.c
+++ b/net/mac80211/rx.c
@@ -1003,6 +1003,31 @@ static void ieee80211_parse_qos(struct ieee80211_rx_data *rx)
 	rx->skb->priority = (tid > 7) ? 0 : tid;
 }
 
+static void ieee80211_qos_mgmt_mscs_set_mark(struct ieee80211_rx_data *rx)
+{
+	struct ieee80211_sta_qos_rcu *qos;
+	u8 tid;
+
+	if (!rx->sta ||
+	    (rx->sdata->vif.type != NL80211_IFTYPE_AP &&
+	     rx->sdata->vif.type != NL80211_IFTYPE_AP_VLAN) ||
+	    rx->seqno_idx >= IEEE80211_QOS_MGMT_MAX_TID)
+		return;
+
+	tid = rx->skb->priority;
+
+	qos = rcu_dereference(rx->sta->qos);
+	if (!qos || !qos->data.mscs_enabled ||
+	    !(BIT(tid) & qos->data.mscs_user_priority_bitmap))
+		return;
+
+	rx->skb->mark = u32_replace_bits(rx->skb->mark,
+					 IEEE80211_QOS_MGMT_MSCS_TAG,
+					 IEEE80211_QOS_MGMT_TAG_MASK);
+	rx->skb->mark = u32_replace_bits(rx->skb->mark, tid,
+					 IEEE80211_QOS_MGMT_ID_MASK);
+}
+
 /**
  * DOC: Packet alignment
  *
@@ -3333,6 +3358,9 @@ ieee80211_rx_h_data(struct ieee80211_rx_data *rx)
 
 	rx->skb->dev = dev;
 
+	if (!port_control)
+		ieee80211_qos_mgmt_mscs_set_mark(rx);
+
 	if (!ieee80211_hw_check(&local->hw, SUPPORTS_DYNAMIC_PS) &&
 	    local->ps_sdata && local->hw.conf.dynamic_ps_timeout > 0 &&
 	    !is_multicast_ether_addr(
@@ -4996,6 +5024,7 @@ static void ieee80211_rx_8023(struct ieee80211_rx_data *rx,
 	stats->packets++;
 
 	skb->dev = fast_rx->dev;
+	ieee80211_qos_mgmt_mscs_set_mark(rx);
 
 	dev_sw_netstats_rx_add(fast_rx->dev, skb->len);
 
diff --git a/net/mac80211/wme.c b/net/mac80211/wme.c
index 4d1bad27a8d6..feca08f28185 100644
--- a/net/mac80211/wme.c
+++ b/net/mac80211/wme.c
@@ -126,10 +126,11 @@ ieee80211_qos_mgmt_set_priority(struct sta_info *sta, struct sk_buff *skb)
 
 	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)
+	if (qos_tag != IEEE80211_QOS_MGMT_SCS_TAG &&
+	    qos_tag != IEEE80211_QOS_MGMT_MSCS_TAG)
 		return;
 
-	if (!qos_id)
+	if (qos_tag == IEEE80211_QOS_MGMT_SCS_TAG && !qos_id)
 		return;
 
 	guard(rcu)();
@@ -138,11 +139,21 @@ ieee80211_qos_mgmt_set_priority(struct sta_info *sta, struct sk_buff *skb)
 	if (!qos)
 		return;
 
-	if (!qos->data.scs_enabled ||
-	    !test_bit(qos_id, qos->data.active_scs_id))
-		return;
+	if (qos_tag == IEEE80211_QOS_MGMT_SCS_TAG) {
+		if (!qos->data.scs_enabled ||
+		    !test_bit(qos_id, qos->data.active_scs_id))
+			return;
+
+		tid = qos->data.scs_id_tid_mapping[qos_id];
+	} else {
+		if (!qos->data.mscs_enabled ||
+		    qos_id >= IEEE80211_QOS_MGMT_MAX_TID ||
+		    !(qos->data.mscs_user_priority_bitmap & BIT(qos_id)))
+			return;
 
-	tid = qos->data.scs_id_tid_mapping[qos_id];
+		tid = min_t(u8, qos_id,
+			    qos->data.mscs_user_priority_limit);
+	}
 
 	if (tid < IEEE80211_QOS_MGMT_MAX_TID)
 		skb->priority = tid;
-- 
2.34.1




More information about the ath12k mailing list