Wireless Daemon for Linux
 help / color / mirror / Atom feed
From: Serenium <serenium@gmx.com>
To: iwd@lists.linux.dev
Subject: [PATCH v2] ap: pass HT and WME station capabilities to kernel
Date: Sat, 29 Aug 2026 17:44:34 +1000	[thread overview]
Message-ID: <20260829074434.11115-1-serenium@gmx.com> (raw)

The AP advertises HT capabilities and a WMM parameter element, but
the association path discards the station HT capability element and does
not pass WME state to the kernel when creating the station.

Consequently, mac80211 treats associated stations as non-HT and non-WME,
restricting traffic to legacy rates even though both the AP and stations
advertise HT and WMM support.

Retain the HT capability and WMM information elements from the association
request. Pass the HT capability, WME parameters, and WME station flag in
NL80211_CMD_NEW_STATION.

Tested with iwd 3.12 and an Intel AX200 in AP mode. Before this change,
associated stations reported WMM/WME: no and used 5.5 or 11 Mbit/s legacy
rates. Afterwards, all tested stations reported WMM/WME: yes, selected HT
MCS rates, and sustained approximately 100 Mbit/s in a 256 MiB transfer.

Signed-off-by: Serenium <serenium@gmx.com>
---
 src/ap.c | 45 +++++++++++++++++++++++++++++++++++++++++++++
 1 file changed, 45 insertions(+)

diff --git a/src/ap.c b/src/ap.c
index 416e1104..3857d82e 100644
--- a/src/ap.c
+++ b/src/ap.c
@@ -127,6 +127,9 @@ struct sta_state {
 	bool rsna;
 	uint16_t aid;
 	struct mmpdu_field_capability capability;
+	uint8_t ht_capabilities[26];
+	uint8_t wmm_uapsd_queues;
+	uint8_t wmm_max_sp;
 	uint16_t listen_interval;
 	struct l_uintset *rates;
 	uint32_t assoc_resp_cmd_id;
@@ -147,6 +150,7 @@ struct sta_state {
 
 	bool ht_support : 1;
 	bool ht_greenfield : 1;
+	bool wmm_support : 1;
 };
 
 struct ap_wsc_pbc_probe_record {
@@ -1683,6 +1687,11 @@ static struct l_genl_msg *ap_build_cmd_new_station(struct sta_state *sta)
 		flags.mask |= (1 << NL80211_STA_FLAG_ASSOCIATED) |
 				(1 << NL80211_STA_FLAG_AUTHENTICATED);
 
+	if (sta->wmm_support) {
+		flags.mask |= 1 << NL80211_STA_FLAG_WME;
+		flags.set |= 1 << NL80211_STA_FLAG_WME;
+	}
+
 	msg = l_genl_msg_new_sized(NL80211_CMD_NEW_STATION, 300);
 
 	l_genl_msg_append_attr(msg, NL80211_ATTR_IFINDEX, 4, &ifindex);
@@ -1835,6 +1844,21 @@ static void ap_associate_sta(struct ap_state *ap, struct sta_state *sta)
 			rates[count++] = r;
 
 	l_genl_msg_append_attr(msg, NL80211_ATTR_STA_AID, 2, &sta->aid);
+	if (sta->ht_support)
+		l_genl_msg_append_attr(msg, NL80211_ATTR_HT_CAPABILITY,
+					sizeof(sta->ht_capabilities),
+					sta->ht_capabilities);
+
+	if (sta->wmm_support) {
+		l_genl_msg_enter_nested(msg, NL80211_ATTR_STA_WME);
+		l_genl_msg_append_attr(msg,
+					NL80211_STA_WME_UAPSD_QUEUES, 1,
+					&sta->wmm_uapsd_queues);
+		l_genl_msg_append_attr(msg, NL80211_STA_WME_MAX_SP, 1,
+					&sta->wmm_max_sp);
+		l_genl_msg_leave_nested(msg);
+	}
+
 	l_genl_msg_append_attr(msg, NL80211_ATTR_STA_SUPPORTED_RATES,
 				count, &rates);
 	l_genl_msg_append_attr(msg, NL80211_ATTR_STA_LISTEN_INTERVAL, 2,
@@ -2173,8 +2197,29 @@ static void ap_assoc_reassoc(struct sta_state *sta, bool reassoc,
 			if (test_bit(ie_tlv_iter_get_data(&iter), 4))
 				sta->ht_greenfield = true;
 
+			memcpy(sta->ht_capabilities,
+					ie_tlv_iter_get_data(&iter),
+					sizeof(sta->ht_capabilities));
 			sta->ht_support = true;
 			break;
+		case IE_TYPE_VENDOR_SPECIFIC: {
+			const uint8_t *vendor =
+					ie_tlv_iter_get_data(&iter);
+			uint8_t qos_info;
+
+			if (ie_tlv_iter_get_length(&iter) != 7 ||
+					memcmp(vendor, microsoft_oui, 3) ||
+					vendor[3] != 2 ||
+					vendor[4] != 0 ||
+					vendor[5] != 1)
+				break;
+
+			qos_info = vendor[6];
+			sta->wmm_uapsd_queues = qos_info & 0x0f;
+			sta->wmm_max_sp = (qos_info >> 5) & 0x03;
+			sta->wmm_support = true;
+			break;
+		}
 		}
 
 	if (!rates || !ssid || (!wsc_data && !rsn) ||
-- 
2.55.0


                 reply	other threads:[~2026-08-29  7:44 UTC|newest]

Thread overview: [no followups] expand[flat|nested]  mbox.gz  Atom feed

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=20260829074434.11115-1-serenium@gmx.com \
    --to=serenium@gmx.com \
    --cc=iwd@lists.linux.dev \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox