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, &param, 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