Download raw body.
sys/ieee80211: support of uAPSD; sys/iwx: enable uAPSD when supported by AP
tech@,
here two diff in one where I implemented support of uAPSD and enabled it
for iwx driver. When AP is misbehaving, uAPSD is disabled till the
reconnect, and I don't keep per AP state like linux for simplicity.
Tested on uAPSD enabled and disabled networks on
iwx0 at pci0 dev 20 function 3 "Intel Wi-Fi 6 AX201" rev 0x00, msix
iwx0: hw rev 0x350, fw 77.30b1cbd8.0, address 98:8d:46:21:2b:6d
with unifi nano AP with enabled roaming with firmware 6.7.41.15623
Index: sys/dev/pci/if_iwx.c
===================================================================
RCS file: /home/cvs/src/sys/dev/pci/if_iwx.c,v
diff -u -p -r1.223 if_iwx.c
--- sys/dev/pci/if_iwx.c 14 Mar 2026 15:37:44 -0000 1.223
+++ sys/dev/pci/if_iwx.c 20 Mar 2026 14:24:23 -0000
@@ -6551,6 +6551,47 @@ iwx_update_beacon_abort(struct iwx_softc
return iwx_beacon_filter_send_cmd(sc, &cmd);
}
+static uint8_t
+iwx_uapsd_qndp_tid(struct ieee80211com *ic, uint8_t acs)
+{
+ if ((acs & IEEE80211_WMM_IE_STA_QOSINFO_AC_VO) &&
+ !ic->ic_edca_ac[EDCA_AC_VO].ac_acm)
+ return 6;
+ if ((acs & IEEE80211_WMM_IE_STA_QOSINFO_AC_VI) &&
+ !ic->ic_edca_ac[EDCA_AC_VI].ac_acm)
+ return 5;
+ if ((acs & IEEE80211_WMM_IE_STA_QOSINFO_AC_BE) &&
+ !ic->ic_edca_ac[EDCA_AC_BE].ac_acm)
+ return 0;
+ if ((acs & IEEE80211_WMM_IE_STA_QOSINFO_AC_BK) &&
+ !ic->ic_edca_ac[EDCA_AC_BK].ac_acm)
+ return 1;
+ return 0;
+}
+
+static uint8_t
+iwx_uapsd_acs(struct ieee80211_node *ni)
+{
+ uint8_t acs = ni->ni_uapsd_ac & IEEE80211_WMM_IE_STA_QOSINFO_AC_MASK;
+
+ return acs | (acs << 4);
+}
+
+static uint8_t
+iwx_uapsd_sp_length(struct ieee80211_node *ni)
+{
+ switch (ni->ni_uapsd_maxsp & IEEE80211_WMM_IE_STA_QOSINFO_SP_MASK) {
+ case IEEE80211_WMM_IE_STA_QOSINFO_SP_2:
+ return 2;
+ case IEEE80211_WMM_IE_STA_QOSINFO_SP_4:
+ return 4;
+ case IEEE80211_WMM_IE_STA_QOSINFO_SP_6:
+ return 6;
+ default:
+ return 128;
+ }
+}
+
int
iwx_set_pslevel(struct iwx_softc *sc, int dtim, int level, int async)
{
@@ -6612,6 +6653,22 @@ iwx_set_pslevel(struct iwx_softc *sc, in
IWX_POWER_FLAGS_POWER_MANAGEMENT_ENA_MSK);
mcmd.rx_data_timeout = htole32(pmgt->rxtimeout * 1024);
mcmd.tx_data_timeout = htole32(pmgt->txtimeout * 1024);
+ if (ni->ni_uapsd) {
+ mcmd.flags |=
+ htole16(IWX_POWER_FLAGS_ADVANCE_PM_ENA_MSK);
+ mcmd.flags |=
+ htole16(IWX_POWER_FLAGS_UAPSD_MISBEHAVING_ENA_MSK);
+ mcmd.rx_data_timeout_uapsd =
+ htole32(IWX_UAPSD_PS_RX_DATA_TIMEOUT);
+ mcmd.tx_data_timeout_uapsd =
+ htole32(IWX_UAPSD_PS_TX_DATA_TIMEOUT);
+ mcmd.qndp_tid = iwx_uapsd_qndp_tid(ic, ni->ni_uapsd_ac);
+ mcmd.uapsd_ac_flags =
+ ni->ni_uapsd_ac &
+ IEEE80211_WMM_IE_STA_QOSINFO_AC_MASK;
+ mcmd.uapsd_max_sp = ni->ni_uapsd_maxsp &
+ IEEE80211_WMM_IE_STA_QOSINFO_SP_MASK;
+ }
if (skip_dtim != 0) {
mcmd.flags |= htole16(IWX_POWER_FLAGS_SKIP_OVER_DTIM_MSK);
mcmd.skip_dtim_periods = skip_dtim + 1;
@@ -6770,6 +6827,11 @@ iwx_add_sta_cmd(struct iwx_softc *sc, st
break;
}
}
+ if (in->in_ni.ni_uapsd) {
+ add_sta_cmd.modify_mask |= IWX_STA_MODIFY_UAPSD_ACS;
+ add_sta_cmd.uapsd_acs = iwx_uapsd_acs(&in->in_ni);
+ add_sta_cmd.sp_length = iwx_uapsd_sp_length(&in->in_ni);
+ }
status = IWX_ADD_STA_SUCCESS;
err = iwx_send_cmd_pdu_status(sc, IWX_ADD_STA, sizeof(add_sta_cmd),
@@ -6976,6 +7038,11 @@ iwx_mld_add_sta_cmd(struct iwx_softc *sc
if (in->in_ni.ni_flags & IEEE80211_NODE_MFP)
sta_cmd.mfp = htole32(1);
+ if (in->in_ni.ni_uapsd) {
+ sta_cmd.sp_length =
+ htole32(iwx_uapsd_sp_length(&in->in_ni));
+ sta_cmd.uapsd_acs = htole32(iwx_uapsd_acs(&in->in_ni));
+ }
return iwx_send_cmd_pdu(sc,
IWX_WIDE_ID(IWX_MAC_CONF_GROUP, IWX_STA_CONFIG_CMD),
@@ -10977,6 +11044,32 @@ iwx_rx_pkt(struct iwx_softc *sc, struct
break;
}
+ case IWX_PSM_UAPSD_AP_MISBEHAVING_NOTIFICATION: {
+ struct ieee80211com *ic = &sc->sc_ic;
+ struct ifnet *ifp = &ic->ic_if;
+ struct ieee80211_node *ni = ic->ic_bss;
+ struct iwx_uapsd_misbehaving_ap_notif *notif;
+
+ SYNC_RESP_STRUCT(notif, pkt);
+
+ if (ni == NULL || !ni->ni_uapsd)
+ break;
+
+ if (ifp->if_flags & IFF_DEBUG)
+ printf("%s: firmware reported uAPSD "
+ "misbehaving AP on sta %u, disabling "
+ "uAPSD\n", ifp->if_xname,
+ le32toh(notif->sta_id));
+
+ ni->ni_uapsd = 0;
+ ni->ni_uapsd_ac = 0;
+ ni->ni_uapsd_maxsp = 0;
+
+ if (ic->ic_flags & IEEE80211_F_PMGTON)
+ (void)iwx_set_pslevel(sc, 0, 3, 1);
+ break;
+ }
+
case IWX_WIDE_ID(IWX_MAC_CONF_GROUP,
IWX_SESSION_PROTECTION_NOTIF): {
struct iwx_session_prot_notif *notif;
@@ -12367,6 +12460,9 @@ iwx_attach(struct device *parent, struct
IEEE80211_C_SHPREAMBLE | /* short preamble supported */
IEEE80211_C_MFP; /* management frame protection */
ic->ic_flags |= IEEE80211_F_PMGTON;
+ ic->ic_uapsd_ac = IEEE80211_WMM_IE_STA_QOSINFO_AC_VI |
+ IEEE80211_WMM_IE_STA_QOSINFO_AC_VO;
+ ic->ic_uapsd_maxsp = IEEE80211_WMM_IE_STA_QOSINFO_SP_2;
ic->ic_htcaps = IEEE80211_HTCAP_SGI20 | IEEE80211_HTCAP_SGI40;
ic->ic_htcaps |= IEEE80211_HTCAP_CBW20_40;
Index: sys/dev/pci/if_iwxreg.h
===================================================================
RCS file: /home/cvs/src/sys/dev/pci/if_iwxreg.h,v
diff -u -p -r1.73 if_iwxreg.h
--- sys/dev/pci/if_iwxreg.h 13 Mar 2026 11:11:02 -0000 1.73
+++ sys/dev/pci/if_iwxreg.h 20 Mar 2026 14:08:49 -0000
@@ -5472,6 +5472,8 @@ struct iwx_mac_power_cmd {
#define IWX_DEFAULT_PS_TX_DATA_TIMEOUT (100 * 1000)
#define IWX_DEFAULT_PS_RX_DATA_TIMEOUT (100 * 1000)
+#define IWX_UAPSD_PS_TX_DATA_TIMEOUT (50 * 1000)
+#define IWX_UAPSD_PS_RX_DATA_TIMEOUT (50 * 1000)
#define IWX_NDTIMRANGES 3
#define IWX_NPOWERLEVELS 6
@@ -8311,6 +8313,7 @@ struct iwx_umac_scan_iter_complete_notif
* @IWX_STA_MODIFY_QUEUE_REMOVAL: this command removes a queue
* @IWX_STA_MODIFY_TID_DISABLE_TX: this command modifies %tid_disable_tx
* @IWX_STA_MODIFY_TX_RATE: unused
+ * @IWX_STA_MODIFY_UAPSD_ACS: this command modifies %uapsd_acs
* @IWX_STA_MODIFY_ADD_BA_TID: this command modifies %add_immediate_ba_tid
* @IWX_STA_MODIFY_REMOVE_BA_TID: this command modifies %remove_immediate_ba_tid
* @IWX_STA_MODIFY_SLEEPING_STA_TX_COUNT: this command modifies %sleep_tx_count
@@ -8320,6 +8323,7 @@ struct iwx_umac_scan_iter_complete_notif
#define IWX_STA_MODIFY_QUEUE_REMOVAL (1 << 0)
#define IWX_STA_MODIFY_TID_DISABLE_TX (1 << 1)
#define IWX_STA_MODIFY_TX_RATE (1 << 2)
+#define IWX_STA_MODIFY_UAPSD_ACS IWX_STA_MODIFY_TX_RATE
#define IWX_STA_MODIFY_ADD_BA_TID (1 << 3)
#define IWX_STA_MODIFY_REMOVE_BA_TID (1 << 4)
#define IWX_STA_MODIFY_SLEEPING_STA_TX_COUNT (1 << 5)
Index: sys/net80211/ieee80211.h
===================================================================
RCS file: /home/cvs/src/sys/net80211/ieee80211.h,v
diff -u -p -r1.65 ieee80211.h
--- sys/net80211/ieee80211.h 19 Mar 2026 16:50:32 -0000 1.65
+++ sys/net80211/ieee80211.h 20 Mar 2026 13:31:42 -0000
@@ -193,6 +193,20 @@ struct ieee80211_htframe_addr4 { /* 11n
#define IEEE80211_QOS_EOSP 0x0010
#define IEEE80211_QOS_TID 0x000f
+#define IEEE80211_WMM_IE_AP_QOSINFO_UAPSD 0x80
+
+#define IEEE80211_WMM_IE_STA_QOSINFO_AC_BE 0x01
+#define IEEE80211_WMM_IE_STA_QOSINFO_AC_BK 0x02
+#define IEEE80211_WMM_IE_STA_QOSINFO_AC_VI 0x04
+#define IEEE80211_WMM_IE_STA_QOSINFO_AC_VO 0x08
+#define IEEE80211_WMM_IE_STA_QOSINFO_AC_MASK 0x0f
+
+#define IEEE80211_WMM_IE_STA_QOSINFO_SP_ALL 0x00
+#define IEEE80211_WMM_IE_STA_QOSINFO_SP_2 0x20
+#define IEEE80211_WMM_IE_STA_QOSINFO_SP_4 0x40
+#define IEEE80211_WMM_IE_STA_QOSINFO_SP_6 0x60
+#define IEEE80211_WMM_IE_STA_QOSINFO_SP_MASK 0x60
+
/*
* Control frames.
*/
Index: sys/net80211/ieee80211_input.c
===================================================================
RCS file: /home/cvs/src/sys/net80211/ieee80211_input.c,v
diff -u -p -r1.260 ieee80211_input.c
--- sys/net80211/ieee80211_input.c 19 Mar 2026 16:50:32 -0000 1.260
+++ sys/net80211/ieee80211_input.c 20 Mar 2026 13:36:36 -0000
@@ -87,6 +87,7 @@ int ieee80211_parse_edca_params_body(str
const u_int8_t *);
int ieee80211_parse_edca_params(struct ieee80211com *, const u_int8_t *);
int ieee80211_parse_wmm_params(struct ieee80211com *, const u_int8_t *);
+static int ieee80211_parse_wmm_qosinfo(const u_int8_t *, u_int8_t *);
enum ieee80211_cipher ieee80211_parse_rsn_cipher(const u_int8_t *);
enum ieee80211_akm ieee80211_parse_rsn_akm(const u_int8_t *);
int ieee80211_parse_rsn_body(struct ieee80211com *, const u_int8_t *,
@@ -1387,6 +1388,30 @@ ieee80211_parse_wmm_params(struct ieee80
return ieee80211_parse_edca_params_body(ic, frm + 8);
}
+static int
+ieee80211_parse_wmm_qosinfo(const u_int8_t *frm, u_int8_t *qosinfo)
+{
+ if (frm[1] < 7)
+ return IEEE80211_REASON_IE_INVALID;
+
+ *qosinfo = frm[8];
+ return 0;
+}
+
+static void
+ieee80211_setup_uapsd(struct ieee80211com *ic, struct ieee80211_node *ni,
+ int peer_uapsd)
+{
+ ni->ni_uapsd = !!peer_uapsd;
+ if (ni->ni_uapsd && (ni->ni_flags & IEEE80211_NODE_QOS)) {
+ ni->ni_uapsd_ac = ic->ic_uapsd_ac;
+ ni->ni_uapsd_maxsp = ic->ic_uapsd_maxsp;
+ } else {
+ ni->ni_uapsd_ac = 0;
+ ni->ni_uapsd_maxsp = 0;
+ }
+}
+
enum ieee80211_cipher
ieee80211_parse_rsn_cipher(const u_int8_t selector[4])
{
@@ -1627,7 +1652,8 @@ ieee80211_recv_probe_resp(struct ieee802
const u_int8_t *tstamp, *ssid, *rates, *xrates, *edcaie, *wmmie, *tim;
const u_int8_t *rsnie, *wpaie, *htcaps, *htop, *vhtcaps, *vhtop, *hecaps, *heop;
u_int16_t capinfo, bintval;
- u_int8_t chan, bchan, erp;
+ u_int8_t chan, bchan, erp, wmm_qosinfo;
+ int has_wmm_qosinfo = 0;
int is_new;
/*
@@ -1845,6 +1871,9 @@ ieee80211_recv_probe_resp(struct ieee802
ni->ni_dtimcount = tim[2];
ni->ni_dtimperiod = tim[3];
}
+ if (wmmie != NULL &&
+ ieee80211_parse_wmm_qosinfo(wmmie, &wmm_qosinfo) == 0)
+ has_wmm_qosinfo = 1;
/*
* When operating in station mode, check for state updates
@@ -1955,11 +1984,18 @@ ieee80211_recv_probe_resp(struct ieee802
else
ni->ni_flags &= ~IEEE80211_NODE_QOS;
}
+ ieee80211_setup_uapsd(ic, ni, has_wmm_qosinfo &&
+ (wmm_qosinfo & IEEE80211_WMM_IE_AP_QOSINFO_UAPSD));
if (ic->ic_state == IEEE80211_S_SCAN ||
(ic->ic_flags & IEEE80211_F_BGSCAN)) {
struct ieee80211_rsnparams rsn, wpa;
+ if (edcaie != NULL || wmmie != NULL)
+ ni->ni_flags |= IEEE80211_NODE_QOS;
+ else
+ ni->ni_flags &= ~IEEE80211_NODE_QOS;
+
ni->ni_rsnprotos = IEEE80211_PROTO_NONE;
ni->ni_supported_rsnprotos = IEEE80211_PROTO_NONE;
ni->ni_rsnakms = 0;
@@ -1980,6 +2016,9 @@ ieee80211_recv_probe_resp(struct ieee802
ni->ni_supported_rsnakms |= wpa.rsn_akms;
}
+ ieee80211_setup_uapsd(ic, ni, has_wmm_qosinfo &&
+ (wmm_qosinfo & IEEE80211_WMM_IE_AP_QOSINFO_UAPSD));
+
/*
* If the AP advertises both WPA and RSN IEs (WPA1+WPA2),
* we only use the highest protocol version we support.
@@ -2608,7 +2647,8 @@ ieee80211_recv_assoc_resp(struct ieee802
const u_int8_t *rates, *xrates, *edcaie, *wmmie, *htcaps, *htop;
const u_int8_t *vhtcaps, *vhtop, *hecaps, *heop;
u_int16_t capinfo, status, associd;
- u_int8_t rate;
+ u_int8_t rate, wmm_qosinfo;
+ int has_wmm_qosinfo = 0;
if (ic->ic_opmode != IEEE80211_M_STA ||
ic->ic_state != IEEE80211_S_ASSOC) {
@@ -2696,6 +2736,9 @@ ieee80211_recv_assoc_resp(struct ieee802
}
frm += 2 + frm[1];
}
+ if (wmmie != NULL &&
+ ieee80211_parse_wmm_qosinfo(wmmie, &wmm_qosinfo) == 0)
+ has_wmm_qosinfo = 1;
/* supported rates element is mandatory */
if (rates == NULL || rates[1] > IEEE80211_RATE_MAXSIZE) {
DPRINTF(("invalid supported rates element\n"));
@@ -2724,6 +2767,8 @@ ieee80211_recv_assoc_resp(struct ieee802
else /* for Reassociation */
ni->ni_flags &= ~IEEE80211_NODE_QOS;
}
+ ieee80211_setup_uapsd(ic, ni, has_wmm_qosinfo &&
+ (wmm_qosinfo & IEEE80211_WMM_IE_AP_QOSINFO_UAPSD));
if (htcaps)
ieee80211_setup_htcaps(ni, htcaps + 2, htcaps[1]);
if (htop)
Index: sys/net80211/ieee80211_node.h
===================================================================
RCS file: /home/cvs/src/sys/net80211/ieee80211_node.h,v
diff -u -p -r1.99 ieee80211_node.h
--- sys/net80211/ieee80211_node.h 19 Mar 2026 16:50:32 -0000 1.99
+++ sys/net80211/ieee80211_node.h 20 Mar 2026 13:31:42 -0000
@@ -306,6 +306,9 @@ struct ieee80211_node {
/* power saving mode */
u_int8_t ni_pwrsave;
struct mbuf_queue ni_savedq; /* packets queued for pspoll */
+ u_int8_t ni_uapsd;
+ u_int8_t ni_uapsd_ac;
+ u_int8_t ni_uapsd_maxsp;
/* RSN */
struct timeout ni_eapol_to;
Index: sys/net80211/ieee80211_output.c
===================================================================
RCS file: /home/cvs/src/sys/net80211/ieee80211_output.c,v
diff -u -p -r1.147 ieee80211_output.c
--- sys/net80211/ieee80211_output.c 19 Mar 2026 16:50:32 -0000 1.147
+++ sys/net80211/ieee80211_output.c 20 Mar 2026 13:31:42 -0000
@@ -985,6 +985,13 @@ ieee80211_add_erp(u_int8_t *frm, struct
}
#endif /* IEEE80211_STA_ONLY */
+static uint8_t
+ieee80211_uapsd_qosinfo(struct ieee80211com *ic)
+{
+ return (ic->ic_uapsd_ac & IEEE80211_WMM_IE_STA_QOSINFO_AC_MASK) |
+ (ic->ic_uapsd_maxsp & IEEE80211_WMM_IE_STA_QOSINFO_SP_MASK);
+}
+
/*
* Add a QoS Capability element to a frame (see 7.3.2.35).
*/
@@ -993,7 +1000,7 @@ ieee80211_add_qos_capability(u_int8_t *f
{
*frm++ = IEEE80211_ELEMID_QOS_CAP;
*frm++ = 1;
- *frm++ = 0; /* QoS Info */
+ *frm++ = ieee80211_uapsd_qosinfo(ic);
return frm;
}
@@ -1011,7 +1018,7 @@ ieee80211_add_wme_info(uint8_t *frm, str
*frm++ = 2; /* OUI type */
*frm++ = 0; /* OUI subtype */
*frm++ = 1; /* version */
- *frm++ = 0; /* info */
+ *frm++ = ieee80211_uapsd_qosinfo(ic);
return frm;
}
@@ -1585,7 +1592,7 @@ ieee80211_get_assoc_req(struct ieee80211
struct mbuf *m;
u_int8_t *frm;
u_int16_t capinfo;
- int addvht = 0;
+ int addvht = 0, addwme;
u_int hecapslen = 0;
if ((ic->ic_flags & IEEE80211_F_VHTON) && ni->ni_chan != NULL &&
@@ -1601,6 +1608,9 @@ ieee80211_get_assoc_req(struct ieee80211
IEEE80211_HE_MCS_NSS_SIZE(ic->ic_he_phy_cap[0]);
}
+ addwme = (ni->ni_flags & IEEE80211_NODE_QOS) ||
+ (ic->ic_flags & IEEE80211_F_HTON);
+
m = ieee80211_getmgmt(M_DONTWAIT, MT_DATA,
2 + 2 +
((type == IEEE80211_FC0_SUBTYPE_REASSOC_REQ) ?
@@ -1616,7 +1626,8 @@ ieee80211_get_assoc_req(struct ieee80211
(((ic->ic_flags & IEEE80211_F_RSNON) &&
(ni->ni_rsnprotos & IEEE80211_PROTO_WPA)) ?
2 + IEEE80211_WPAIE_MAXLEN : 0) +
- ((ic->ic_flags & IEEE80211_F_HTON) ? 28 + 9 : 0) +
+ ((ic->ic_flags & IEEE80211_F_HTON) ? 28 : 0) +
+ (addwme ? 9 : 0) +
(addvht ? 14 : 0) +
hecapslen);
if (m == NULL)
@@ -1649,10 +1660,10 @@ ieee80211_get_assoc_req(struct ieee80211
if ((ic->ic_flags & IEEE80211_F_RSNON) &&
(ni->ni_rsnprotos & IEEE80211_PROTO_WPA))
frm = ieee80211_add_wpa(frm, ic, ni);
- if (ic->ic_flags & IEEE80211_F_HTON) {
+ if (ic->ic_flags & IEEE80211_F_HTON)
frm = ieee80211_add_htcaps(frm, ic);
+ if (addwme)
frm = ieee80211_add_wme_info(frm, ic);
- }
if (addvht)
frm = ieee80211_add_vhtcaps(frm, ic);
if (hecapslen)
Index: sys/net80211/ieee80211_proto.c
===================================================================
RCS file: /home/cvs/src/sys/net80211/ieee80211_proto.c,v
diff -u -p -r1.112 ieee80211_proto.c
--- sys/net80211/ieee80211_proto.c 19 Mar 2026 16:50:32 -0000 1.112
+++ sys/net80211/ieee80211_proto.c 20 Mar 2026 14:17:27 -0000
@@ -1376,7 +1376,7 @@ justcleanup:
else
printf(" start %u%sMb",
rate / 2, (rate & 1) ? ".5" : "");
- printf(" %s preamble %s slot time%s%s%s\n",
+ printf(" %s preamble %s slot time%s%s%s%s\n",
(ic->ic_flags & IEEE80211_F_SHPREAMBLE) ?
"short" : "long",
(ic->ic_flags & IEEE80211_F_SHSLOT) ?
@@ -1386,7 +1386,12 @@ justcleanup:
(ni->ni_flags & IEEE80211_NODE_HT) ?
" HT enabled" : "",
(ni->ni_flags & IEEE80211_NODE_VHT) ?
- " VHT enabled" : "");
+ " VHT enabled" : "",
+ ic->ic_uapsd_ac != 0 ?
+ (ni->ni_uapsd ?
+ " uAPSD enabled" :
+ " uAPSD disabled") :
+ "");
}
if (!(ic->ic_flags & IEEE80211_F_RSNON)) {
/*
Index: sys/net80211/ieee80211_var.h
===================================================================
RCS file: /home/cvs/src/sys/net80211/ieee80211_var.h,v
diff -u -p -r1.114 ieee80211_var.h
--- sys/net80211/ieee80211_var.h 19 Mar 2026 16:50:32 -0000 1.114
+++ sys/net80211/ieee80211_var.h 20 Mar 2026 13:31:42 -0000
@@ -344,6 +344,8 @@ struct ieee80211com {
u_int ic_edca_txop_count[EDCA_NUM_AC];
struct timeval ic_edca_txop_time[EDCA_NUM_AC];
u_int16_t ic_tid_noack;
+ u_int8_t ic_uapsd_ac;
+ u_int8_t ic_uapsd_maxsp;
u_int8_t ic_globalcnt[EAPOL_KEY_NONCE_LEN];
u_int8_t ic_nonce[EAPOL_KEY_NONCE_LEN];
u_int8_t ic_psk[IEEE80211_PMK_LEN];
--
wbr, Kirill
sys/ieee80211: support of uAPSD; sys/iwx: enable uAPSD when supported by AP