summaryrefslogtreecommitdiffstats
path: root/freebsd/sys/net80211/ieee80211_output.c
diff options
context:
space:
mode:
Diffstat (limited to 'freebsd/sys/net80211/ieee80211_output.c')
-rw-r--r--freebsd/sys/net80211/ieee80211_output.c300
1 files changed, 268 insertions, 32 deletions
diff --git a/freebsd/sys/net80211/ieee80211_output.c b/freebsd/sys/net80211/ieee80211_output.c
index c9251796..bb42f945 100644
--- a/freebsd/sys/net80211/ieee80211_output.c
+++ b/freebsd/sys/net80211/ieee80211_output.c
@@ -60,6 +60,7 @@ __FBSDID("$FreeBSD$");
#endif
#include <net80211/ieee80211_wds.h>
#include <net80211/ieee80211_mesh.h>
+#include <net80211/ieee80211_vht.h>
#if defined(INET) || defined(INET6)
#include <netinet/in.h>
@@ -123,9 +124,7 @@ ieee80211_vap_pkt_send_dest(struct ieee80211vap *vap, struct mbuf *m,
{
struct ieee80211com *ic = vap->iv_ic;
struct ifnet *ifp = vap->iv_ifp;
-#ifdef IEEE80211_SUPPORT_SUPERG
int mcast;
-#endif
if ((ni->ni_flags & IEEE80211_NODE_PWR_MGT) &&
(m->m_flags & M_PWR_SAV) == 0) {
@@ -165,9 +164,7 @@ ieee80211_vap_pkt_send_dest(struct ieee80211vap *vap, struct mbuf *m,
* interface it (might have been) received on.
*/
m->m_pkthdr.rcvif = (void *)ni;
-#ifdef IEEE80211_SUPPORT_SUPERG
mcast = (m->m_flags & (M_MCAST | M_BCAST)) ? 1: 0;
-#endif
BPF_MTAP(ifp, m); /* 802.3 tx */
@@ -182,10 +179,15 @@ ieee80211_vap_pkt_send_dest(struct ieee80211vap *vap, struct mbuf *m,
* The default ic_ampdu_enable routine handles staggering
* ADDBA requests in case the receiver NAK's us or we are
* otherwise unable to establish a BA stream.
+ *
+ * Don't treat group-addressed frames as candidates for aggregation;
+ * net80211 doesn't support 802.11aa-2012 and so group addressed
+ * frames will always have sequence numbers allocated from the NON_QOS
+ * TID.
*/
if ((ni->ni_flags & IEEE80211_NODE_AMPDU_TX) &&
(vap->iv_flags_ht & IEEE80211_FHT_AMPDU_TX)) {
- if ((m->m_flags & M_EAPOL) == 0) {
+ if ((m->m_flags & M_EAPOL) == 0 && (! mcast)) {
int tid = WME_AC_TO_TID(M_WME_GETAC(m));
struct ieee80211_tx_ampdu *tap = &ni->ni_tx_ampdu[tid];
@@ -766,13 +768,31 @@ ieee80211_send_setup(
}
*(uint16_t *)&wh->i_dur[0] = 0;
+ /*
+ * XXX TODO: this is what the TX lock is for.
+ * Here we're incrementing sequence numbers, and they
+ * need to be in lock-step with what the driver is doing
+ * both in TX ordering and crypto encap (IV increment.)
+ *
+ * If the driver does seqno itself, then we can skip
+ * assigning sequence numbers here, and we can avoid
+ * requiring the TX lock.
+ */
tap = &ni->ni_tx_ampdu[tid];
- if (tid != IEEE80211_NONQOS_TID && IEEE80211_AMPDU_RUNNING(tap))
+ if (tid != IEEE80211_NONQOS_TID && IEEE80211_AMPDU_RUNNING(tap)) {
m->m_flags |= M_AMPDU_MPDU;
- else {
+ } else {
if (IEEE80211_HAS_SEQ(type & IEEE80211_FC0_TYPE_MASK,
type & IEEE80211_FC0_SUBTYPE_MASK))
- seqno = ni->ni_txseqs[tid]++;
+ /*
+ * 802.11-2012 9.3.2.10 - QoS multicast frames
+ * come out of a different seqno space.
+ */
+ if (IEEE80211_IS_MULTICAST(wh->i_addr1)) {
+ seqno = ni->ni_txseqs[IEEE80211_NONQOS_TID]++;
+ } else {
+ seqno = ni->ni_txseqs[tid]++;
+ }
else
seqno = 0;
@@ -1230,7 +1250,7 @@ ieee80211_encap(struct ieee80211vap *vap, struct ieee80211_node *ni,
struct ieee80211_frame *wh;
struct ieee80211_key *key;
struct llc *llc;
- int hdrsize, hdrspace, datalen, addqos, txfrag, is4addr;
+ int hdrsize, hdrspace, datalen, addqos, txfrag, is4addr, is_mcast;
ieee80211_seq seqno;
int meshhdrsize, meshae;
uint8_t *qos;
@@ -1238,6 +1258,8 @@ ieee80211_encap(struct ieee80211vap *vap, struct ieee80211_node *ni,
IEEE80211_TX_LOCK_ASSERT(ic);
+ is_mcast = !! (m->m_flags & (M_MCAST | M_BCAST));
+
/*
* Copy existing Ethernet header to a safe place. The
* rest of the code assumes it's ok to strip it when
@@ -1282,11 +1304,19 @@ ieee80211_encap(struct ieee80211vap *vap, struct ieee80211_node *ni,
* ap's require all data frames to be QoS-encapsulated
* once negotiated in which case we'll need to make this
* configurable.
- * NB: mesh data frames are QoS.
+ *
+ * Don't send multicast QoS frames.
+ * Technically multicast frames can be QoS if all stations in the
+ * BSS are also QoS.
+ *
+ * NB: mesh data frames are QoS, including multicast frames.
*/
- addqos = ((ni->ni_flags & (IEEE80211_NODE_QOS|IEEE80211_NODE_HT)) ||
+ addqos =
+ (((is_mcast == 0) && (ni->ni_flags &
+ (IEEE80211_NODE_QOS|IEEE80211_NODE_HT))) ||
(vap->iv_opmode == IEEE80211_M_MBSS)) &&
(m->m_flags & M_EAPOL) == 0;
+
if (addqos)
hdrsize = sizeof(struct ieee80211_qosframe);
else
@@ -1544,8 +1574,29 @@ ieee80211_encap(struct ieee80211vap *vap, struct ieee80211_node *ni,
if (is_amsdu)
qos[0] |= IEEE80211_QOS_AMSDU;
+ /*
+ * XXX TODO TX lock is needed for atomic updates of sequence
+ * numbers. If the driver does it, then don't do it here;
+ * and we don't need the TX lock held.
+ */
if ((m->m_flags & M_AMPDU_MPDU) == 0) {
/*
+ * 802.11-2012 9.3.2.10 -
+ *
+ * If this is a multicast frame then we need
+ * to ensure that the sequence number comes from
+ * a separate seqno space and not the TID space.
+ *
+ * Otherwise multicast frames may actually cause
+ * holes in the TX blockack window space and
+ * upset various things.
+ */
+ if (IEEE80211_IS_MULTICAST(wh->i_addr1))
+ seqno = ni->ni_txseqs[IEEE80211_NONQOS_TID]++;
+ else
+ seqno = ni->ni_txseqs[tid]++;
+
+ /*
* NB: don't assign a sequence # to potential
* aggregates; we expect this happens at the
* point the frame comes off any aggregation q
@@ -1563,6 +1614,11 @@ ieee80211_encap(struct ieee80211vap *vap, struct ieee80211_node *ni,
M_SEQNO_SET(m, seqno);
}
} else {
+ /*
+ * XXX TODO TX lock is needed for atomic updates of sequence
+ * numbers. If the driver does it, then don't do it here;
+ * and we don't need the TX lock held.
+ */
seqno = ni->ni_txseqs[IEEE80211_NONQOS_TID]++;
*(uint16_t *)wh->i_seq =
htole16(seqno << IEEE80211_SEQ_SEQ_SHIFT);
@@ -1577,12 +1633,20 @@ ieee80211_encap(struct ieee80211vap *vap, struct ieee80211_node *ni,
__func__);
}
+ /*
+ * Check if xmit fragmentation is required.
+ *
+ * If the hardware does fragmentation offload, then don't bother
+ * doing it here.
+ */
+ if (IEEE80211_CONF_FRAG_OFFLOAD(ic))
+ txfrag = 0;
+ else
+ txfrag = (m->m_pkthdr.len > vap->iv_fragthreshold &&
+ !IEEE80211_IS_MULTICAST(wh->i_addr1) &&
+ (vap->iv_caps & IEEE80211_C_TXFRAG) &&
+ (m->m_flags & (M_FF | M_AMPDU_MPDU)) == 0);
- /* check if xmit fragmentation is required */
- txfrag = (m->m_pkthdr.len > vap->iv_fragthreshold &&
- !IEEE80211_IS_MULTICAST(wh->i_addr1) &&
- (vap->iv_caps & IEEE80211_C_TXFRAG) &&
- (m->m_flags & (M_FF | M_AMPDU_MPDU)) == 0);
if (key != NULL) {
/*
* IEEE 802.1X: send EAPOL frames always in the clear.
@@ -1962,16 +2026,23 @@ ieee80211_add_supportedchannels(uint8_t *frm, struct ieee80211com *ic)
* Add an 11h Quiet time element to a frame.
*/
static uint8_t *
-ieee80211_add_quiet(uint8_t *frm, struct ieee80211vap *vap)
+ieee80211_add_quiet(uint8_t *frm, struct ieee80211vap *vap, int update)
{
struct ieee80211_quiet_ie *quiet = (struct ieee80211_quiet_ie *) frm;
quiet->quiet_ie = IEEE80211_ELEMID_QUIET;
quiet->len = 6;
- if (vap->iv_quiet_count_value == 1)
- vap->iv_quiet_count_value = vap->iv_quiet_count;
- else if (vap->iv_quiet_count_value > 1)
- vap->iv_quiet_count_value--;
+
+ /*
+ * Only update every beacon interval - otherwise probe responses
+ * would update the quiet count value.
+ */
+ if (update) {
+ if (vap->iv_quiet_count_value == 1)
+ vap->iv_quiet_count_value = vap->iv_quiet_count;
+ else if (vap->iv_quiet_count_value > 1)
+ vap->iv_quiet_count_value--;
+ }
if (vap->iv_quiet_count_value == 0) {
/* value 0 is reserved as per 802.11h standerd */
@@ -2113,6 +2184,7 @@ ieee80211_send_probereq(struct ieee80211_node *ni,
* [tlv] RSN (optional)
* [tlv] extended supported rates
* [tlv] HT cap (optional)
+ * [tlv] VHT cap (optional)
* [tlv] WPA (optional)
* [tlv] user-specified ie's
*/
@@ -2121,7 +2193,8 @@ ieee80211_send_probereq(struct ieee80211_node *ni,
2 + IEEE80211_NWID_LEN
+ 2 + IEEE80211_RATE_SIZE
+ sizeof(struct ieee80211_ie_htcap)
- + sizeof(struct ieee80211_ie_htinfo)
+ + sizeof(struct ieee80211_ie_vhtcap)
+ + sizeof(struct ieee80211_ie_htinfo) /* XXX not needed? */
+ sizeof(struct ieee80211_ie_wpa)
+ 2 + (IEEE80211_RATE_MAXSIZE - IEEE80211_RATE_SIZE)
+ sizeof(struct ieee80211_ie_wpa)
@@ -2161,6 +2234,21 @@ ieee80211_send_probereq(struct ieee80211_node *ni,
frm = ieee80211_add_htcap_ch(frm, vap, c);
}
+ /*
+ * XXX TODO: need to figure out what/how to update the
+ * VHT channel.
+ */
+#if 0
+ (vap->iv_flags_vht & IEEE80211_FVHT_VHT) {
+ struct ieee80211_channel *c;
+
+ c = ieee80211_ht_adjust_channel(ic, ic->ic_curchan,
+ vap->iv_flags_ht);
+ c = ieee80211_vht_adjust_channel(ic, c, vap->iv_flags_vht);
+ frm = ieee80211_add_vhtcap_ch(frm, vap, c);
+ }
+#endif
+
frm = ieee80211_add_wpa(frm, vap);
if (vap->iv_appie_probereq != NULL)
frm = add_appie(frm, vap->iv_appie_probereq);
@@ -2370,6 +2458,7 @@ ieee80211_send_mgmt(struct ieee80211_node *ni, int type, int arg)
* [4] power capability (optional)
* [28] supported channels (optional)
* [tlv] HT capabilities
+ * [tlv] VHT capabilities
* [tlv] WME (optional)
* [tlv] Vendor OUI HT capabilities (optional)
* [tlv] Atheros capabilities (if negotiated)
@@ -2387,6 +2476,7 @@ ieee80211_send_mgmt(struct ieee80211_node *ni, int type, int arg)
+ 2 + 26
+ sizeof(struct ieee80211_wme_info)
+ sizeof(struct ieee80211_ie_htcap)
+ + sizeof(struct ieee80211_ie_vhtcap)
+ 4 + sizeof(struct ieee80211_ie_htcap)
#ifdef IEEE80211_SUPPORT_SUPERG
+ sizeof(struct ieee80211_ath_ie)
@@ -2451,6 +2541,14 @@ ieee80211_send_mgmt(struct ieee80211_node *ni, int type, int arg)
ni->ni_ies.htcap_ie[0] == IEEE80211_ELEMID_HTCAP) {
frm = ieee80211_add_htcap(frm, ni);
}
+
+ if ((vap->iv_flags_vht & IEEE80211_FVHT_VHT) &&
+ IEEE80211_IS_CHAN_VHT(ni->ni_chan) &&
+ ni->ni_ies.vhtcap_ie != NULL &&
+ ni->ni_ies.vhtcap_ie[0] == IEEE80211_ELEMID_VHT_CAP) {
+ frm = ieee80211_add_vhtcap(frm, ni);
+ }
+
frm = ieee80211_add_wpa(frm, vap);
if ((ic->ic_flags & IEEE80211_F_WME) &&
ni->ni_ies.wme_ie != NULL)
@@ -2494,6 +2592,8 @@ ieee80211_send_mgmt(struct ieee80211_node *ni, int type, int arg)
* [tlv] extended supported rates
* [tlv] HT capabilities (standard, if STA enabled)
* [tlv] HT information (standard, if STA enabled)
+ * [tlv] VHT capabilities (standard, if STA enabled)
+ * [tlv] VHT information (standard, if STA enabled)
* [tlv] WME (if configured and STA enabled)
* [tlv] HT capabilities (vendor OUI, if STA enabled)
* [tlv] HT information (vendor OUI, if STA enabled)
@@ -2509,6 +2609,8 @@ ieee80211_send_mgmt(struct ieee80211_node *ni, int type, int arg)
+ 2 + (IEEE80211_RATE_MAXSIZE - IEEE80211_RATE_SIZE)
+ sizeof(struct ieee80211_ie_htcap) + 4
+ sizeof(struct ieee80211_ie_htinfo) + 4
+ + sizeof(struct ieee80211_ie_vhtcap)
+ + sizeof(struct ieee80211_ie_vht_operation)
+ sizeof(struct ieee80211_wme_param)
#ifdef IEEE80211_SUPPORT_SUPERG
+ sizeof(struct ieee80211_ath_ie)
@@ -2547,6 +2649,10 @@ ieee80211_send_mgmt(struct ieee80211_node *ni, int type, int arg)
frm = ieee80211_add_htcap_vendor(frm, ni);
frm = ieee80211_add_htinfo_vendor(frm, ni);
}
+ if (ni->ni_flags & IEEE80211_NODE_VHT) {
+ frm = ieee80211_add_vhtcap(frm, ni);
+ frm = ieee80211_add_vhtinfo(frm, ni);
+ }
#ifdef IEEE80211_SUPPORT_SUPERG
if (IEEE80211_ATH_CAP(vap, ni, IEEE80211_F_ATHEROS))
frm = ieee80211_add_ath(frm,
@@ -2629,6 +2735,8 @@ ieee80211_alloc_proberesp(struct ieee80211_node *bss, int legacy)
* [tlv] RSN (optional)
* [tlv] HT capabilities
* [tlv] HT information
+ * [tlv] VHT capabilities
+ * [tlv] VHT information
* [tlv] WPA (optional)
* [tlv] WME (optional)
* [tlv] Vendor OUI HT capabilities (optional)
@@ -2659,6 +2767,8 @@ ieee80211_alloc_proberesp(struct ieee80211_node *bss, int legacy)
+ sizeof(struct ieee80211_wme_param)
+ 4 + sizeof(struct ieee80211_ie_htcap)
+ 4 + sizeof(struct ieee80211_ie_htinfo)
+ + sizeof(struct ieee80211_ie_vhtcap)
+ + sizeof(struct ieee80211_ie_vht_operation)
#ifdef IEEE80211_SUPPORT_SUPERG
+ sizeof(struct ieee80211_ath_ie)
#endif
@@ -2720,7 +2830,7 @@ ieee80211_alloc_proberesp(struct ieee80211_node *bss, int legacy)
if (IEEE80211_IS_CHAN_DFS(ic->ic_bsschan) &&
(vap->iv_flags_ext & IEEE80211_FEXT_DFS)) {
if (vap->iv_quiet)
- frm = ieee80211_add_quiet(frm, vap);
+ frm = ieee80211_add_quiet(frm, vap, 0);
}
}
if (IEEE80211_IS_CHAN_ANYG(bss->ni_chan))
@@ -2738,6 +2848,11 @@ ieee80211_alloc_proberesp(struct ieee80211_node *bss, int legacy)
frm = ieee80211_add_htcap(frm, bss);
frm = ieee80211_add_htinfo(frm, bss);
}
+ if (IEEE80211_IS_CHAN_VHT(bss->ni_chan) &&
+ legacy != IEEE80211_SEND_LEGACY_11B) {
+ frm = ieee80211_add_vhtcap(frm, bss);
+ frm = ieee80211_add_vhtinfo(frm, bss);
+ }
frm = ieee80211_add_wpa(frm, vap);
if (vap->iv_flags & IEEE80211_F_WME)
frm = ieee80211_add_wme_param(frm, &ic->ic_wme);
@@ -2948,6 +3063,10 @@ ieee80211_beacon_construct(struct mbuf *m, uint8_t *frm,
/*
* beacon frame format
+ *
+ * TODO: update to 802.11-2012; a lot of stuff has changed;
+ * vendor extensions should be at the end, etc.
+ *
* [8] time stamp
* [2] beacon interval
* [2] cabability information
@@ -2959,11 +3078,34 @@ ieee80211_beacon_construct(struct mbuf *m, uint8_t *frm,
* [tlv] country (optional)
* [3] power control (optional)
* [5] channel switch announcement (CSA) (optional)
+ * XXX TODO: Quiet
+ * XXX TODO: IBSS DFS
+ * XXX TODO: TPC report
* [tlv] extended rate phy (ERP)
* [tlv] extended supported rates
* [tlv] RSN parameters
+ * XXX TODO: BSSLOAD
+ * (XXX EDCA parameter set, QoS capability?)
+ * XXX TODO: AP channel report
+ *
* [tlv] HT capabilities
* [tlv] HT information
+ * XXX TODO: 20/40 BSS coexistence
+ * Mesh:
+ * XXX TODO: Meshid
+ * XXX TODO: mesh config
+ * XXX TODO: mesh awake window
+ * XXX TODO: beacon timing (mesh, etc)
+ * XXX TODO: MCCAOP Advertisement Overview
+ * XXX TODO: MCCAOP Advertisement
+ * XXX TODO: Mesh channel switch parameters
+ * VHT:
+ * XXX TODO: VHT capabilities
+ * XXX TODO: VHT operation
+ * XXX TODO: VHT transmit power envelope
+ * XXX TODO: channel switch wrapper element
+ * XXX TODO: extended BSS load element
+ *
* XXX Vendor-specific OIDs (e.g. Atheros)
* [tlv] WPA parameters
* [tlv] WME parameters
@@ -3036,15 +3178,23 @@ ieee80211_beacon_construct(struct mbuf *m, uint8_t *frm,
} else
bo->bo_csa = frm;
+ bo->bo_quiet = NULL;
if (vap->iv_flags & IEEE80211_F_DOTH) {
- bo->bo_quiet = frm;
if (IEEE80211_IS_CHAN_DFS(ic->ic_bsschan) &&
- (vap->iv_flags_ext & IEEE80211_FEXT_DFS)) {
- if (vap->iv_quiet)
- frm = ieee80211_add_quiet(frm,vap);
+ (vap->iv_flags_ext & IEEE80211_FEXT_DFS) &&
+ (vap->iv_quiet == 1)) {
+ /*
+ * We only insert the quiet IE offset if
+ * the quiet IE is enabled. Otherwise don't
+ * put it here or we'll just overwrite
+ * some other beacon contents.
+ */
+ if (vap->iv_quiet) {
+ bo->bo_quiet = frm;
+ frm = ieee80211_add_quiet(frm,vap, 0);
+ }
}
- } else
- bo->bo_quiet = frm;
+ }
if (IEEE80211_IS_CHAN_ANYG(ni->ni_chan)) {
bo->bo_erp = frm;
@@ -3057,6 +3207,16 @@ ieee80211_beacon_construct(struct mbuf *m, uint8_t *frm,
bo->bo_htinfo = frm;
frm = ieee80211_add_htinfo(frm, ni);
}
+
+ if (IEEE80211_IS_CHAN_VHT(ni->ni_chan)) {
+ frm = ieee80211_add_vhtcap(frm, ni);
+ bo->bo_vhtinfo = frm;
+ frm = ieee80211_add_vhtinfo(frm, ni);
+ /* Transmit power envelope */
+ /* Channel switch wrapper element */
+ /* Extended bss load element */
+ }
+
frm = ieee80211_add_wpa(frm, vap);
if (vap->iv_flags & IEEE80211_F_WME) {
bo->bo_wme = frm;
@@ -3067,6 +3227,7 @@ ieee80211_beacon_construct(struct mbuf *m, uint8_t *frm,
frm = ieee80211_add_htcap_vendor(frm, ni);
frm = ieee80211_add_htinfo_vendor(frm, ni);
}
+
#ifdef IEEE80211_SUPPORT_SUPERG
if (vap->iv_flags & IEEE80211_F_ATHEROS) {
bo->bo_ath = frm;
@@ -3084,6 +3245,8 @@ ieee80211_beacon_construct(struct mbuf *m, uint8_t *frm,
bo->bo_appie_len = vap->iv_appie_beacon->ie_len;
frm = add_appie(frm, vap->iv_appie_beacon);
}
+
+ /* XXX TODO: move meshid/meshconf up to before vendor extensions? */
#ifdef IEEE80211_SUPPORT_MESH
if (vap->iv_opmode == IEEE80211_M_MBSS) {
frm = ieee80211_add_meshid(frm, vap);
@@ -3111,7 +3274,18 @@ ieee80211_beacon_alloc(struct ieee80211_node *ni)
uint8_t *frm;
/*
+ * Update the "We're putting the quiet IE in the beacon" state.
+ */
+ if (vap->iv_quiet == 1)
+ vap->iv_flags_ext |= IEEE80211_FEXT_QUIET_IE;
+ else if (vap->iv_quiet == 0)
+ vap->iv_flags_ext &= ~IEEE80211_FEXT_QUIET_IE;
+
+ /*
* beacon frame format
+ *
+ * Note: This needs updating for 802.11-2012.
+ *
* [8] time stamp
* [2] beacon interval
* [2] cabability information
@@ -3128,6 +3302,8 @@ ieee80211_beacon_alloc(struct ieee80211_node *ni)
* [tlv] RSN parameters
* [tlv] HT capabilities
* [tlv] HT information
+ * [tlv] VHT capabilities
+ * [tlv] VHT operation
* [tlv] Vendor OUI HT capabilities (optional)
* [tlv] Vendor OUI HT information (optional)
* XXX Vendor-specific OIDs (e.g. Atheros)
@@ -3159,6 +3335,8 @@ ieee80211_beacon_alloc(struct ieee80211_node *ni)
/* XXX conditional? */
+ 4+2*sizeof(struct ieee80211_ie_htcap)/* HT caps */
+ 4+2*sizeof(struct ieee80211_ie_htinfo)/* HT info */
+ + sizeof(struct ieee80211_ie_vhtcap)/* VHT caps */
+ + sizeof(struct ieee80211_ie_vht_operation)/* VHT info */
+ (vap->iv_caps & IEEE80211_C_WME ? /* WME */
sizeof(struct ieee80211_wme_param) : 0)
#ifdef IEEE80211_SUPPORT_SUPERG
@@ -3243,7 +3421,52 @@ ieee80211_beacon_update(struct ieee80211_node *ni, struct mbuf *m, int mcast)
return 1; /* just assume length changed */
}
+ /*
+ * Handle the quiet time element being added and removed.
+ * Again, for now we just cheat and reconstruct the whole
+ * beacon - that way the gap is provided as appropriate.
+ *
+ * So, track whether we have already added the IE versus
+ * whether we want to be adding the IE.
+ */
+ if ((vap->iv_flags_ext & IEEE80211_FEXT_QUIET_IE) &&
+ (vap->iv_quiet == 0)) {
+ /*
+ * Quiet time beacon IE enabled, but it's disabled;
+ * recalc
+ */
+ vap->iv_flags_ext &= ~IEEE80211_FEXT_QUIET_IE;
+ ieee80211_beacon_construct(m,
+ mtod(m, uint8_t*) + sizeof(struct ieee80211_frame), ni);
+ /* XXX do WME aggressive mode processing? */
+ IEEE80211_UNLOCK(ic);
+ return 1; /* just assume length changed */
+ }
+
+ if (((vap->iv_flags_ext & IEEE80211_FEXT_QUIET_IE) == 0) &&
+ (vap->iv_quiet == 1)) {
+ /*
+ * Quiet time beacon IE disabled, but it's now enabled;
+ * recalc
+ */
+ vap->iv_flags_ext |= IEEE80211_FEXT_QUIET_IE;
+ ieee80211_beacon_construct(m,
+ mtod(m, uint8_t*) + sizeof(struct ieee80211_frame), ni);
+ /* XXX do WME aggressive mode processing? */
+ IEEE80211_UNLOCK(ic);
+ return 1; /* just assume length changed */
+ }
+
wh = mtod(m, struct ieee80211_frame *);
+
+ /*
+ * XXX TODO Strictly speaking this should be incremented with the TX
+ * lock held so as to serialise access to the non-qos TID sequence
+ * number space.
+ *
+ * If the driver identifies it does its own TX seqno management then
+ * we can skip this (and still not do the TX seqno.)
+ */
seqno = ni->ni_txseqs[IEEE80211_NONQOS_TID]++;
*(uint16_t *)&wh->i_seq[0] =
htole16(seqno << IEEE80211_SEQ_SEQ_SHIFT);
@@ -3349,6 +3572,10 @@ ieee80211_beacon_update(struct ieee80211_node *ni, struct mbuf *m, int mcast)
timoff = 0;
timlen = 1;
}
+
+ /*
+ * TODO: validate this!
+ */
if (timlen != bo->bo_tim_len) {
/* copy up/down trailer */
int adjust = tie->tim_bitmap+timlen
@@ -3359,6 +3586,7 @@ ieee80211_beacon_update(struct ieee80211_node *ni, struct mbuf *m, int mcast)
bo->bo_tim_trailer += adjust;
bo->bo_erp += adjust;
bo->bo_htinfo += adjust;
+ bo->bo_vhtinfo += adjust;
#ifdef IEEE80211_SUPPORT_SUPERG
bo->bo_ath += adjust;
#endif
@@ -3413,6 +3641,7 @@ ieee80211_beacon_update(struct ieee80211_node *ni, struct mbuf *m, int mcast)
memmove(&csa[1], csa, bo->bo_csa_trailer_len);
bo->bo_erp += sizeof(*csa);
bo->bo_htinfo += sizeof(*csa);
+ bo->bo_vhtinfo += sizeof(*csa);
bo->bo_wme += sizeof(*csa);
#ifdef IEEE80211_SUPPORT_SUPERG
bo->bo_ath += sizeof(*csa);
@@ -3436,10 +3665,17 @@ ieee80211_beacon_update(struct ieee80211_node *ni, struct mbuf *m, int mcast)
vap->iv_csa_count++;
/* NB: don't clear IEEE80211_BEACON_CSA */
}
+
+ /*
+ * Only add the quiet time IE if we've enabled it
+ * as appropriate.
+ */
if (IEEE80211_IS_CHAN_DFS(ic->ic_bsschan) &&
- (vap->iv_flags_ext & IEEE80211_FEXT_DFS) ){
- if (vap->iv_quiet)
- ieee80211_add_quiet(bo->bo_quiet, vap);
+ (vap->iv_flags_ext & IEEE80211_FEXT_DFS)) {
+ if (vap->iv_quiet &&
+ (vap->iv_flags_ext & IEEE80211_FEXT_QUIET_IE)) {
+ ieee80211_add_quiet(bo->bo_quiet, vap, 1);
+ }
}
if (isset(bo->bo_flags, IEEE80211_BEACON_ERP)) {
/*