[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.
This commit is contained in:
parent
3d8dd98381
commit
8379e8db7a
@ -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 */
|
||||
|
@ -616,6 +616,12 @@ ieee80211_vap_setup(struct ieee80211com *ic, struct ieee80211vap *vap,
|
||||
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;
|
||||
|
@ -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 mbuf *m0,
|
||||
* 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 mbuf *m0,
|
||||
#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);
|
||||
|
@ -1145,6 +1145,11 @@ ieee80211_ioctl_get80211(struct ieee80211vap *vap, u_long cmd,
|
||||
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:
|
||||
@ -3462,6 +3467,16 @@ ieee80211_ioctl_set80211(struct ieee80211vap *vap, u_long cmd, struct ieee80211r
|
||||
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 */
|
||||
case IEEE80211_IOC_VHTCONF:
|
||||
|
@ -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) */
|
||||
|
@ -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 */
|
||||
@ -256,6 +257,9 @@ struct ieee80211_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];
|
||||
};
|
||||
MALLOC_DECLARE(M_80211_NODE);
|
||||
|
@ -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_wme_state *wme)
|
||||
|
||||
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 type, int arg)
|
||||
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 type, int arg)
|
||||
}
|
||||
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, int legacy)
|
||||
}
|
||||
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 *frm,
|
||||
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, struct mbuf *m, int mcast)
|
||||
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);
|
||||
}
|
||||
}
|
||||
|
@ -1147,8 +1147,11 @@ ieee80211_wme_initparams_locked(struct ieee80211vap *vap)
|
||||
* 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
|
||||
|
@ -1129,25 +1129,56 @@ sta_auth_shared(struct ieee80211_node *ni, struct ieee80211_frame *wh,
|
||||
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, uint8_t *frm,
|
||||
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 *m0, int subtype,
|
||||
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 *m0, int subtype,
|
||||
/* 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 *m0, int subtype,
|
||||
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
|
||||
|
@ -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_ */
|
||||
|
@ -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" \
|
||||
|
Loading…
Reference in New Issue
Block a user