mirror of
https://github.com/openbsd/src.git
synced 2026-06-18 07:13:36 +02:00
sys/ieee80211: add support of uAPSD
OK: phessler@, stsp@
This commit is contained in:
@@ -1,4 +1,4 @@
|
||||
/* $OpenBSD: ieee80211.h,v 1.66 2026/03/29 21:16:21 kirill Exp $ */
|
||||
/* $OpenBSD: ieee80211.h,v 1.67 2026/05/28 10:50:47 kirill Exp $ */
|
||||
/* $NetBSD: ieee80211.h,v 1.6 2004/04/30 23:51:53 dyoung Exp $ */
|
||||
|
||||
/*-
|
||||
@@ -193,6 +193,21 @@ 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_VO 0x01
|
||||
#define IEEE80211_WMM_IE_STA_QOSINFO_AC_VI 0x02
|
||||
#define IEEE80211_WMM_IE_STA_QOSINFO_AC_BK 0x04
|
||||
#define IEEE80211_WMM_IE_STA_QOSINFO_AC_BE 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 0x01
|
||||
#define IEEE80211_WMM_IE_STA_QOSINFO_SP_4 0x02
|
||||
#define IEEE80211_WMM_IE_STA_QOSINFO_SP_6 0x03
|
||||
#define IEEE80211_WMM_IE_STA_QOSINFO_SP_MASK 0x03
|
||||
#define IEEE80211_WMM_IE_STA_QOSINFO_SP_SHIFT 5
|
||||
|
||||
/*
|
||||
* Control frames.
|
||||
*/
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
/* $OpenBSD: ieee80211_input.c,v 1.262 2026/05/24 16:28:44 kirill Exp $ */
|
||||
/* $OpenBSD: ieee80211_input.c,v 1.263 2026/05/28 10:50:47 kirill Exp $ */
|
||||
/* $NetBSD: ieee80211_input.c,v 1.24 2004/05/31 11:12:24 dyoung Exp $ */
|
||||
|
||||
/*-
|
||||
@@ -87,6 +87,7 @@ int ieee80211_parse_edca_params_body(struct ieee80211com *,
|
||||
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 *);
|
||||
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 *,
|
||||
@@ -1388,6 +1389,32 @@ ieee80211_parse_wmm_params(struct ieee80211com *ic, const u_int8_t *frm)
|
||||
return ieee80211_parse_edca_params_body(ic, frm + 8);
|
||||
}
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
void
|
||||
ieee80211_setup_uapsd(struct ieee80211com *ic, struct ieee80211_node *ni,
|
||||
int peer_uapsd)
|
||||
{
|
||||
if (peer_uapsd && (ic->ic_userflags & IEEE80211_F_UAPSD) &&
|
||||
(ni->ni_flags & IEEE80211_NODE_QOS)) {
|
||||
ni->ni_flags |= IEEE80211_NODE_UAPSD;
|
||||
ni->ni_uapsd_ac = ic->ic_uapsd_ac;
|
||||
ni->ni_uapsd_maxsp = ic->ic_uapsd_maxsp;
|
||||
} else {
|
||||
ni->ni_flags &= ~IEEE80211_NODE_UAPSD;
|
||||
ni->ni_uapsd_ac = 0;
|
||||
ni->ni_uapsd_maxsp = 0;
|
||||
}
|
||||
}
|
||||
|
||||
enum ieee80211_cipher
|
||||
ieee80211_parse_rsn_cipher(const u_int8_t selector[4])
|
||||
{
|
||||
@@ -1628,7 +1655,8 @@ ieee80211_recv_probe_resp(struct ieee80211com *ic, struct mbuf *m,
|
||||
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;
|
||||
|
||||
/*
|
||||
@@ -1863,6 +1891,9 @@ ieee80211_recv_probe_resp(struct ieee80211com *ic, struct mbuf *m,
|
||||
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
|
||||
@@ -1973,11 +2004,18 @@ ieee80211_recv_probe_resp(struct ieee80211com *ic, struct mbuf *m,
|
||||
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;
|
||||
@@ -1998,6 +2036,9 @@ ieee80211_recv_probe_resp(struct ieee80211com *ic, struct mbuf *m,
|
||||
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.
|
||||
@@ -2626,7 +2667,8 @@ ieee80211_recv_assoc_resp(struct ieee80211com *ic, struct mbuf *m,
|
||||
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) {
|
||||
@@ -2714,6 +2756,9 @@ ieee80211_recv_assoc_resp(struct ieee80211com *ic, struct mbuf *m,
|
||||
}
|
||||
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"));
|
||||
@@ -2742,6 +2787,8 @@ ieee80211_recv_assoc_resp(struct ieee80211com *ic, struct mbuf *m,
|
||||
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)
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
/* $OpenBSD: ieee80211_ioctl.h,v 1.45 2026/03/26 12:15:01 kirill Exp $ */
|
||||
/* $OpenBSD: ieee80211_ioctl.h,v 1.46 2026/05/28 10:50:47 kirill Exp $ */
|
||||
/* $NetBSD: ieee80211_ioctl.h,v 1.7 2004/04/30 22:51:04 dyoung Exp $ */
|
||||
|
||||
/*-
|
||||
@@ -410,7 +410,9 @@ struct ieee80211_nodereq_all {
|
||||
#define IEEE80211_F_HOSTAPMASK 0x00000003
|
||||
#define IEEE80211_F_STAYAUTH 0x00000004 /* CONF: ignore deauth */
|
||||
#define IEEE80211_F_NOMIMO 0x00000008 /* CONF: disable MIMO */
|
||||
#define IEEE80211_F_USERBITS "\20\01HIDENWID\02NOBRIDGE\03STAYAUTH\04NOMIMO"
|
||||
#define IEEE80211_F_UAPSD 0x00000010 /* CONF: enable u-APSD */
|
||||
#define IEEE80211_F_USERBITS "\20\01HIDENWID\02NOBRIDGE\03STAYAUTH\04NOMIMO" \
|
||||
"\05UAPSD"
|
||||
|
||||
struct ieee80211_flags {
|
||||
const char *f_name;
|
||||
@@ -421,7 +423,8 @@ struct ieee80211_flags {
|
||||
{ "hidenwid", IEEE80211_F_HIDENWID }, \
|
||||
{ "nobridge", IEEE80211_F_NOBRIDGE }, \
|
||||
{ "stayauth", IEEE80211_F_STAYAUTH }, \
|
||||
{ "nomimo", IEEE80211_F_NOMIMO } \
|
||||
{ "nomimo", IEEE80211_F_NOMIMO }, \
|
||||
{ "uapsd", IEEE80211_F_UAPSD } \
|
||||
}
|
||||
|
||||
#define SIOCG80211FLAGS _IOWR('i', 216, struct ifreq)
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
/* $OpenBSD: ieee80211_node.h,v 1.101 2026/03/29 21:16:21 kirill Exp $ */
|
||||
/* $OpenBSD: ieee80211_node.h,v 1.102 2026/05/28 10:50:47 kirill Exp $ */
|
||||
/* $NetBSD: ieee80211_node.h,v 1.9 2004/04/30 22:57:32 dyoung Exp $ */
|
||||
|
||||
/*-
|
||||
@@ -306,6 +306,8 @@ 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_ac;
|
||||
u_int8_t ni_uapsd_maxsp;
|
||||
|
||||
/* RSN */
|
||||
struct timeout ni_eapol_to;
|
||||
@@ -446,6 +448,7 @@ struct ieee80211_node {
|
||||
#define IEEE80211_NODE_HE 0x200000 /* HE negotiated */
|
||||
#define IEEE80211_NODE_HECAP 0x400000 /* claims to support HE */
|
||||
#define IEEE80211_NODE_CSA 0x800000 /* channel switch announced */
|
||||
#define IEEE80211_NODE_UAPSD 0x1000000 /* uAPSD negotiated */
|
||||
|
||||
/* If not NULL, this function gets called when ni_refcnt hits zero. */
|
||||
void (*ni_unref_cb)(struct ieee80211com *,
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
/* $OpenBSD: ieee80211_output.c,v 1.147 2026/03/19 16:50:32 chris Exp $ */
|
||||
/* $OpenBSD: ieee80211_output.c,v 1.148 2026/05/28 10:50:47 kirill Exp $ */
|
||||
/* $NetBSD: ieee80211_output.c,v 1.13 2004/05/31 11:02:55 dyoung Exp $ */
|
||||
|
||||
/*-
|
||||
@@ -985,6 +985,16 @@ ieee80211_add_erp(u_int8_t *frm, struct ieee80211com *ic)
|
||||
}
|
||||
#endif /* IEEE80211_STA_ONLY */
|
||||
|
||||
uint8_t
|
||||
ieee80211_uapsd_qosinfo(struct ieee80211com *ic)
|
||||
{
|
||||
if ((ic->ic_userflags & IEEE80211_F_UAPSD) == 0)
|
||||
return 0;
|
||||
return (ic->ic_uapsd_ac & IEEE80211_WMM_IE_STA_QOSINFO_AC_MASK) |
|
||||
((ic->ic_uapsd_maxsp & IEEE80211_WMM_IE_STA_QOSINFO_SP_MASK) <<
|
||||
IEEE80211_WMM_IE_STA_QOSINFO_SP_SHIFT);
|
||||
}
|
||||
|
||||
/*
|
||||
* Add a QoS Capability element to a frame (see 7.3.2.35).
|
||||
*/
|
||||
@@ -993,7 +1003,7 @@ ieee80211_add_qos_capability(u_int8_t *frm, struct ieee80211com *ic)
|
||||
{
|
||||
*frm++ = IEEE80211_ELEMID_QOS_CAP;
|
||||
*frm++ = 1;
|
||||
*frm++ = 0; /* QoS Info */
|
||||
*frm++ = ieee80211_uapsd_qosinfo(ic);
|
||||
return frm;
|
||||
}
|
||||
|
||||
@@ -1011,7 +1021,7 @@ ieee80211_add_wme_info(uint8_t *frm, struct ieee80211com *ic)
|
||||
*frm++ = 2; /* OUI type */
|
||||
*frm++ = 0; /* OUI subtype */
|
||||
*frm++ = 1; /* version */
|
||||
*frm++ = 0; /* info */
|
||||
*frm++ = ieee80211_uapsd_qosinfo(ic);
|
||||
|
||||
return frm;
|
||||
}
|
||||
@@ -1585,7 +1595,7 @@ ieee80211_get_assoc_req(struct ieee80211com *ic, struct ieee80211_node *ni,
|
||||
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 +1611,10 @@ ieee80211_get_assoc_req(struct ieee80211com *ic, struct ieee80211_node *ni,
|
||||
IEEE80211_HE_MCS_NSS_SIZE(ic->ic_he_phy_cap[0]);
|
||||
}
|
||||
|
||||
/* Keep QoS Capability aligned with ieee80211_add_wme_info(). */
|
||||
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) ?
|
||||
@@ -1612,11 +1626,12 @@ ieee80211_get_assoc_req(struct ieee80211com *ic, struct ieee80211_node *ni,
|
||||
(((ic->ic_flags & IEEE80211_F_RSNON) &&
|
||||
(ni->ni_rsnprotos & IEEE80211_PROTO_RSN)) ?
|
||||
2 + IEEE80211_RSNIE_MAXLEN : 0) +
|
||||
((ni->ni_flags & IEEE80211_NODE_QOS) ? 2 + 1 : 0) +
|
||||
(addwme ? 2 + 1 : 0) +
|
||||
(((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)
|
||||
@@ -1644,15 +1659,15 @@ ieee80211_get_assoc_req(struct ieee80211com *ic, struct ieee80211_node *ni,
|
||||
if ((ic->ic_flags & IEEE80211_F_RSNON) &&
|
||||
(ni->ni_rsnprotos & IEEE80211_PROTO_RSN))
|
||||
frm = ieee80211_add_rsn(frm, ic, ni);
|
||||
if (ni->ni_flags & IEEE80211_NODE_QOS)
|
||||
if (addwme)
|
||||
frm = ieee80211_add_qos_capability(frm, ic);
|
||||
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)
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
/* $OpenBSD: ieee80211_proto.c,v 1.112 2026/03/19 16:50:32 chris Exp $ */
|
||||
/* $OpenBSD: ieee80211_proto.c,v 1.113 2026/05/28 10:50:47 kirill Exp $ */
|
||||
/* $NetBSD: ieee80211_proto.c,v 1.8 2004/04/30 23:58:20 dyoung Exp $ */
|
||||
|
||||
/*-
|
||||
@@ -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_flags & IEEE80211_NODE_UAPSD) ?
|
||||
" uAPSD enabled" :
|
||||
" uAPSD disabled") :
|
||||
"");
|
||||
}
|
||||
if (!(ic->ic_flags & IEEE80211_F_RSNON)) {
|
||||
/*
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
/* $OpenBSD: ieee80211_var.h,v 1.114 2026/03/19 16:50:32 chris Exp $ */
|
||||
/* $OpenBSD: ieee80211_var.h,v 1.115 2026/05/28 10:50:47 kirill Exp $ */
|
||||
/* $NetBSD: ieee80211_var.h,v 1.7 2004/05/06 03:07:10 dyoung Exp $ */
|
||||
|
||||
/*-
|
||||
@@ -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];
|
||||
|
||||
Reference in New Issue
Block a user