svn commit: r362210 - head/sys/net80211
Adrian Chadd
adrian at FreeBSD.org
Tue Jun 16 00:27:34 UTC 2020
Author: adrian
Date: Tue Jun 16 00:27:32 2020
New Revision: 362210
URL: https://svnweb.freebsd.org/changeset/base/362210
Log:
[net80211] Add initial U-APSD negotiation support.
U-APSD (unscheduled automatic power save delivery) is a power save method
that's a bit better than legacy PS-POLL - stations can mark frames with
an extra flag that tells the AP to leak out more frames after it sends
its own frames rather than needing to send a PS-POLL to get another frame
from the AP.
Now, this code just handles the negotiation bits; it doesn't actually
implement U-APSD. That's up to drivers, and nothing in the tree yet
implements this. I /may/ implement this for ath(4) if I eventually care
enough but right now I plan on just implementing it for firmware offload
based NICs that handle this in the NIC.
I'll commit the ifconfig bit after this and I may have some follow-up
commits as this gets used more by me in local testing.
This should be a glorious no-op for everyone else. If things change
for anyone that isn't fixed by a complete recompile then please reach out
to me.
Modified:
head/sys/net80211/_ieee80211.h
head/sys/net80211/ieee80211.c
head/sys/net80211/ieee80211_hostap.c
head/sys/net80211/ieee80211_ioctl.c
head/sys/net80211/ieee80211_ioctl.h
head/sys/net80211/ieee80211_node.h
head/sys/net80211/ieee80211_output.c
head/sys/net80211/ieee80211_proto.c
head/sys/net80211/ieee80211_sta.c
head/sys/net80211/ieee80211_sta.h
head/sys/net80211/ieee80211_var.h
Modified: head/sys/net80211/_ieee80211.h
==============================================================================
--- head/sys/net80211/_ieee80211.h Mon Jun 15 22:43:46 2020 (r362209)
+++ head/sys/net80211/_ieee80211.h Tue Jun 16 00:27:32 2020 (r362210)
@@ -488,6 +488,7 @@ struct ieee80211_mimo_info {
#define IEEE80211_C_MBSS 0x00040000 /* CAPABILITY: MBSS available */
#define IEEE80211_C_SWSLEEP 0x00080000 /* CAPABILITY: do sleep here */
#define IEEE80211_C_SWAMSDUTX 0x00100000 /* CAPABILITY: software A-MSDU TX */
+#define IEEE80211_C_UAPSD 0x00200000 /* CAPABILITY: U-APSD */
/* 0x7c0000 available */
#define IEEE80211_C_WPA1 0x00800000 /* CAPABILITY: WPA1 avail */
#define IEEE80211_C_WPA2 0x01000000 /* CAPABILITY: WPA2 avail */
Modified: head/sys/net80211/ieee80211.c
==============================================================================
--- head/sys/net80211/ieee80211.c Mon Jun 15 22:43:46 2020 (r362209)
+++ head/sys/net80211/ieee80211.c Tue Jun 16 00:27:32 2020 (r362210)
@@ -616,6 +616,12 @@ ieee80211_vap_setup(struct ieee80211com *ic, struct ie
if (vap->iv_opmode == IEEE80211_M_HOSTAP &&
(vap->iv_caps & IEEE80211_C_DFS))
vap->iv_flags_ext |= IEEE80211_FEXT_DFS;
+ /* NB: only flip on U-APSD for hostap/sta for now */
+ if ((vap->iv_opmode == IEEE80211_M_STA)
+ || (vap->iv_opmode == IEEE80211_M_HOSTAP)) {
+ if (vap->iv_caps & IEEE80211_C_UAPSD)
+ vap->iv_flags_ext |= IEEE80211_FEXT_UAPSD;
+ }
vap->iv_des_chan = IEEE80211_CHAN_ANYC; /* any channel is ok */
vap->iv_bmissthreshold = IEEE80211_HWBMISS_DEFAULT;
Modified: head/sys/net80211/ieee80211_hostap.c
==============================================================================
--- head/sys/net80211/ieee80211_hostap.c Mon Jun 15 22:43:46 2020 (r362209)
+++ head/sys/net80211/ieee80211_hostap.c Tue Jun 16 00:27:32 2020 (r362210)
@@ -65,6 +65,7 @@ __FBSDID("$FreeBSD$");
#endif
#include <net80211/ieee80211_wds.h>
#include <net80211/ieee80211_vht.h>
+#include <net80211/ieee80211_sta.h> /* for parse_wmeie */
#define IEEE80211_RATE2MBS(r) (((r) & IEEE80211_RATE_VAL) / 2)
@@ -2253,8 +2254,18 @@ hostap_recv_mgmt(struct ieee80211_node *ni, struct mbu
* Mark node as capable of QoS.
*/
ni->ni_flags |= IEEE80211_NODE_QOS;
+ if (ieee80211_parse_wmeie(wme, wh, ni) > 0) {
+ if (ni->ni_uapsd != 0)
+ ni->ni_flags |=
+ IEEE80211_NODE_UAPSD;
+ else
+ ni->ni_flags &=
+ ~IEEE80211_NODE_UAPSD;
+ }
} else
- ni->ni_flags &= ~IEEE80211_NODE_QOS;
+ ni->ni_flags &=
+ ~(IEEE80211_NODE_QOS |
+ IEEE80211_NODE_UAPSD);
#ifdef IEEE80211_SUPPORT_SUPERG
if (ath != NULL) {
setie(ath_ie, ath - sfrm);
@@ -2268,6 +2279,7 @@ hostap_recv_mgmt(struct ieee80211_node *ni, struct mbu
#undef setie
} else {
ni->ni_flags &= ~IEEE80211_NODE_QOS;
+ ni->ni_flags &= ~IEEE80211_NODE_UAPSD;
ni->ni_ath_flags = 0;
}
ieee80211_node_join(ni, resp);
Modified: head/sys/net80211/ieee80211_ioctl.c
==============================================================================
--- head/sys/net80211/ieee80211_ioctl.c Mon Jun 15 22:43:46 2020 (r362209)
+++ head/sys/net80211/ieee80211_ioctl.c Tue Jun 16 00:27:32 2020 (r362210)
@@ -1145,6 +1145,11 @@ ieee80211_ioctl_get80211(struct ieee80211vap *vap, u_l
if (vap->iv_flags_ht & IEEE80211_FHT_LDPC_RX)
ireq->i_val |= 2;
break;
+ case IEEE80211_IOC_UAPSD:
+ ireq->i_val = 0;
+ if (vap->iv_flags_ext & IEEE80211_FEXT_UAPSD)
+ ireq->i_val = 1;
+ break;
/* VHT */
case IEEE80211_IOC_VHTCONF:
@@ -3461,6 +3466,16 @@ ieee80211_ioctl_set80211(struct ieee80211vap *vap, u_l
/* NB: reset only if we're operating on an 11n channel */
if (isvapht(vap))
error = ERESTART;
+ break;
+ case IEEE80211_IOC_UAPSD:
+ if ((vap->iv_caps & IEEE80211_C_UAPSD) == 0)
+ return EOPNOTSUPP;
+ if (ireq->i_val == 0)
+ vap->iv_flags_ext &= ~IEEE80211_FEXT_UAPSD;
+ else if (ireq->i_val == 1)
+ vap->iv_flags_ext |= IEEE80211_FEXT_UAPSD;
+ else
+ return EINVAL;
break;
/* VHT */
Modified: head/sys/net80211/ieee80211_ioctl.h
==============================================================================
--- head/sys/net80211/ieee80211_ioctl.h Mon Jun 15 22:43:46 2020 (r362209)
+++ head/sys/net80211/ieee80211_ioctl.h Tue Jun 16 00:27:32 2020 (r362210)
@@ -710,6 +710,8 @@ struct ieee80211req {
#define IEEE80211_IOC_GREENFIELD 112 /* Greenfield (on, off) */
#define IEEE80211_IOC_STBC 113 /* STBC Tx/RX (on, off) */
#define IEEE80211_IOC_LDPC 114 /* LDPC Tx/RX (on, off) */
+#define IEEE80211_IOC_UAPSD 115 /* UAPSD (on, off) */
+#define IEEE80211_IOC_UAPSD_INFO 116 /* UAPSD (SP, per-AC enable) */
/* VHT */
#define IEEE80211_IOC_VHTCONF 130 /* VHT config (off, on; widths) */
Modified: head/sys/net80211/ieee80211_node.h
==============================================================================
--- head/sys/net80211/ieee80211_node.h Mon Jun 15 22:43:46 2020 (r362209)
+++ head/sys/net80211/ieee80211_node.h Tue Jun 16 00:27:32 2020 (r362210)
@@ -146,6 +146,7 @@ struct ieee80211_node {
#define IEEE80211_NODE_AMSDU_TX 0x080000 /* AMSDU tx enabled */
#define IEEE80211_NODE_VHT 0x100000 /* VHT enabled */
#define IEEE80211_NODE_LDPC 0x200000 /* LDPC enabled */
+#define IEEE80211_NODE_UAPSD 0x400000 /* U-APSD power save enabled */
uint16_t ni_associd; /* association ID */
uint16_t ni_vlan; /* vlan tag */
uint16_t ni_txpower; /* current transmit power */
@@ -255,6 +256,9 @@ struct ieee80211_node {
/* quiet time IE state for the given node */
uint32_t ni_quiet_ie_set; /* Quiet time IE was seen */
struct ieee80211_quiet_ie ni_quiet_ie; /* last seen quiet IE */
+
+ /* U-APSD */
+ uint8_t ni_uapsd; /* U-APSD per-node flags matching WMM STA QoS Info field */
uint64_t ni_spare[3];
};
Modified: head/sys/net80211/ieee80211_output.c
==============================================================================
--- head/sys/net80211/ieee80211_output.c Mon Jun 15 22:43:46 2020 (r362209)
+++ head/sys/net80211/ieee80211_output.c Tue Jun 16 00:27:32 2020 (r362210)
@@ -2156,26 +2156,48 @@ add_ie(uint8_t *frm, const uint8_t *ie)
* Add a WME information element to a frame.
*/
uint8_t *
-ieee80211_add_wme_info(uint8_t *frm, struct ieee80211_wme_state *wme)
+ieee80211_add_wme_info(uint8_t *frm, struct ieee80211_wme_state *wme,
+ struct ieee80211_node *ni)
{
- static const struct ieee80211_wme_info info = {
- .wme_id = IEEE80211_ELEMID_VENDOR,
- .wme_len = sizeof(struct ieee80211_wme_info) - 2,
- .wme_oui = { WME_OUI_BYTES },
- .wme_type = WME_OUI_TYPE,
- .wme_subtype = WME_INFO_OUI_SUBTYPE,
- .wme_version = WME_VERSION,
- .wme_info = 0,
- };
- memcpy(frm, &info, sizeof(info));
- return frm + sizeof(info);
+ static const uint8_t oui[4] = { WME_OUI_BYTES, WME_OUI_TYPE };
+ struct ieee80211vap *vap = ni->ni_vap;
+
+ *frm++ = IEEE80211_ELEMID_VENDOR;
+ *frm++ = sizeof(struct ieee80211_wme_info) - 2;
+ memcpy(frm, oui, sizeof(oui));
+ frm += sizeof(oui);
+ *frm++ = WME_INFO_OUI_SUBTYPE;
+ *frm++ = WME_VERSION;
+
+ /* QoS info field depends upon operating mode */
+ switch (vap->iv_opmode) {
+ case IEEE80211_M_HOSTAP:
+ *frm = wme->wme_bssChanParams.cap_info;
+ if (vap->iv_flags_ext & IEEE80211_FEXT_UAPSD)
+ *frm |= WME_CAPINFO_UAPSD_EN;
+ frm++;
+ break;
+ case IEEE80211_M_STA:
+ /*
+ * NB: UAPSD drivers must set this up in their
+ * VAP creation method.
+ */
+ *frm++ = vap->iv_uapsdinfo;
+ break;
+ default:
+ *frm++ = 0;
+ break;
+ }
+
+ return frm;
}
/*
* Add a WME parameters element to a frame.
*/
static uint8_t *
-ieee80211_add_wme_param(uint8_t *frm, struct ieee80211_wme_state *wme)
+ieee80211_add_wme_param(uint8_t *frm, struct ieee80211_wme_state *wme,
+ int uapsd_enable)
{
#define SM(_v, _f) (((_v) << _f##_S) & _f)
#define ADDSHORT(frm, v) do { \
@@ -2195,8 +2217,12 @@ ieee80211_add_wme_param(uint8_t *frm, struct ieee80211
memcpy(frm, ¶m, sizeof(param));
frm += __offsetof(struct ieee80211_wme_info, wme_info);
- *frm++ = wme->wme_bssChanParams.cap_info; /* AC info */
+ *frm = wme->wme_bssChanParams.cap_info; /* AC info */
+ if (uapsd_enable)
+ *frm |= WME_CAPINFO_UAPSD_EN;
+ frm++;
*frm++ = 0; /* reserved field */
+ /* XXX TODO - U-APSD bits - SP, flags below */
for (i = 0; i < WME_NUM_AC; i++) {
const struct wmeParams *ac =
&wme->wme_bssChanParams.cap_wmeParams[i];
@@ -2789,7 +2815,7 @@ ieee80211_send_mgmt(struct ieee80211_node *ni, int typ
frm = ieee80211_add_wpa(frm, vap);
if ((ic->ic_flags & IEEE80211_F_WME) &&
ni->ni_ies.wme_ie != NULL)
- frm = ieee80211_add_wme_info(frm, &ic->ic_wme);
+ frm = ieee80211_add_wme_info(frm, &ic->ic_wme, ni);
/*
* Same deal - only send HT info if we're on an 11n
@@ -2881,7 +2907,8 @@ ieee80211_send_mgmt(struct ieee80211_node *ni, int typ
}
if ((vap->iv_flags & IEEE80211_F_WME) &&
ni->ni_ies.wme_ie != NULL)
- frm = ieee80211_add_wme_param(frm, &ic->ic_wme);
+ frm = ieee80211_add_wme_param(frm, &ic->ic_wme,
+ !! (vap->iv_flags_ext & IEEE80211_FEXT_UAPSD));
if ((ni->ni_flags & HTFLAGS) == HTFLAGS) {
frm = ieee80211_add_htcap_vendor(frm, ni);
frm = ieee80211_add_htinfo_vendor(frm, ni);
@@ -3092,7 +3119,8 @@ ieee80211_alloc_proberesp(struct ieee80211_node *bss,
}
frm = ieee80211_add_wpa(frm, vap);
if (vap->iv_flags & IEEE80211_F_WME)
- frm = ieee80211_add_wme_param(frm, &ic->ic_wme);
+ frm = ieee80211_add_wme_param(frm, &ic->ic_wme,
+ !! (vap->iv_flags_ext & IEEE80211_FEXT_UAPSD));
if (IEEE80211_IS_CHAN_HT(bss->ni_chan) &&
(vap->iv_flags_ht & IEEE80211_FHT_HTCOMPAT) &&
legacy != IEEE80211_SEND_LEGACY_11B) {
@@ -3490,7 +3518,8 @@ ieee80211_beacon_construct(struct mbuf *m, uint8_t *fr
frm = ieee80211_add_wpa(frm, vap);
if (vap->iv_flags & IEEE80211_F_WME) {
bo->bo_wme = frm;
- frm = ieee80211_add_wme_param(frm, &ic->ic_wme);
+ frm = ieee80211_add_wme_param(frm, &ic->ic_wme,
+ !! (vap->iv_flags_ext & IEEE80211_FEXT_UAPSD));
}
if (IEEE80211_IS_CHAN_HT(ni->ni_chan) &&
(vap->iv_flags_ht & IEEE80211_FHT_HTCOMPAT)) {
@@ -3782,7 +3811,8 @@ ieee80211_beacon_update(struct ieee80211_node *ni, str
wme->wme_hipri_switch_hysteresis;
}
if (isset(bo->bo_flags, IEEE80211_BEACON_WME)) {
- (void) ieee80211_add_wme_param(bo->bo_wme, wme);
+ (void) ieee80211_add_wme_param(bo->bo_wme, wme,
+ vap->iv_flags_ext & IEEE80211_FEXT_UAPSD);
clrbit(bo->bo_flags, IEEE80211_BEACON_WME);
}
}
Modified: head/sys/net80211/ieee80211_proto.c
==============================================================================
--- head/sys/net80211/ieee80211_proto.c Mon Jun 15 22:43:46 2020 (r362209)
+++ head/sys/net80211/ieee80211_proto.c Tue Jun 16 00:27:32 2020 (r362210)
@@ -1147,8 +1147,11 @@ ieee80211_wme_initparams_locked(struct ieee80211vap *v
* field and updates hardware when said field changes.
* Otherwise the hardware is programmed with defaults, not what
* the beacon actually announces.
+ *
+ * Note that we can't ever have 0xff as an actual value;
+ * the only valid values are 0..15.
*/
- wme->wme_wmeChanParams.cap_info = 0;
+ wme->wme_wmeChanParams.cap_info = 0xfe;
/*
* Select mode; we can be called early in which case we
Modified: head/sys/net80211/ieee80211_sta.c
==============================================================================
--- head/sys/net80211/ieee80211_sta.c Mon Jun 15 22:43:46 2020 (r362209)
+++ head/sys/net80211/ieee80211_sta.c Tue Jun 16 00:27:32 2020 (r362210)
@@ -1129,25 +1129,56 @@ bad:
IEEE80211_SCAN_FAIL_STATUS);
}
+/*
+ * Parse the WME IE for QoS and U-APSD information.
+ *
+ * Returns -1 if the IE isn't found, 1 if it's found.
+ */
int
+ieee80211_parse_wmeie(uint8_t *frm, const struct ieee80211_frame *wh,
+ struct ieee80211_node *ni)
+{
+ u_int len = frm[1];
+
+ ni->ni_uapsd = 0;
+
+ if (len < sizeof(struct ieee80211_wme_param)-2) {
+ IEEE80211_DISCARD_IE(ni->ni_vap,
+ IEEE80211_MSG_ELEMID | IEEE80211_MSG_WME,
+ wh, "WME", "too short, len %u", len);
+ return -1;
+ }
+
+ ni->ni_uapsd = frm[WME_CAPINFO_IE_OFFSET];
+
+ IEEE80211_NOTE(ni->ni_vap, IEEE80211_MSG_POWER | IEEE80211_MSG_ASSOC,
+ ni, "U-APSD settings from STA: 0x%02x", ni->ni_uapsd);
+
+ return 1;
+}
+
+int
ieee80211_parse_wmeparams(struct ieee80211vap *vap, uint8_t *frm,
- const struct ieee80211_frame *wh)
+ const struct ieee80211_frame *wh, uint8_t *qosinfo)
{
#define MS(_v, _f) (((_v) & _f) >> _f##_S)
struct ieee80211_wme_state *wme = &vap->iv_ic->ic_wme;
- u_int len = frm[1], qosinfo;
+ u_int len = frm[1], qosinfo_count;
int i;
+ *qosinfo = 0;
+
if (len < sizeof(struct ieee80211_wme_param)-2) {
IEEE80211_DISCARD_IE(vap,
IEEE80211_MSG_ELEMID | IEEE80211_MSG_WME,
wh, "WME", "too short, len %u", len);
return -1;
}
- qosinfo = frm[__offsetof(struct ieee80211_wme_param, param_qosInfo)];
- qosinfo &= WME_QOSINFO_COUNT;
+ *qosinfo = frm[__offsetof(struct ieee80211_wme_param, param_qosInfo)];
+ qosinfo_count = *qosinfo & WME_QOSINFO_COUNT;
+
/* XXX do proper check for wraparound */
- if (qosinfo == wme->wme_wmeChanParams.cap_info)
+ if (qosinfo_count == wme->wme_wmeChanParams.cap_info)
return 0;
frm += __offsetof(struct ieee80211_wme_param, params_acParams);
for (i = 0; i < WME_NUM_AC; i++) {
@@ -1159,9 +1190,18 @@ ieee80211_parse_wmeparams(struct ieee80211vap *vap, ui
wmep->wmep_logcwmin = MS(frm[1], WME_PARAM_LOGCWMIN);
wmep->wmep_logcwmax = MS(frm[1], WME_PARAM_LOGCWMAX);
wmep->wmep_txopLimit = le16dec(frm+2);
+ IEEE80211_DPRINTF(vap, IEEE80211_MSG_WME,
+ "%s: WME: %d: acm=%d aifsn=%d logcwmin=%d logcwmax=%d txopLimit=%d\n",
+ __func__,
+ i,
+ wmep->wmep_acm,
+ wmep->wmep_aifsn,
+ wmep->wmep_logcwmin,
+ wmep->wmep_logcwmax,
+ wmep->wmep_txopLimit);
frm += 4;
}
- wme->wme_wmeChanParams.cap_info = qosinfo;
+ wme->wme_wmeChanParams.cap_info = qosinfo_count;
return 1;
#undef MS
}
@@ -1350,11 +1390,12 @@ sta_recv_mgmt(struct ieee80211_node *ni, struct mbuf *
struct ieee80211com *ic = ni->ni_ic;
struct ieee80211_channel *rxchan = ic->ic_curchan;
struct ieee80211_frame *wh;
+ int ht_state_change = 0, do_ht = 0;
uint8_t *frm, *efrm;
uint8_t *rates, *xrates, *wme, *htcap, *htinfo;
uint8_t *vhtcap, *vhtopmode;
uint8_t rate;
- int ht_state_change = 0, do_ht = 0;
+ uint8_t qosinfo;
wh = mtod(m0, struct ieee80211_frame *);
frm = (uint8_t *)&wh[1];
@@ -1443,9 +1484,18 @@ sta_recv_mgmt(struct ieee80211_node *ni, struct mbuf *
/* XXX statistic */
}
if (scan.wme != NULL &&
- (ni->ni_flags & IEEE80211_NODE_QOS) &&
- ieee80211_parse_wmeparams(vap, scan.wme, wh) > 0)
- ieee80211_wme_updateparams(vap);
+ (ni->ni_flags & IEEE80211_NODE_QOS)) {
+ int _retval;
+ if ((_retval = ieee80211_parse_wmeparams(vap,
+ scan.wme, wh, &qosinfo)) >= 0) {
+ if (qosinfo & WME_CAPINFO_UAPSD_EN)
+ ni->ni_flags |=
+ IEEE80211_NODE_UAPSD;
+ if (_retval > 0)
+ ieee80211_wme_updateparams(vap);
+ }
+ } else
+ ni->ni_flags &= ~IEEE80211_NODE_UAPSD;
#ifdef IEEE80211_SUPPORT_SUPERG
if (scan.ath != NULL)
ieee80211_parse_athparams(ni, scan.ath, wh);
@@ -1782,7 +1832,7 @@ sta_recv_mgmt(struct ieee80211_node *ni, struct mbuf *
if (ni->ni_jointime == 0)
ni->ni_jointime = time_uptime;
if (wme != NULL &&
- ieee80211_parse_wmeparams(vap, wme, wh) >= 0) {
+ ieee80211_parse_wmeparams(vap, wme, wh, &qosinfo) >= 0) {
ni->ni_flags |= IEEE80211_NODE_QOS;
ieee80211_wme_updateparams(vap);
} else
Modified: head/sys/net80211/ieee80211_sta.h
==============================================================================
--- head/sys/net80211/ieee80211_sta.h Mon Jun 15 22:43:46 2020 (r362209)
+++ head/sys/net80211/ieee80211_sta.h Tue Jun 16 00:27:32 2020 (r362210)
@@ -40,5 +40,12 @@ void ieee80211_sta_vattach(struct ieee80211vap *);
* Used by the adhoc/mesh/tdma paths.
*/
extern int ieee80211_parse_wmeparams(struct ieee80211vap *vap, uint8_t *frm,
- const struct ieee80211_frame *wh);
+ const struct ieee80211_frame *wh, uint8_t *qosinfo);
+
+/*
+ * Used in the hostap path.
+ */
+extern int ieee80211_parse_wmeie(uint8_t *frm,
+ const struct ieee80211_frame *wh, struct ieee80211_node *ni);
+
#endif /* !_NET80211_IEEE80211_STA_H_ */
Modified: head/sys/net80211/ieee80211_var.h
==============================================================================
--- head/sys/net80211/ieee80211_var.h Mon Jun 15 22:43:46 2020 (r362209)
+++ head/sys/net80211/ieee80211_var.h Tue Jun 16 00:27:32 2020 (r362210)
@@ -581,6 +581,9 @@ struct ieee80211vap {
void (*iv_updateslot)(struct ieee80211vap *);
struct task iv_slot_task; /* deferred slot time update */
+ /* per-vap U-APSD state */
+ uint8_t iv_uapsdinfo; /* sta mode QoS Info flags */
+
uint64_t iv_spare[6];
};
MALLOC_DECLARE(M_80211_VAP);
@@ -662,6 +665,7 @@ MALLOC_DECLARE(M_80211_VAP);
#define IEEE80211_FEXT_FRAG_OFFLOAD 0x00200000 /* CONF: hardware does 802.11 fragmentation + assignment */
#define IEEE80211_FEXT_VHT 0x00400000 /* CONF: VHT support */
#define IEEE80211_FEXT_QUIET_IE 0x00800000 /* STATUS: quiet IE in a beacon has been added */
+#define IEEE80211_FEXT_UAPSD 0x01000000 /* CONF: enable U-APSD */
#define IEEE80211_FEXT_BITS \
"\20\2INACT\3SCANWAIT\4BGSCAN\5WPS\6TSN\7SCANREQ\10RESUME" \
More information about the svn-src-all
mailing list