From: "Serenium" <serenium@gmx.com>
To: <iwd@lists.linux.dev>
Subject: [PATCH] ap: pass HT and WME station capabilities
Date: Sat, 29 Aug 2026 15:13:35 +1000 [thread overview]
Message-ID: <DL165RCXD4PO.1EH5BPELX2Y1Q@gmx.com> (raw)
Greetings,
iwd 3.12 and current upstream master silently install HT/WMM-capable AP clients into mac80211 as legacy, non-WME stations.
This was reproduced on Intel's own AX200 hardware.
Test system:
* iwd 3.12
* Intel AX200
* Linux 7.1.5
* Alpine Linux Edge
* channel 6, 2437 MHz
* 40 MHz AP channel width
* three independently associated clients
Before this patch, every client reported:
```
WMM/WME: no
tx bitrate: 5.5 MBit/s
```
or:
```
WMM/WME: no
tx bitrate: 11.0 MBit/s
```
Measured transfer performance was approximately 788 kB/s.
This is not a driver capability, regulatory-domain, beacon-generation, or client problem.
An iwmon netlink PCAP proves that:
1. iwd correctly parses the AX200's 2.4 GHz HT40 capabilities.
2. iwd's probe response contains HT Capabilities, HT Operation, and a WMM Parameter IE.
3. The client association request contains a valid 26-byte HT Capability IE.
4. The client association request contains a valid WMM Information IE:
```
dd 07 00 50 f2 02 00 01 00
```
5. iwd's association response contains HT Capabilities, HT Operation, and WMM.
The failure occurs when iwd constructs NL80211_CMD_NEW_STATION.
The existing AP code retains only a Boolean indication that the station supports HT. It discards the station's actual HT Capability element, does not parse its WMM Information element, and does not provide the corresponding station state to mac80211.
Specifically, it omits:
* NL80211_ATTR_HT_CAPABILITY
* nested NL80211_ATTR_STA_WME
* NL80211_STA_FLAG_WME in NL80211_ATTR_STA_FLAGS2
The missing WME station flag is decisive. Without it, mac80211 records the station as non-WME and does not enable HT operation.
After applying the patch below, all three clients report:
```
WMM/WME: yes
tx bitrate: 26.0 MBit/s MCS 3
```
MCS varies normally under rate control.
The same 256 MiB transfer test then produced:
```
268435456 bytes copied, 21.5456 s, 12.5 MB/s
```
That is approximately 100 Mbit/s and around sixteen times the previous measured throughput.
The patched daemon has been built, packaged as iwd-3.12-r1, installed under normal OpenRC management, and verified with three simultaneous clients.
The defect is also present on current upstream master. There are no post-3.12 src/ap.c commits addressing it, and current master does not use NL80211_ATTR_HT_CAPABILITY or NL80211_ATTR_STA_WME in the AP station-install path.
Patch follows.
---
src/ap.c | 45 +++++++++++++++++++++++++++++++++++++++++++++
1 file changed, 45 insertions(+)
diff --git a/src/ap.c b/src/ap.c
--- 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)
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,7 +2197,28 @@ 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;
```
* ```
}
}
```
}
Tested-by: Saarin <serenium@gmx.com>
## Independent engineering statement
Defect isolation, source tracing, netlink capture, patch development,
Alpine packaging, deployment, and performance validation consumed
approximately three days of independent, unpaid engineering work.
Compensation provided by Intel: AUD $0.00
Mock invoice:
```
Client: Intel / iwd project
Service: Completion of AP HT/WME station installation
Hardware: Intel AX200
Investigation: 3 days
Demonstrated performance recovery: approximately 16x
Amount paid: AUD $0.00
Balance: one conspicuously unfinished AP code path
```
If Intel does not compensate independent users who complete and validate
its wireless stack, an appropriate alternative would be a public donation
to Alpine Linux or another community Linux project, accompanied by a
receipt to this list.
The technical evidence, before/after station dumps, signed Alpine package,
packaging commit, and full iwmon PCAP are available.
Regards,
Saarin
reply other threads:[~2026-08-29 5:13 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=DL165RCXD4PO.1EH5BPELX2Y1Q@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