xref: /freebsd/sys/net80211/ieee80211_output.c (revision fb3bc59600e25268ed5750fdc351b1e9423a8fb4)
11a1e1d21SSam Leffler /*-
2fe267a55SPedro F. Giffuni  * SPDX-License-Identifier: BSD-2-Clause-FreeBSD
3fe267a55SPedro F. Giffuni  *
47535e66aSSam Leffler  * Copyright (c) 2001 Atsushi Onoe
510ad9a77SSam Leffler  * Copyright (c) 2002-2009 Sam Leffler, Errno Consulting
61a1e1d21SSam Leffler  * All rights reserved.
71a1e1d21SSam Leffler  *
81a1e1d21SSam Leffler  * Redistribution and use in source and binary forms, with or without
91a1e1d21SSam Leffler  * modification, are permitted provided that the following conditions
101a1e1d21SSam Leffler  * are met:
111a1e1d21SSam Leffler  * 1. Redistributions of source code must retain the above copyright
127535e66aSSam Leffler  *    notice, this list of conditions and the following disclaimer.
137535e66aSSam Leffler  * 2. Redistributions in binary form must reproduce the above copyright
147535e66aSSam Leffler  *    notice, this list of conditions and the following disclaimer in the
157535e66aSSam Leffler  *    documentation and/or other materials provided with the distribution.
161a1e1d21SSam Leffler  *
177535e66aSSam Leffler  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
187535e66aSSam Leffler  * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
197535e66aSSam Leffler  * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
207535e66aSSam Leffler  * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
217535e66aSSam Leffler  * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
227535e66aSSam Leffler  * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
237535e66aSSam Leffler  * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
247535e66aSSam Leffler  * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
257535e66aSSam Leffler  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
267535e66aSSam Leffler  * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
271a1e1d21SSam Leffler  */
281a1e1d21SSam Leffler 
291a1e1d21SSam Leffler #include <sys/cdefs.h>
301a1e1d21SSam Leffler __FBSDID("$FreeBSD$");
311a1e1d21SSam Leffler 
321a1e1d21SSam Leffler #include "opt_inet.h"
33e755a73dSSam Leffler #include "opt_inet6.h"
34b032f27cSSam Leffler #include "opt_wlan.h"
351a1e1d21SSam Leffler 
361a1e1d21SSam Leffler #include <sys/param.h>
371a1e1d21SSam Leffler #include <sys/systm.h>
381a1e1d21SSam Leffler #include <sys/kernel.h>
398ec07310SGleb Smirnoff #include <sys/malloc.h>
408ec07310SGleb Smirnoff #include <sys/mbuf.h>
411a1e1d21SSam Leffler #include <sys/endian.h>
421a1e1d21SSam Leffler 
438a1b9b6aSSam Leffler #include <sys/socket.h>
441a1e1d21SSam Leffler 
451a1e1d21SSam Leffler #include <net/bpf.h>
468a1b9b6aSSam Leffler #include <net/ethernet.h>
478a1b9b6aSSam Leffler #include <net/if.h>
4876039bc8SGleb Smirnoff #include <net/if_var.h>
498a1b9b6aSSam Leffler #include <net/if_llc.h>
508a1b9b6aSSam Leffler #include <net/if_media.h>
518a1b9b6aSSam Leffler #include <net/if_vlan_var.h>
528a1b9b6aSSam Leffler 
538a1b9b6aSSam Leffler #include <net80211/ieee80211_var.h>
5468e8e04eSSam Leffler #include <net80211/ieee80211_regdomain.h>
55616190d0SSam Leffler #ifdef IEEE80211_SUPPORT_SUPERG
56616190d0SSam Leffler #include <net80211/ieee80211_superg.h>
57616190d0SSam Leffler #endif
5810ad9a77SSam Leffler #ifdef IEEE80211_SUPPORT_TDMA
5910ad9a77SSam Leffler #include <net80211/ieee80211_tdma.h>
6010ad9a77SSam Leffler #endif
61b032f27cSSam Leffler #include <net80211/ieee80211_wds.h>
6259aa14a9SRui Paulo #include <net80211/ieee80211_mesh.h>
6351172f62SAdrian Chadd #include <net80211/ieee80211_vht.h>
641a1e1d21SSam Leffler 
658355d59dSBjoern A. Zeeb #if defined(INET) || defined(INET6)
661a1e1d21SSam Leffler #include <netinet/in.h>
678355d59dSBjoern A. Zeeb #endif
688355d59dSBjoern A. Zeeb 
698355d59dSBjoern A. Zeeb #ifdef INET
701a1e1d21SSam Leffler #include <netinet/if_ether.h>
718a1b9b6aSSam Leffler #include <netinet/in_systm.h>
728a1b9b6aSSam Leffler #include <netinet/ip.h>
738a1b9b6aSSam Leffler #endif
74e755a73dSSam Leffler #ifdef INET6
75e755a73dSSam Leffler #include <netinet/ip6.h>
76e755a73dSSam Leffler #endif
778a1b9b6aSSam Leffler 
78c27b9cdbSRobert Watson #include <security/mac/mac_framework.h>
79c27b9cdbSRobert Watson 
8068e8e04eSSam Leffler #define	ETHER_HEADER_COPY(dst, src) \
8168e8e04eSSam Leffler 	memcpy(dst, src, sizeof(struct ether_header))
8268e8e04eSSam Leffler 
83b032f27cSSam Leffler static int ieee80211_fragment(struct ieee80211vap *, struct mbuf *,
8468e8e04eSSam Leffler 	u_int hdrsize, u_int ciphdrsize, u_int mtu);
8568e8e04eSSam Leffler static	void ieee80211_tx_mgt_cb(struct ieee80211_node *, void *, int);
8668e8e04eSSam Leffler 
878a1b9b6aSSam Leffler #ifdef IEEE80211_DEBUG
888a1b9b6aSSam Leffler /*
898a1b9b6aSSam Leffler  * Decide if an outbound management frame should be
908a1b9b6aSSam Leffler  * printed when debugging is enabled.  This filters some
918a1b9b6aSSam Leffler  * of the less interesting frames that come frequently
928a1b9b6aSSam Leffler  * (e.g. beacons).
938a1b9b6aSSam Leffler  */
948a1b9b6aSSam Leffler static __inline int
95b032f27cSSam Leffler doprint(struct ieee80211vap *vap, int subtype)
968a1b9b6aSSam Leffler {
978a1b9b6aSSam Leffler 	switch (subtype) {
988a1b9b6aSSam Leffler 	case IEEE80211_FC0_SUBTYPE_PROBE_RESP:
99b032f27cSSam Leffler 		return (vap->iv_opmode == IEEE80211_M_IBSS);
1008a1b9b6aSSam Leffler 	}
1018a1b9b6aSSam Leffler 	return 1;
1028a1b9b6aSSam Leffler }
1031a1e1d21SSam Leffler #endif
1041a1e1d21SSam Leffler 
1050a915fadSSam Leffler /*
106363a2c3cSAdrian Chadd  * Transmit a frame to the given destination on the given VAP.
107363a2c3cSAdrian Chadd  *
108363a2c3cSAdrian Chadd  * It's up to the caller to figure out the details of who this
109363a2c3cSAdrian Chadd  * is going to and resolving the node.
110363a2c3cSAdrian Chadd  *
111363a2c3cSAdrian Chadd  * This routine takes care of queuing it for power save,
112363a2c3cSAdrian Chadd  * A-MPDU state stuff, fast-frames state stuff, encapsulation
113363a2c3cSAdrian Chadd  * if required, then passing it up to the driver layer.
114363a2c3cSAdrian Chadd  *
115363a2c3cSAdrian Chadd  * This routine (for now) consumes the mbuf and frees the node
116363a2c3cSAdrian Chadd  * reference; it ideally will return a TX status which reflects
117363a2c3cSAdrian Chadd  * whether the mbuf was consumed or not, so the caller can
118363a2c3cSAdrian Chadd  * free the mbuf (if appropriate) and the node reference (again,
119363a2c3cSAdrian Chadd  * if appropriate.)
120363a2c3cSAdrian Chadd  */
121363a2c3cSAdrian Chadd int
122363a2c3cSAdrian Chadd ieee80211_vap_pkt_send_dest(struct ieee80211vap *vap, struct mbuf *m,
123363a2c3cSAdrian Chadd     struct ieee80211_node *ni)
124363a2c3cSAdrian Chadd {
125363a2c3cSAdrian Chadd 	struct ieee80211com *ic = vap->iv_ic;
126363a2c3cSAdrian Chadd 	struct ifnet *ifp = vap->iv_ifp;
1272e9090dfSBjoern A. Zeeb 	int mcast;
128363a2c3cSAdrian Chadd 
129363a2c3cSAdrian Chadd 	if ((ni->ni_flags & IEEE80211_NODE_PWR_MGT) &&
130363a2c3cSAdrian Chadd 	    (m->m_flags & M_PWR_SAV) == 0) {
131363a2c3cSAdrian Chadd 		/*
132363a2c3cSAdrian Chadd 		 * Station in power save mode; pass the frame
133363a2c3cSAdrian Chadd 		 * to the 802.11 layer and continue.  We'll get
134363a2c3cSAdrian Chadd 		 * the frame back when the time is right.
135363a2c3cSAdrian Chadd 		 * XXX lose WDS vap linkage?
136363a2c3cSAdrian Chadd 		 */
13779077edcSAndrey V. Elsukov 		if (ieee80211_pwrsave(ni, m) != 0)
13879077edcSAndrey V. Elsukov 			if_inc_counter(ifp, IFCOUNTER_OERRORS, 1);
139363a2c3cSAdrian Chadd 		ieee80211_free_node(ni);
140c6d5b600SAdrian Chadd 
141c6d5b600SAdrian Chadd 		/*
142c6d5b600SAdrian Chadd 		 * We queued it fine, so tell the upper layer
143c6d5b600SAdrian Chadd 		 * that we consumed it.
144c6d5b600SAdrian Chadd 		 */
145c6d5b600SAdrian Chadd 		return (0);
146363a2c3cSAdrian Chadd 	}
147363a2c3cSAdrian Chadd 	/* calculate priority so drivers can find the tx queue */
148363a2c3cSAdrian Chadd 	if (ieee80211_classify(ni, m)) {
149363a2c3cSAdrian Chadd 		IEEE80211_DISCARD_MAC(vap, IEEE80211_MSG_OUTPUT,
150363a2c3cSAdrian Chadd 		    ni->ni_macaddr, NULL,
151363a2c3cSAdrian Chadd 		    "%s", "classification failure");
152363a2c3cSAdrian Chadd 		vap->iv_stats.is_tx_classify++;
153dea45121SGleb Smirnoff 		if_inc_counter(ifp, IFCOUNTER_OERRORS, 1);
154363a2c3cSAdrian Chadd 		m_freem(m);
155363a2c3cSAdrian Chadd 		ieee80211_free_node(ni);
156c6d5b600SAdrian Chadd 
157363a2c3cSAdrian Chadd 		/* XXX better status? */
158c6d5b600SAdrian Chadd 		return (0);
159363a2c3cSAdrian Chadd 	}
160363a2c3cSAdrian Chadd 	/*
161363a2c3cSAdrian Chadd 	 * Stash the node pointer.  Note that we do this after
162363a2c3cSAdrian Chadd 	 * any call to ieee80211_dwds_mcast because that code
163363a2c3cSAdrian Chadd 	 * uses any existing value for rcvif to identify the
164363a2c3cSAdrian Chadd 	 * interface it (might have been) received on.
165363a2c3cSAdrian Chadd 	 */
166*fb3bc596SJohn Baldwin 	MPASS((m->m_pkthdr.csum_flags & CSUM_SND_TAG) == 0);
167363a2c3cSAdrian Chadd 	m->m_pkthdr.rcvif = (void *)ni;
1682e9090dfSBjoern A. Zeeb 	mcast = (m->m_flags & (M_MCAST | M_BCAST)) ? 1: 0;
169363a2c3cSAdrian Chadd 
170363a2c3cSAdrian Chadd 	BPF_MTAP(ifp, m);		/* 802.3 tx */
171363a2c3cSAdrian Chadd 
172363a2c3cSAdrian Chadd 	/*
173363a2c3cSAdrian Chadd 	 * Check if A-MPDU tx aggregation is setup or if we
174363a2c3cSAdrian Chadd 	 * should try to enable it.  The sta must be associated
175363a2c3cSAdrian Chadd 	 * with HT and A-MPDU enabled for use.  When the policy
176363a2c3cSAdrian Chadd 	 * routine decides we should enable A-MPDU we issue an
177363a2c3cSAdrian Chadd 	 * ADDBA request and wait for a reply.  The frame being
178363a2c3cSAdrian Chadd 	 * encapsulated will go out w/o using A-MPDU, or possibly
179363a2c3cSAdrian Chadd 	 * it might be collected by the driver and held/retransmit.
180363a2c3cSAdrian Chadd 	 * The default ic_ampdu_enable routine handles staggering
181363a2c3cSAdrian Chadd 	 * ADDBA requests in case the receiver NAK's us or we are
182363a2c3cSAdrian Chadd 	 * otherwise unable to establish a BA stream.
1839764ef21SAdrian Chadd 	 *
1849764ef21SAdrian Chadd 	 * Don't treat group-addressed frames as candidates for aggregation;
1859764ef21SAdrian Chadd 	 * net80211 doesn't support 802.11aa-2012 and so group addressed
1869764ef21SAdrian Chadd 	 * frames will always have sequence numbers allocated from the NON_QOS
1879764ef21SAdrian Chadd 	 * TID.
188363a2c3cSAdrian Chadd 	 */
189363a2c3cSAdrian Chadd 	if ((ni->ni_flags & IEEE80211_NODE_AMPDU_TX) &&
1901c7b0c84SAdrian Chadd 	    (vap->iv_flags_ht & IEEE80211_FHT_AMPDU_TX)) {
1919764ef21SAdrian Chadd 		if ((m->m_flags & M_EAPOL) == 0 && (! mcast)) {
192363a2c3cSAdrian Chadd 			int tid = WME_AC_TO_TID(M_WME_GETAC(m));
193363a2c3cSAdrian Chadd 			struct ieee80211_tx_ampdu *tap = &ni->ni_tx_ampdu[tid];
194363a2c3cSAdrian Chadd 
195363a2c3cSAdrian Chadd 			ieee80211_txampdu_count_packet(tap);
196363a2c3cSAdrian Chadd 			if (IEEE80211_AMPDU_RUNNING(tap)) {
197363a2c3cSAdrian Chadd 				/*
198363a2c3cSAdrian Chadd 				 * Operational, mark frame for aggregation.
199363a2c3cSAdrian Chadd 				 *
200363a2c3cSAdrian Chadd 				 * XXX do tx aggregation here
201363a2c3cSAdrian Chadd 				 */
202363a2c3cSAdrian Chadd 				m->m_flags |= M_AMPDU_MPDU;
203363a2c3cSAdrian Chadd 			} else if (!IEEE80211_AMPDU_REQUESTED(tap) &&
204363a2c3cSAdrian Chadd 			    ic->ic_ampdu_enable(ni, tap)) {
205363a2c3cSAdrian Chadd 				/*
206363a2c3cSAdrian Chadd 				 * Not negotiated yet, request service.
207363a2c3cSAdrian Chadd 				 */
208363a2c3cSAdrian Chadd 				ieee80211_ampdu_request(ni, tap);
209363a2c3cSAdrian Chadd 				/* XXX hold frame for reply? */
210363a2c3cSAdrian Chadd 			}
211363a2c3cSAdrian Chadd 		}
2121c7b0c84SAdrian Chadd 	}
213363a2c3cSAdrian Chadd 
214363a2c3cSAdrian Chadd #ifdef IEEE80211_SUPPORT_SUPERG
2151c7b0c84SAdrian Chadd 	/*
2161c7b0c84SAdrian Chadd 	 * Check for AMSDU/FF; queue for aggregation
2171c7b0c84SAdrian Chadd 	 *
2181c7b0c84SAdrian Chadd 	 * Note: we don't bother trying to do fast frames or
2191c7b0c84SAdrian Chadd 	 * A-MSDU encapsulation for 802.3 drivers.  Now, we
2201c7b0c84SAdrian Chadd 	 * likely could do it for FF (because it's a magic
2211c7b0c84SAdrian Chadd 	 * atheros tunnel LLC type) but I don't think we're going
2221c7b0c84SAdrian Chadd 	 * to really need to.  For A-MSDU we'd have to set the
2231c7b0c84SAdrian Chadd 	 * A-MSDU QoS bit in the wifi header, so we just plain
2241c7b0c84SAdrian Chadd 	 * can't do it.
2251c7b0c84SAdrian Chadd 	 *
2261c7b0c84SAdrian Chadd 	 * Strictly speaking, we could actually /do/ A-MSDU / FF
2271c7b0c84SAdrian Chadd 	 * with A-MPDU together which for certain circumstances
2281c7b0c84SAdrian Chadd 	 * is beneficial (eg A-MSDU of TCK ACKs.)  However,
2291c7b0c84SAdrian Chadd 	 * I'll ignore that for now so existing behaviour is maintained.
2301c7b0c84SAdrian Chadd 	 * Later on it would be good to make "amsdu + ampdu" configurable.
2311c7b0c84SAdrian Chadd 	 */
2321c7b0c84SAdrian Chadd 	else if (__predict_true((vap->iv_caps & IEEE80211_C_8023ENCAP) == 0)) {
2331c7b0c84SAdrian Chadd 		if ((! mcast) && ieee80211_amsdu_tx_ok(ni)) {
2341c7b0c84SAdrian Chadd 			m = ieee80211_amsdu_check(ni, m);
2351c7b0c84SAdrian Chadd 			if (m == NULL) {
2361c7b0c84SAdrian Chadd 				/* NB: any ni ref held on stageq */
2371c7b0c84SAdrian Chadd 				IEEE80211_DPRINTF(vap, IEEE80211_MSG_SUPERG,
2381c7b0c84SAdrian Chadd 				    "%s: amsdu_check queued frame\n",
2391c7b0c84SAdrian Chadd 				    __func__);
2401c7b0c84SAdrian Chadd 				return (0);
2411c7b0c84SAdrian Chadd 			}
2421c7b0c84SAdrian Chadd 		} else if ((! mcast) && IEEE80211_ATH_CAP(vap, ni,
2431c7b0c84SAdrian Chadd 		    IEEE80211_NODE_FF)) {
244363a2c3cSAdrian Chadd 			m = ieee80211_ff_check(ni, m);
245363a2c3cSAdrian Chadd 			if (m == NULL) {
246363a2c3cSAdrian Chadd 				/* NB: any ni ref held on stageq */
2471c7b0c84SAdrian Chadd 				IEEE80211_DPRINTF(vap, IEEE80211_MSG_SUPERG,
2481c7b0c84SAdrian Chadd 				    "%s: ff_check queued frame\n",
2491c7b0c84SAdrian Chadd 				    __func__);
25011e0ddb1SAdrian Chadd 				return (0);
251363a2c3cSAdrian Chadd 			}
252363a2c3cSAdrian Chadd 		}
2531c7b0c84SAdrian Chadd 	}
254363a2c3cSAdrian Chadd #endif /* IEEE80211_SUPPORT_SUPERG */
255363a2c3cSAdrian Chadd 
256363a2c3cSAdrian Chadd 	/*
257363a2c3cSAdrian Chadd 	 * Grab the TX lock - serialise the TX process from this
258363a2c3cSAdrian Chadd 	 * point (where TX state is being checked/modified)
259363a2c3cSAdrian Chadd 	 * through to driver queue.
260363a2c3cSAdrian Chadd 	 */
261363a2c3cSAdrian Chadd 	IEEE80211_TX_LOCK(ic);
262363a2c3cSAdrian Chadd 
263f9128a1bSAdrian Chadd 	/*
264f9128a1bSAdrian Chadd 	 * XXX make the encap and transmit code a separate function
265f9128a1bSAdrian Chadd 	 * so things like the FF (and later A-MSDU) path can just call
266f9128a1bSAdrian Chadd 	 * it for flushed frames.
267f9128a1bSAdrian Chadd 	 */
268363a2c3cSAdrian Chadd 	if (__predict_true((vap->iv_caps & IEEE80211_C_8023ENCAP) == 0)) {
269363a2c3cSAdrian Chadd 		/*
270363a2c3cSAdrian Chadd 		 * Encapsulate the packet in prep for transmission.
271363a2c3cSAdrian Chadd 		 */
272363a2c3cSAdrian Chadd 		m = ieee80211_encap(vap, ni, m);
273363a2c3cSAdrian Chadd 		if (m == NULL) {
274363a2c3cSAdrian Chadd 			/* NB: stat+msg handled in ieee80211_encap */
275363a2c3cSAdrian Chadd 			IEEE80211_TX_UNLOCK(ic);
276363a2c3cSAdrian Chadd 			ieee80211_free_node(ni);
27779077edcSAndrey V. Elsukov 			if_inc_counter(ifp, IFCOUNTER_OERRORS, 1);
278363a2c3cSAdrian Chadd 			return (ENOBUFS);
279363a2c3cSAdrian Chadd 		}
280363a2c3cSAdrian Chadd 	}
281d3a4ade3SAdrian Chadd 	(void) ieee80211_parent_xmitpkt(ic, m);
282363a2c3cSAdrian Chadd 
283363a2c3cSAdrian Chadd 	/*
284363a2c3cSAdrian Chadd 	 * Unlock at this point - no need to hold it across
285363a2c3cSAdrian Chadd 	 * ieee80211_free_node() (ie, the comlock)
286363a2c3cSAdrian Chadd 	 */
287363a2c3cSAdrian Chadd 	IEEE80211_TX_UNLOCK(ic);
288363a2c3cSAdrian Chadd 	ic->ic_lastdata = ticks;
289363a2c3cSAdrian Chadd 
290363a2c3cSAdrian Chadd 	return (0);
291363a2c3cSAdrian Chadd }
292363a2c3cSAdrian Chadd 
293363a2c3cSAdrian Chadd 
294363a2c3cSAdrian Chadd 
295363a2c3cSAdrian Chadd /*
2965cda6006SAdrian Chadd  * Send the given mbuf through the given vap.
2975cda6006SAdrian Chadd  *
2985cda6006SAdrian Chadd  * This consumes the mbuf regardless of whether the transmit
2995cda6006SAdrian Chadd  * was successful or not.
3005cda6006SAdrian Chadd  *
3015cda6006SAdrian Chadd  * This does none of the initial checks that ieee80211_start()
3025cda6006SAdrian Chadd  * does (eg CAC timeout, interface wakeup) - the caller must
3035cda6006SAdrian Chadd  * do this first.
3045cda6006SAdrian Chadd  */
3055cda6006SAdrian Chadd static int
3065cda6006SAdrian Chadd ieee80211_start_pkt(struct ieee80211vap *vap, struct mbuf *m)
3075cda6006SAdrian Chadd {
3085cda6006SAdrian Chadd #define	IS_DWDS(vap) \
3095cda6006SAdrian Chadd 	(vap->iv_opmode == IEEE80211_M_WDS && \
3105cda6006SAdrian Chadd 	 (vap->iv_flags_ext & IEEE80211_FEXT_WDSLEGACY) == 0)
3115cda6006SAdrian Chadd 	struct ieee80211com *ic = vap->iv_ic;
3125cda6006SAdrian Chadd 	struct ifnet *ifp = vap->iv_ifp;
3135cda6006SAdrian Chadd 	struct ieee80211_node *ni;
3145cda6006SAdrian Chadd 	struct ether_header *eh;
3155cda6006SAdrian Chadd 
3165cda6006SAdrian Chadd 	/*
3175cda6006SAdrian Chadd 	 * Cancel any background scan.
3185cda6006SAdrian Chadd 	 */
3195cda6006SAdrian Chadd 	if (ic->ic_flags & IEEE80211_F_SCAN)
3205cda6006SAdrian Chadd 		ieee80211_cancel_anyscan(vap);
3215cda6006SAdrian Chadd 	/*
3225cda6006SAdrian Chadd 	 * Find the node for the destination so we can do
3235cda6006SAdrian Chadd 	 * things like power save and fast frames aggregation.
3245cda6006SAdrian Chadd 	 *
3255cda6006SAdrian Chadd 	 * NB: past this point various code assumes the first
3265cda6006SAdrian Chadd 	 *     mbuf has the 802.3 header present (and contiguous).
3275cda6006SAdrian Chadd 	 */
3285cda6006SAdrian Chadd 	ni = NULL;
3295cda6006SAdrian Chadd 	if (m->m_len < sizeof(struct ether_header) &&
3305cda6006SAdrian Chadd 	   (m = m_pullup(m, sizeof(struct ether_header))) == NULL) {
3315cda6006SAdrian Chadd 		IEEE80211_DPRINTF(vap, IEEE80211_MSG_OUTPUT,
3325cda6006SAdrian Chadd 		    "discard frame, %s\n", "m_pullup failed");
3335cda6006SAdrian Chadd 		vap->iv_stats.is_tx_nobuf++;	/* XXX */
334dea45121SGleb Smirnoff 		if_inc_counter(ifp, IFCOUNTER_OERRORS, 1);
3355cda6006SAdrian Chadd 		return (ENOBUFS);
3365cda6006SAdrian Chadd 	}
3375cda6006SAdrian Chadd 	eh = mtod(m, struct ether_header *);
3385cda6006SAdrian Chadd 	if (ETHER_IS_MULTICAST(eh->ether_dhost)) {
3395cda6006SAdrian Chadd 		if (IS_DWDS(vap)) {
3405cda6006SAdrian Chadd 			/*
3415cda6006SAdrian Chadd 			 * Only unicast frames from the above go out
3425cda6006SAdrian Chadd 			 * DWDS vaps; multicast frames are handled by
3435cda6006SAdrian Chadd 			 * dispatching the frame as it comes through
3445cda6006SAdrian Chadd 			 * the AP vap (see below).
3455cda6006SAdrian Chadd 			 */
3465cda6006SAdrian Chadd 			IEEE80211_DISCARD_MAC(vap, IEEE80211_MSG_WDS,
3475cda6006SAdrian Chadd 			    eh->ether_dhost, "mcast", "%s", "on DWDS");
3485cda6006SAdrian Chadd 			vap->iv_stats.is_dwds_mcast++;
3495cda6006SAdrian Chadd 			m_freem(m);
35079077edcSAndrey V. Elsukov 			if_inc_counter(ifp, IFCOUNTER_OERRORS, 1);
3515cda6006SAdrian Chadd 			/* XXX better status? */
3525cda6006SAdrian Chadd 			return (ENOBUFS);
3535cda6006SAdrian Chadd 		}
3545cda6006SAdrian Chadd 		if (vap->iv_opmode == IEEE80211_M_HOSTAP) {
3555cda6006SAdrian Chadd 			/*
3565cda6006SAdrian Chadd 			 * Spam DWDS vap's w/ multicast traffic.
3575cda6006SAdrian Chadd 			 */
3585cda6006SAdrian Chadd 			/* XXX only if dwds in use? */
3595cda6006SAdrian Chadd 			ieee80211_dwds_mcast(vap, m);
3605cda6006SAdrian Chadd 		}
3615cda6006SAdrian Chadd 	}
3625cda6006SAdrian Chadd #ifdef IEEE80211_SUPPORT_MESH
3635cda6006SAdrian Chadd 	if (vap->iv_opmode != IEEE80211_M_MBSS) {
3645cda6006SAdrian Chadd #endif
3655cda6006SAdrian Chadd 		ni = ieee80211_find_txnode(vap, eh->ether_dhost);
3665cda6006SAdrian Chadd 		if (ni == NULL) {
3675cda6006SAdrian Chadd 			/* NB: ieee80211_find_txnode does stat+msg */
368dea45121SGleb Smirnoff 			if_inc_counter(ifp, IFCOUNTER_OERRORS, 1);
3695cda6006SAdrian Chadd 			m_freem(m);
3705cda6006SAdrian Chadd 			/* XXX better status? */
3715cda6006SAdrian Chadd 			return (ENOBUFS);
3725cda6006SAdrian Chadd 		}
3735cda6006SAdrian Chadd 		if (ni->ni_associd == 0 &&
3745cda6006SAdrian Chadd 		    (ni->ni_flags & IEEE80211_NODE_ASSOCID)) {
3755cda6006SAdrian Chadd 			IEEE80211_DISCARD_MAC(vap, IEEE80211_MSG_OUTPUT,
3765cda6006SAdrian Chadd 			    eh->ether_dhost, NULL,
3775cda6006SAdrian Chadd 			    "sta not associated (type 0x%04x)",
3785cda6006SAdrian Chadd 			    htons(eh->ether_type));
3795cda6006SAdrian Chadd 			vap->iv_stats.is_tx_notassoc++;
380dea45121SGleb Smirnoff 			if_inc_counter(ifp, IFCOUNTER_OERRORS, 1);
3815cda6006SAdrian Chadd 			m_freem(m);
3825cda6006SAdrian Chadd 			ieee80211_free_node(ni);
3835cda6006SAdrian Chadd 			/* XXX better status? */
3845cda6006SAdrian Chadd 			return (ENOBUFS);
3855cda6006SAdrian Chadd 		}
3865cda6006SAdrian Chadd #ifdef IEEE80211_SUPPORT_MESH
3875cda6006SAdrian Chadd 	} else {
3885cda6006SAdrian Chadd 		if (!IEEE80211_ADDR_EQ(eh->ether_shost, vap->iv_myaddr)) {
3895cda6006SAdrian Chadd 			/*
3905cda6006SAdrian Chadd 			 * Proxy station only if configured.
3915cda6006SAdrian Chadd 			 */
3925cda6006SAdrian Chadd 			if (!ieee80211_mesh_isproxyena(vap)) {
3935cda6006SAdrian Chadd 				IEEE80211_DISCARD_MAC(vap,
3945cda6006SAdrian Chadd 				    IEEE80211_MSG_OUTPUT |
3955cda6006SAdrian Chadd 				    IEEE80211_MSG_MESH,
3965cda6006SAdrian Chadd 				    eh->ether_dhost, NULL,
3975cda6006SAdrian Chadd 				    "%s", "proxy not enabled");
3985cda6006SAdrian Chadd 				vap->iv_stats.is_mesh_notproxy++;
399dea45121SGleb Smirnoff 				if_inc_counter(ifp, IFCOUNTER_OERRORS, 1);
4005cda6006SAdrian Chadd 				m_freem(m);
4015cda6006SAdrian Chadd 				/* XXX better status? */
4025cda6006SAdrian Chadd 				return (ENOBUFS);
4035cda6006SAdrian Chadd 			}
4045cda6006SAdrian Chadd 			IEEE80211_DPRINTF(vap, IEEE80211_MSG_OUTPUT,
4055cda6006SAdrian Chadd 			    "forward frame from DS SA(%6D), DA(%6D)\n",
4065cda6006SAdrian Chadd 			    eh->ether_shost, ":",
4075cda6006SAdrian Chadd 			    eh->ether_dhost, ":");
4085cda6006SAdrian Chadd 			ieee80211_mesh_proxy_check(vap, eh->ether_shost);
4095cda6006SAdrian Chadd 		}
4105cda6006SAdrian Chadd 		ni = ieee80211_mesh_discover(vap, eh->ether_dhost, m);
4115cda6006SAdrian Chadd 		if (ni == NULL) {
4125cda6006SAdrian Chadd 			/*
4135cda6006SAdrian Chadd 			 * NB: ieee80211_mesh_discover holds/disposes
4145cda6006SAdrian Chadd 			 * frame (e.g. queueing on path discovery).
4155cda6006SAdrian Chadd 			 */
416dea45121SGleb Smirnoff 			if_inc_counter(ifp, IFCOUNTER_OERRORS, 1);
4175cda6006SAdrian Chadd 			/* XXX better status? */
4185cda6006SAdrian Chadd 			return (ENOBUFS);
4195cda6006SAdrian Chadd 		}
4205cda6006SAdrian Chadd 	}
4215cda6006SAdrian Chadd #endif
422363a2c3cSAdrian Chadd 
4235cda6006SAdrian Chadd 	/*
424363a2c3cSAdrian Chadd 	 * We've resolved the sender, so attempt to transmit it.
4255cda6006SAdrian Chadd 	 */
426ddd9ebbcSAdrian Chadd 
427ddd9ebbcSAdrian Chadd 	if (vap->iv_state == IEEE80211_S_SLEEP) {
428ddd9ebbcSAdrian Chadd 		/*
429ddd9ebbcSAdrian Chadd 		 * In power save; queue frame and then  wakeup device
430ddd9ebbcSAdrian Chadd 		 * for transmit.
431ddd9ebbcSAdrian Chadd 		 */
432ddd9ebbcSAdrian Chadd 		ic->ic_lastdata = ticks;
43379077edcSAndrey V. Elsukov 		if (ieee80211_pwrsave(ni, m) != 0)
43479077edcSAndrey V. Elsukov 			if_inc_counter(ifp, IFCOUNTER_OERRORS, 1);
435ddd9ebbcSAdrian Chadd 		ieee80211_free_node(ni);
436ddd9ebbcSAdrian Chadd 		ieee80211_new_state(vap, IEEE80211_S_RUN, 0);
437ddd9ebbcSAdrian Chadd 		return (0);
438ddd9ebbcSAdrian Chadd 	}
439ddd9ebbcSAdrian Chadd 
440363a2c3cSAdrian Chadd 	if (ieee80211_vap_pkt_send_dest(vap, m, ni) != 0)
4415cda6006SAdrian Chadd 		return (ENOBUFS);
4425cda6006SAdrian Chadd 	return (0);
4435cda6006SAdrian Chadd #undef	IS_DWDS
4445cda6006SAdrian Chadd }
4455cda6006SAdrian Chadd 
4465cda6006SAdrian Chadd /*
447b032f27cSSam Leffler  * Start method for vap's.  All packets from the stack come
448b032f27cSSam Leffler  * through here.  We handle common processing of the packets
449b032f27cSSam Leffler  * before dispatching them to the underlying device.
4501df885c8SAdrian Chadd  *
4511df885c8SAdrian Chadd  * if_transmit() requires that the mbuf be consumed by this call
4521df885c8SAdrian Chadd  * regardless of the return condition.
453b032f27cSSam Leffler  */
454e7495198SAdrian Chadd int
455e7495198SAdrian Chadd ieee80211_vap_transmit(struct ifnet *ifp, struct mbuf *m)
456b032f27cSSam Leffler {
457b032f27cSSam Leffler 	struct ieee80211vap *vap = ifp->if_softc;
458b032f27cSSam Leffler 	struct ieee80211com *ic = vap->iv_ic;
459ddd9ebbcSAdrian Chadd 
460b032f27cSSam Leffler 	/*
461b032f27cSSam Leffler 	 * No data frames go out unless we're running.
462b032f27cSSam Leffler 	 * Note in particular this covers CAC and CSA
463b032f27cSSam Leffler 	 * states (though maybe we should check muting
464b032f27cSSam Leffler 	 * for CSA).
465b032f27cSSam Leffler 	 */
466ddd9ebbcSAdrian Chadd 	if (vap->iv_state != IEEE80211_S_RUN &&
467ddd9ebbcSAdrian Chadd 	    vap->iv_state != IEEE80211_S_SLEEP) {
468b032f27cSSam Leffler 		IEEE80211_LOCK(ic);
469b032f27cSSam Leffler 		/* re-check under the com lock to avoid races */
470ddd9ebbcSAdrian Chadd 		if (vap->iv_state != IEEE80211_S_RUN &&
471ddd9ebbcSAdrian Chadd 		    vap->iv_state != IEEE80211_S_SLEEP) {
472b032f27cSSam Leffler 			IEEE80211_DPRINTF(vap, IEEE80211_MSG_OUTPUT,
473b032f27cSSam Leffler 			    "%s: ignore queue, in %s state\n",
474b032f27cSSam Leffler 			    __func__, ieee80211_state_name[vap->iv_state]);
475b032f27cSSam Leffler 			vap->iv_stats.is_tx_badstate++;
476b032f27cSSam Leffler 			IEEE80211_UNLOCK(ic);
47770e0b5acSAdrian Chadd 			ifp->if_drv_flags |= IFF_DRV_OACTIVE;
4781df885c8SAdrian Chadd 			m_freem(m);
47979077edcSAndrey V. Elsukov 			if_inc_counter(ifp, IFCOUNTER_OERRORS, 1);
48079077edcSAndrey V. Elsukov 			return (ENETDOWN);
481b032f27cSSam Leffler 		}
482b032f27cSSam Leffler 		IEEE80211_UNLOCK(ic);
483b032f27cSSam Leffler 	}
4845cda6006SAdrian Chadd 
485b032f27cSSam Leffler 	/*
486b032f27cSSam Leffler 	 * Sanitize mbuf flags for net80211 use.  We cannot
487927ef5ffSSam Leffler 	 * clear M_PWR_SAV or M_MORE_DATA because these may
488927ef5ffSSam Leffler 	 * be set for frames that are re-submitted from the
489927ef5ffSSam Leffler 	 * power save queue.
490b032f27cSSam Leffler 	 *
491b032f27cSSam Leffler 	 * NB: This must be done before ieee80211_classify as
492b032f27cSSam Leffler 	 *     it marks EAPOL in frames with M_EAPOL.
493b032f27cSSam Leffler 	 */
494927ef5ffSSam Leffler 	m->m_flags &= ~(M_80211_TX - M_PWR_SAV - M_MORE_DATA);
495e7495198SAdrian Chadd 
496b032f27cSSam Leffler 	/*
4975cda6006SAdrian Chadd 	 * Bump to the packet transmission path.
498e7495198SAdrian Chadd 	 * The mbuf will be consumed here.
499b032f27cSSam Leffler 	 */
500e7495198SAdrian Chadd 	return (ieee80211_start_pkt(vap, m));
501b032f27cSSam Leffler }
502e7495198SAdrian Chadd 
503e7495198SAdrian Chadd void
504e7495198SAdrian Chadd ieee80211_vap_qflush(struct ifnet *ifp)
505e7495198SAdrian Chadd {
506e7495198SAdrian Chadd 
507e7495198SAdrian Chadd 	/* Empty for now */
508b032f27cSSam Leffler }
509b032f27cSSam Leffler 
510168f582eSSam Leffler /*
5115cda6006SAdrian Chadd  * 802.11 raw output routine.
512ddd9ebbcSAdrian Chadd  *
513ddd9ebbcSAdrian Chadd  * XXX TODO: this (and other send routines) should correctly
514ddd9ebbcSAdrian Chadd  * XXX keep the pwr mgmt bit set if it decides to call into the
515ddd9ebbcSAdrian Chadd  * XXX driver to send a frame whilst the state is SLEEP.
516ddd9ebbcSAdrian Chadd  *
517ddd9ebbcSAdrian Chadd  * Otherwise the peer may decide that we're awake and flood us
518ddd9ebbcSAdrian Chadd  * with traffic we are still too asleep to receive!
519168f582eSSam Leffler  */
5205cda6006SAdrian Chadd int
5215cda6006SAdrian Chadd ieee80211_raw_output(struct ieee80211vap *vap, struct ieee80211_node *ni,
5225cda6006SAdrian Chadd     struct mbuf *m, const struct ieee80211_bpf_params *params)
5235cda6006SAdrian Chadd {
5245cda6006SAdrian Chadd 	struct ieee80211com *ic = vap->iv_ic;
5257a79cebfSGleb Smirnoff 	int error;
526168f582eSSam Leffler 
527ff09e23fSAdrian Chadd 	/*
528ff09e23fSAdrian Chadd 	 * Set node - the caller has taken a reference, so ensure
529ff09e23fSAdrian Chadd 	 * that the mbuf has the same node value that
530ff09e23fSAdrian Chadd 	 * it would if it were going via the normal path.
531ff09e23fSAdrian Chadd 	 */
532*fb3bc596SJohn Baldwin 	MPASS((m->m_pkthdr.csum_flags & CSUM_SND_TAG) == 0);
533ff09e23fSAdrian Chadd 	m->m_pkthdr.rcvif = (void *)ni;
534ff09e23fSAdrian Chadd 
535ff09e23fSAdrian Chadd 	/*
536ff09e23fSAdrian Chadd 	 * Attempt to add bpf transmit parameters.
537ff09e23fSAdrian Chadd 	 *
538ff09e23fSAdrian Chadd 	 * For now it's ok to fail; the raw_xmit api still takes
539ff09e23fSAdrian Chadd 	 * them as an option.
540ff09e23fSAdrian Chadd 	 *
541ff09e23fSAdrian Chadd 	 * Later on when ic_raw_xmit() has params removed,
542ff09e23fSAdrian Chadd 	 * they'll have to be added - so fail the transmit if
543ff09e23fSAdrian Chadd 	 * they can't be.
544ff09e23fSAdrian Chadd 	 */
5453a1da00bSAdrian Chadd 	if (params)
546ff09e23fSAdrian Chadd 		(void) ieee80211_add_xmit_params(m, params);
547ff09e23fSAdrian Chadd 
5487a79cebfSGleb Smirnoff 	error = ic->ic_raw_xmit(ni, m, params);
549d957a93aSAdrian Chadd 	if (error) {
5507a79cebfSGleb Smirnoff 		if_inc_counter(vap->iv_ifp, IFCOUNTER_OERRORS, 1);
551d957a93aSAdrian Chadd 		ieee80211_free_node(ni);
552d957a93aSAdrian Chadd 	}
5537a79cebfSGleb Smirnoff 	return (error);
554b032f27cSSam Leffler }
555b032f27cSSam Leffler 
556bcabc908SAndriy Voskoboinyk static int
557bcabc908SAndriy Voskoboinyk ieee80211_validate_frame(struct mbuf *m,
558bcabc908SAndriy Voskoboinyk     const struct ieee80211_bpf_params *params)
559bcabc908SAndriy Voskoboinyk {
560bcabc908SAndriy Voskoboinyk 	struct ieee80211_frame *wh;
561bcabc908SAndriy Voskoboinyk 	int type;
562bcabc908SAndriy Voskoboinyk 
563bcabc908SAndriy Voskoboinyk 	if (m->m_pkthdr.len < sizeof(struct ieee80211_frame_ack))
564bcabc908SAndriy Voskoboinyk 		return (EINVAL);
565bcabc908SAndriy Voskoboinyk 
566bcabc908SAndriy Voskoboinyk 	wh = mtod(m, struct ieee80211_frame *);
567bcabc908SAndriy Voskoboinyk 	if ((wh->i_fc[0] & IEEE80211_FC0_VERSION_MASK) !=
568bcabc908SAndriy Voskoboinyk 	    IEEE80211_FC0_VERSION_0)
569bcabc908SAndriy Voskoboinyk 		return (EINVAL);
570bcabc908SAndriy Voskoboinyk 
571bcabc908SAndriy Voskoboinyk 	type = wh->i_fc[0] & IEEE80211_FC0_TYPE_MASK;
572bcabc908SAndriy Voskoboinyk 	if (type != IEEE80211_FC0_TYPE_DATA) {
573bcabc908SAndriy Voskoboinyk 		if ((wh->i_fc[1] & IEEE80211_FC1_DIR_MASK) !=
574bcabc908SAndriy Voskoboinyk 		    IEEE80211_FC1_DIR_NODS)
575bcabc908SAndriy Voskoboinyk 			return (EINVAL);
576bcabc908SAndriy Voskoboinyk 
577bcabc908SAndriy Voskoboinyk 		if (type != IEEE80211_FC0_TYPE_MGT &&
578bcabc908SAndriy Voskoboinyk 		    (wh->i_fc[1] & IEEE80211_FC1_MORE_FRAG) != 0)
579bcabc908SAndriy Voskoboinyk 			return (EINVAL);
580bcabc908SAndriy Voskoboinyk 
581bcabc908SAndriy Voskoboinyk 		/* XXX skip other field checks? */
582bcabc908SAndriy Voskoboinyk 	}
583bcabc908SAndriy Voskoboinyk 
584bcabc908SAndriy Voskoboinyk 	if ((params && (params->ibp_flags & IEEE80211_BPF_CRYPTO) != 0) ||
585bcabc908SAndriy Voskoboinyk 	    (wh->i_fc[1] & IEEE80211_FC1_PROTECTED) != 0) {
586bcabc908SAndriy Voskoboinyk 		int subtype;
587bcabc908SAndriy Voskoboinyk 
588bcabc908SAndriy Voskoboinyk 		subtype = wh->i_fc[0] & IEEE80211_FC0_SUBTYPE_MASK;
589bcabc908SAndriy Voskoboinyk 
590bcabc908SAndriy Voskoboinyk 		/*
591bcabc908SAndriy Voskoboinyk 		 * See IEEE Std 802.11-2012,
592bcabc908SAndriy Voskoboinyk 		 * 8.2.4.1.9 'Protected Frame field'
593bcabc908SAndriy Voskoboinyk 		 */
594bcabc908SAndriy Voskoboinyk 		/* XXX no support for robust management frames yet. */
595bcabc908SAndriy Voskoboinyk 		if (!(type == IEEE80211_FC0_TYPE_DATA ||
596bcabc908SAndriy Voskoboinyk 		    (type == IEEE80211_FC0_TYPE_MGT &&
597bcabc908SAndriy Voskoboinyk 		     subtype == IEEE80211_FC0_SUBTYPE_AUTH)))
598bcabc908SAndriy Voskoboinyk 			return (EINVAL);
599bcabc908SAndriy Voskoboinyk 
600bcabc908SAndriy Voskoboinyk 		wh->i_fc[1] |= IEEE80211_FC1_PROTECTED;
601bcabc908SAndriy Voskoboinyk 	}
602bcabc908SAndriy Voskoboinyk 
603bcabc908SAndriy Voskoboinyk 	if (m->m_pkthdr.len < ieee80211_anyhdrsize(wh))
604bcabc908SAndriy Voskoboinyk 		return (EINVAL);
605bcabc908SAndriy Voskoboinyk 
606bcabc908SAndriy Voskoboinyk 	return (0);
607bcabc908SAndriy Voskoboinyk }
608bcabc908SAndriy Voskoboinyk 
609e42e878bSAndriy Voskoboinyk static int
610e42e878bSAndriy Voskoboinyk ieee80211_validate_rate(struct ieee80211_node *ni, uint8_t rate)
611e42e878bSAndriy Voskoboinyk {
612e42e878bSAndriy Voskoboinyk 	struct ieee80211com *ic = ni->ni_ic;
613e42e878bSAndriy Voskoboinyk 
614e42e878bSAndriy Voskoboinyk 	if (IEEE80211_IS_HT_RATE(rate)) {
615e42e878bSAndriy Voskoboinyk 		if ((ic->ic_htcaps & IEEE80211_HTC_HT) == 0)
616e42e878bSAndriy Voskoboinyk 			return (EINVAL);
617e42e878bSAndriy Voskoboinyk 
618e42e878bSAndriy Voskoboinyk 		rate = IEEE80211_RV(rate);
619e42e878bSAndriy Voskoboinyk 		if (rate <= 31) {
620e42e878bSAndriy Voskoboinyk 			if (rate > ic->ic_txstream * 8 - 1)
621e42e878bSAndriy Voskoboinyk 				return (EINVAL);
622e42e878bSAndriy Voskoboinyk 
623e42e878bSAndriy Voskoboinyk 			return (0);
624e42e878bSAndriy Voskoboinyk 		}
625e42e878bSAndriy Voskoboinyk 
626e42e878bSAndriy Voskoboinyk 		if (rate == 32) {
627e42e878bSAndriy Voskoboinyk 			if ((ic->ic_htcaps & IEEE80211_HTC_TXMCS32) == 0)
628e42e878bSAndriy Voskoboinyk 				return (EINVAL);
629e42e878bSAndriy Voskoboinyk 
630e42e878bSAndriy Voskoboinyk 			return (0);
631e42e878bSAndriy Voskoboinyk 		}
632e42e878bSAndriy Voskoboinyk 
633e42e878bSAndriy Voskoboinyk 		if ((ic->ic_htcaps & IEEE80211_HTC_TXUNEQUAL) == 0)
634e42e878bSAndriy Voskoboinyk 			return (EINVAL);
635e42e878bSAndriy Voskoboinyk 
636e42e878bSAndriy Voskoboinyk 		switch (ic->ic_txstream) {
637e42e878bSAndriy Voskoboinyk 		case 0:
638e42e878bSAndriy Voskoboinyk 		case 1:
639e42e878bSAndriy Voskoboinyk 			return (EINVAL);
640e42e878bSAndriy Voskoboinyk 		case 2:
641e42e878bSAndriy Voskoboinyk 			if (rate > 38)
642e42e878bSAndriy Voskoboinyk 				return (EINVAL);
643e42e878bSAndriy Voskoboinyk 
644e42e878bSAndriy Voskoboinyk 			return (0);
645e42e878bSAndriy Voskoboinyk 		case 3:
646e42e878bSAndriy Voskoboinyk 			if (rate > 52)
647e42e878bSAndriy Voskoboinyk 				return (EINVAL);
648e42e878bSAndriy Voskoboinyk 
649e42e878bSAndriy Voskoboinyk 			return (0);
650e42e878bSAndriy Voskoboinyk 		case 4:
651e42e878bSAndriy Voskoboinyk 		default:
652e42e878bSAndriy Voskoboinyk 			if (rate > 76)
653e42e878bSAndriy Voskoboinyk 				return (EINVAL);
654e42e878bSAndriy Voskoboinyk 
655e42e878bSAndriy Voskoboinyk 			return (0);
656e42e878bSAndriy Voskoboinyk 		}
657e42e878bSAndriy Voskoboinyk 	}
658e42e878bSAndriy Voskoboinyk 
659e42e878bSAndriy Voskoboinyk 	if (!ieee80211_isratevalid(ic->ic_rt, rate))
660e42e878bSAndriy Voskoboinyk 		return (EINVAL);
661e42e878bSAndriy Voskoboinyk 
662e42e878bSAndriy Voskoboinyk 	return (0);
663e42e878bSAndriy Voskoboinyk }
664e42e878bSAndriy Voskoboinyk 
665e42e878bSAndriy Voskoboinyk static int
666e42e878bSAndriy Voskoboinyk ieee80211_sanitize_rates(struct ieee80211_node *ni, struct mbuf *m,
667e42e878bSAndriy Voskoboinyk     const struct ieee80211_bpf_params *params)
668e42e878bSAndriy Voskoboinyk {
669e42e878bSAndriy Voskoboinyk 	int error;
670e42e878bSAndriy Voskoboinyk 
671e42e878bSAndriy Voskoboinyk 	if (!params)
672e42e878bSAndriy Voskoboinyk 		return (0);	/* nothing to do */
673e42e878bSAndriy Voskoboinyk 
674e42e878bSAndriy Voskoboinyk 	/* NB: most drivers assume that ibp_rate0 is set (!= 0). */
675e42e878bSAndriy Voskoboinyk 	if (params->ibp_rate0 != 0) {
676e42e878bSAndriy Voskoboinyk 		error = ieee80211_validate_rate(ni, params->ibp_rate0);
677e42e878bSAndriy Voskoboinyk 		if (error != 0)
678e42e878bSAndriy Voskoboinyk 			return (error);
679e42e878bSAndriy Voskoboinyk 	} else {
680e42e878bSAndriy Voskoboinyk 		/* XXX pre-setup some default (e.g., mgmt / mcast) rate */
681e42e878bSAndriy Voskoboinyk 		/* XXX __DECONST? */
682e42e878bSAndriy Voskoboinyk 		(void) m;
683e42e878bSAndriy Voskoboinyk 	}
684e42e878bSAndriy Voskoboinyk 
685e42e878bSAndriy Voskoboinyk 	if (params->ibp_rate1 != 0 &&
686e42e878bSAndriy Voskoboinyk 	    (error = ieee80211_validate_rate(ni, params->ibp_rate1)) != 0)
687e42e878bSAndriy Voskoboinyk 		return (error);
688e42e878bSAndriy Voskoboinyk 
689e42e878bSAndriy Voskoboinyk 	if (params->ibp_rate2 != 0 &&
690e42e878bSAndriy Voskoboinyk 	    (error = ieee80211_validate_rate(ni, params->ibp_rate2)) != 0)
691e42e878bSAndriy Voskoboinyk 		return (error);
692e42e878bSAndriy Voskoboinyk 
693e42e878bSAndriy Voskoboinyk 	if (params->ibp_rate3 != 0 &&
694e42e878bSAndriy Voskoboinyk 	    (error = ieee80211_validate_rate(ni, params->ibp_rate3)) != 0)
695e42e878bSAndriy Voskoboinyk 		return (error);
696e42e878bSAndriy Voskoboinyk 
697e42e878bSAndriy Voskoboinyk 	return (0);
698e42e878bSAndriy Voskoboinyk }
699e42e878bSAndriy Voskoboinyk 
700b032f27cSSam Leffler /*
701b032f27cSSam Leffler  * 802.11 output routine. This is (currently) used only to
702b032f27cSSam Leffler  * connect bpf write calls to the 802.11 layer for injecting
703fad788b1SSam Leffler  * raw 802.11 frames.
704b032f27cSSam Leffler  */
705b032f27cSSam Leffler int
706b032f27cSSam Leffler ieee80211_output(struct ifnet *ifp, struct mbuf *m,
70747e8d432SGleb Smirnoff 	const struct sockaddr *dst, struct route *ro)
708b032f27cSSam Leffler {
709b032f27cSSam Leffler #define senderr(e) do { error = (e); goto bad;} while (0)
710bcabc908SAndriy Voskoboinyk 	const struct ieee80211_bpf_params *params = NULL;
711b032f27cSSam Leffler 	struct ieee80211_node *ni = NULL;
7128ed1835dSSam Leffler 	struct ieee80211vap *vap;
713b032f27cSSam Leffler 	struct ieee80211_frame *wh;
7145cda6006SAdrian Chadd 	struct ieee80211com *ic = NULL;
715b032f27cSSam Leffler 	int error;
7165cda6006SAdrian Chadd 	int ret;
717b032f27cSSam Leffler 
7188ed1835dSSam Leffler 	if (ifp->if_drv_flags & IFF_DRV_OACTIVE) {
7198ed1835dSSam Leffler 		/*
7208ed1835dSSam Leffler 		 * Short-circuit requests if the vap is marked OACTIVE
7218ed1835dSSam Leffler 		 * as this can happen because a packet came down through
7228ed1835dSSam Leffler 		 * ieee80211_start before the vap entered RUN state in
7238ed1835dSSam Leffler 		 * which case it's ok to just drop the frame.  This
7248ed1835dSSam Leffler 		 * should not be necessary but callers of if_output don't
7258ed1835dSSam Leffler 		 * check OACTIVE.
7268ed1835dSSam Leffler 		 */
7278ed1835dSSam Leffler 		senderr(ENETDOWN);
7288ed1835dSSam Leffler 	}
7298ed1835dSSam Leffler 	vap = ifp->if_softc;
7305cda6006SAdrian Chadd 	ic = vap->iv_ic;
731b032f27cSSam Leffler 	/*
732b032f27cSSam Leffler 	 * Hand to the 802.3 code if not tagged as
733b032f27cSSam Leffler 	 * a raw 802.11 frame.
734b032f27cSSam Leffler 	 */
735b032f27cSSam Leffler 	if (dst->sa_family != AF_IEEE80211)
736279aa3d4SKip Macy 		return vap->iv_output(ifp, m, dst, ro);
737b032f27cSSam Leffler #ifdef MAC
738c27b9cdbSRobert Watson 	error = mac_ifnet_check_transmit(ifp, m);
739b032f27cSSam Leffler 	if (error)
740b032f27cSSam Leffler 		senderr(error);
741b032f27cSSam Leffler #endif
742b032f27cSSam Leffler 	if (ifp->if_flags & IFF_MONITOR)
743b032f27cSSam Leffler 		senderr(ENETDOWN);
744b032f27cSSam Leffler 	if (!IFNET_IS_UP_RUNNING(ifp))
745b032f27cSSam Leffler 		senderr(ENETDOWN);
746b032f27cSSam Leffler 	if (vap->iv_state == IEEE80211_S_CAC) {
747b032f27cSSam Leffler 		IEEE80211_DPRINTF(vap,
748b032f27cSSam Leffler 		    IEEE80211_MSG_OUTPUT | IEEE80211_MSG_DOTH,
749b032f27cSSam Leffler 		    "block %s frame in CAC state\n", "raw data");
750b032f27cSSam Leffler 		vap->iv_stats.is_tx_badstate++;
751b032f27cSSam Leffler 		senderr(EIO);		/* XXX */
7520d9aed8aSBernhard Schmidt 	} else if (vap->iv_state == IEEE80211_S_SCAN)
7530d9aed8aSBernhard Schmidt 		senderr(EIO);
754b032f27cSSam Leffler 	/* XXX bypass bridge, pfil, carp, etc. */
755b032f27cSSam Leffler 
756bcabc908SAndriy Voskoboinyk 	/*
757bcabc908SAndriy Voskoboinyk 	 * NB: DLT_IEEE802_11_RADIO identifies the parameters are
758bcabc908SAndriy Voskoboinyk 	 * present by setting the sa_len field of the sockaddr (yes,
759bcabc908SAndriy Voskoboinyk 	 * this is a hack).
760bcabc908SAndriy Voskoboinyk 	 * NB: we assume sa_data is suitably aligned to cast.
761bcabc908SAndriy Voskoboinyk 	 */
762bcabc908SAndriy Voskoboinyk 	if (dst->sa_len != 0)
763bcabc908SAndriy Voskoboinyk 		params = (const struct ieee80211_bpf_params *)dst->sa_data;
764bcabc908SAndriy Voskoboinyk 
765bcabc908SAndriy Voskoboinyk 	error = ieee80211_validate_frame(m, params);
766bcabc908SAndriy Voskoboinyk 	if (error != 0)
767bcabc908SAndriy Voskoboinyk 		senderr(error);
768bcabc908SAndriy Voskoboinyk 
769b032f27cSSam Leffler 	wh = mtod(m, struct ieee80211_frame *);
770b032f27cSSam Leffler 
771b032f27cSSam Leffler 	/* locate destination node */
772b032f27cSSam Leffler 	switch (wh->i_fc[1] & IEEE80211_FC1_DIR_MASK) {
773b032f27cSSam Leffler 	case IEEE80211_FC1_DIR_NODS:
774b032f27cSSam Leffler 	case IEEE80211_FC1_DIR_FROMDS:
775b032f27cSSam Leffler 		ni = ieee80211_find_txnode(vap, wh->i_addr1);
776b032f27cSSam Leffler 		break;
777b032f27cSSam Leffler 	case IEEE80211_FC1_DIR_TODS:
778b032f27cSSam Leffler 	case IEEE80211_FC1_DIR_DSTODS:
779b032f27cSSam Leffler 		ni = ieee80211_find_txnode(vap, wh->i_addr3);
780b032f27cSSam Leffler 		break;
781b032f27cSSam Leffler 	default:
782bcabc908SAndriy Voskoboinyk 		senderr(EDOOFUS);
783b032f27cSSam Leffler 	}
784b032f27cSSam Leffler 	if (ni == NULL) {
785b032f27cSSam Leffler 		/*
786b032f27cSSam Leffler 		 * Permit packets w/ bpf params through regardless
787b032f27cSSam Leffler 		 * (see below about sa_len).
788b032f27cSSam Leffler 		 */
789b032f27cSSam Leffler 		if (dst->sa_len == 0)
790b032f27cSSam Leffler 			senderr(EHOSTUNREACH);
791b032f27cSSam Leffler 		ni = ieee80211_ref_node(vap->iv_bss);
792b032f27cSSam Leffler 	}
793b032f27cSSam Leffler 
794b032f27cSSam Leffler 	/*
795b032f27cSSam Leffler 	 * Sanitize mbuf for net80211 flags leaked from above.
796b032f27cSSam Leffler 	 *
797b032f27cSSam Leffler 	 * NB: This must be done before ieee80211_classify as
798b032f27cSSam Leffler 	 *     it marks EAPOL in frames with M_EAPOL.
799b032f27cSSam Leffler 	 */
800b032f27cSSam Leffler 	m->m_flags &= ~M_80211_TX;
801bcabc908SAndriy Voskoboinyk 	m->m_flags |= M_ENCAP;		/* mark encapsulated */
802b032f27cSSam Leffler 
803bcabc908SAndriy Voskoboinyk 	if (IEEE80211_IS_DATA(wh)) {
804b032f27cSSam Leffler 		/* calculate priority so drivers can find the tx queue */
805b032f27cSSam Leffler 		if (ieee80211_classify(ni, m))
806b032f27cSSam Leffler 			senderr(EIO);		/* XXX */
807b032f27cSSam Leffler 
808bcabc908SAndriy Voskoboinyk 		/* NB: ieee80211_encap does not include 802.11 header */
809bcabc908SAndriy Voskoboinyk 		IEEE80211_NODE_STAT_ADD(ni, tx_bytes,
810bcabc908SAndriy Voskoboinyk 		    m->m_pkthdr.len - ieee80211_hdrsize(wh));
811bcabc908SAndriy Voskoboinyk 	} else
812bcabc908SAndriy Voskoboinyk 		M_WME_SETAC(m, WME_AC_BE);
813bcabc908SAndriy Voskoboinyk 
814e42e878bSAndriy Voskoboinyk 	error = ieee80211_sanitize_rates(ni, m, params);
815e42e878bSAndriy Voskoboinyk 	if (error != 0)
816e42e878bSAndriy Voskoboinyk 		senderr(error);
817e42e878bSAndriy Voskoboinyk 
8180e910c94SSam Leffler 	IEEE80211_NODE_STAT(ni, tx_data);
8190e910c94SSam Leffler 	if (IEEE80211_IS_MULTICAST(wh->i_addr1)) {
8200e910c94SSam Leffler 		IEEE80211_NODE_STAT(ni, tx_mcast);
8210e910c94SSam Leffler 		m->m_flags |= M_MCAST;
8220e910c94SSam Leffler 	} else
8230e910c94SSam Leffler 		IEEE80211_NODE_STAT(ni, tx_ucast);
824b032f27cSSam Leffler 
8255cda6006SAdrian Chadd 	IEEE80211_TX_LOCK(ic);
826bcabc908SAndriy Voskoboinyk 	ret = ieee80211_raw_output(vap, ni, m, params);
8275cda6006SAdrian Chadd 	IEEE80211_TX_UNLOCK(ic);
8285cda6006SAdrian Chadd 	return (ret);
829b032f27cSSam Leffler bad:
830b032f27cSSam Leffler 	if (m != NULL)
831b032f27cSSam Leffler 		m_freem(m);
832b032f27cSSam Leffler 	if (ni != NULL)
833b032f27cSSam Leffler 		ieee80211_free_node(ni);
834dea45121SGleb Smirnoff 	if_inc_counter(ifp, IFCOUNTER_OERRORS, 1);
835b032f27cSSam Leffler 	return error;
836b032f27cSSam Leffler #undef senderr
837b032f27cSSam Leffler }
838b032f27cSSam Leffler 
839b032f27cSSam Leffler /*
840add59d08SSam Leffler  * Set the direction field and address fields of an outgoing
8410e66722dSSam Leffler  * frame.  Note this should be called early on in constructing
8420e66722dSSam Leffler  * a frame as it sets i_fc[1]; other bits can then be or'd in.
843add59d08SSam Leffler  */
84459aa14a9SRui Paulo void
845b032f27cSSam Leffler ieee80211_send_setup(
846add59d08SSam Leffler 	struct ieee80211_node *ni,
8479e80b1dfSSam Leffler 	struct mbuf *m,
8488ac160cdSSam Leffler 	int type, int tid,
84968e8e04eSSam Leffler 	const uint8_t sa[IEEE80211_ADDR_LEN],
85068e8e04eSSam Leffler 	const uint8_t da[IEEE80211_ADDR_LEN],
85168e8e04eSSam Leffler 	const uint8_t bssid[IEEE80211_ADDR_LEN])
852add59d08SSam Leffler {
853add59d08SSam Leffler #define	WH4(wh)	((struct ieee80211_frame_addr4 *)wh)
85459aa14a9SRui Paulo 	struct ieee80211vap *vap = ni->ni_vap;
85550cfec0eSBernhard Schmidt 	struct ieee80211_tx_ampdu *tap;
8569e80b1dfSSam Leffler 	struct ieee80211_frame *wh = mtod(m, struct ieee80211_frame *);
8579e80b1dfSSam Leffler 	ieee80211_seq seqno;
858add59d08SSam Leffler 
8596ce4aeb8SAdrian Chadd 	IEEE80211_TX_LOCK_ASSERT(ni->ni_ic);
8605cda6006SAdrian Chadd 
861add59d08SSam Leffler 	wh->i_fc[0] = IEEE80211_FC0_VERSION_0 | type;
862add59d08SSam Leffler 	if ((type & IEEE80211_FC0_TYPE_MASK) == IEEE80211_FC0_TYPE_DATA) {
863b032f27cSSam Leffler 		switch (vap->iv_opmode) {
864add59d08SSam Leffler 		case IEEE80211_M_STA:
865add59d08SSam Leffler 			wh->i_fc[1] = IEEE80211_FC1_DIR_TODS;
866add59d08SSam Leffler 			IEEE80211_ADDR_COPY(wh->i_addr1, bssid);
867add59d08SSam Leffler 			IEEE80211_ADDR_COPY(wh->i_addr2, sa);
868add59d08SSam Leffler 			IEEE80211_ADDR_COPY(wh->i_addr3, da);
869add59d08SSam Leffler 			break;
870add59d08SSam Leffler 		case IEEE80211_M_IBSS:
871add59d08SSam Leffler 		case IEEE80211_M_AHDEMO:
872add59d08SSam Leffler 			wh->i_fc[1] = IEEE80211_FC1_DIR_NODS;
873add59d08SSam Leffler 			IEEE80211_ADDR_COPY(wh->i_addr1, da);
874add59d08SSam Leffler 			IEEE80211_ADDR_COPY(wh->i_addr2, sa);
875add59d08SSam Leffler 			IEEE80211_ADDR_COPY(wh->i_addr3, bssid);
876add59d08SSam Leffler 			break;
877add59d08SSam Leffler 		case IEEE80211_M_HOSTAP:
878add59d08SSam Leffler 			wh->i_fc[1] = IEEE80211_FC1_DIR_FROMDS;
879add59d08SSam Leffler 			IEEE80211_ADDR_COPY(wh->i_addr1, da);
880add59d08SSam Leffler 			IEEE80211_ADDR_COPY(wh->i_addr2, bssid);
881add59d08SSam Leffler 			IEEE80211_ADDR_COPY(wh->i_addr3, sa);
882add59d08SSam Leffler 			break;
88368e8e04eSSam Leffler 		case IEEE80211_M_WDS:
88468e8e04eSSam Leffler 			wh->i_fc[1] = IEEE80211_FC1_DIR_DSTODS;
885b032f27cSSam Leffler 			IEEE80211_ADDR_COPY(wh->i_addr1, da);
886b032f27cSSam Leffler 			IEEE80211_ADDR_COPY(wh->i_addr2, vap->iv_myaddr);
88768e8e04eSSam Leffler 			IEEE80211_ADDR_COPY(wh->i_addr3, da);
88868e8e04eSSam Leffler 			IEEE80211_ADDR_COPY(WH4(wh)->i_addr4, sa);
88968e8e04eSSam Leffler 			break;
89059aa14a9SRui Paulo 		case IEEE80211_M_MBSS:
89159aa14a9SRui Paulo #ifdef IEEE80211_SUPPORT_MESH
89259aa14a9SRui Paulo 			if (IEEE80211_IS_MULTICAST(da)) {
89359aa14a9SRui Paulo 				wh->i_fc[1] = IEEE80211_FC1_DIR_FROMDS;
89459aa14a9SRui Paulo 				/* XXX next hop */
89559aa14a9SRui Paulo 				IEEE80211_ADDR_COPY(wh->i_addr1, da);
89659aa14a9SRui Paulo 				IEEE80211_ADDR_COPY(wh->i_addr2,
89759aa14a9SRui Paulo 				    vap->iv_myaddr);
89859aa14a9SRui Paulo 			} else {
89959aa14a9SRui Paulo 				wh->i_fc[1] = IEEE80211_FC1_DIR_DSTODS;
90059aa14a9SRui Paulo 				IEEE80211_ADDR_COPY(wh->i_addr1, da);
90159aa14a9SRui Paulo 				IEEE80211_ADDR_COPY(wh->i_addr2,
90259aa14a9SRui Paulo 				    vap->iv_myaddr);
90359aa14a9SRui Paulo 				IEEE80211_ADDR_COPY(wh->i_addr3, da);
90459aa14a9SRui Paulo 				IEEE80211_ADDR_COPY(WH4(wh)->i_addr4, sa);
90559aa14a9SRui Paulo 			}
90659aa14a9SRui Paulo #endif
90759aa14a9SRui Paulo 			break;
908add59d08SSam Leffler 		case IEEE80211_M_MONITOR:	/* NB: to quiet compiler */
909add59d08SSam Leffler 			break;
910add59d08SSam Leffler 		}
911add59d08SSam Leffler 	} else {
912add59d08SSam Leffler 		wh->i_fc[1] = IEEE80211_FC1_DIR_NODS;
913add59d08SSam Leffler 		IEEE80211_ADDR_COPY(wh->i_addr1, da);
914add59d08SSam Leffler 		IEEE80211_ADDR_COPY(wh->i_addr2, sa);
91559aa14a9SRui Paulo #ifdef IEEE80211_SUPPORT_MESH
91659aa14a9SRui Paulo 		if (vap->iv_opmode == IEEE80211_M_MBSS)
91759aa14a9SRui Paulo 			IEEE80211_ADDR_COPY(wh->i_addr3, sa);
91859aa14a9SRui Paulo 		else
91959aa14a9SRui Paulo #endif
920add59d08SSam Leffler 			IEEE80211_ADDR_COPY(wh->i_addr3, bssid);
921add59d08SSam Leffler 	}
92268e8e04eSSam Leffler 	*(uint16_t *)&wh->i_dur[0] = 0;
9239e80b1dfSSam Leffler 
92451172f62SAdrian Chadd 	/*
92551172f62SAdrian Chadd 	 * XXX TODO: this is what the TX lock is for.
92651172f62SAdrian Chadd 	 * Here we're incrementing sequence numbers, and they
92751172f62SAdrian Chadd 	 * need to be in lock-step with what the driver is doing
92851172f62SAdrian Chadd 	 * both in TX ordering and crypto encap (IV increment.)
92951172f62SAdrian Chadd 	 *
93051172f62SAdrian Chadd 	 * If the driver does seqno itself, then we can skip
93151172f62SAdrian Chadd 	 * assigning sequence numbers here, and we can avoid
93251172f62SAdrian Chadd 	 * requiring the TX lock.
93351172f62SAdrian Chadd 	 */
9342aa563dfSAdrian Chadd 	tap = &ni->ni_tx_ampdu[tid];
9359764ef21SAdrian Chadd 	if (tid != IEEE80211_NONQOS_TID && IEEE80211_AMPDU_RUNNING(tap)) {
93650cfec0eSBernhard Schmidt 		m->m_flags |= M_AMPDU_MPDU;
9372db223f9SAndriy Voskoboinyk 
9382db223f9SAndriy Voskoboinyk 		/* NB: zero out i_seq field (for s/w encryption etc) */
9392db223f9SAndriy Voskoboinyk 		*(uint16_t *)&wh->i_seq[0] = 0;
9409764ef21SAdrian Chadd 	} else {
941c3ebe019SAdrian Chadd 		if (IEEE80211_HAS_SEQ(type & IEEE80211_FC0_TYPE_MASK,
942c3ebe019SAdrian Chadd 				      type & IEEE80211_FC0_SUBTYPE_MASK))
9439764ef21SAdrian Chadd 			/*
9449764ef21SAdrian Chadd 			 * 802.11-2012 9.3.2.10 - QoS multicast frames
9459764ef21SAdrian Chadd 			 * come out of a different seqno space.
9469764ef21SAdrian Chadd 			 */
9479764ef21SAdrian Chadd 			if (IEEE80211_IS_MULTICAST(wh->i_addr1)) {
9489764ef21SAdrian Chadd 				seqno = ni->ni_txseqs[IEEE80211_NONQOS_TID]++;
9499764ef21SAdrian Chadd 			} else {
9509e80b1dfSSam Leffler 				seqno = ni->ni_txseqs[tid]++;
9519764ef21SAdrian Chadd 			}
952c3ebe019SAdrian Chadd 		else
953c3ebe019SAdrian Chadd 			seqno = 0;
954c3ebe019SAdrian Chadd 
95550cfec0eSBernhard Schmidt 		*(uint16_t *)&wh->i_seq[0] =
95650cfec0eSBernhard Schmidt 		    htole16(seqno << IEEE80211_SEQ_SEQ_SHIFT);
9579a841c7fSSam Leffler 		M_SEQNO_SET(m, seqno);
95850cfec0eSBernhard Schmidt 	}
9599e80b1dfSSam Leffler 
9609e80b1dfSSam Leffler 	if (IEEE80211_IS_MULTICAST(wh->i_addr1))
9619e80b1dfSSam Leffler 		m->m_flags |= M_MCAST;
962add59d08SSam Leffler #undef WH4
963add59d08SSam Leffler }
964add59d08SSam Leffler 
965add59d08SSam Leffler /*
9660a915fadSSam Leffler  * Send a management frame to the specified node.  The node pointer
9670a915fadSSam Leffler  * must have a reference as the pointer will be passed to the driver
9680a915fadSSam Leffler  * and potentially held for a long time.  If the frame is successfully
9690a915fadSSam Leffler  * dispatched to the driver, then it is responsible for freeing the
970b032f27cSSam Leffler  * reference (and potentially free'ing up any associated storage);
971b032f27cSSam Leffler  * otherwise deal with reclaiming any reference (on error).
9720a915fadSSam Leffler  */
97368e8e04eSSam Leffler int
9748ac160cdSSam Leffler ieee80211_mgmt_output(struct ieee80211_node *ni, struct mbuf *m, int type,
9758ac160cdSSam Leffler 	struct ieee80211_bpf_params *params)
9761a1e1d21SSam Leffler {
977b032f27cSSam Leffler 	struct ieee80211vap *vap = ni->ni_vap;
978b032f27cSSam Leffler 	struct ieee80211com *ic = ni->ni_ic;
9791a1e1d21SSam Leffler 	struct ieee80211_frame *wh;
9805cda6006SAdrian Chadd 	int ret;
9811a1e1d21SSam Leffler 
9820a915fadSSam Leffler 	KASSERT(ni != NULL, ("null node"));
9831a1e1d21SSam Leffler 
984b032f27cSSam Leffler 	if (vap->iv_state == IEEE80211_S_CAC) {
985b032f27cSSam Leffler 		IEEE80211_NOTE(vap, IEEE80211_MSG_OUTPUT | IEEE80211_MSG_DOTH,
986b032f27cSSam Leffler 		    ni, "block %s frame in CAC state",
9874357a5d1SAndriy Voskoboinyk 			ieee80211_mgt_subtype_name(type));
988b032f27cSSam Leffler 		vap->iv_stats.is_tx_badstate++;
989b032f27cSSam Leffler 		ieee80211_free_node(ni);
990b032f27cSSam Leffler 		m_freem(m);
991b032f27cSSam Leffler 		return EIO;		/* XXX */
992b032f27cSSam Leffler 	}
993b032f27cSSam Leffler 
994eb1b1807SGleb Smirnoff 	M_PREPEND(m, sizeof(struct ieee80211_frame), M_NOWAIT);
995b032f27cSSam Leffler 	if (m == NULL) {
996b032f27cSSam Leffler 		ieee80211_free_node(ni);
9971a1e1d21SSam Leffler 		return ENOMEM;
998b032f27cSSam Leffler 	}
9990a915fadSSam Leffler 
10005cda6006SAdrian Chadd 	IEEE80211_TX_LOCK(ic);
10015cda6006SAdrian Chadd 
10021a1e1d21SSam Leffler 	wh = mtod(m, struct ieee80211_frame *);
10039e80b1dfSSam Leffler 	ieee80211_send_setup(ni, m,
10048ac160cdSSam Leffler 	     IEEE80211_FC0_TYPE_MGT | type, IEEE80211_NONQOS_TID,
1005b032f27cSSam Leffler 	     vap->iv_myaddr, ni->ni_macaddr, ni->ni_bssid);
10068ac160cdSSam Leffler 	if (params->ibp_flags & IEEE80211_BPF_CRYPTO) {
1007b032f27cSSam Leffler 		IEEE80211_NOTE_MAC(vap, IEEE80211_MSG_AUTH, wh->i_addr1,
1008b032f27cSSam Leffler 		    "encrypting frame (%s)", __func__);
10095945b5f5SKevin Lo 		wh->i_fc[1] |= IEEE80211_FC1_PROTECTED;
10108a1b9b6aSSam Leffler 	}
1011c1af44bdSSam Leffler 	m->m_flags |= M_ENCAP;		/* mark encapsulated */
10128ac160cdSSam Leffler 
10138ac160cdSSam Leffler 	KASSERT(type != IEEE80211_FC0_SUBTYPE_PROBE_RESP, ("probe response?"));
10148ac160cdSSam Leffler 	M_WME_SETAC(m, params->ibp_pri);
10158ac160cdSSam Leffler 
10168a1b9b6aSSam Leffler #ifdef IEEE80211_DEBUG
10178a1b9b6aSSam Leffler 	/* avoid printing too many frames */
1018b032f27cSSam Leffler 	if ((ieee80211_msg_debug(vap) && doprint(vap, type)) ||
1019b032f27cSSam Leffler 	    ieee80211_msg_dumppkts(vap)) {
10208a1b9b6aSSam Leffler 		printf("[%s] send %s on channel %u\n",
10218a1b9b6aSSam Leffler 		    ether_sprintf(wh->i_addr1),
10224357a5d1SAndriy Voskoboinyk 		    ieee80211_mgt_subtype_name(type),
1023b5c99415SSam Leffler 		    ieee80211_chan2ieee(ic, ic->ic_curchan));
10248a1b9b6aSSam Leffler 	}
10258a1b9b6aSSam Leffler #endif
10268a1b9b6aSSam Leffler 	IEEE80211_NODE_STAT(ni, tx_mgmt);
102768e8e04eSSam Leffler 
10285cda6006SAdrian Chadd 	ret = ieee80211_raw_output(vap, ni, m, params);
10295cda6006SAdrian Chadd 	IEEE80211_TX_UNLOCK(ic);
10305cda6006SAdrian Chadd 	return (ret);
1031246b5467SSam Leffler }
1032246b5467SSam Leffler 
10339f82bedaSAndriy Voskoboinyk static void
10349f82bedaSAndriy Voskoboinyk ieee80211_nulldata_transmitted(struct ieee80211_node *ni, void *arg,
10359f82bedaSAndriy Voskoboinyk     int status)
10369f82bedaSAndriy Voskoboinyk {
10379f82bedaSAndriy Voskoboinyk 	struct ieee80211vap *vap = ni->ni_vap;
10389f82bedaSAndriy Voskoboinyk 
10399f82bedaSAndriy Voskoboinyk 	wakeup(vap);
10409f82bedaSAndriy Voskoboinyk }
10419f82bedaSAndriy Voskoboinyk 
1042246b5467SSam Leffler /*
10436683931eSSam Leffler  * Send a null data frame to the specified node.  If the station
10446683931eSSam Leffler  * is setup for QoS then a QoS Null Data frame is constructed.
10456683931eSSam Leffler  * If this is a WDS station then a 4-address frame is constructed.
104619ad2dd7SSam Leffler  *
104719ad2dd7SSam Leffler  * NB: the caller is assumed to have setup a node reference
104819ad2dd7SSam Leffler  *     for use; this is necessary to deal with a race condition
1049b032f27cSSam Leffler  *     when probing for inactive stations.  Like ieee80211_mgmt_output
1050b032f27cSSam Leffler  *     we must cleanup any node reference on error;  however we
1051b032f27cSSam Leffler  *     can safely just unref it as we know it will never be the
1052b032f27cSSam Leffler  *     last reference to the node.
10538a1b9b6aSSam Leffler  */
10548a1b9b6aSSam Leffler int
1055f62121ceSSam Leffler ieee80211_send_nulldata(struct ieee80211_node *ni)
10568a1b9b6aSSam Leffler {
1057b032f27cSSam Leffler 	struct ieee80211vap *vap = ni->ni_vap;
1058f62121ceSSam Leffler 	struct ieee80211com *ic = ni->ni_ic;
10598a1b9b6aSSam Leffler 	struct mbuf *m;
10608a1b9b6aSSam Leffler 	struct ieee80211_frame *wh;
10616683931eSSam Leffler 	int hdrlen;
10626683931eSSam Leffler 	uint8_t *frm;
10635cda6006SAdrian Chadd 	int ret;
10648a1b9b6aSSam Leffler 
1065b032f27cSSam Leffler 	if (vap->iv_state == IEEE80211_S_CAC) {
1066b032f27cSSam Leffler 		IEEE80211_NOTE(vap, IEEE80211_MSG_OUTPUT | IEEE80211_MSG_DOTH,
1067b032f27cSSam Leffler 		    ni, "block %s frame in CAC state", "null data");
1068b032f27cSSam Leffler 		ieee80211_unref_node(&ni);
1069b032f27cSSam Leffler 		vap->iv_stats.is_tx_badstate++;
1070b032f27cSSam Leffler 		return EIO;		/* XXX */
1071b032f27cSSam Leffler 	}
1072b032f27cSSam Leffler 
10736683931eSSam Leffler 	if (ni->ni_flags & (IEEE80211_NODE_QOS|IEEE80211_NODE_HT))
10746683931eSSam Leffler 		hdrlen = sizeof(struct ieee80211_qosframe);
10756683931eSSam Leffler 	else
10766683931eSSam Leffler 		hdrlen = sizeof(struct ieee80211_frame);
10776683931eSSam Leffler 	/* NB: only WDS vap's get 4-address frames */
10786683931eSSam Leffler 	if (vap->iv_opmode == IEEE80211_M_WDS)
10796683931eSSam Leffler 		hdrlen += IEEE80211_ADDR_LEN;
10806683931eSSam Leffler 	if (ic->ic_flags & IEEE80211_F_DATAPAD)
10816683931eSSam Leffler 		hdrlen = roundup(hdrlen, sizeof(uint32_t));
10826683931eSSam Leffler 
10836683931eSSam Leffler 	m = ieee80211_getmgtframe(&frm, ic->ic_headroom + hdrlen, 0);
10848a1b9b6aSSam Leffler 	if (m == NULL) {
10858a1b9b6aSSam Leffler 		/* XXX debug msg */
108619ad2dd7SSam Leffler 		ieee80211_unref_node(&ni);
1087b032f27cSSam Leffler 		vap->iv_stats.is_tx_nobuf++;
10888a1b9b6aSSam Leffler 		return ENOMEM;
10898a1b9b6aSSam Leffler 	}
10906683931eSSam Leffler 	KASSERT(M_LEADINGSPACE(m) >= hdrlen,
10916683931eSSam Leffler 	    ("leading space %zd", M_LEADINGSPACE(m)));
1092eb1b1807SGleb Smirnoff 	M_PREPEND(m, hdrlen, M_NOWAIT);
10936683931eSSam Leffler 	if (m == NULL) {
10946683931eSSam Leffler 		/* NB: cannot happen */
10956683931eSSam Leffler 		ieee80211_free_node(ni);
10966683931eSSam Leffler 		return ENOMEM;
10976683931eSSam Leffler 	}
10988a1b9b6aSSam Leffler 
10995cda6006SAdrian Chadd 	IEEE80211_TX_LOCK(ic);
11005cda6006SAdrian Chadd 
11016683931eSSam Leffler 	wh = mtod(m, struct ieee80211_frame *);		/* NB: a little lie */
11026683931eSSam Leffler 	if (ni->ni_flags & IEEE80211_NODE_QOS) {
11036683931eSSam Leffler 		const int tid = WME_AC_TO_TID(WME_AC_BE);
11046683931eSSam Leffler 		uint8_t *qos;
11056683931eSSam Leffler 
11069e80b1dfSSam Leffler 		ieee80211_send_setup(ni, m,
11076683931eSSam Leffler 		    IEEE80211_FC0_TYPE_DATA | IEEE80211_FC0_SUBTYPE_QOS_NULL,
11086683931eSSam Leffler 		    tid, vap->iv_myaddr, ni->ni_macaddr, ni->ni_bssid);
11096683931eSSam Leffler 
11106683931eSSam Leffler 		if (vap->iv_opmode == IEEE80211_M_WDS)
11116683931eSSam Leffler 			qos = ((struct ieee80211_qosframe_addr4 *) wh)->i_qos;
11126683931eSSam Leffler 		else
11136683931eSSam Leffler 			qos = ((struct ieee80211_qosframe *) wh)->i_qos;
11146683931eSSam Leffler 		qos[0] = tid & IEEE80211_QOS_TID;
11156683931eSSam Leffler 		if (ic->ic_wme.wme_wmeChanParams.cap_wmeParams[WME_AC_BE].wmep_noackPolicy)
11166683931eSSam Leffler 			qos[0] |= IEEE80211_QOS_ACKPOLICY_NOACK;
11176683931eSSam Leffler 		qos[1] = 0;
11186683931eSSam Leffler 	} else {
11199e80b1dfSSam Leffler 		ieee80211_send_setup(ni, m,
1120add59d08SSam Leffler 		    IEEE80211_FC0_TYPE_DATA | IEEE80211_FC0_SUBTYPE_NODATA,
11218ac160cdSSam Leffler 		    IEEE80211_NONQOS_TID,
1122b032f27cSSam Leffler 		    vap->iv_myaddr, ni->ni_macaddr, ni->ni_bssid);
11236683931eSSam Leffler 	}
1124b032f27cSSam Leffler 	if (vap->iv_opmode != IEEE80211_M_WDS) {
1125add59d08SSam Leffler 		/* NB: power management bit is never sent by an AP */
1126add59d08SSam Leffler 		if ((ni->ni_flags & IEEE80211_NODE_PWR_MGT) &&
1127b032f27cSSam Leffler 		    vap->iv_opmode != IEEE80211_M_HOSTAP)
1128add59d08SSam Leffler 			wh->i_fc[1] |= IEEE80211_FC1_PWR_MGT;
1129b032f27cSSam Leffler 	}
11309f82bedaSAndriy Voskoboinyk 	if ((ic->ic_flags & IEEE80211_F_SCAN) &&
11319f82bedaSAndriy Voskoboinyk 	    (ni->ni_flags & IEEE80211_NODE_PWR_MGT)) {
11329f82bedaSAndriy Voskoboinyk 		ieee80211_add_callback(m, ieee80211_nulldata_transmitted,
11339f82bedaSAndriy Voskoboinyk 		    NULL);
11349f82bedaSAndriy Voskoboinyk 	}
11356683931eSSam Leffler 	m->m_len = m->m_pkthdr.len = hdrlen;
1136c1af44bdSSam Leffler 	m->m_flags |= M_ENCAP;		/* mark encapsulated */
11376683931eSSam Leffler 
1138bb239ce9SSam Leffler 	M_WME_SETAC(m, WME_AC_BE);
11398a1b9b6aSSam Leffler 
11408a1b9b6aSSam Leffler 	IEEE80211_NODE_STAT(ni, tx_data);
11418a1b9b6aSSam Leffler 
1142b032f27cSSam Leffler 	IEEE80211_NOTE(vap, IEEE80211_MSG_DEBUG | IEEE80211_MSG_DUMPPKTS, ni,
11436683931eSSam Leffler 	    "send %snull data frame on channel %u, pwr mgt %s",
11446683931eSSam Leffler 	    ni->ni_flags & IEEE80211_NODE_QOS ? "QoS " : "",
1145b5c99415SSam Leffler 	    ieee80211_chan2ieee(ic, ic->ic_curchan),
1146add59d08SSam Leffler 	    wh->i_fc[1] & IEEE80211_FC1_PWR_MGT ? "ena" : "dis");
1147add59d08SSam Leffler 
11485cda6006SAdrian Chadd 	ret = ieee80211_raw_output(vap, ni, m, NULL);
11495cda6006SAdrian Chadd 	IEEE80211_TX_UNLOCK(ic);
11505cda6006SAdrian Chadd 	return (ret);
11518a1b9b6aSSam Leffler }
11528a1b9b6aSSam Leffler 
11538a1b9b6aSSam Leffler /*
11548a1b9b6aSSam Leffler  * Assign priority to a frame based on any vlan tag assigned
11558a1b9b6aSSam Leffler  * to the station and/or any Diffserv setting in an IP header.
11568a1b9b6aSSam Leffler  * Finally, if an ACM policy is setup (in station mode) it's
11578a1b9b6aSSam Leffler  * applied.
11588a1b9b6aSSam Leffler  */
11598a1b9b6aSSam Leffler int
1160b032f27cSSam Leffler ieee80211_classify(struct ieee80211_node *ni, struct mbuf *m)
11618a1b9b6aSSam Leffler {
1162bcabc908SAndriy Voskoboinyk 	const struct ether_header *eh = NULL;
1163bcabc908SAndriy Voskoboinyk 	uint16_t ether_type;
11648a1b9b6aSSam Leffler 	int v_wme_ac, d_wme_ac, ac;
11658a1b9b6aSSam Leffler 
1166bcabc908SAndriy Voskoboinyk 	if (__predict_false(m->m_flags & M_ENCAP)) {
1167bcabc908SAndriy Voskoboinyk 		struct ieee80211_frame *wh = mtod(m, struct ieee80211_frame *);
1168bcabc908SAndriy Voskoboinyk 		struct llc *llc;
1169bcabc908SAndriy Voskoboinyk 		int hdrlen, subtype;
1170bcabc908SAndriy Voskoboinyk 
1171bcabc908SAndriy Voskoboinyk 		subtype = wh->i_fc[0] & IEEE80211_FC0_SUBTYPE_MASK;
1172bcabc908SAndriy Voskoboinyk 		if (subtype & IEEE80211_FC0_SUBTYPE_NODATA) {
1173bcabc908SAndriy Voskoboinyk 			ac = WME_AC_BE;
1174bcabc908SAndriy Voskoboinyk 			goto done;
1175bcabc908SAndriy Voskoboinyk 		}
1176bcabc908SAndriy Voskoboinyk 
1177bcabc908SAndriy Voskoboinyk 		hdrlen = ieee80211_hdrsize(wh);
1178bcabc908SAndriy Voskoboinyk 		if (m->m_pkthdr.len < hdrlen + sizeof(*llc))
1179bcabc908SAndriy Voskoboinyk 			return 1;
1180bcabc908SAndriy Voskoboinyk 
1181bcabc908SAndriy Voskoboinyk 		llc = (struct llc *)mtodo(m, hdrlen);
1182bcabc908SAndriy Voskoboinyk 		if (llc->llc_dsap != LLC_SNAP_LSAP ||
1183bcabc908SAndriy Voskoboinyk 		    llc->llc_ssap != LLC_SNAP_LSAP ||
1184bcabc908SAndriy Voskoboinyk 		    llc->llc_control != LLC_UI ||
1185bcabc908SAndriy Voskoboinyk 		    llc->llc_snap.org_code[0] != 0 ||
1186bcabc908SAndriy Voskoboinyk 		    llc->llc_snap.org_code[1] != 0 ||
1187bcabc908SAndriy Voskoboinyk 		    llc->llc_snap.org_code[2] != 0)
1188bcabc908SAndriy Voskoboinyk 			return 1;
1189bcabc908SAndriy Voskoboinyk 
1190bcabc908SAndriy Voskoboinyk 		ether_type = llc->llc_snap.ether_type;
1191bcabc908SAndriy Voskoboinyk 	} else {
1192bcabc908SAndriy Voskoboinyk 		eh = mtod(m, struct ether_header *);
1193bcabc908SAndriy Voskoboinyk 		ether_type = eh->ether_type;
1194bcabc908SAndriy Voskoboinyk 	}
1195bcabc908SAndriy Voskoboinyk 
1196b032f27cSSam Leffler 	/*
1197b032f27cSSam Leffler 	 * Always promote PAE/EAPOL frames to high priority.
1198b032f27cSSam Leffler 	 */
1199bcabc908SAndriy Voskoboinyk 	if (ether_type == htons(ETHERTYPE_PAE)) {
1200b032f27cSSam Leffler 		/* NB: mark so others don't need to check header */
1201b032f27cSSam Leffler 		m->m_flags |= M_EAPOL;
1202b032f27cSSam Leffler 		ac = WME_AC_VO;
1203b032f27cSSam Leffler 		goto done;
1204b032f27cSSam Leffler 	}
1205b032f27cSSam Leffler 	/*
1206b032f27cSSam Leffler 	 * Non-qos traffic goes to BE.
1207b032f27cSSam Leffler 	 */
12088a1b9b6aSSam Leffler 	if ((ni->ni_flags & IEEE80211_NODE_QOS) == 0) {
12098a1b9b6aSSam Leffler 		ac = WME_AC_BE;
12108a1b9b6aSSam Leffler 		goto done;
12118a1b9b6aSSam Leffler 	}
12128a1b9b6aSSam Leffler 
12138a1b9b6aSSam Leffler 	/*
12148a1b9b6aSSam Leffler 	 * If node has a vlan tag then all traffic
12158a1b9b6aSSam Leffler 	 * to it must have a matching tag.
12168a1b9b6aSSam Leffler 	 */
12178a1b9b6aSSam Leffler 	v_wme_ac = 0;
12188a1b9b6aSSam Leffler 	if (ni->ni_vlan != 0) {
121978ba57b9SAndre Oppermann 		 if ((m->m_flags & M_VLANTAG) == 0) {
12208a1b9b6aSSam Leffler 			IEEE80211_NODE_STAT(ni, tx_novlantag);
12218a1b9b6aSSam Leffler 			return 1;
12228a1b9b6aSSam Leffler 		}
122378ba57b9SAndre Oppermann 		if (EVL_VLANOFTAG(m->m_pkthdr.ether_vtag) !=
12248a1b9b6aSSam Leffler 		    EVL_VLANOFTAG(ni->ni_vlan)) {
12258a1b9b6aSSam Leffler 			IEEE80211_NODE_STAT(ni, tx_vlanmismatch);
12268a1b9b6aSSam Leffler 			return 1;
12278a1b9b6aSSam Leffler 		}
12288a1b9b6aSSam Leffler 		/* map vlan priority to AC */
1229f4558c9aSSam Leffler 		v_wme_ac = TID_TO_WME_AC(EVL_PRIOFTAG(ni->ni_vlan));
12308a1b9b6aSSam Leffler 	}
12318a1b9b6aSSam Leffler 
1232e755a73dSSam Leffler 	/* XXX m_copydata may be too slow for fast path */
12338a1b9b6aSSam Leffler #ifdef INET
1234bcabc908SAndriy Voskoboinyk 	if (eh && eh->ether_type == htons(ETHERTYPE_IP)) {
1235f4558c9aSSam Leffler 		uint8_t tos;
12368a1b9b6aSSam Leffler 		/*
1237f4558c9aSSam Leffler 		 * IP frame, map the DSCP bits from the TOS field.
12388a1b9b6aSSam Leffler 		 */
1239f4558c9aSSam Leffler 		/* NB: ip header may not be in first mbuf */
1240f4558c9aSSam Leffler 		m_copydata(m, sizeof(struct ether_header) +
1241f4558c9aSSam Leffler 		    offsetof(struct ip, ip_tos), sizeof(tos), &tos);
1242f4558c9aSSam Leffler 		tos >>= 5;		/* NB: ECN + low 3 bits of DSCP */
1243f4558c9aSSam Leffler 		d_wme_ac = TID_TO_WME_AC(tos);
12448a1b9b6aSSam Leffler 	} else {
12458a1b9b6aSSam Leffler #endif /* INET */
1246e755a73dSSam Leffler #ifdef INET6
1247bcabc908SAndriy Voskoboinyk 	if (eh && eh->ether_type == htons(ETHERTYPE_IPV6)) {
1248e755a73dSSam Leffler 		uint32_t flow;
1249e755a73dSSam Leffler 		uint8_t tos;
1250e755a73dSSam Leffler 		/*
12516ffd0ca9SBjoern A. Zeeb 		 * IPv6 frame, map the DSCP bits from the traffic class field.
1252e755a73dSSam Leffler 		 */
1253e755a73dSSam Leffler 		m_copydata(m, sizeof(struct ether_header) +
1254e755a73dSSam Leffler 		    offsetof(struct ip6_hdr, ip6_flow), sizeof(flow),
1255e755a73dSSam Leffler 		    (caddr_t) &flow);
1256e755a73dSSam Leffler 		tos = (uint8_t)(ntohl(flow) >> 20);
1257e755a73dSSam Leffler 		tos >>= 5;		/* NB: ECN + low 3 bits of DSCP */
1258e755a73dSSam Leffler 		d_wme_ac = TID_TO_WME_AC(tos);
1259e755a73dSSam Leffler 	} else {
1260e755a73dSSam Leffler #endif /* INET6 */
12618a1b9b6aSSam Leffler 		d_wme_ac = WME_AC_BE;
1262e755a73dSSam Leffler #ifdef INET6
1263e755a73dSSam Leffler 	}
1264e755a73dSSam Leffler #endif
12658a1b9b6aSSam Leffler #ifdef INET
12668a1b9b6aSSam Leffler 	}
12678a1b9b6aSSam Leffler #endif
12688a1b9b6aSSam Leffler 	/*
12698a1b9b6aSSam Leffler 	 * Use highest priority AC.
12708a1b9b6aSSam Leffler 	 */
12718a1b9b6aSSam Leffler 	if (v_wme_ac > d_wme_ac)
12728a1b9b6aSSam Leffler 		ac = v_wme_ac;
12738a1b9b6aSSam Leffler 	else
12748a1b9b6aSSam Leffler 		ac = d_wme_ac;
12758a1b9b6aSSam Leffler 
12768a1b9b6aSSam Leffler 	/*
12778a1b9b6aSSam Leffler 	 * Apply ACM policy.
12788a1b9b6aSSam Leffler 	 */
1279b032f27cSSam Leffler 	if (ni->ni_vap->iv_opmode == IEEE80211_M_STA) {
12808a1b9b6aSSam Leffler 		static const int acmap[4] = {
12818a1b9b6aSSam Leffler 			WME_AC_BK,	/* WME_AC_BE */
12828a1b9b6aSSam Leffler 			WME_AC_BK,	/* WME_AC_BK */
12838a1b9b6aSSam Leffler 			WME_AC_BE,	/* WME_AC_VI */
12848a1b9b6aSSam Leffler 			WME_AC_VI,	/* WME_AC_VO */
12858a1b9b6aSSam Leffler 		};
1286b032f27cSSam Leffler 		struct ieee80211com *ic = ni->ni_ic;
1287b032f27cSSam Leffler 
12888a1b9b6aSSam Leffler 		while (ac != WME_AC_BK &&
12898a1b9b6aSSam Leffler 		    ic->ic_wme.wme_wmeBssChanParams.cap_wmeParams[ac].wmep_acm)
12908a1b9b6aSSam Leffler 			ac = acmap[ac];
12918a1b9b6aSSam Leffler 	}
12928a1b9b6aSSam Leffler done:
12938a1b9b6aSSam Leffler 	M_WME_SETAC(m, ac);
12948a1b9b6aSSam Leffler 	return 0;
12958a1b9b6aSSam Leffler }
12968a1b9b6aSSam Leffler 
12978a1b9b6aSSam Leffler /*
12985e923d2eSSam Leffler  * Insure there is sufficient contiguous space to encapsulate the
12995e923d2eSSam Leffler  * 802.11 data frame.  If room isn't already there, arrange for it.
13005e923d2eSSam Leffler  * Drivers and cipher modules assume we have done the necessary work
13015e923d2eSSam Leffler  * and fail rudely if they don't find the space they need.
13025e923d2eSSam Leffler  */
1303616190d0SSam Leffler struct mbuf *
1304b032f27cSSam Leffler ieee80211_mbuf_adjust(struct ieee80211vap *vap, int hdrsize,
13055e923d2eSSam Leffler 	struct ieee80211_key *key, struct mbuf *m)
13065e923d2eSSam Leffler {
1307ab96db10SSam Leffler #define	TO_BE_RECLAIMED	(sizeof(struct ether_header) - sizeof(struct llc))
1308b032f27cSSam Leffler 	int needed_space = vap->iv_ic->ic_headroom + hdrsize;
13095e923d2eSSam Leffler 
13105e923d2eSSam Leffler 	if (key != NULL) {
13115e923d2eSSam Leffler 		/* XXX belongs in crypto code? */
13125e923d2eSSam Leffler 		needed_space += key->wk_cipher->ic_header;
13135e923d2eSSam Leffler 		/* XXX frags */
131483a244dbSSam Leffler 		/*
131583a244dbSSam Leffler 		 * When crypto is being done in the host we must insure
131683a244dbSSam Leffler 		 * the data are writable for the cipher routines; clone
131783a244dbSSam Leffler 		 * a writable mbuf chain.
131883a244dbSSam Leffler 		 * XXX handle SWMIC specially
131983a244dbSSam Leffler 		 */
13205c1f7f19SSam Leffler 		if (key->wk_flags & (IEEE80211_KEY_SWENCRYPT|IEEE80211_KEY_SWENMIC)) {
132183a244dbSSam Leffler 			m = m_unshare(m, M_NOWAIT);
132283a244dbSSam Leffler 			if (m == NULL) {
1323b032f27cSSam Leffler 				IEEE80211_DPRINTF(vap, IEEE80211_MSG_OUTPUT,
132483a244dbSSam Leffler 				    "%s: cannot get writable mbuf\n", __func__);
1325b032f27cSSam Leffler 				vap->iv_stats.is_tx_nobuf++; /* XXX new stat */
132683a244dbSSam Leffler 				return NULL;
132783a244dbSSam Leffler 			}
132883a244dbSSam Leffler 		}
13295e923d2eSSam Leffler 	}
13305e923d2eSSam Leffler 	/*
13315e923d2eSSam Leffler 	 * We know we are called just before stripping an Ethernet
13325e923d2eSSam Leffler 	 * header and prepending an LLC header.  This means we know
13335e923d2eSSam Leffler 	 * there will be
1334ab96db10SSam Leffler 	 *	sizeof(struct ether_header) - sizeof(struct llc)
13355e923d2eSSam Leffler 	 * bytes recovered to which we need additional space for the
13365e923d2eSSam Leffler 	 * 802.11 header and any crypto header.
13375e923d2eSSam Leffler 	 */
13385e923d2eSSam Leffler 	/* XXX check trailing space and copy instead? */
13395e923d2eSSam Leffler 	if (M_LEADINGSPACE(m) < needed_space - TO_BE_RECLAIMED) {
13405e923d2eSSam Leffler 		struct mbuf *n = m_gethdr(M_NOWAIT, m->m_type);
13415e923d2eSSam Leffler 		if (n == NULL) {
1342b032f27cSSam Leffler 			IEEE80211_DPRINTF(vap, IEEE80211_MSG_OUTPUT,
13435e923d2eSSam Leffler 			    "%s: cannot expand storage\n", __func__);
1344b032f27cSSam Leffler 			vap->iv_stats.is_tx_nobuf++;
13455e923d2eSSam Leffler 			m_freem(m);
13465e923d2eSSam Leffler 			return NULL;
13475e923d2eSSam Leffler 		}
13485e923d2eSSam Leffler 		KASSERT(needed_space <= MHLEN,
1349d7b5c50bSAlfred Perlstein 		    ("not enough room, need %u got %d\n", needed_space, MHLEN));
13505e923d2eSSam Leffler 		/*
13515e923d2eSSam Leffler 		 * Setup new mbuf to have leading space to prepend the
13525e923d2eSSam Leffler 		 * 802.11 header and any crypto header bits that are
13535e923d2eSSam Leffler 		 * required (the latter are added when the driver calls
13545e923d2eSSam Leffler 		 * back to ieee80211_crypto_encap to do crypto encapsulation).
13555e923d2eSSam Leffler 		 */
13565e923d2eSSam Leffler 		/* NB: must be first 'cuz it clobbers m_data */
13575e923d2eSSam Leffler 		m_move_pkthdr(n, m);
13585e923d2eSSam Leffler 		n->m_len = 0;			/* NB: m_gethdr does not set */
13595e923d2eSSam Leffler 		n->m_data += needed_space;
13605e923d2eSSam Leffler 		/*
13615e923d2eSSam Leffler 		 * Pull up Ethernet header to create the expected layout.
13625e923d2eSSam Leffler 		 * We could use m_pullup but that's overkill (i.e. we don't
13635e923d2eSSam Leffler 		 * need the actual data) and it cannot fail so do it inline
13645e923d2eSSam Leffler 		 * for speed.
13655e923d2eSSam Leffler 		 */
13665e923d2eSSam Leffler 		/* NB: struct ether_header is known to be contiguous */
13675e923d2eSSam Leffler 		n->m_len += sizeof(struct ether_header);
13685e923d2eSSam Leffler 		m->m_len -= sizeof(struct ether_header);
13695e923d2eSSam Leffler 		m->m_data += sizeof(struct ether_header);
13705e923d2eSSam Leffler 		/*
13715e923d2eSSam Leffler 		 * Replace the head of the chain.
13725e923d2eSSam Leffler 		 */
13735e923d2eSSam Leffler 		n->m_next = m;
13745e923d2eSSam Leffler 		m = n;
13755e923d2eSSam Leffler 	}
13765e923d2eSSam Leffler 	return m;
13775e923d2eSSam Leffler #undef TO_BE_RECLAIMED
13785e923d2eSSam Leffler }
13795e923d2eSSam Leffler 
13805e923d2eSSam Leffler /*
13815e923d2eSSam Leffler  * Return the transmit key to use in sending a unicast frame.
13825e923d2eSSam Leffler  * If a unicast key is set we use that.  When no unicast key is set
13835e923d2eSSam Leffler  * we fall back to the default transmit key.
13848a1b9b6aSSam Leffler  */
13858a1b9b6aSSam Leffler static __inline struct ieee80211_key *
1386b032f27cSSam Leffler ieee80211_crypto_getucastkey(struct ieee80211vap *vap,
1387b032f27cSSam Leffler 	struct ieee80211_node *ni)
13888a1b9b6aSSam Leffler {
1389cda15ce1SSam Leffler 	if (IEEE80211_KEY_UNDEFINED(&ni->ni_ucastkey)) {
1390b032f27cSSam Leffler 		if (vap->iv_def_txkey == IEEE80211_KEYIX_NONE ||
1391b032f27cSSam Leffler 		    IEEE80211_KEY_UNDEFINED(&vap->iv_nw_keys[vap->iv_def_txkey]))
13928a1b9b6aSSam Leffler 			return NULL;
1393b032f27cSSam Leffler 		return &vap->iv_nw_keys[vap->iv_def_txkey];
13948a1b9b6aSSam Leffler 	} else {
13958a1b9b6aSSam Leffler 		return &ni->ni_ucastkey;
13968a1b9b6aSSam Leffler 	}
13975e923d2eSSam Leffler }
13985e923d2eSSam Leffler 
13995e923d2eSSam Leffler /*
14005e923d2eSSam Leffler  * Return the transmit key to use in sending a multicast frame.
14015e923d2eSSam Leffler  * Multicast traffic always uses the group key which is installed as
14025e923d2eSSam Leffler  * the default tx key.
14035e923d2eSSam Leffler  */
14045e923d2eSSam Leffler static __inline struct ieee80211_key *
1405b032f27cSSam Leffler ieee80211_crypto_getmcastkey(struct ieee80211vap *vap,
1406b032f27cSSam Leffler 	struct ieee80211_node *ni)
14075e923d2eSSam Leffler {
1408b032f27cSSam Leffler 	if (vap->iv_def_txkey == IEEE80211_KEYIX_NONE ||
1409b032f27cSSam Leffler 	    IEEE80211_KEY_UNDEFINED(&vap->iv_nw_keys[vap->iv_def_txkey]))
14105e923d2eSSam Leffler 		return NULL;
1411b032f27cSSam Leffler 	return &vap->iv_nw_keys[vap->iv_def_txkey];
14128a1b9b6aSSam Leffler }
14138a1b9b6aSSam Leffler 
14148a1b9b6aSSam Leffler /*
14158a1b9b6aSSam Leffler  * Encapsulate an outbound data frame.  The mbuf chain is updated.
14168a1b9b6aSSam Leffler  * If an error is encountered NULL is returned.  The caller is required
14178a1b9b6aSSam Leffler  * to provide a node reference and pullup the ethernet header in the
14188a1b9b6aSSam Leffler  * first mbuf.
1419b032f27cSSam Leffler  *
1420b032f27cSSam Leffler  * NB: Packet is assumed to be processed by ieee80211_classify which
1421b032f27cSSam Leffler  *     marked EAPOL frames w/ M_EAPOL.
14220a915fadSSam Leffler  */
14231a1e1d21SSam Leffler struct mbuf *
1424339ccfb3SSam Leffler ieee80211_encap(struct ieee80211vap *vap, struct ieee80211_node *ni,
1425339ccfb3SSam Leffler     struct mbuf *m)
14261a1e1d21SSam Leffler {
1427b032f27cSSam Leffler #define	WH4(wh)	((struct ieee80211_frame_addr4 *)(wh))
14283c314f6dSMonthadar Al Jaberi #define MC01(mc)	((struct ieee80211_meshcntl_ae01 *)mc)
1429b032f27cSSam Leffler 	struct ieee80211com *ic = ni->ni_ic;
143059aa14a9SRui Paulo #ifdef IEEE80211_SUPPORT_MESH
143159aa14a9SRui Paulo 	struct ieee80211_mesh_state *ms = vap->iv_mesh;
1432c104cff2SRui Paulo 	struct ieee80211_meshcntl_ae10 *mc;
14333c314f6dSMonthadar Al Jaberi 	struct ieee80211_mesh_route *rt = NULL;
14343c314f6dSMonthadar Al Jaberi 	int dir = -1;
143559aa14a9SRui Paulo #endif
14361a1e1d21SSam Leffler 	struct ether_header eh;
14371a1e1d21SSam Leffler 	struct ieee80211_frame *wh;
14388a1b9b6aSSam Leffler 	struct ieee80211_key *key;
14391a1e1d21SSam Leffler 	struct llc *llc;
14409764ef21SAdrian Chadd 	int hdrsize, hdrspace, datalen, addqos, txfrag, is4addr, is_mcast;
14419e80b1dfSSam Leffler 	ieee80211_seq seqno;
144259aa14a9SRui Paulo 	int meshhdrsize, meshae;
144359aa14a9SRui Paulo 	uint8_t *qos;
14441c7b0c84SAdrian Chadd 	int is_amsdu = 0;
14451a1e1d21SSam Leffler 
14465cda6006SAdrian Chadd 	IEEE80211_TX_LOCK_ASSERT(ic);
14475cda6006SAdrian Chadd 
14489764ef21SAdrian Chadd 	is_mcast = !! (m->m_flags & (M_MCAST | M_BCAST));
14499764ef21SAdrian Chadd 
145068e8e04eSSam Leffler 	/*
145168e8e04eSSam Leffler 	 * Copy existing Ethernet header to a safe place.  The
145268e8e04eSSam Leffler 	 * rest of the code assumes it's ok to strip it when
145368e8e04eSSam Leffler 	 * reorganizing state for the final encapsulation.
145468e8e04eSSam Leffler 	 */
14558a1b9b6aSSam Leffler 	KASSERT(m->m_len >= sizeof(eh), ("no ethernet header!"));
1456b032f27cSSam Leffler 	ETHER_HEADER_COPY(&eh, mtod(m, caddr_t));
14571a1e1d21SSam Leffler 
14588a1b9b6aSSam Leffler 	/*
14598a1b9b6aSSam Leffler 	 * Insure space for additional headers.  First identify
14608a1b9b6aSSam Leffler 	 * transmit key to use in calculating any buffer adjustments
14618a1b9b6aSSam Leffler 	 * required.  This is also used below to do privacy
14628a1b9b6aSSam Leffler 	 * encapsulation work.  Then calculate the 802.11 header
14638a1b9b6aSSam Leffler 	 * size and any padding required by the driver.
14648a1b9b6aSSam Leffler 	 *
14658a1b9b6aSSam Leffler 	 * Note key may be NULL if we fall back to the default
14668a1b9b6aSSam Leffler 	 * transmit key and that is not set.  In that case the
14678a1b9b6aSSam Leffler 	 * buffer may not be expanded as needed by the cipher
14688a1b9b6aSSam Leffler 	 * routines, but they will/should discard it.
14698a1b9b6aSSam Leffler 	 */
1470b032f27cSSam Leffler 	if (vap->iv_flags & IEEE80211_F_PRIVACY) {
1471b032f27cSSam Leffler 		if (vap->iv_opmode == IEEE80211_M_STA ||
1472b032f27cSSam Leffler 		    !IEEE80211_IS_MULTICAST(eh.ether_dhost) ||
1473b032f27cSSam Leffler 		    (vap->iv_opmode == IEEE80211_M_WDS &&
1474b032f27cSSam Leffler 		     (vap->iv_flags_ext & IEEE80211_FEXT_WDSLEGACY)))
1475b032f27cSSam Leffler 			key = ieee80211_crypto_getucastkey(vap, ni);
14765e923d2eSSam Leffler 		else
1477b032f27cSSam Leffler 			key = ieee80211_crypto_getmcastkey(vap, ni);
1478b032f27cSSam Leffler 		if (key == NULL && (m->m_flags & M_EAPOL) == 0) {
1479b032f27cSSam Leffler 			IEEE80211_NOTE_MAC(vap, IEEE80211_MSG_CRYPTO,
1480b032f27cSSam Leffler 			    eh.ether_dhost,
1481b032f27cSSam Leffler 			    "no default transmit key (%s) deftxkey %u",
1482b032f27cSSam Leffler 			    __func__, vap->iv_def_txkey);
1483b032f27cSSam Leffler 			vap->iv_stats.is_tx_nodefkey++;
1484d72c7253SSam Leffler 			goto bad;
14858a1b9b6aSSam Leffler 		}
14868a1b9b6aSSam Leffler 	} else
14878a1b9b6aSSam Leffler 		key = NULL;
14885e923d2eSSam Leffler 	/*
14895e923d2eSSam Leffler 	 * XXX Some ap's don't handle QoS-encapsulated EAPOL
14905e923d2eSSam Leffler 	 * frames so suppress use.  This may be an issue if other
14915e923d2eSSam Leffler 	 * ap's require all data frames to be QoS-encapsulated
14925e923d2eSSam Leffler 	 * once negotiated in which case we'll need to make this
14935e923d2eSSam Leffler 	 * configurable.
14949764ef21SAdrian Chadd 	 *
14959764ef21SAdrian Chadd 	 * Don't send multicast QoS frames.
14969764ef21SAdrian Chadd 	 * Technically multicast frames can be QoS if all stations in the
14979764ef21SAdrian Chadd 	 * BSS are also QoS.
14989764ef21SAdrian Chadd 	 *
14999764ef21SAdrian Chadd 	 * NB: mesh data frames are QoS, including multicast frames.
15005e923d2eSSam Leffler 	 */
15019764ef21SAdrian Chadd 	addqos =
15029764ef21SAdrian Chadd 	    (((is_mcast == 0) && (ni->ni_flags &
15039764ef21SAdrian Chadd 	     (IEEE80211_NODE_QOS|IEEE80211_NODE_HT))) ||
150491216c71SAdrian Chadd 	    (vap->iv_opmode == IEEE80211_M_MBSS)) &&
1505b032f27cSSam Leffler 	    (m->m_flags & M_EAPOL) == 0;
15069764ef21SAdrian Chadd 
15075e923d2eSSam Leffler 	if (addqos)
15088a1b9b6aSSam Leffler 		hdrsize = sizeof(struct ieee80211_qosframe);
15098a1b9b6aSSam Leffler 	else
15108a1b9b6aSSam Leffler 		hdrsize = sizeof(struct ieee80211_frame);
151159aa14a9SRui Paulo #ifdef IEEE80211_SUPPORT_MESH
151259aa14a9SRui Paulo 	if (vap->iv_opmode == IEEE80211_M_MBSS) {
151359aa14a9SRui Paulo 		/*
151459aa14a9SRui Paulo 		 * Mesh data frames are encapsulated according to the
151559aa14a9SRui Paulo 		 * rules of Section 11B.8.5 (p.139 of D3.0 spec).
151659aa14a9SRui Paulo 		 * o Group Addressed data (aka multicast) originating
151759aa14a9SRui Paulo 		 *   at the local sta are sent w/ 3-address format and
151859aa14a9SRui Paulo 		 *   address extension mode 00
151959aa14a9SRui Paulo 		 * o Individually Addressed data (aka unicast) originating
152059aa14a9SRui Paulo 		 *   at the local sta are sent w/ 4-address format and
152159aa14a9SRui Paulo 		 *   address extension mode 00
152259aa14a9SRui Paulo 		 * o Group Addressed data forwarded from a non-mesh sta are
152359aa14a9SRui Paulo 		 *   sent w/ 3-address format and address extension mode 01
152459aa14a9SRui Paulo 		 * o Individually Address data from another sta are sent
152559aa14a9SRui Paulo 		 *   w/ 4-address format and address extension mode 10
152659aa14a9SRui Paulo 		 */
152759aa14a9SRui Paulo 		is4addr = 0;		/* NB: don't use, disable */
15283c314f6dSMonthadar Al Jaberi 		if (!IEEE80211_IS_MULTICAST(eh.ether_dhost)) {
15293c314f6dSMonthadar Al Jaberi 			rt = ieee80211_mesh_rt_find(vap, eh.ether_dhost);
15303c314f6dSMonthadar Al Jaberi 			KASSERT(rt != NULL, ("route is NULL"));
15313c314f6dSMonthadar Al Jaberi 			dir = IEEE80211_FC1_DIR_DSTODS;
15323c314f6dSMonthadar Al Jaberi 			hdrsize += IEEE80211_ADDR_LEN;
15333c314f6dSMonthadar Al Jaberi 			if (rt->rt_flags & IEEE80211_MESHRT_FLAGS_PROXY) {
15343c314f6dSMonthadar Al Jaberi 				if (IEEE80211_ADDR_EQ(rt->rt_mesh_gate,
15353c314f6dSMonthadar Al Jaberi 				    vap->iv_myaddr)) {
15363c314f6dSMonthadar Al Jaberi 					IEEE80211_NOTE_MAC(vap,
15373c314f6dSMonthadar Al Jaberi 					    IEEE80211_MSG_MESH,
15383c314f6dSMonthadar Al Jaberi 					    eh.ether_dhost,
15393c314f6dSMonthadar Al Jaberi 					    "%s", "trying to send to ourself");
15403c314f6dSMonthadar Al Jaberi 					goto bad;
15413c314f6dSMonthadar Al Jaberi 				}
15423c314f6dSMonthadar Al Jaberi 				meshae = IEEE80211_MESH_AE_10;
15433c314f6dSMonthadar Al Jaberi 				meshhdrsize =
15443c314f6dSMonthadar Al Jaberi 				    sizeof(struct ieee80211_meshcntl_ae10);
154559aa14a9SRui Paulo 			} else {
15463c314f6dSMonthadar Al Jaberi 				meshae = IEEE80211_MESH_AE_00;
15473c314f6dSMonthadar Al Jaberi 				meshhdrsize =
15483c314f6dSMonthadar Al Jaberi 				    sizeof(struct ieee80211_meshcntl);
15493c314f6dSMonthadar Al Jaberi 			}
15503c314f6dSMonthadar Al Jaberi 		} else {
15513c314f6dSMonthadar Al Jaberi 			dir = IEEE80211_FC1_DIR_FROMDS;
15523c314f6dSMonthadar Al Jaberi 			if (!IEEE80211_ADDR_EQ(eh.ether_shost, vap->iv_myaddr)) {
15533c314f6dSMonthadar Al Jaberi 				/* proxy group */
15543c314f6dSMonthadar Al Jaberi 				meshae = IEEE80211_MESH_AE_01;
15553c314f6dSMonthadar Al Jaberi 				meshhdrsize =
15563c314f6dSMonthadar Al Jaberi 				    sizeof(struct ieee80211_meshcntl_ae01);
15573c314f6dSMonthadar Al Jaberi 			} else {
15583c314f6dSMonthadar Al Jaberi 				/* group */
15593c314f6dSMonthadar Al Jaberi 				meshae = IEEE80211_MESH_AE_00;
15603c314f6dSMonthadar Al Jaberi 				meshhdrsize = sizeof(struct ieee80211_meshcntl);
15613c314f6dSMonthadar Al Jaberi 			}
156259aa14a9SRui Paulo 		}
156359aa14a9SRui Paulo 	} else {
156459aa14a9SRui Paulo #endif
1565b032f27cSSam Leffler 		/*
1566b032f27cSSam Leffler 		 * 4-address frames need to be generated for:
15676437e6daSSam Leffler 		 * o packets sent through a WDS vap (IEEE80211_M_WDS)
1568f2a6a13cSSam Leffler 		 * o packets sent through a vap marked for relaying
1569f2a6a13cSSam Leffler 		 *   (e.g. a station operating with dynamic WDS)
1570b032f27cSSam Leffler 		 */
15716437e6daSSam Leffler 		is4addr = vap->iv_opmode == IEEE80211_M_WDS ||
1572f2a6a13cSSam Leffler 		    ((vap->iv_flags_ext & IEEE80211_FEXT_4ADDR) &&
1573b032f27cSSam Leffler 		     !IEEE80211_ADDR_EQ(eh.ether_shost, vap->iv_myaddr));
1574b032f27cSSam Leffler 		if (is4addr)
1575b032f27cSSam Leffler 			hdrsize += IEEE80211_ADDR_LEN;
157659aa14a9SRui Paulo 		meshhdrsize = meshae = 0;
157759aa14a9SRui Paulo #ifdef IEEE80211_SUPPORT_MESH
157859aa14a9SRui Paulo 	}
157959aa14a9SRui Paulo #endif
1580b032f27cSSam Leffler 	/*
1581b032f27cSSam Leffler 	 * Honor driver DATAPAD requirement.
1582b032f27cSSam Leffler 	 */
15838a1b9b6aSSam Leffler 	if (ic->ic_flags & IEEE80211_F_DATAPAD)
1584b032f27cSSam Leffler 		hdrspace = roundup(hdrsize, sizeof(uint32_t));
1585b032f27cSSam Leffler 	else
1586b032f27cSSam Leffler 		hdrspace = hdrsize;
158768e8e04eSSam Leffler 
1588616190d0SSam Leffler 	if (__predict_true((m->m_flags & M_FF) == 0)) {
158968e8e04eSSam Leffler 		/*
159068e8e04eSSam Leffler 		 * Normal frame.
159168e8e04eSSam Leffler 		 */
159259aa14a9SRui Paulo 		m = ieee80211_mbuf_adjust(vap, hdrspace + meshhdrsize, key, m);
15938a1b9b6aSSam Leffler 		if (m == NULL) {
15948a1b9b6aSSam Leffler 			/* NB: ieee80211_mbuf_adjust handles msgs+statistics */
15950a915fadSSam Leffler 			goto bad;
15960a915fadSSam Leffler 		}
159768e8e04eSSam Leffler 		/* NB: this could be optimized 'cuz of ieee80211_mbuf_adjust */
1598ab96db10SSam Leffler 		m_adj(m, sizeof(struct ether_header) - sizeof(struct llc));
15991a1e1d21SSam Leffler 		llc = mtod(m, struct llc *);
16001a1e1d21SSam Leffler 		llc->llc_dsap = llc->llc_ssap = LLC_SNAP_LSAP;
16011a1e1d21SSam Leffler 		llc->llc_control = LLC_UI;
16021a1e1d21SSam Leffler 		llc->llc_snap.org_code[0] = 0;
16031a1e1d21SSam Leffler 		llc->llc_snap.org_code[1] = 0;
16041a1e1d21SSam Leffler 		llc->llc_snap.org_code[2] = 0;
16051a1e1d21SSam Leffler 		llc->llc_snap.ether_type = eh.ether_type;
1606616190d0SSam Leffler 	} else {
1607616190d0SSam Leffler #ifdef IEEE80211_SUPPORT_SUPERG
1608339ccfb3SSam Leffler 		/*
16091c7b0c84SAdrian Chadd 		 * Aggregated frame.  Check if it's for AMSDU or FF.
16101c7b0c84SAdrian Chadd 		 *
16111c7b0c84SAdrian Chadd 		 * XXX TODO: IEEE80211_NODE_AMSDU* isn't implemented
16121c7b0c84SAdrian Chadd 		 * anywhere for some reason.  But, since 11n requires
16131c7b0c84SAdrian Chadd 		 * AMSDU RX, we can just assume "11n" == "AMSDU".
1614339ccfb3SSam Leffler 		 */
16151c7b0c84SAdrian Chadd 		IEEE80211_DPRINTF(vap, IEEE80211_MSG_SUPERG, "%s: called; M_FF\n", __func__);
16161c7b0c84SAdrian Chadd 		if (ieee80211_amsdu_tx_ok(ni)) {
16171c7b0c84SAdrian Chadd 			m = ieee80211_amsdu_encap(vap, m, hdrspace + meshhdrsize, key);
16181c7b0c84SAdrian Chadd 			is_amsdu = 1;
16191c7b0c84SAdrian Chadd 		} else {
162059aa14a9SRui Paulo 			m = ieee80211_ff_encap(vap, m, hdrspace + meshhdrsize, key);
16211c7b0c84SAdrian Chadd 		}
1622616190d0SSam Leffler 		if (m == NULL)
1623616190d0SSam Leffler #endif
1624616190d0SSam Leffler 			goto bad;
162568e8e04eSSam Leffler 	}
16268a1b9b6aSSam Leffler 	datalen = m->m_pkthdr.len;		/* NB: w/o 802.11 header */
16278a1b9b6aSSam Leffler 
1628eb1b1807SGleb Smirnoff 	M_PREPEND(m, hdrspace + meshhdrsize, M_NOWAIT);
16291be50176SSam Leffler 	if (m == NULL) {
1630b032f27cSSam Leffler 		vap->iv_stats.is_tx_nobuf++;
16310a915fadSSam Leffler 		goto bad;
16321be50176SSam Leffler 	}
16331a1e1d21SSam Leffler 	wh = mtod(m, struct ieee80211_frame *);
16341a1e1d21SSam Leffler 	wh->i_fc[0] = IEEE80211_FC0_VERSION_0 | IEEE80211_FC0_TYPE_DATA;
163568e8e04eSSam Leffler 	*(uint16_t *)wh->i_dur = 0;
163659aa14a9SRui Paulo 	qos = NULL;	/* NB: quiet compiler */
1637b032f27cSSam Leffler 	if (is4addr) {
1638b032f27cSSam Leffler 		wh->i_fc[1] = IEEE80211_FC1_DIR_DSTODS;
1639b032f27cSSam Leffler 		IEEE80211_ADDR_COPY(wh->i_addr1, ni->ni_macaddr);
1640b032f27cSSam Leffler 		IEEE80211_ADDR_COPY(wh->i_addr2, vap->iv_myaddr);
1641b032f27cSSam Leffler 		IEEE80211_ADDR_COPY(wh->i_addr3, eh.ether_dhost);
1642b032f27cSSam Leffler 		IEEE80211_ADDR_COPY(WH4(wh)->i_addr4, eh.ether_shost);
1643b032f27cSSam Leffler 	} else switch (vap->iv_opmode) {
16441a1e1d21SSam Leffler 	case IEEE80211_M_STA:
16451a1e1d21SSam Leffler 		wh->i_fc[1] = IEEE80211_FC1_DIR_TODS;
16461a1e1d21SSam Leffler 		IEEE80211_ADDR_COPY(wh->i_addr1, ni->ni_bssid);
16471a1e1d21SSam Leffler 		IEEE80211_ADDR_COPY(wh->i_addr2, eh.ether_shost);
16481a1e1d21SSam Leffler 		IEEE80211_ADDR_COPY(wh->i_addr3, eh.ether_dhost);
16491a1e1d21SSam Leffler 		break;
16501a1e1d21SSam Leffler 	case IEEE80211_M_IBSS:
16511a1e1d21SSam Leffler 	case IEEE80211_M_AHDEMO:
16521a1e1d21SSam Leffler 		wh->i_fc[1] = IEEE80211_FC1_DIR_NODS;
16531a1e1d21SSam Leffler 		IEEE80211_ADDR_COPY(wh->i_addr1, eh.ether_dhost);
16541a1e1d21SSam Leffler 		IEEE80211_ADDR_COPY(wh->i_addr2, eh.ether_shost);
1655a8b16e87SSam Leffler 		/*
1656b032f27cSSam Leffler 		 * NB: always use the bssid from iv_bss as the
1657a8b16e87SSam Leffler 		 *     neighbor's may be stale after an ibss merge
1658a8b16e87SSam Leffler 		 */
1659b032f27cSSam Leffler 		IEEE80211_ADDR_COPY(wh->i_addr3, vap->iv_bss->ni_bssid);
16601a1e1d21SSam Leffler 		break;
16611a1e1d21SSam Leffler 	case IEEE80211_M_HOSTAP:
16621a1e1d21SSam Leffler 		wh->i_fc[1] = IEEE80211_FC1_DIR_FROMDS;
16631a1e1d21SSam Leffler 		IEEE80211_ADDR_COPY(wh->i_addr1, eh.ether_dhost);
16641a1e1d21SSam Leffler 		IEEE80211_ADDR_COPY(wh->i_addr2, ni->ni_bssid);
16651a1e1d21SSam Leffler 		IEEE80211_ADDR_COPY(wh->i_addr3, eh.ether_shost);
16661a1e1d21SSam Leffler 		break;
166759aa14a9SRui Paulo #ifdef IEEE80211_SUPPORT_MESH
166859aa14a9SRui Paulo 	case IEEE80211_M_MBSS:
166959aa14a9SRui Paulo 		/* NB: offset by hdrspace to deal with DATAPAD */
1670c104cff2SRui Paulo 		mc = (struct ieee80211_meshcntl_ae10 *)
167159aa14a9SRui Paulo 		     (mtod(m, uint8_t *) + hdrspace);
16723c314f6dSMonthadar Al Jaberi 		wh->i_fc[1] = dir;
167359aa14a9SRui Paulo 		switch (meshae) {
16743c314f6dSMonthadar Al Jaberi 		case IEEE80211_MESH_AE_00:	/* no proxy */
167559aa14a9SRui Paulo 			mc->mc_flags = 0;
16763c314f6dSMonthadar Al Jaberi 			if (dir == IEEE80211_FC1_DIR_DSTODS) { /* ucast */
16773c314f6dSMonthadar Al Jaberi 				IEEE80211_ADDR_COPY(wh->i_addr1,
16783c314f6dSMonthadar Al Jaberi 				    ni->ni_macaddr);
16793c314f6dSMonthadar Al Jaberi 				IEEE80211_ADDR_COPY(wh->i_addr2,
16803c314f6dSMonthadar Al Jaberi 				    vap->iv_myaddr);
16813c314f6dSMonthadar Al Jaberi 				IEEE80211_ADDR_COPY(wh->i_addr3,
16823c314f6dSMonthadar Al Jaberi 				    eh.ether_dhost);
16833c314f6dSMonthadar Al Jaberi 				IEEE80211_ADDR_COPY(WH4(wh)->i_addr4,
16843c314f6dSMonthadar Al Jaberi 				    eh.ether_shost);
16853c314f6dSMonthadar Al Jaberi 				qos =((struct ieee80211_qosframe_addr4 *)
16863c314f6dSMonthadar Al Jaberi 				    wh)->i_qos;
16873c314f6dSMonthadar Al Jaberi 			} else if (dir == IEEE80211_FC1_DIR_FROMDS) {
16883c314f6dSMonthadar Al Jaberi 				 /* mcast */
16893c314f6dSMonthadar Al Jaberi 				IEEE80211_ADDR_COPY(wh->i_addr1,
16903c314f6dSMonthadar Al Jaberi 				    eh.ether_dhost);
16913c314f6dSMonthadar Al Jaberi 				IEEE80211_ADDR_COPY(wh->i_addr2,
16923c314f6dSMonthadar Al Jaberi 				    vap->iv_myaddr);
16933c314f6dSMonthadar Al Jaberi 				IEEE80211_ADDR_COPY(wh->i_addr3,
16943c314f6dSMonthadar Al Jaberi 				    eh.ether_shost);
16953c314f6dSMonthadar Al Jaberi 				qos = ((struct ieee80211_qosframe *)
16963c314f6dSMonthadar Al Jaberi 				    wh)->i_qos;
16973c314f6dSMonthadar Al Jaberi 			}
169859aa14a9SRui Paulo 			break;
16993c314f6dSMonthadar Al Jaberi 		case IEEE80211_MESH_AE_01:	/* mcast, proxy */
170059aa14a9SRui Paulo 			wh->i_fc[1] = IEEE80211_FC1_DIR_FROMDS;
170159aa14a9SRui Paulo 			IEEE80211_ADDR_COPY(wh->i_addr1, eh.ether_dhost);
170259aa14a9SRui Paulo 			IEEE80211_ADDR_COPY(wh->i_addr2, vap->iv_myaddr);
1703c104cff2SRui Paulo 			IEEE80211_ADDR_COPY(wh->i_addr3, vap->iv_myaddr);
170459aa14a9SRui Paulo 			mc->mc_flags = 1;
17053c314f6dSMonthadar Al Jaberi 			IEEE80211_ADDR_COPY(MC01(mc)->mc_addr4,
17063c314f6dSMonthadar Al Jaberi 			    eh.ether_shost);
170759aa14a9SRui Paulo 			qos = ((struct ieee80211_qosframe *) wh)->i_qos;
170859aa14a9SRui Paulo 			break;
17093c314f6dSMonthadar Al Jaberi 		case IEEE80211_MESH_AE_10:	/* ucast, proxy */
17103c314f6dSMonthadar Al Jaberi 			KASSERT(rt != NULL, ("route is NULL"));
17113c314f6dSMonthadar Al Jaberi 			IEEE80211_ADDR_COPY(wh->i_addr1, rt->rt_nexthop);
171259aa14a9SRui Paulo 			IEEE80211_ADDR_COPY(wh->i_addr2, vap->iv_myaddr);
17133c314f6dSMonthadar Al Jaberi 			IEEE80211_ADDR_COPY(wh->i_addr3, rt->rt_mesh_gate);
1714c104cff2SRui Paulo 			IEEE80211_ADDR_COPY(WH4(wh)->i_addr4, vap->iv_myaddr);
17153c314f6dSMonthadar Al Jaberi 			mc->mc_flags = IEEE80211_MESH_AE_10;
17163c314f6dSMonthadar Al Jaberi 			IEEE80211_ADDR_COPY(mc->mc_addr5, eh.ether_dhost);
17173c314f6dSMonthadar Al Jaberi 			IEEE80211_ADDR_COPY(mc->mc_addr6, eh.ether_shost);
171859aa14a9SRui Paulo 			qos = ((struct ieee80211_qosframe_addr4 *) wh)->i_qos;
171959aa14a9SRui Paulo 			break;
172059aa14a9SRui Paulo 		default:
172159aa14a9SRui Paulo 			KASSERT(0, ("meshae %d", meshae));
172259aa14a9SRui Paulo 			break;
172359aa14a9SRui Paulo 		}
172459aa14a9SRui Paulo 		mc->mc_ttl = ms->ms_ttl;
172559aa14a9SRui Paulo 		ms->ms_seq++;
172631021a2bSAndriy Voskoboinyk 		le32enc(mc->mc_seq, ms->ms_seq);
172759aa14a9SRui Paulo 		break;
172859aa14a9SRui Paulo #endif
1729b032f27cSSam Leffler 	case IEEE80211_M_WDS:		/* NB: is4addr should always be true */
173059aa14a9SRui Paulo 	default:
17310a915fadSSam Leffler 		goto bad;
17321a1e1d21SSam Leffler 	}
1733bc5627d9SSam Leffler 	if (m->m_flags & M_MORE_DATA)
1734bc5627d9SSam Leffler 		wh->i_fc[1] |= IEEE80211_FC1_MORE_DATA;
17355e923d2eSSam Leffler 	if (addqos) {
17368a1b9b6aSSam Leffler 		int ac, tid;
17378a1b9b6aSSam Leffler 
1738b032f27cSSam Leffler 		if (is4addr) {
1739b032f27cSSam Leffler 			qos = ((struct ieee80211_qosframe_addr4 *) wh)->i_qos;
174059aa14a9SRui Paulo 		/* NB: mesh case handled earlier */
174159aa14a9SRui Paulo 		} else if (vap->iv_opmode != IEEE80211_M_MBSS)
1742b032f27cSSam Leffler 			qos = ((struct ieee80211_qosframe *) wh)->i_qos;
17438a1b9b6aSSam Leffler 		ac = M_WME_GETAC(m);
17448a1b9b6aSSam Leffler 		/* map from access class/queue to 11e header priorty value */
17458a1b9b6aSSam Leffler 		tid = WME_AC_TO_TID(ac);
1746b032f27cSSam Leffler 		qos[0] = tid & IEEE80211_QOS_TID;
17478a1b9b6aSSam Leffler 		if (ic->ic_wme.wme_wmeChanParams.cap_wmeParams[ac].wmep_noackPolicy)
1748b032f27cSSam Leffler 			qos[0] |= IEEE80211_QOS_ACKPOLICY_NOACK;
174991216c71SAdrian Chadd #ifdef IEEE80211_SUPPORT_MESH
1750d566999aSMonthadar Al Jaberi 		if (vap->iv_opmode == IEEE80211_M_MBSS)
1751d566999aSMonthadar Al Jaberi 			qos[1] = IEEE80211_QOS_MC;
1752d566999aSMonthadar Al Jaberi 		else
175391216c71SAdrian Chadd #endif
1754b032f27cSSam Leffler 			qos[1] = 0;
1755b032f27cSSam Leffler 		wh->i_fc[0] |= IEEE80211_FC0_SUBTYPE_QOS;
17568a1b9b6aSSam Leffler 
17571c7b0c84SAdrian Chadd 		/*
17581c7b0c84SAdrian Chadd 		 * If this is an A-MSDU then ensure we set the
17591c7b0c84SAdrian Chadd 		 * relevant field.
17601c7b0c84SAdrian Chadd 		 */
17611c7b0c84SAdrian Chadd 		if (is_amsdu)
17621c7b0c84SAdrian Chadd 			qos[0] |= IEEE80211_QOS_AMSDU;
17631c7b0c84SAdrian Chadd 
176451172f62SAdrian Chadd 		/*
176551172f62SAdrian Chadd 		 * XXX TODO TX lock is needed for atomic updates of sequence
176651172f62SAdrian Chadd 		 * numbers.  If the driver does it, then don't do it here;
176751172f62SAdrian Chadd 		 * and we don't need the TX lock held.
176851172f62SAdrian Chadd 		 */
176945f856e3SSam Leffler 		if ((m->m_flags & M_AMPDU_MPDU) == 0) {
177045f856e3SSam Leffler 			/*
17719764ef21SAdrian Chadd 			 * 802.11-2012 9.3.2.10 -
17729764ef21SAdrian Chadd 			 *
17739764ef21SAdrian Chadd 			 * If this is a multicast frame then we need
17749764ef21SAdrian Chadd 			 * to ensure that the sequence number comes from
17759764ef21SAdrian Chadd 			 * a separate seqno space and not the TID space.
17769764ef21SAdrian Chadd 			 *
17779764ef21SAdrian Chadd 			 * Otherwise multicast frames may actually cause
17789764ef21SAdrian Chadd 			 * holes in the TX blockack window space and
17799764ef21SAdrian Chadd 			 * upset various things.
17809764ef21SAdrian Chadd 			 */
17819764ef21SAdrian Chadd 			if (IEEE80211_IS_MULTICAST(wh->i_addr1))
17829764ef21SAdrian Chadd 				seqno = ni->ni_txseqs[IEEE80211_NONQOS_TID]++;
17839764ef21SAdrian Chadd 			else
17849764ef21SAdrian Chadd 				seqno = ni->ni_txseqs[tid]++;
17859764ef21SAdrian Chadd 
17869764ef21SAdrian Chadd 			/*
178745f856e3SSam Leffler 			 * NB: don't assign a sequence # to potential
178845f856e3SSam Leffler 			 * aggregates; we expect this happens at the
178945f856e3SSam Leffler 			 * point the frame comes off any aggregation q
179045f856e3SSam Leffler 			 * as otherwise we may introduce holes in the
179145f856e3SSam Leffler 			 * BA sequence space and/or make window accouting
179245f856e3SSam Leffler 			 * more difficult.
179345f856e3SSam Leffler 			 *
179445f856e3SSam Leffler 			 * XXX may want to control this with a driver
179545f856e3SSam Leffler 			 * capability; this may also change when we pull
179645f856e3SSam Leffler 			 * aggregation up into net80211
179745f856e3SSam Leffler 			 */
179868e8e04eSSam Leffler 			*(uint16_t *)wh->i_seq =
17999e80b1dfSSam Leffler 			    htole16(seqno << IEEE80211_SEQ_SEQ_SHIFT);
18009a841c7fSSam Leffler 			M_SEQNO_SET(m, seqno);
18012db223f9SAndriy Voskoboinyk 		} else {
18022db223f9SAndriy Voskoboinyk 			/* NB: zero out i_seq field (for s/w encryption etc) */
18032db223f9SAndriy Voskoboinyk 			*(uint16_t *)wh->i_seq = 0;
180445f856e3SSam Leffler 		}
18058a1b9b6aSSam Leffler 	} else {
180651172f62SAdrian Chadd 		/*
180751172f62SAdrian Chadd 		 * XXX TODO TX lock is needed for atomic updates of sequence
180851172f62SAdrian Chadd 		 * numbers.  If the driver does it, then don't do it here;
180951172f62SAdrian Chadd 		 * and we don't need the TX lock held.
181051172f62SAdrian Chadd 		 */
18119e80b1dfSSam Leffler 		seqno = ni->ni_txseqs[IEEE80211_NONQOS_TID]++;
181268e8e04eSSam Leffler 		*(uint16_t *)wh->i_seq =
18139e80b1dfSSam Leffler 		    htole16(seqno << IEEE80211_SEQ_SEQ_SHIFT);
18149a841c7fSSam Leffler 		M_SEQNO_SET(m, seqno);
18151c7b0c84SAdrian Chadd 
18161c7b0c84SAdrian Chadd 		/*
18171c7b0c84SAdrian Chadd 		 * XXX TODO: we shouldn't allow EAPOL, etc that would
18181c7b0c84SAdrian Chadd 		 * be forced to be non-QoS traffic to be A-MSDU encapsulated.
18191c7b0c84SAdrian Chadd 		 */
18201c7b0c84SAdrian Chadd 		if (is_amsdu)
18211c7b0c84SAdrian Chadd 			printf("%s: XXX ERROR: is_amsdu set; not QoS!\n",
18221c7b0c84SAdrian Chadd 			    __func__);
18238a1b9b6aSSam Leffler 	}
18249a841c7fSSam Leffler 
182543eafd0dSAdrian Chadd 	/*
182643eafd0dSAdrian Chadd 	 * Check if xmit fragmentation is required.
182743eafd0dSAdrian Chadd 	 *
182843eafd0dSAdrian Chadd 	 * If the hardware does fragmentation offload, then don't bother
182943eafd0dSAdrian Chadd 	 * doing it here.
183043eafd0dSAdrian Chadd 	 */
183143eafd0dSAdrian Chadd 	if (IEEE80211_CONF_FRAG_OFFLOAD(ic))
183243eafd0dSAdrian Chadd 		txfrag = 0;
183343eafd0dSAdrian Chadd 	else
1834b032f27cSSam Leffler 		txfrag = (m->m_pkthdr.len > vap->iv_fragthreshold &&
183568e8e04eSSam Leffler 		    !IEEE80211_IS_MULTICAST(wh->i_addr1) &&
1836b032f27cSSam Leffler 		    (vap->iv_caps & IEEE80211_C_TXFRAG) &&
1837e9cfc1f5SSam Leffler 		    (m->m_flags & (M_FF | M_AMPDU_MPDU)) == 0);
183843eafd0dSAdrian Chadd 
18395e923d2eSSam Leffler 	if (key != NULL) {
18405e923d2eSSam Leffler 		/*
18415e923d2eSSam Leffler 		 * IEEE 802.1X: send EAPOL frames always in the clear.
18425e923d2eSSam Leffler 		 * WPA/WPA2: encrypt EAPOL keys when pairwise keys are set.
18435e923d2eSSam Leffler 		 */
1844b032f27cSSam Leffler 		if ((m->m_flags & M_EAPOL) == 0 ||
1845b032f27cSSam Leffler 		    ((vap->iv_flags & IEEE80211_F_WPA) &&
1846b032f27cSSam Leffler 		     (vap->iv_opmode == IEEE80211_M_STA ?
1847cda15ce1SSam Leffler 		      !IEEE80211_KEY_UNDEFINED(key) :
1848cda15ce1SSam Leffler 		      !IEEE80211_KEY_UNDEFINED(&ni->ni_ucastkey)))) {
18495945b5f5SKevin Lo 			wh->i_fc[1] |= IEEE80211_FC1_PROTECTED;
1850b032f27cSSam Leffler 			if (!ieee80211_crypto_enmic(vap, key, m, txfrag)) {
1851b032f27cSSam Leffler 				IEEE80211_NOTE_MAC(vap, IEEE80211_MSG_OUTPUT,
1852b032f27cSSam Leffler 				    eh.ether_dhost,
1853b032f27cSSam Leffler 				    "%s", "enmic failed, discard frame");
1854b032f27cSSam Leffler 				vap->iv_stats.is_crypto_enmicfail++;
18555e923d2eSSam Leffler 				goto bad;
18565e923d2eSSam Leffler 			}
18575e923d2eSSam Leffler 		}
18585e923d2eSSam Leffler 	}
1859b032f27cSSam Leffler 	if (txfrag && !ieee80211_fragment(vap, m, hdrsize,
1860b032f27cSSam Leffler 	    key != NULL ? key->wk_cipher->ic_header : 0, vap->iv_fragthreshold))
186168e8e04eSSam Leffler 		goto bad;
18628a1b9b6aSSam Leffler 
1863c1af44bdSSam Leffler 	m->m_flags |= M_ENCAP;		/* mark encapsulated */
1864c1af44bdSSam Leffler 
18658a1b9b6aSSam Leffler 	IEEE80211_NODE_STAT(ni, tx_data);
18669e80b1dfSSam Leffler 	if (IEEE80211_IS_MULTICAST(wh->i_addr1)) {
1867b6e9b119SSam Leffler 		IEEE80211_NODE_STAT(ni, tx_mcast);
18689e80b1dfSSam Leffler 		m->m_flags |= M_MCAST;
18699e80b1dfSSam Leffler 	} else
1870b6e9b119SSam Leffler 		IEEE80211_NODE_STAT(ni, tx_ucast);
18718a1b9b6aSSam Leffler 	IEEE80211_NODE_STAT_ADD(ni, tx_bytes, datalen);
18728a1b9b6aSSam Leffler 
18731a1e1d21SSam Leffler 	return m;
18740a915fadSSam Leffler bad:
18750a915fadSSam Leffler 	if (m != NULL)
18760a915fadSSam Leffler 		m_freem(m);
18770a915fadSSam Leffler 	return NULL;
1878b032f27cSSam Leffler #undef WH4
18793c314f6dSMonthadar Al Jaberi #undef MC01
18801a1e1d21SSam Leffler }
18811a1e1d21SSam Leffler 
1882d07be335SAdrian Chadd void
1883d07be335SAdrian Chadd ieee80211_free_mbuf(struct mbuf *m)
1884d07be335SAdrian Chadd {
1885d07be335SAdrian Chadd 	struct mbuf *next;
1886d07be335SAdrian Chadd 
1887d07be335SAdrian Chadd 	if (m == NULL)
1888d07be335SAdrian Chadd 		return;
1889d07be335SAdrian Chadd 
1890d07be335SAdrian Chadd 	do {
1891d07be335SAdrian Chadd 		next = m->m_nextpkt;
1892d07be335SAdrian Chadd 		m->m_nextpkt = NULL;
1893d07be335SAdrian Chadd 		m_freem(m);
1894d07be335SAdrian Chadd 	} while ((m = next) != NULL);
1895d07be335SAdrian Chadd }
1896d07be335SAdrian Chadd 
18971a1e1d21SSam Leffler /*
189868e8e04eSSam Leffler  * Fragment the frame according to the specified mtu.
189968e8e04eSSam Leffler  * The size of the 802.11 header (w/o padding) is provided
190068e8e04eSSam Leffler  * so we don't need to recalculate it.  We create a new
190168e8e04eSSam Leffler  * mbuf for each fragment and chain it through m_nextpkt;
190268e8e04eSSam Leffler  * we might be able to optimize this by reusing the original
190368e8e04eSSam Leffler  * packet's mbufs but that is significantly more complicated.
190468e8e04eSSam Leffler  */
190568e8e04eSSam Leffler static int
1906b032f27cSSam Leffler ieee80211_fragment(struct ieee80211vap *vap, struct mbuf *m0,
190768e8e04eSSam Leffler 	u_int hdrsize, u_int ciphdrsize, u_int mtu)
190868e8e04eSSam Leffler {
19098d46c25dSAdrian Chadd 	struct ieee80211com *ic = vap->iv_ic;
191068e8e04eSSam Leffler 	struct ieee80211_frame *wh, *whf;
1911d07be335SAdrian Chadd 	struct mbuf *m, *prev;
191268e8e04eSSam Leffler 	u_int totalhdrsize, fragno, fragsize, off, remainder, payload;
19138d46c25dSAdrian Chadd 	u_int hdrspace;
191468e8e04eSSam Leffler 
191568e8e04eSSam Leffler 	KASSERT(m0->m_nextpkt == NULL, ("mbuf already chained?"));
191668e8e04eSSam Leffler 	KASSERT(m0->m_pkthdr.len > mtu,
191768e8e04eSSam Leffler 		("pktlen %u mtu %u", m0->m_pkthdr.len, mtu));
191868e8e04eSSam Leffler 
19198d46c25dSAdrian Chadd 	/*
19208d46c25dSAdrian Chadd 	 * Honor driver DATAPAD requirement.
19218d46c25dSAdrian Chadd 	 */
19228d46c25dSAdrian Chadd 	if (ic->ic_flags & IEEE80211_F_DATAPAD)
19238d46c25dSAdrian Chadd 		hdrspace = roundup(hdrsize, sizeof(uint32_t));
19248d46c25dSAdrian Chadd 	else
19258d46c25dSAdrian Chadd 		hdrspace = hdrsize;
19268d46c25dSAdrian Chadd 
192768e8e04eSSam Leffler 	wh = mtod(m0, struct ieee80211_frame *);
192868e8e04eSSam Leffler 	/* NB: mark the first frag; it will be propagated below */
192968e8e04eSSam Leffler 	wh->i_fc[1] |= IEEE80211_FC1_MORE_FRAG;
19308d46c25dSAdrian Chadd 	totalhdrsize = hdrspace + ciphdrsize;
193168e8e04eSSam Leffler 	fragno = 1;
193268e8e04eSSam Leffler 	off = mtu - ciphdrsize;
193368e8e04eSSam Leffler 	remainder = m0->m_pkthdr.len - off;
193468e8e04eSSam Leffler 	prev = m0;
193568e8e04eSSam Leffler 	do {
193618d20be0SAndriy Voskoboinyk 		fragsize = MIN(totalhdrsize + remainder, mtu);
193718d20be0SAndriy Voskoboinyk 		m = m_get2(fragsize, M_NOWAIT, MT_DATA, M_PKTHDR);
193868e8e04eSSam Leffler 		if (m == NULL)
193968e8e04eSSam Leffler 			goto bad;
194068e8e04eSSam Leffler 		/* leave room to prepend any cipher header */
194168e8e04eSSam Leffler 		m_align(m, fragsize - ciphdrsize);
194268e8e04eSSam Leffler 
194368e8e04eSSam Leffler 		/*
194468e8e04eSSam Leffler 		 * Form the header in the fragment.  Note that since
194568e8e04eSSam Leffler 		 * we mark the first fragment with the MORE_FRAG bit
194668e8e04eSSam Leffler 		 * it automatically is propagated to each fragment; we
194768e8e04eSSam Leffler 		 * need only clear it on the last fragment (done below).
194891216c71SAdrian Chadd 		 * NB: frag 1+ dont have Mesh Control field present.
194968e8e04eSSam Leffler 		 */
195068e8e04eSSam Leffler 		whf = mtod(m, struct ieee80211_frame *);
195168e8e04eSSam Leffler 		memcpy(whf, wh, hdrsize);
195291216c71SAdrian Chadd #ifdef IEEE80211_SUPPORT_MESH
1953f3f08e16SAndriy Voskoboinyk 		if (vap->iv_opmode == IEEE80211_M_MBSS)
1954f3f08e16SAndriy Voskoboinyk 			ieee80211_getqos(wh)[1] &= ~IEEE80211_QOS_MC;
195591216c71SAdrian Chadd #endif
195668e8e04eSSam Leffler 		*(uint16_t *)&whf->i_seq[0] |= htole16(
195768e8e04eSSam Leffler 			(fragno & IEEE80211_SEQ_FRAG_MASK) <<
195868e8e04eSSam Leffler 				IEEE80211_SEQ_FRAG_SHIFT);
195968e8e04eSSam Leffler 		fragno++;
196068e8e04eSSam Leffler 
196168e8e04eSSam Leffler 		payload = fragsize - totalhdrsize;
196268e8e04eSSam Leffler 		/* NB: destination is known to be contiguous */
19638d46c25dSAdrian Chadd 
19648d46c25dSAdrian Chadd 		m_copydata(m0, off, payload, mtod(m, uint8_t *) + hdrspace);
19658d46c25dSAdrian Chadd 		m->m_len = hdrspace + payload;
19668d46c25dSAdrian Chadd 		m->m_pkthdr.len = hdrspace + payload;
196768e8e04eSSam Leffler 		m->m_flags |= M_FRAG;
196868e8e04eSSam Leffler 
196968e8e04eSSam Leffler 		/* chain up the fragment */
197068e8e04eSSam Leffler 		prev->m_nextpkt = m;
197168e8e04eSSam Leffler 		prev = m;
197268e8e04eSSam Leffler 
197368e8e04eSSam Leffler 		/* deduct fragment just formed */
197468e8e04eSSam Leffler 		remainder -= payload;
197568e8e04eSSam Leffler 		off += payload;
197668e8e04eSSam Leffler 	} while (remainder != 0);
197751cec121SWeongyo Jeong 
197851cec121SWeongyo Jeong 	/* set the last fragment */
197951cec121SWeongyo Jeong 	m->m_flags |= M_LASTFRAG;
198068e8e04eSSam Leffler 	whf->i_fc[1] &= ~IEEE80211_FC1_MORE_FRAG;
198168e8e04eSSam Leffler 
198268e8e04eSSam Leffler 	/* strip first mbuf now that everything has been copied */
198368e8e04eSSam Leffler 	m_adj(m0, -(m0->m_pkthdr.len - (mtu - ciphdrsize)));
198468e8e04eSSam Leffler 	m0->m_flags |= M_FIRSTFRAG | M_FRAG;
198568e8e04eSSam Leffler 
1986b032f27cSSam Leffler 	vap->iv_stats.is_tx_fragframes++;
1987b032f27cSSam Leffler 	vap->iv_stats.is_tx_frags += fragno-1;
198868e8e04eSSam Leffler 
198968e8e04eSSam Leffler 	return 1;
199068e8e04eSSam Leffler bad:
199168e8e04eSSam Leffler 	/* reclaim fragments but leave original frame for caller to free */
1992d07be335SAdrian Chadd 	ieee80211_free_mbuf(m0->m_nextpkt);
199368e8e04eSSam Leffler 	m0->m_nextpkt = NULL;
199468e8e04eSSam Leffler 	return 0;
199568e8e04eSSam Leffler }
199668e8e04eSSam Leffler 
199768e8e04eSSam Leffler /*
19981a1e1d21SSam Leffler  * Add a supported rates element id to a frame.
19991a1e1d21SSam Leffler  */
200059aa14a9SRui Paulo uint8_t *
200168e8e04eSSam Leffler ieee80211_add_rates(uint8_t *frm, const struct ieee80211_rateset *rs)
20021a1e1d21SSam Leffler {
20031a1e1d21SSam Leffler 	int nrates;
20041a1e1d21SSam Leffler 
20051a1e1d21SSam Leffler 	*frm++ = IEEE80211_ELEMID_RATES;
20061a1e1d21SSam Leffler 	nrates = rs->rs_nrates;
20071a1e1d21SSam Leffler 	if (nrates > IEEE80211_RATE_SIZE)
20081a1e1d21SSam Leffler 		nrates = IEEE80211_RATE_SIZE;
20091a1e1d21SSam Leffler 	*frm++ = nrates;
20101a1e1d21SSam Leffler 	memcpy(frm, rs->rs_rates, nrates);
20111a1e1d21SSam Leffler 	return frm + nrates;
20121a1e1d21SSam Leffler }
20131a1e1d21SSam Leffler 
20141a1e1d21SSam Leffler /*
20151a1e1d21SSam Leffler  * Add an extended supported rates element id to a frame.
20161a1e1d21SSam Leffler  */
201759aa14a9SRui Paulo uint8_t *
201868e8e04eSSam Leffler ieee80211_add_xrates(uint8_t *frm, const struct ieee80211_rateset *rs)
20191a1e1d21SSam Leffler {
20201a1e1d21SSam Leffler 	/*
20211a1e1d21SSam Leffler 	 * Add an extended supported rates element if operating in 11g mode.
20221a1e1d21SSam Leffler 	 */
20231a1e1d21SSam Leffler 	if (rs->rs_nrates > IEEE80211_RATE_SIZE) {
20241a1e1d21SSam Leffler 		int nrates = rs->rs_nrates - IEEE80211_RATE_SIZE;
20251a1e1d21SSam Leffler 		*frm++ = IEEE80211_ELEMID_XRATES;
20261a1e1d21SSam Leffler 		*frm++ = nrates;
20271a1e1d21SSam Leffler 		memcpy(frm, rs->rs_rates + IEEE80211_RATE_SIZE, nrates);
20281a1e1d21SSam Leffler 		frm += nrates;
20291a1e1d21SSam Leffler 	}
20301a1e1d21SSam Leffler 	return frm;
20311a1e1d21SSam Leffler }
20321a1e1d21SSam Leffler 
20331a1e1d21SSam Leffler /*
2034b032f27cSSam Leffler  * Add an ssid element to a frame.
20351a1e1d21SSam Leffler  */
2036de981aecSAdrian Chadd uint8_t *
203768e8e04eSSam Leffler ieee80211_add_ssid(uint8_t *frm, const uint8_t *ssid, u_int len)
20381a1e1d21SSam Leffler {
20391a1e1d21SSam Leffler 	*frm++ = IEEE80211_ELEMID_SSID;
20401a1e1d21SSam Leffler 	*frm++ = len;
20411a1e1d21SSam Leffler 	memcpy(frm, ssid, len);
20421a1e1d21SSam Leffler 	return frm + len;
20431a1e1d21SSam Leffler }
20441a1e1d21SSam Leffler 
20458a1b9b6aSSam Leffler /*
20468a1b9b6aSSam Leffler  * Add an erp element to a frame.
20478a1b9b6aSSam Leffler  */
204868e8e04eSSam Leffler static uint8_t *
204968e8e04eSSam Leffler ieee80211_add_erp(uint8_t *frm, struct ieee80211com *ic)
20501a1e1d21SSam Leffler {
205168e8e04eSSam Leffler 	uint8_t erp;
20521a1e1d21SSam Leffler 
20538a1b9b6aSSam Leffler 	*frm++ = IEEE80211_ELEMID_ERP;
20548a1b9b6aSSam Leffler 	*frm++ = 1;
20558a1b9b6aSSam Leffler 	erp = 0;
20568a1b9b6aSSam Leffler 	if (ic->ic_nonerpsta != 0)
20578a1b9b6aSSam Leffler 		erp |= IEEE80211_ERP_NON_ERP_PRESENT;
20588a1b9b6aSSam Leffler 	if (ic->ic_flags & IEEE80211_F_USEPROT)
20598a1b9b6aSSam Leffler 		erp |= IEEE80211_ERP_USE_PROTECTION;
20608a1b9b6aSSam Leffler 	if (ic->ic_flags & IEEE80211_F_USEBARKER)
20618a1b9b6aSSam Leffler 		erp |= IEEE80211_ERP_LONG_PREAMBLE;
20628a1b9b6aSSam Leffler 	*frm++ = erp;
20638a1b9b6aSSam Leffler 	return frm;
20641a1e1d21SSam Leffler }
20651a1e1d21SSam Leffler 
20668a1b9b6aSSam Leffler /*
2067b032f27cSSam Leffler  * Add a CFParams element to a frame.
20688a1b9b6aSSam Leffler  */
206968e8e04eSSam Leffler static uint8_t *
2070b032f27cSSam Leffler ieee80211_add_cfparms(uint8_t *frm, struct ieee80211com *ic)
20718a1b9b6aSSam Leffler {
2072b032f27cSSam Leffler #define	ADDSHORT(frm, v) do {	\
207331021a2bSAndriy Voskoboinyk 	le16enc(frm, v);	\
2074b032f27cSSam Leffler 	frm += 2;		\
2075b032f27cSSam Leffler } while (0)
2076b032f27cSSam Leffler 	*frm++ = IEEE80211_ELEMID_CFPARMS;
2077b032f27cSSam Leffler 	*frm++ = 6;
2078b032f27cSSam Leffler 	*frm++ = 0;		/* CFP count */
2079b032f27cSSam Leffler 	*frm++ = 2;		/* CFP period */
2080b032f27cSSam Leffler 	ADDSHORT(frm, 0);	/* CFP MaxDuration (TU) */
2081b032f27cSSam Leffler 	ADDSHORT(frm, 0);	/* CFP CurRemaining (TU) */
20828a1b9b6aSSam Leffler 	return frm;
2083b032f27cSSam Leffler #undef ADDSHORT
2084b032f27cSSam Leffler }
2085b032f27cSSam Leffler 
2086b032f27cSSam Leffler static __inline uint8_t *
2087b032f27cSSam Leffler add_appie(uint8_t *frm, const struct ieee80211_appie *ie)
2088b032f27cSSam Leffler {
2089b032f27cSSam Leffler 	memcpy(frm, ie->ie_data, ie->ie_len);
2090b032f27cSSam Leffler 	return frm + ie->ie_len;
2091b032f27cSSam Leffler }
2092b032f27cSSam Leffler 
2093b032f27cSSam Leffler static __inline uint8_t *
2094b032f27cSSam Leffler add_ie(uint8_t *frm, const uint8_t *ie)
2095b032f27cSSam Leffler {
2096b032f27cSSam Leffler 	memcpy(frm, ie, 2 + ie[1]);
2097b032f27cSSam Leffler 	return frm + 2 + ie[1];
20988a1b9b6aSSam Leffler }
20998a1b9b6aSSam Leffler 
21008a1b9b6aSSam Leffler #define	WME_OUI_BYTES		0x00, 0x50, 0xf2
21018a1b9b6aSSam Leffler /*
21028a1b9b6aSSam Leffler  * Add a WME information element to a frame.
21038a1b9b6aSSam Leffler  */
21044eadefc2SAdrian Chadd uint8_t *
210568e8e04eSSam Leffler ieee80211_add_wme_info(uint8_t *frm, struct ieee80211_wme_state *wme)
21068a1b9b6aSSam Leffler {
21078a1b9b6aSSam Leffler 	static const struct ieee80211_wme_info info = {
21088a1b9b6aSSam Leffler 		.wme_id		= IEEE80211_ELEMID_VENDOR,
21098a1b9b6aSSam Leffler 		.wme_len	= sizeof(struct ieee80211_wme_info) - 2,
21108a1b9b6aSSam Leffler 		.wme_oui	= { WME_OUI_BYTES },
21118a1b9b6aSSam Leffler 		.wme_type	= WME_OUI_TYPE,
21128a1b9b6aSSam Leffler 		.wme_subtype	= WME_INFO_OUI_SUBTYPE,
21138a1b9b6aSSam Leffler 		.wme_version	= WME_VERSION,
21148a1b9b6aSSam Leffler 		.wme_info	= 0,
21158a1b9b6aSSam Leffler 	};
21168a1b9b6aSSam Leffler 	memcpy(frm, &info, sizeof(info));
21178a1b9b6aSSam Leffler 	return frm + sizeof(info);
21188a1b9b6aSSam Leffler }
21198a1b9b6aSSam Leffler 
21208a1b9b6aSSam Leffler /*
21218a1b9b6aSSam Leffler  * Add a WME parameters element to a frame.
21228a1b9b6aSSam Leffler  */
212368e8e04eSSam Leffler static uint8_t *
212468e8e04eSSam Leffler ieee80211_add_wme_param(uint8_t *frm, struct ieee80211_wme_state *wme)
21258a1b9b6aSSam Leffler {
21268a1b9b6aSSam Leffler #define	SM(_v, _f)	(((_v) << _f##_S) & _f)
21278a1b9b6aSSam Leffler #define	ADDSHORT(frm, v) do {	\
212831021a2bSAndriy Voskoboinyk 	le16enc(frm, v);	\
21298a1b9b6aSSam Leffler 	frm += 2;		\
21308a1b9b6aSSam Leffler } while (0)
21318a1b9b6aSSam Leffler 	/* NB: this works 'cuz a param has an info at the front */
21328a1b9b6aSSam Leffler 	static const struct ieee80211_wme_info param = {
21338a1b9b6aSSam Leffler 		.wme_id		= IEEE80211_ELEMID_VENDOR,
21348a1b9b6aSSam Leffler 		.wme_len	= sizeof(struct ieee80211_wme_param) - 2,
21358a1b9b6aSSam Leffler 		.wme_oui	= { WME_OUI_BYTES },
21368a1b9b6aSSam Leffler 		.wme_type	= WME_OUI_TYPE,
21378a1b9b6aSSam Leffler 		.wme_subtype	= WME_PARAM_OUI_SUBTYPE,
21388a1b9b6aSSam Leffler 		.wme_version	= WME_VERSION,
21398a1b9b6aSSam Leffler 	};
21408a1b9b6aSSam Leffler 	int i;
21418a1b9b6aSSam Leffler 
21428a1b9b6aSSam Leffler 	memcpy(frm, &param, sizeof(param));
21438a1b9b6aSSam Leffler 	frm += __offsetof(struct ieee80211_wme_info, wme_info);
21448a1b9b6aSSam Leffler 	*frm++ = wme->wme_bssChanParams.cap_info;	/* AC info */
21458a1b9b6aSSam Leffler 	*frm++ = 0;					/* reserved field */
21468a1b9b6aSSam Leffler 	for (i = 0; i < WME_NUM_AC; i++) {
21478a1b9b6aSSam Leffler 		const struct wmeParams *ac =
21488a1b9b6aSSam Leffler 		       &wme->wme_bssChanParams.cap_wmeParams[i];
21498a1b9b6aSSam Leffler 		*frm++ = SM(i, WME_PARAM_ACI)
21508a1b9b6aSSam Leffler 		       | SM(ac->wmep_acm, WME_PARAM_ACM)
21518a1b9b6aSSam Leffler 		       | SM(ac->wmep_aifsn, WME_PARAM_AIFSN)
21528a1b9b6aSSam Leffler 		       ;
21538a1b9b6aSSam Leffler 		*frm++ = SM(ac->wmep_logcwmax, WME_PARAM_LOGCWMAX)
21548a1b9b6aSSam Leffler 		       | SM(ac->wmep_logcwmin, WME_PARAM_LOGCWMIN)
21558a1b9b6aSSam Leffler 		       ;
21568a1b9b6aSSam Leffler 		ADDSHORT(frm, ac->wmep_txopLimit);
21578a1b9b6aSSam Leffler 	}
21588a1b9b6aSSam Leffler 	return frm;
21598a1b9b6aSSam Leffler #undef SM
21608a1b9b6aSSam Leffler #undef ADDSHORT
21618a1b9b6aSSam Leffler }
21628a1b9b6aSSam Leffler #undef WME_OUI_BYTES
21638a1b9b6aSSam Leffler 
21640a915fadSSam Leffler /*
2165b032f27cSSam Leffler  * Add an 11h Power Constraint element to a frame.
2166b032f27cSSam Leffler  */
2167b032f27cSSam Leffler static uint8_t *
2168b032f27cSSam Leffler ieee80211_add_powerconstraint(uint8_t *frm, struct ieee80211vap *vap)
2169b032f27cSSam Leffler {
2170b032f27cSSam Leffler 	const struct ieee80211_channel *c = vap->iv_bss->ni_chan;
2171b032f27cSSam Leffler 	/* XXX per-vap tx power limit? */
2172b032f27cSSam Leffler 	int8_t limit = vap->iv_ic->ic_txpowlimit / 2;
2173b032f27cSSam Leffler 
2174b032f27cSSam Leffler 	frm[0] = IEEE80211_ELEMID_PWRCNSTR;
2175b032f27cSSam Leffler 	frm[1] = 1;
2176b032f27cSSam Leffler 	frm[2] = c->ic_maxregpower > limit ?  c->ic_maxregpower - limit : 0;
2177b032f27cSSam Leffler 	return frm + 3;
2178b032f27cSSam Leffler }
2179b032f27cSSam Leffler 
2180b032f27cSSam Leffler /*
2181b032f27cSSam Leffler  * Add an 11h Power Capability element to a frame.
2182b032f27cSSam Leffler  */
2183b032f27cSSam Leffler static uint8_t *
2184b032f27cSSam Leffler ieee80211_add_powercapability(uint8_t *frm, const struct ieee80211_channel *c)
2185b032f27cSSam Leffler {
2186b032f27cSSam Leffler 	frm[0] = IEEE80211_ELEMID_PWRCAP;
2187b032f27cSSam Leffler 	frm[1] = 2;
2188b032f27cSSam Leffler 	frm[2] = c->ic_minpower;
2189b032f27cSSam Leffler 	frm[3] = c->ic_maxpower;
2190b032f27cSSam Leffler 	return frm + 4;
2191b032f27cSSam Leffler }
2192b032f27cSSam Leffler 
2193b032f27cSSam Leffler /*
2194b032f27cSSam Leffler  * Add an 11h Supported Channels element to a frame.
2195b032f27cSSam Leffler  */
2196b032f27cSSam Leffler static uint8_t *
2197b032f27cSSam Leffler ieee80211_add_supportedchannels(uint8_t *frm, struct ieee80211com *ic)
2198b032f27cSSam Leffler {
2199b032f27cSSam Leffler 	static const int ielen = 26;
2200b032f27cSSam Leffler 
2201b032f27cSSam Leffler 	frm[0] = IEEE80211_ELEMID_SUPPCHAN;
2202b032f27cSSam Leffler 	frm[1] = ielen;
2203b032f27cSSam Leffler 	/* XXX not correct */
2204b032f27cSSam Leffler 	memcpy(frm+2, ic->ic_chan_avail, ielen);
2205b032f27cSSam Leffler 	return frm + 2 + ielen;
2206b032f27cSSam Leffler }
2207b032f27cSSam Leffler 
2208b032f27cSSam Leffler /*
220932b0e64bSAdrian Chadd  * Add an 11h Quiet time element to a frame.
221032b0e64bSAdrian Chadd  */
221132b0e64bSAdrian Chadd static uint8_t *
2212ce4552cdSAdrian Chadd ieee80211_add_quiet(uint8_t *frm, struct ieee80211vap *vap, int update)
221332b0e64bSAdrian Chadd {
221432b0e64bSAdrian Chadd 	struct ieee80211_quiet_ie *quiet = (struct ieee80211_quiet_ie *) frm;
221532b0e64bSAdrian Chadd 
221632b0e64bSAdrian Chadd 	quiet->quiet_ie = IEEE80211_ELEMID_QUIET;
221732b0e64bSAdrian Chadd 	quiet->len = 6;
2218ce4552cdSAdrian Chadd 
2219ce4552cdSAdrian Chadd 	/*
2220ce4552cdSAdrian Chadd 	 * Only update every beacon interval - otherwise probe responses
2221ce4552cdSAdrian Chadd 	 * would update the quiet count value.
2222ce4552cdSAdrian Chadd 	 */
2223ce4552cdSAdrian Chadd 	if (update) {
222432b0e64bSAdrian Chadd 		if (vap->iv_quiet_count_value == 1)
222532b0e64bSAdrian Chadd 			vap->iv_quiet_count_value = vap->iv_quiet_count;
222632b0e64bSAdrian Chadd 		else if (vap->iv_quiet_count_value > 1)
222732b0e64bSAdrian Chadd 			vap->iv_quiet_count_value--;
2228ce4552cdSAdrian Chadd 	}
222932b0e64bSAdrian Chadd 
223032b0e64bSAdrian Chadd 	if (vap->iv_quiet_count_value == 0) {
223132b0e64bSAdrian Chadd 		/* value 0 is reserved as per 802.11h standerd */
223232b0e64bSAdrian Chadd 		vap->iv_quiet_count_value = 1;
223332b0e64bSAdrian Chadd 	}
223432b0e64bSAdrian Chadd 
223532b0e64bSAdrian Chadd 	quiet->tbttcount = vap->iv_quiet_count_value;
223632b0e64bSAdrian Chadd 	quiet->period = vap->iv_quiet_period;
223732b0e64bSAdrian Chadd 	quiet->duration = htole16(vap->iv_quiet_duration);
223832b0e64bSAdrian Chadd 	quiet->offset = htole16(vap->iv_quiet_offset);
223932b0e64bSAdrian Chadd 	return frm + sizeof(*quiet);
224032b0e64bSAdrian Chadd }
224132b0e64bSAdrian Chadd 
224232b0e64bSAdrian Chadd /*
2243b032f27cSSam Leffler  * Add an 11h Channel Switch Announcement element to a frame.
2244b032f27cSSam Leffler  * Note that we use the per-vap CSA count to adjust the global
2245b032f27cSSam Leffler  * counter so we can use this routine to form probe response
2246b032f27cSSam Leffler  * frames and get the current count.
2247b032f27cSSam Leffler  */
2248b032f27cSSam Leffler static uint8_t *
2249b032f27cSSam Leffler ieee80211_add_csa(uint8_t *frm, struct ieee80211vap *vap)
2250b032f27cSSam Leffler {
2251b032f27cSSam Leffler 	struct ieee80211com *ic = vap->iv_ic;
2252b032f27cSSam Leffler 	struct ieee80211_csa_ie *csa = (struct ieee80211_csa_ie *) frm;
2253b032f27cSSam Leffler 
2254c70761e6SSam Leffler 	csa->csa_ie = IEEE80211_ELEMID_CSA;
2255b032f27cSSam Leffler 	csa->csa_len = 3;
2256b032f27cSSam Leffler 	csa->csa_mode = 1;		/* XXX force quiet on channel */
2257b032f27cSSam Leffler 	csa->csa_newchan = ieee80211_chan2ieee(ic, ic->ic_csa_newchan);
2258b032f27cSSam Leffler 	csa->csa_count = ic->ic_csa_count - vap->iv_csa_count;
2259b032f27cSSam Leffler 	return frm + sizeof(*csa);
2260b032f27cSSam Leffler }
2261b032f27cSSam Leffler 
2262b032f27cSSam Leffler /*
2263b032f27cSSam Leffler  * Add an 11h country information element to a frame.
2264b032f27cSSam Leffler  */
2265b032f27cSSam Leffler static uint8_t *
2266b032f27cSSam Leffler ieee80211_add_countryie(uint8_t *frm, struct ieee80211com *ic)
2267b032f27cSSam Leffler {
2268b032f27cSSam Leffler 
2269b032f27cSSam Leffler 	if (ic->ic_countryie == NULL ||
2270b032f27cSSam Leffler 	    ic->ic_countryie_chan != ic->ic_bsschan) {
2271b032f27cSSam Leffler 		/*
2272b032f27cSSam Leffler 		 * Handle lazy construction of ie.  This is done on
2273b032f27cSSam Leffler 		 * first use and after a channel change that requires
2274b032f27cSSam Leffler 		 * re-calculation.
2275b032f27cSSam Leffler 		 */
2276b032f27cSSam Leffler 		if (ic->ic_countryie != NULL)
2277b9b53389SAdrian Chadd 			IEEE80211_FREE(ic->ic_countryie, M_80211_NODE_IE);
2278b032f27cSSam Leffler 		ic->ic_countryie = ieee80211_alloc_countryie(ic);
2279b032f27cSSam Leffler 		if (ic->ic_countryie == NULL)
2280b032f27cSSam Leffler 			return frm;
2281b032f27cSSam Leffler 		ic->ic_countryie_chan = ic->ic_bsschan;
2282b032f27cSSam Leffler 	}
2283b032f27cSSam Leffler 	return add_appie(frm, ic->ic_countryie);
2284b032f27cSSam Leffler }
2285b032f27cSSam Leffler 
2286d8df5f3dSRui Paulo uint8_t *
2287d8df5f3dSRui Paulo ieee80211_add_wpa(uint8_t *frm, const struct ieee80211vap *vap)
2288d8df5f3dSRui Paulo {
2289d8df5f3dSRui Paulo 	if (vap->iv_flags & IEEE80211_F_WPA1 && vap->iv_wpa_ie != NULL)
2290d8df5f3dSRui Paulo 		return (add_ie(frm, vap->iv_wpa_ie));
2291d8df5f3dSRui Paulo 	else {
2292d8df5f3dSRui Paulo 		/* XXX else complain? */
2293d8df5f3dSRui Paulo 		return (frm);
2294d8df5f3dSRui Paulo 	}
2295d8df5f3dSRui Paulo }
2296d8df5f3dSRui Paulo 
2297d8df5f3dSRui Paulo uint8_t *
2298d8df5f3dSRui Paulo ieee80211_add_rsn(uint8_t *frm, const struct ieee80211vap *vap)
2299d8df5f3dSRui Paulo {
2300d8df5f3dSRui Paulo 	if (vap->iv_flags & IEEE80211_F_WPA2 && vap->iv_rsn_ie != NULL)
2301d8df5f3dSRui Paulo 		return (add_ie(frm, vap->iv_rsn_ie));
2302d8df5f3dSRui Paulo 	else {
2303d8df5f3dSRui Paulo 		/* XXX else complain? */
2304d8df5f3dSRui Paulo 		return (frm);
2305d8df5f3dSRui Paulo 	}
2306d8df5f3dSRui Paulo }
2307d8df5f3dSRui Paulo 
2308d8df5f3dSRui Paulo uint8_t *
2309d8df5f3dSRui Paulo ieee80211_add_qos(uint8_t *frm, const struct ieee80211_node *ni)
2310d8df5f3dSRui Paulo {
2311d8df5f3dSRui Paulo 	if (ni->ni_flags & IEEE80211_NODE_QOS) {
2312d8df5f3dSRui Paulo 		*frm++ = IEEE80211_ELEMID_QOS;
2313d8df5f3dSRui Paulo 		*frm++ = 1;
2314d8df5f3dSRui Paulo 		*frm++ = 0;
2315d8df5f3dSRui Paulo 	}
2316d8df5f3dSRui Paulo 
2317d8df5f3dSRui Paulo 	return (frm);
2318d8df5f3dSRui Paulo }
2319d8df5f3dSRui Paulo 
2320b032f27cSSam Leffler /*
2321af8418dcSSam Leffler  * Send a probe request frame with the specified ssid
2322af8418dcSSam Leffler  * and any optional information element data.
2323af8418dcSSam Leffler  */
2324af8418dcSSam Leffler int
2325af8418dcSSam Leffler ieee80211_send_probereq(struct ieee80211_node *ni,
232668e8e04eSSam Leffler 	const uint8_t sa[IEEE80211_ADDR_LEN],
232768e8e04eSSam Leffler 	const uint8_t da[IEEE80211_ADDR_LEN],
232868e8e04eSSam Leffler 	const uint8_t bssid[IEEE80211_ADDR_LEN],
2329b032f27cSSam Leffler 	const uint8_t *ssid, size_t ssidlen)
2330af8418dcSSam Leffler {
2331b032f27cSSam Leffler 	struct ieee80211vap *vap = ni->ni_vap;
2332af8418dcSSam Leffler 	struct ieee80211com *ic = ni->ni_ic;
2333f8a67728SAdrian Chadd 	struct ieee80211_node *bss;
233416d7cbb1SSam Leffler 	const struct ieee80211_txparam *tp;
233516d7cbb1SSam Leffler 	struct ieee80211_bpf_params params;
233641b3c790SSam Leffler 	const struct ieee80211_rateset *rs;
2337af8418dcSSam Leffler 	struct mbuf *m;
233868e8e04eSSam Leffler 	uint8_t *frm;
23395cda6006SAdrian Chadd 	int ret;
2340af8418dcSSam Leffler 
2341f8a67728SAdrian Chadd 	bss = ieee80211_ref_node(vap->iv_bss);
2342f8a67728SAdrian Chadd 
2343b032f27cSSam Leffler 	if (vap->iv_state == IEEE80211_S_CAC) {
2344b032f27cSSam Leffler 		IEEE80211_NOTE(vap, IEEE80211_MSG_OUTPUT, ni,
2345b032f27cSSam Leffler 		    "block %s frame in CAC state", "probe request");
2346b032f27cSSam Leffler 		vap->iv_stats.is_tx_badstate++;
2347f8a67728SAdrian Chadd 		ieee80211_free_node(bss);
2348b032f27cSSam Leffler 		return EIO;		/* XXX */
2349b032f27cSSam Leffler 	}
2350b032f27cSSam Leffler 
2351af8418dcSSam Leffler 	/*
2352af8418dcSSam Leffler 	 * Hold a reference on the node so it doesn't go away until after
2353af8418dcSSam Leffler 	 * the xmit is complete all the way in the driver.  On error we
2354af8418dcSSam Leffler 	 * will remove our reference.
2355af8418dcSSam Leffler 	 */
2356b032f27cSSam Leffler 	IEEE80211_DPRINTF(vap, IEEE80211_MSG_NODE,
2357af8418dcSSam Leffler 		"ieee80211_ref_node (%s:%u) %p<%s> refcnt %d\n",
2358af8418dcSSam Leffler 		__func__, __LINE__,
2359af8418dcSSam Leffler 		ni, ether_sprintf(ni->ni_macaddr),
2360af8418dcSSam Leffler 		ieee80211_node_refcnt(ni)+1);
2361af8418dcSSam Leffler 	ieee80211_ref_node(ni);
2362af8418dcSSam Leffler 
2363af8418dcSSam Leffler 	/*
2364af8418dcSSam Leffler 	 * prreq frame format
2365af8418dcSSam Leffler 	 *	[tlv] ssid
2366af8418dcSSam Leffler 	 *	[tlv] supported rates
2367b032f27cSSam Leffler 	 *	[tlv] RSN (optional)
2368af8418dcSSam Leffler 	 *	[tlv] extended supported rates
2369f8a67728SAdrian Chadd 	 *	[tlv] HT cap (optional)
237051172f62SAdrian Chadd 	 *	[tlv] VHT cap (optional)
2371b032f27cSSam Leffler 	 *	[tlv] WPA (optional)
2372af8418dcSSam Leffler 	 *	[tlv] user-specified ie's
2373af8418dcSSam Leffler 	 */
2374af8418dcSSam Leffler 	m = ieee80211_getmgtframe(&frm,
237568e8e04eSSam Leffler 		 ic->ic_headroom + sizeof(struct ieee80211_frame),
2376af8418dcSSam Leffler 	       	 2 + IEEE80211_NWID_LEN
2377af8418dcSSam Leffler 	       + 2 + IEEE80211_RATE_SIZE
2378f8a67728SAdrian Chadd 	       + sizeof(struct ieee80211_ie_htcap)
237951172f62SAdrian Chadd 	       + sizeof(struct ieee80211_ie_vhtcap)
238051172f62SAdrian Chadd 	       + sizeof(struct ieee80211_ie_htinfo)	/* XXX not needed? */
2381b032f27cSSam Leffler 	       + sizeof(struct ieee80211_ie_wpa)
2382af8418dcSSam Leffler 	       + 2 + (IEEE80211_RATE_MAXSIZE - IEEE80211_RATE_SIZE)
2383b032f27cSSam Leffler 	       + sizeof(struct ieee80211_ie_wpa)
2384b032f27cSSam Leffler 	       + (vap->iv_appie_probereq != NULL ?
2385b032f27cSSam Leffler 		   vap->iv_appie_probereq->ie_len : 0)
2386af8418dcSSam Leffler 	);
2387af8418dcSSam Leffler 	if (m == NULL) {
2388b032f27cSSam Leffler 		vap->iv_stats.is_tx_nobuf++;
2389af8418dcSSam Leffler 		ieee80211_free_node(ni);
2390f8a67728SAdrian Chadd 		ieee80211_free_node(bss);
2391af8418dcSSam Leffler 		return ENOMEM;
2392af8418dcSSam Leffler 	}
2393af8418dcSSam Leffler 
2394af8418dcSSam Leffler 	frm = ieee80211_add_ssid(frm, ssid, ssidlen);
239541b3c790SSam Leffler 	rs = ieee80211_get_suprates(ic, ic->ic_curchan);
239641b3c790SSam Leffler 	frm = ieee80211_add_rates(frm, rs);
2397d8df5f3dSRui Paulo 	frm = ieee80211_add_rsn(frm, vap);
2398b032f27cSSam Leffler 	frm = ieee80211_add_xrates(frm, rs);
2399f8a67728SAdrian Chadd 
2400f8a67728SAdrian Chadd 	/*
2401f8a67728SAdrian Chadd 	 * Note: we can't use bss; we don't have one yet.
2402f8a67728SAdrian Chadd 	 *
2403f8a67728SAdrian Chadd 	 * So, we should announce our capabilities
2404f8a67728SAdrian Chadd 	 * in this channel mode (2g/5g), not the
2405f8a67728SAdrian Chadd 	 * channel details itself.
2406f8a67728SAdrian Chadd 	 */
2407f8a67728SAdrian Chadd 	if ((vap->iv_opmode == IEEE80211_M_IBSS) &&
2408f8a67728SAdrian Chadd 	    (vap->iv_flags_ht & IEEE80211_FHT_HT)) {
2409f8a67728SAdrian Chadd 		struct ieee80211_channel *c;
2410f8a67728SAdrian Chadd 
2411f8a67728SAdrian Chadd 		/*
2412f8a67728SAdrian Chadd 		 * Get the HT channel that we should try upgrading to.
2413f8a67728SAdrian Chadd 		 * If we can do 40MHz then this'll upgrade it appropriately.
2414f8a67728SAdrian Chadd 		 */
2415f8a67728SAdrian Chadd 		c = ieee80211_ht_adjust_channel(ic, ic->ic_curchan,
2416f8a67728SAdrian Chadd 		    vap->iv_flags_ht);
2417f8a67728SAdrian Chadd 		frm = ieee80211_add_htcap_ch(frm, vap, c);
2418f8a67728SAdrian Chadd 	}
2419f8a67728SAdrian Chadd 
242051172f62SAdrian Chadd 	/*
242151172f62SAdrian Chadd 	 * XXX TODO: need to figure out what/how to update the
242251172f62SAdrian Chadd 	 * VHT channel.
242351172f62SAdrian Chadd 	 */
242451172f62SAdrian Chadd #if 0
242551172f62SAdrian Chadd 	(vap->iv_flags_vht & IEEE80211_FVHT_VHT) {
242651172f62SAdrian Chadd 		struct ieee80211_channel *c;
242751172f62SAdrian Chadd 
242851172f62SAdrian Chadd 		c = ieee80211_ht_adjust_channel(ic, ic->ic_curchan,
242951172f62SAdrian Chadd 		    vap->iv_flags_ht);
243051172f62SAdrian Chadd 		c = ieee80211_vht_adjust_channel(ic, c, vap->iv_flags_vht);
243151172f62SAdrian Chadd 		frm = ieee80211_add_vhtcap_ch(frm, vap, c);
243251172f62SAdrian Chadd 	}
243351172f62SAdrian Chadd #endif
243451172f62SAdrian Chadd 
2435d8df5f3dSRui Paulo 	frm = ieee80211_add_wpa(frm, vap);
2436b032f27cSSam Leffler 	if (vap->iv_appie_probereq != NULL)
2437b032f27cSSam Leffler 		frm = add_appie(frm, vap->iv_appie_probereq);
243868e8e04eSSam Leffler 	m->m_pkthdr.len = m->m_len = frm - mtod(m, uint8_t *);
2439af8418dcSSam Leffler 
244016d7cbb1SSam Leffler 	KASSERT(M_LEADINGSPACE(m) >= sizeof(struct ieee80211_frame),
244116d7cbb1SSam Leffler 	    ("leading space %zd", M_LEADINGSPACE(m)));
2442eb1b1807SGleb Smirnoff 	M_PREPEND(m, sizeof(struct ieee80211_frame), M_NOWAIT);
244316d7cbb1SSam Leffler 	if (m == NULL) {
244416d7cbb1SSam Leffler 		/* NB: cannot happen */
244516d7cbb1SSam Leffler 		ieee80211_free_node(ni);
2446f8a67728SAdrian Chadd 		ieee80211_free_node(bss);
2447af8418dcSSam Leffler 		return ENOMEM;
244816d7cbb1SSam Leffler 	}
2449af8418dcSSam Leffler 
24505cda6006SAdrian Chadd 	IEEE80211_TX_LOCK(ic);
24519e80b1dfSSam Leffler 	ieee80211_send_setup(ni, m,
2452af8418dcSSam Leffler 	     IEEE80211_FC0_TYPE_MGT | IEEE80211_FC0_SUBTYPE_PROBE_REQ,
24538ac160cdSSam Leffler 	     IEEE80211_NONQOS_TID, sa, da, bssid);
2454af8418dcSSam Leffler 	/* XXX power management? */
2455c1af44bdSSam Leffler 	m->m_flags |= M_ENCAP;		/* mark encapsulated */
2456af8418dcSSam Leffler 
2457b032f27cSSam Leffler 	M_WME_SETAC(m, WME_AC_BE);
2458b032f27cSSam Leffler 
2459af8418dcSSam Leffler 	IEEE80211_NODE_STAT(ni, tx_probereq);
2460af8418dcSSam Leffler 	IEEE80211_NODE_STAT(ni, tx_mgmt);
2461af8418dcSSam Leffler 
2462b032f27cSSam Leffler 	IEEE80211_DPRINTF(vap, IEEE80211_MSG_DEBUG | IEEE80211_MSG_DUMPPKTS,
2463f8a67728SAdrian Chadd 	    "send probe req on channel %u bssid %s sa %6D da %6D ssid \"%.*s\"\n",
2464f8a67728SAdrian Chadd 	    ieee80211_chan2ieee(ic, ic->ic_curchan),
2465f8a67728SAdrian Chadd 	    ether_sprintf(bssid),
2466f8a67728SAdrian Chadd 	    sa, ":",
2467f8a67728SAdrian Chadd 	    da, ":",
2468b032f27cSSam Leffler 	    ssidlen, ssid);
2469af8418dcSSam Leffler 
247016d7cbb1SSam Leffler 	memset(&params, 0, sizeof(params));
247116d7cbb1SSam Leffler 	params.ibp_pri = M_WME_GETAC(m);
247216d7cbb1SSam Leffler 	tp = &vap->iv_txparms[ieee80211_chan2mode(ic->ic_curchan)];
247316d7cbb1SSam Leffler 	params.ibp_rate0 = tp->mgmtrate;
247416d7cbb1SSam Leffler 	if (IEEE80211_IS_MULTICAST(da)) {
247516d7cbb1SSam Leffler 		params.ibp_flags |= IEEE80211_BPF_NOACK;
247616d7cbb1SSam Leffler 		params.ibp_try0 = 1;
247716d7cbb1SSam Leffler 	} else
247816d7cbb1SSam Leffler 		params.ibp_try0 = tp->maxretry;
247916d7cbb1SSam Leffler 	params.ibp_power = ni->ni_txpower;
24805cda6006SAdrian Chadd 	ret = ieee80211_raw_output(vap, ni, m, &params);
24815cda6006SAdrian Chadd 	IEEE80211_TX_UNLOCK(ic);
2482f8a67728SAdrian Chadd 	ieee80211_free_node(bss);
24835cda6006SAdrian Chadd 	return (ret);
2484af8418dcSSam Leffler }
2485af8418dcSSam Leffler 
2486af8418dcSSam Leffler /*
2487667dad55SSam Leffler  * Calculate capability information for mgt frames.
2488667dad55SSam Leffler  */
248959aa14a9SRui Paulo uint16_t
249059aa14a9SRui Paulo ieee80211_getcapinfo(struct ieee80211vap *vap, struct ieee80211_channel *chan)
2491667dad55SSam Leffler {
2492b032f27cSSam Leffler 	struct ieee80211com *ic = vap->iv_ic;
249368e8e04eSSam Leffler 	uint16_t capinfo;
2494667dad55SSam Leffler 
2495b032f27cSSam Leffler 	KASSERT(vap->iv_opmode != IEEE80211_M_STA, ("station mode"));
2496667dad55SSam Leffler 
2497b032f27cSSam Leffler 	if (vap->iv_opmode == IEEE80211_M_HOSTAP)
2498667dad55SSam Leffler 		capinfo = IEEE80211_CAPINFO_ESS;
2499b032f27cSSam Leffler 	else if (vap->iv_opmode == IEEE80211_M_IBSS)
2500667dad55SSam Leffler 		capinfo = IEEE80211_CAPINFO_IBSS;
2501667dad55SSam Leffler 	else
2502667dad55SSam Leffler 		capinfo = 0;
2503b032f27cSSam Leffler 	if (vap->iv_flags & IEEE80211_F_PRIVACY)
2504667dad55SSam Leffler 		capinfo |= IEEE80211_CAPINFO_PRIVACY;
2505667dad55SSam Leffler 	if ((ic->ic_flags & IEEE80211_F_SHPREAMBLE) &&
2506667dad55SSam Leffler 	    IEEE80211_IS_CHAN_2GHZ(chan))
2507667dad55SSam Leffler 		capinfo |= IEEE80211_CAPINFO_SHORT_PREAMBLE;
2508667dad55SSam Leffler 	if (ic->ic_flags & IEEE80211_F_SHSLOT)
2509667dad55SSam Leffler 		capinfo |= IEEE80211_CAPINFO_SHORT_SLOTTIME;
2510b032f27cSSam Leffler 	if (IEEE80211_IS_CHAN_5GHZ(chan) && (vap->iv_flags & IEEE80211_F_DOTH))
2511b032f27cSSam Leffler 		capinfo |= IEEE80211_CAPINFO_SPECTRUM_MGMT;
2512667dad55SSam Leffler 	return capinfo;
2513667dad55SSam Leffler }
2514667dad55SSam Leffler 
2515667dad55SSam Leffler /*
25160a915fadSSam Leffler  * Send a management frame.  The node is for the destination (or ic_bss
25170a915fadSSam Leffler  * when in station mode).  Nodes other than ic_bss have their reference
25180a915fadSSam Leffler  * count bumped to reflect our use for an indeterminant time.
25190a915fadSSam Leffler  */
25201a1e1d21SSam Leffler int
2521b032f27cSSam Leffler ieee80211_send_mgmt(struct ieee80211_node *ni, int type, int arg)
25221a1e1d21SSam Leffler {
25231b6167d2SSam Leffler #define	HTFLAGS (IEEE80211_NODE_HT | IEEE80211_NODE_HTCOMPAT)
2524b032f27cSSam Leffler #define	senderr(_x, _v)	do { vap->iv_stats._v++; ret = _x; goto bad; } while (0)
2525b032f27cSSam Leffler 	struct ieee80211vap *vap = ni->ni_vap;
2526b032f27cSSam Leffler 	struct ieee80211com *ic = ni->ni_ic;
2527b032f27cSSam Leffler 	struct ieee80211_node *bss = vap->iv_bss;
25288ac160cdSSam Leffler 	struct ieee80211_bpf_params params;
25291a1e1d21SSam Leffler 	struct mbuf *m;
253068e8e04eSSam Leffler 	uint8_t *frm;
253168e8e04eSSam Leffler 	uint16_t capinfo;
253268e8e04eSSam Leffler 	int has_challenge, is_shared_key, ret, status;
25331a1e1d21SSam Leffler 
25340a915fadSSam Leffler 	KASSERT(ni != NULL, ("null node"));
25350a915fadSSam Leffler 
25360a915fadSSam Leffler 	/*
25370a915fadSSam Leffler 	 * Hold a reference on the node so it doesn't go away until after
25380a915fadSSam Leffler 	 * the xmit is complete all the way in the driver.  On error we
25390a915fadSSam Leffler 	 * will remove our reference.
25400a915fadSSam Leffler 	 */
2541b032f27cSSam Leffler 	IEEE80211_DPRINTF(vap, IEEE80211_MSG_NODE,
254249a15236SSam Leffler 		"ieee80211_ref_node (%s:%u) %p<%s> refcnt %d\n",
25438a1b9b6aSSam Leffler 		__func__, __LINE__,
254449a15236SSam Leffler 		ni, ether_sprintf(ni->ni_macaddr),
25458a1b9b6aSSam Leffler 		ieee80211_node_refcnt(ni)+1);
25460a915fadSSam Leffler 	ieee80211_ref_node(ni);
25478a1b9b6aSSam Leffler 
25488ac160cdSSam Leffler 	memset(&params, 0, sizeof(params));
25491a1e1d21SSam Leffler 	switch (type) {
25501a1e1d21SSam Leffler 
25511a1e1d21SSam Leffler 	case IEEE80211_FC0_SUBTYPE_AUTH:
25528a1b9b6aSSam Leffler 		status = arg >> 16;
25538a1b9b6aSSam Leffler 		arg &= 0xffff;
25548a1b9b6aSSam Leffler 		has_challenge = ((arg == IEEE80211_AUTH_SHARED_CHALLENGE ||
25558a1b9b6aSSam Leffler 		    arg == IEEE80211_AUTH_SHARED_RESPONSE) &&
25568a1b9b6aSSam Leffler 		    ni->ni_challenge != NULL);
25578a1b9b6aSSam Leffler 
25588a1b9b6aSSam Leffler 		/*
25598a1b9b6aSSam Leffler 		 * Deduce whether we're doing open authentication or
25608a1b9b6aSSam Leffler 		 * shared key authentication.  We do the latter if
25618a1b9b6aSSam Leffler 		 * we're in the middle of a shared key authentication
25628a1b9b6aSSam Leffler 		 * handshake or if we're initiating an authentication
25638a1b9b6aSSam Leffler 		 * request and configured to use shared key.
25648a1b9b6aSSam Leffler 		 */
25658a1b9b6aSSam Leffler 		is_shared_key = has_challenge ||
25668a1b9b6aSSam Leffler 		     arg >= IEEE80211_AUTH_SHARED_RESPONSE ||
25678a1b9b6aSSam Leffler 		     (arg == IEEE80211_AUTH_SHARED_REQUEST &&
2568b032f27cSSam Leffler 		      bss->ni_authmode == IEEE80211_AUTH_SHARED);
25698a1b9b6aSSam Leffler 
25708a1b9b6aSSam Leffler 		m = ieee80211_getmgtframe(&frm,
257168e8e04eSSam Leffler 			  ic->ic_headroom + sizeof(struct ieee80211_frame),
257268e8e04eSSam Leffler 			  3 * sizeof(uint16_t)
25738a1b9b6aSSam Leffler 			+ (has_challenge && status == IEEE80211_STATUS_SUCCESS ?
257468e8e04eSSam Leffler 				sizeof(uint16_t)+IEEE80211_CHALLENGE_LEN : 0)
25758a1b9b6aSSam Leffler 		);
25761a1e1d21SSam Leffler 		if (m == NULL)
25778a1b9b6aSSam Leffler 			senderr(ENOMEM, is_tx_nobuf);
25788a1b9b6aSSam Leffler 
257968e8e04eSSam Leffler 		((uint16_t *)frm)[0] =
25808a1b9b6aSSam Leffler 		    (is_shared_key) ? htole16(IEEE80211_AUTH_ALG_SHARED)
25818a1b9b6aSSam Leffler 		                    : htole16(IEEE80211_AUTH_ALG_OPEN);
258268e8e04eSSam Leffler 		((uint16_t *)frm)[1] = htole16(arg);	/* sequence number */
258368e8e04eSSam Leffler 		((uint16_t *)frm)[2] = htole16(status);/* status */
25848a1b9b6aSSam Leffler 
25858a1b9b6aSSam Leffler 		if (has_challenge && status == IEEE80211_STATUS_SUCCESS) {
258668e8e04eSSam Leffler 			((uint16_t *)frm)[3] =
25878a1b9b6aSSam Leffler 			    htole16((IEEE80211_CHALLENGE_LEN << 8) |
25888a1b9b6aSSam Leffler 			    IEEE80211_ELEMID_CHALLENGE);
258968e8e04eSSam Leffler 			memcpy(&((uint16_t *)frm)[4], ni->ni_challenge,
25908a1b9b6aSSam Leffler 			    IEEE80211_CHALLENGE_LEN);
25918a1b9b6aSSam Leffler 			m->m_pkthdr.len = m->m_len =
259268e8e04eSSam Leffler 				4 * sizeof(uint16_t) + IEEE80211_CHALLENGE_LEN;
25938a1b9b6aSSam Leffler 			if (arg == IEEE80211_AUTH_SHARED_RESPONSE) {
2594b032f27cSSam Leffler 				IEEE80211_NOTE(vap, IEEE80211_MSG_AUTH, ni,
2595b032f27cSSam Leffler 				    "request encrypt frame (%s)", __func__);
25968ac160cdSSam Leffler 				/* mark frame for encryption */
25978ac160cdSSam Leffler 				params.ibp_flags |= IEEE80211_BPF_CRYPTO;
25988a1b9b6aSSam Leffler 			}
25998a1b9b6aSSam Leffler 		} else
260068e8e04eSSam Leffler 			m->m_pkthdr.len = m->m_len = 3 * sizeof(uint16_t);
26018a1b9b6aSSam Leffler 
26028a1b9b6aSSam Leffler 		/* XXX not right for shared key */
26038a1b9b6aSSam Leffler 		if (status == IEEE80211_STATUS_SUCCESS)
26048a1b9b6aSSam Leffler 			IEEE80211_NODE_STAT(ni, tx_auth);
26058a1b9b6aSSam Leffler 		else
26068a1b9b6aSSam Leffler 			IEEE80211_NODE_STAT(ni, tx_auth_fail);
26078a1b9b6aSSam Leffler 
2608b032f27cSSam Leffler 		if (vap->iv_opmode == IEEE80211_M_STA)
260968e8e04eSSam Leffler 			ieee80211_add_callback(m, ieee80211_tx_mgt_cb,
2610b032f27cSSam Leffler 				(void *) vap->iv_state);
26111a1e1d21SSam Leffler 		break;
26121a1e1d21SSam Leffler 
26131a1e1d21SSam Leffler 	case IEEE80211_FC0_SUBTYPE_DEAUTH:
2614b032f27cSSam Leffler 		IEEE80211_NOTE(vap, IEEE80211_MSG_AUTH, ni,
2615d72d72d3SAndriy Voskoboinyk 		    "send station deauthenticate (reason: %d (%s))", arg,
2616d72d72d3SAndriy Voskoboinyk 		    ieee80211_reason_to_string(arg));
261768e8e04eSSam Leffler 		m = ieee80211_getmgtframe(&frm,
261868e8e04eSSam Leffler 			ic->ic_headroom + sizeof(struct ieee80211_frame),
261968e8e04eSSam Leffler 			sizeof(uint16_t));
26201a1e1d21SSam Leffler 		if (m == NULL)
26218a1b9b6aSSam Leffler 			senderr(ENOMEM, is_tx_nobuf);
262268e8e04eSSam Leffler 		*(uint16_t *)frm = htole16(arg);	/* reason */
262368e8e04eSSam Leffler 		m->m_pkthdr.len = m->m_len = sizeof(uint16_t);
26248a1b9b6aSSam Leffler 
26258a1b9b6aSSam Leffler 		IEEE80211_NODE_STAT(ni, tx_deauth);
26268a1b9b6aSSam Leffler 		IEEE80211_NODE_STAT_SET(ni, tx_deauth_code, arg);
26278a1b9b6aSSam Leffler 
2628e4918ecdSSam Leffler 		ieee80211_node_unauthorize(ni);		/* port closed */
26291a1e1d21SSam Leffler 		break;
26301a1e1d21SSam Leffler 
26311a1e1d21SSam Leffler 	case IEEE80211_FC0_SUBTYPE_ASSOC_REQ:
26321a1e1d21SSam Leffler 	case IEEE80211_FC0_SUBTYPE_REASSOC_REQ:
26331a1e1d21SSam Leffler 		/*
26341a1e1d21SSam Leffler 		 * asreq frame format
26351a1e1d21SSam Leffler 		 *	[2] capability information
26361a1e1d21SSam Leffler 		 *	[2] listen interval
26371a1e1d21SSam Leffler 		 *	[6*] current AP address (reassoc only)
26381a1e1d21SSam Leffler 		 *	[tlv] ssid
26391a1e1d21SSam Leffler 		 *	[tlv] supported rates
26401a1e1d21SSam Leffler 		 *	[tlv] extended supported rates
2641b032f27cSSam Leffler 		 *	[4] power capability (optional)
2642b032f27cSSam Leffler 		 *	[28] supported channels (optional)
264368e8e04eSSam Leffler 		 *	[tlv] HT capabilities
264451172f62SAdrian Chadd 		 *	[tlv] VHT capabilities
2645b032f27cSSam Leffler 		 *	[tlv] WME (optional)
264668e8e04eSSam Leffler 		 *	[tlv] Vendor OUI HT capabilities (optional)
264768e8e04eSSam Leffler 		 *	[tlv] Atheros capabilities (if negotiated)
2648b032f27cSSam Leffler 		 *	[tlv] AppIE's (optional)
26491a1e1d21SSam Leffler 		 */
26508a1b9b6aSSam Leffler 		m = ieee80211_getmgtframe(&frm,
265168e8e04eSSam Leffler 			 ic->ic_headroom + sizeof(struct ieee80211_frame),
265268e8e04eSSam Leffler 			 sizeof(uint16_t)
265368e8e04eSSam Leffler 		       + sizeof(uint16_t)
26541a1e1d21SSam Leffler 		       + IEEE80211_ADDR_LEN
26558a1b9b6aSSam Leffler 		       + 2 + IEEE80211_NWID_LEN
26561a1e1d21SSam Leffler 		       + 2 + IEEE80211_RATE_SIZE
26578a1b9b6aSSam Leffler 		       + 2 + (IEEE80211_RATE_MAXSIZE - IEEE80211_RATE_SIZE)
2658b032f27cSSam Leffler 		       + 4
2659b032f27cSSam Leffler 		       + 2 + 26
26608a1b9b6aSSam Leffler 		       + sizeof(struct ieee80211_wme_info)
2661b032f27cSSam Leffler 		       + sizeof(struct ieee80211_ie_htcap)
266251172f62SAdrian Chadd 		       + sizeof(struct ieee80211_ie_vhtcap)
2663b032f27cSSam Leffler 		       + 4 + sizeof(struct ieee80211_ie_htcap)
2664616190d0SSam Leffler #ifdef IEEE80211_SUPPORT_SUPERG
266568e8e04eSSam Leffler 		       + sizeof(struct ieee80211_ath_ie)
2666616190d0SSam Leffler #endif
2667b032f27cSSam Leffler 		       + (vap->iv_appie_wpa != NULL ?
2668b032f27cSSam Leffler 				vap->iv_appie_wpa->ie_len : 0)
2669b032f27cSSam Leffler 		       + (vap->iv_appie_assocreq != NULL ?
2670b032f27cSSam Leffler 				vap->iv_appie_assocreq->ie_len : 0)
26718a1b9b6aSSam Leffler 		);
26721a1e1d21SSam Leffler 		if (m == NULL)
26738a1b9b6aSSam Leffler 			senderr(ENOMEM, is_tx_nobuf);
26741a1e1d21SSam Leffler 
2675b032f27cSSam Leffler 		KASSERT(vap->iv_opmode == IEEE80211_M_STA,
2676b032f27cSSam Leffler 		    ("wrong mode %u", vap->iv_opmode));
2677667dad55SSam Leffler 		capinfo = IEEE80211_CAPINFO_ESS;
2678b032f27cSSam Leffler 		if (vap->iv_flags & IEEE80211_F_PRIVACY)
26791a1e1d21SSam Leffler 			capinfo |= IEEE80211_CAPINFO_PRIVACY;
26804f2e09c4SSam Leffler 		/*
26814f2e09c4SSam Leffler 		 * NB: Some 11a AP's reject the request when
2682191ccdf5SAndriy Voskoboinyk 		 *     short preamble is set.
26834f2e09c4SSam Leffler 		 */
26844f2e09c4SSam Leffler 		if ((ic->ic_flags & IEEE80211_F_SHPREAMBLE) &&
2685b5c99415SSam Leffler 		    IEEE80211_IS_CHAN_2GHZ(ic->ic_curchan))
26861a1e1d21SSam Leffler 			capinfo |= IEEE80211_CAPINFO_SHORT_PREAMBLE;
268768e8e04eSSam Leffler 		if (IEEE80211_IS_CHAN_ANYG(ic->ic_curchan) &&
26888a1b9b6aSSam Leffler 		    (ic->ic_caps & IEEE80211_C_SHSLOT))
26891a1e1d21SSam Leffler 			capinfo |= IEEE80211_CAPINFO_SHORT_SLOTTIME;
26901b6167d2SSam Leffler 		if ((ni->ni_capinfo & IEEE80211_CAPINFO_SPECTRUM_MGMT) &&
2691b032f27cSSam Leffler 		    (vap->iv_flags & IEEE80211_F_DOTH))
26921b6167d2SSam Leffler 			capinfo |= IEEE80211_CAPINFO_SPECTRUM_MGMT;
269368e8e04eSSam Leffler 		*(uint16_t *)frm = htole16(capinfo);
26941a1e1d21SSam Leffler 		frm += 2;
26951a1e1d21SSam Leffler 
2696b032f27cSSam Leffler 		KASSERT(bss->ni_intval != 0, ("beacon interval is zero!"));
269768e8e04eSSam Leffler 		*(uint16_t *)frm = htole16(howmany(ic->ic_lintval,
2698b032f27cSSam Leffler 						    bss->ni_intval));
26991a1e1d21SSam Leffler 		frm += 2;
27001a1e1d21SSam Leffler 
27011a1e1d21SSam Leffler 		if (type == IEEE80211_FC0_SUBTYPE_REASSOC_REQ) {
2702b032f27cSSam Leffler 			IEEE80211_ADDR_COPY(frm, bss->ni_bssid);
27031a1e1d21SSam Leffler 			frm += IEEE80211_ADDR_LEN;
27041a1e1d21SSam Leffler 		}
27051a1e1d21SSam Leffler 
27061a1e1d21SSam Leffler 		frm = ieee80211_add_ssid(frm, ni->ni_essid, ni->ni_esslen);
27071a1e1d21SSam Leffler 		frm = ieee80211_add_rates(frm, &ni->ni_rates);
2708d8df5f3dSRui Paulo 		frm = ieee80211_add_rsn(frm, vap);
2709b032f27cSSam Leffler 		frm = ieee80211_add_xrates(frm, &ni->ni_rates);
2710b032f27cSSam Leffler 		if (capinfo & IEEE80211_CAPINFO_SPECTRUM_MGMT) {
2711b032f27cSSam Leffler 			frm = ieee80211_add_powercapability(frm,
2712b032f27cSSam Leffler 			    ic->ic_curchan);
2713b032f27cSSam Leffler 			frm = ieee80211_add_supportedchannels(frm, ic);
2714b032f27cSSam Leffler 		}
2715b83391bfSAdrian Chadd 
2716b83391bfSAdrian Chadd 		/*
2717b83391bfSAdrian Chadd 		 * Check the channel - we may be using an 11n NIC with an
2718b83391bfSAdrian Chadd 		 * 11n capable station, but we're configured to be an 11b
2719b83391bfSAdrian Chadd 		 * channel.
2720b83391bfSAdrian Chadd 		 */
27212bfc8a91SSam Leffler 		if ((vap->iv_flags_ht & IEEE80211_FHT_HT) &&
2722b83391bfSAdrian Chadd 		    IEEE80211_IS_CHAN_HT(ni->ni_chan) &&
2723b032f27cSSam Leffler 		    ni->ni_ies.htcap_ie != NULL &&
2724b83391bfSAdrian Chadd 		    ni->ni_ies.htcap_ie[0] == IEEE80211_ELEMID_HTCAP) {
2725b032f27cSSam Leffler 			frm = ieee80211_add_htcap(frm, ni);
2726b83391bfSAdrian Chadd 		}
272751172f62SAdrian Chadd 
272851172f62SAdrian Chadd 		if ((vap->iv_flags_vht & IEEE80211_FVHT_VHT) &&
272951172f62SAdrian Chadd 		    IEEE80211_IS_CHAN_VHT(ni->ni_chan) &&
273051172f62SAdrian Chadd 		    ni->ni_ies.vhtcap_ie != NULL &&
273151172f62SAdrian Chadd 		    ni->ni_ies.vhtcap_ie[0] == IEEE80211_ELEMID_VHT_CAP) {
273251172f62SAdrian Chadd 			frm = ieee80211_add_vhtcap(frm, ni);
273351172f62SAdrian Chadd 		}
273451172f62SAdrian Chadd 
2735d8df5f3dSRui Paulo 		frm = ieee80211_add_wpa(frm, vap);
2736b032f27cSSam Leffler 		if ((ic->ic_flags & IEEE80211_F_WME) &&
2737b032f27cSSam Leffler 		    ni->ni_ies.wme_ie != NULL)
2738b032f27cSSam Leffler 			frm = ieee80211_add_wme_info(frm, &ic->ic_wme);
2739b83391bfSAdrian Chadd 
2740b83391bfSAdrian Chadd 		/*
2741b83391bfSAdrian Chadd 		 * Same deal - only send HT info if we're on an 11n
2742b83391bfSAdrian Chadd 		 * capable channel.
2743b83391bfSAdrian Chadd 		 */
27442bfc8a91SSam Leffler 		if ((vap->iv_flags_ht & IEEE80211_FHT_HT) &&
2745b83391bfSAdrian Chadd 		    IEEE80211_IS_CHAN_HT(ni->ni_chan) &&
2746b032f27cSSam Leffler 		    ni->ni_ies.htcap_ie != NULL &&
2747b83391bfSAdrian Chadd 		    ni->ni_ies.htcap_ie[0] == IEEE80211_ELEMID_VENDOR) {
2748b032f27cSSam Leffler 			frm = ieee80211_add_htcap_vendor(frm, ni);
2749b83391bfSAdrian Chadd 		}
2750616190d0SSam Leffler #ifdef IEEE80211_SUPPORT_SUPERG
27514207227cSSam Leffler 		if (IEEE80211_ATH_CAP(vap, ni, IEEE80211_F_ATHEROS)) {
2752b032f27cSSam Leffler 			frm = ieee80211_add_ath(frm,
2753b032f27cSSam Leffler 				IEEE80211_ATH_CAP(vap, ni, IEEE80211_F_ATHEROS),
27544207227cSSam Leffler 				((vap->iv_flags & IEEE80211_F_WPA) == 0 &&
27554207227cSSam Leffler 				 ni->ni_authmode != IEEE80211_AUTH_8021X) ?
27564207227cSSam Leffler 				vap->iv_def_txkey : IEEE80211_KEYIX_NONE);
27574207227cSSam Leffler 		}
2758616190d0SSam Leffler #endif /* IEEE80211_SUPPORT_SUPERG */
2759b032f27cSSam Leffler 		if (vap->iv_appie_assocreq != NULL)
2760b032f27cSSam Leffler 			frm = add_appie(frm, vap->iv_appie_assocreq);
276168e8e04eSSam Leffler 		m->m_pkthdr.len = m->m_len = frm - mtod(m, uint8_t *);
27621a1e1d21SSam Leffler 
276368e8e04eSSam Leffler 		ieee80211_add_callback(m, ieee80211_tx_mgt_cb,
2764b032f27cSSam Leffler 			(void *) vap->iv_state);
27651a1e1d21SSam Leffler 		break;
27661a1e1d21SSam Leffler 
27671a1e1d21SSam Leffler 	case IEEE80211_FC0_SUBTYPE_ASSOC_RESP:
27681a1e1d21SSam Leffler 	case IEEE80211_FC0_SUBTYPE_REASSOC_RESP:
27691a1e1d21SSam Leffler 		/*
277068e8e04eSSam Leffler 		 * asresp frame format
27711a1e1d21SSam Leffler 		 *	[2] capability information
27721a1e1d21SSam Leffler 		 *	[2] status
27731a1e1d21SSam Leffler 		 *	[2] association ID
27741a1e1d21SSam Leffler 		 *	[tlv] supported rates
27751a1e1d21SSam Leffler 		 *	[tlv] extended supported rates
2776b032f27cSSam Leffler 		 *	[tlv] HT capabilities (standard, if STA enabled)
2777b032f27cSSam Leffler 		 *	[tlv] HT information (standard, if STA enabled)
277851172f62SAdrian Chadd 		 *	[tlv] VHT capabilities (standard, if STA enabled)
277951172f62SAdrian Chadd 		 *	[tlv] VHT information (standard, if STA enabled)
2780b032f27cSSam Leffler 		 *	[tlv] WME (if configured and STA enabled)
2781b032f27cSSam Leffler 		 *	[tlv] HT capabilities (vendor OUI, if STA enabled)
2782b032f27cSSam Leffler 		 *	[tlv] HT information (vendor OUI, if STA enabled)
2783b032f27cSSam Leffler 		 *	[tlv] Atheros capabilities (if STA enabled)
2784b032f27cSSam Leffler 		 *	[tlv] AppIE's (optional)
27851a1e1d21SSam Leffler 		 */
27868a1b9b6aSSam Leffler 		m = ieee80211_getmgtframe(&frm,
278768e8e04eSSam Leffler 			 ic->ic_headroom + sizeof(struct ieee80211_frame),
278868e8e04eSSam Leffler 			 sizeof(uint16_t)
278968e8e04eSSam Leffler 		       + sizeof(uint16_t)
279068e8e04eSSam Leffler 		       + sizeof(uint16_t)
27911a1e1d21SSam Leffler 		       + 2 + IEEE80211_RATE_SIZE
27928a1b9b6aSSam Leffler 		       + 2 + (IEEE80211_RATE_MAXSIZE - IEEE80211_RATE_SIZE)
279368e8e04eSSam Leffler 		       + sizeof(struct ieee80211_ie_htcap) + 4
279468e8e04eSSam Leffler 		       + sizeof(struct ieee80211_ie_htinfo) + 4
279551172f62SAdrian Chadd 		       + sizeof(struct ieee80211_ie_vhtcap)
279651172f62SAdrian Chadd 		       + sizeof(struct ieee80211_ie_vht_operation)
2797b032f27cSSam Leffler 		       + sizeof(struct ieee80211_wme_param)
2798616190d0SSam Leffler #ifdef IEEE80211_SUPPORT_SUPERG
279968e8e04eSSam Leffler 		       + sizeof(struct ieee80211_ath_ie)
2800616190d0SSam Leffler #endif
2801b032f27cSSam Leffler 		       + (vap->iv_appie_assocresp != NULL ?
2802b032f27cSSam Leffler 				vap->iv_appie_assocresp->ie_len : 0)
28038a1b9b6aSSam Leffler 		);
28041a1e1d21SSam Leffler 		if (m == NULL)
28058a1b9b6aSSam Leffler 			senderr(ENOMEM, is_tx_nobuf);
28061a1e1d21SSam Leffler 
280759aa14a9SRui Paulo 		capinfo = ieee80211_getcapinfo(vap, bss->ni_chan);
280868e8e04eSSam Leffler 		*(uint16_t *)frm = htole16(capinfo);
28091a1e1d21SSam Leffler 		frm += 2;
28101a1e1d21SSam Leffler 
281168e8e04eSSam Leffler 		*(uint16_t *)frm = htole16(arg);	/* status */
28121a1e1d21SSam Leffler 		frm += 2;
28131a1e1d21SSam Leffler 
28148a1b9b6aSSam Leffler 		if (arg == IEEE80211_STATUS_SUCCESS) {
281568e8e04eSSam Leffler 			*(uint16_t *)frm = htole16(ni->ni_associd);
28168a1b9b6aSSam Leffler 			IEEE80211_NODE_STAT(ni, tx_assoc);
28178a1b9b6aSSam Leffler 		} else
28188a1b9b6aSSam Leffler 			IEEE80211_NODE_STAT(ni, tx_assoc_fail);
28191a1e1d21SSam Leffler 		frm += 2;
28201a1e1d21SSam Leffler 
28211a1e1d21SSam Leffler 		frm = ieee80211_add_rates(frm, &ni->ni_rates);
28221a1e1d21SSam Leffler 		frm = ieee80211_add_xrates(frm, &ni->ni_rates);
282368e8e04eSSam Leffler 		/* NB: respond according to what we received */
28241b6167d2SSam Leffler 		if ((ni->ni_flags & HTFLAGS) == IEEE80211_NODE_HT) {
282568e8e04eSSam Leffler 			frm = ieee80211_add_htcap(frm, ni);
282668e8e04eSSam Leffler 			frm = ieee80211_add_htinfo(frm, ni);
282768e8e04eSSam Leffler 		}
2828b032f27cSSam Leffler 		if ((vap->iv_flags & IEEE80211_F_WME) &&
2829b032f27cSSam Leffler 		    ni->ni_ies.wme_ie != NULL)
28301b6167d2SSam Leffler 			frm = ieee80211_add_wme_param(frm, &ic->ic_wme);
28311b6167d2SSam Leffler 		if ((ni->ni_flags & HTFLAGS) == HTFLAGS) {
28321b6167d2SSam Leffler 			frm = ieee80211_add_htcap_vendor(frm, ni);
28331b6167d2SSam Leffler 			frm = ieee80211_add_htinfo_vendor(frm, ni);
283468e8e04eSSam Leffler 		}
283551172f62SAdrian Chadd 		if (ni->ni_flags & IEEE80211_NODE_VHT) {
283651172f62SAdrian Chadd 			frm = ieee80211_add_vhtcap(frm, ni);
283751172f62SAdrian Chadd 			frm = ieee80211_add_vhtinfo(frm, ni);
283851172f62SAdrian Chadd 		}
2839616190d0SSam Leffler #ifdef IEEE80211_SUPPORT_SUPERG
2840b032f27cSSam Leffler 		if (IEEE80211_ATH_CAP(vap, ni, IEEE80211_F_ATHEROS))
284168e8e04eSSam Leffler 			frm = ieee80211_add_ath(frm,
2842b032f27cSSam Leffler 				IEEE80211_ATH_CAP(vap, ni, IEEE80211_F_ATHEROS),
28434207227cSSam Leffler 				((vap->iv_flags & IEEE80211_F_WPA) == 0 &&
28444207227cSSam Leffler 				 ni->ni_authmode != IEEE80211_AUTH_8021X) ?
28454207227cSSam Leffler 				vap->iv_def_txkey : IEEE80211_KEYIX_NONE);
2846616190d0SSam Leffler #endif /* IEEE80211_SUPPORT_SUPERG */
2847b032f27cSSam Leffler 		if (vap->iv_appie_assocresp != NULL)
2848b032f27cSSam Leffler 			frm = add_appie(frm, vap->iv_appie_assocresp);
284968e8e04eSSam Leffler 		m->m_pkthdr.len = m->m_len = frm - mtod(m, uint8_t *);
28501a1e1d21SSam Leffler 		break;
28511a1e1d21SSam Leffler 
28521a1e1d21SSam Leffler 	case IEEE80211_FC0_SUBTYPE_DISASSOC:
2853b032f27cSSam Leffler 		IEEE80211_NOTE(vap, IEEE80211_MSG_ASSOC, ni,
2854d72d72d3SAndriy Voskoboinyk 		    "send station disassociate (reason: %d (%s))", arg,
2855d72d72d3SAndriy Voskoboinyk 		    ieee80211_reason_to_string(arg));
285668e8e04eSSam Leffler 		m = ieee80211_getmgtframe(&frm,
285768e8e04eSSam Leffler 			ic->ic_headroom + sizeof(struct ieee80211_frame),
285868e8e04eSSam Leffler 			sizeof(uint16_t));
28591a1e1d21SSam Leffler 		if (m == NULL)
28608a1b9b6aSSam Leffler 			senderr(ENOMEM, is_tx_nobuf);
286168e8e04eSSam Leffler 		*(uint16_t *)frm = htole16(arg);	/* reason */
286268e8e04eSSam Leffler 		m->m_pkthdr.len = m->m_len = sizeof(uint16_t);
28638a1b9b6aSSam Leffler 
28648a1b9b6aSSam Leffler 		IEEE80211_NODE_STAT(ni, tx_disassoc);
28658a1b9b6aSSam Leffler 		IEEE80211_NODE_STAT_SET(ni, tx_disassoc_code, arg);
28661a1e1d21SSam Leffler 		break;
28671a1e1d21SSam Leffler 
28681a1e1d21SSam Leffler 	default:
2869b032f27cSSam Leffler 		IEEE80211_NOTE(vap, IEEE80211_MSG_ANY, ni,
2870b032f27cSSam Leffler 		    "invalid mgmt frame type %u", type);
28711be50176SSam Leffler 		senderr(EINVAL, is_tx_unknownmgt);
28720a915fadSSam Leffler 		/* NOTREACHED */
28731a1e1d21SSam Leffler 	}
287468e8e04eSSam Leffler 
28758ac160cdSSam Leffler 	/* NB: force non-ProbeResp frames to the highest queue */
28768ac160cdSSam Leffler 	params.ibp_pri = WME_AC_VO;
28778ac160cdSSam Leffler 	params.ibp_rate0 = bss->ni_txparms->mgmtrate;
28788ac160cdSSam Leffler 	/* NB: we know all frames are unicast */
28798ac160cdSSam Leffler 	params.ibp_try0 = bss->ni_txparms->maxretry;
28808ac160cdSSam Leffler 	params.ibp_power = bss->ni_txpower;
28818ac160cdSSam Leffler 	return ieee80211_mgmt_output(ni, m, type, &params);
28820a915fadSSam Leffler bad:
28838a1b9b6aSSam Leffler 	ieee80211_free_node(ni);
28841a1e1d21SSam Leffler 	return ret;
28850a915fadSSam Leffler #undef senderr
28861b6167d2SSam Leffler #undef HTFLAGS
28871a1e1d21SSam Leffler }
28888a1b9b6aSSam Leffler 
2889b032f27cSSam Leffler /*
2890b032f27cSSam Leffler  * Return an mbuf with a probe response frame in it.
2891b032f27cSSam Leffler  * Space is left to prepend and 802.11 header at the
2892b032f27cSSam Leffler  * front but it's left to the caller to fill in.
2893b032f27cSSam Leffler  */
2894b032f27cSSam Leffler struct mbuf *
2895b032f27cSSam Leffler ieee80211_alloc_proberesp(struct ieee80211_node *bss, int legacy)
2896b032f27cSSam Leffler {
2897b032f27cSSam Leffler 	struct ieee80211vap *vap = bss->ni_vap;
2898b032f27cSSam Leffler 	struct ieee80211com *ic = bss->ni_ic;
2899b032f27cSSam Leffler 	const struct ieee80211_rateset *rs;
2900b032f27cSSam Leffler 	struct mbuf *m;
2901b032f27cSSam Leffler 	uint16_t capinfo;
2902b032f27cSSam Leffler 	uint8_t *frm;
2903b032f27cSSam Leffler 
2904b032f27cSSam Leffler 	/*
2905b032f27cSSam Leffler 	 * probe response frame format
2906b032f27cSSam Leffler 	 *	[8] time stamp
2907b032f27cSSam Leffler 	 *	[2] beacon interval
2908b032f27cSSam Leffler 	 *	[2] cabability information
2909b032f27cSSam Leffler 	 *	[tlv] ssid
2910b032f27cSSam Leffler 	 *	[tlv] supported rates
2911b032f27cSSam Leffler 	 *	[tlv] parameter set (FH/DS)
2912b032f27cSSam Leffler 	 *	[tlv] parameter set (IBSS)
2913b032f27cSSam Leffler 	 *	[tlv] country (optional)
2914b032f27cSSam Leffler 	 *	[3] power control (optional)
2915b032f27cSSam Leffler 	 *	[5] channel switch announcement (CSA) (optional)
2916b032f27cSSam Leffler 	 *	[tlv] extended rate phy (ERP)
2917b032f27cSSam Leffler 	 *	[tlv] extended supported rates
2918688fe74dSSam Leffler 	 *	[tlv] RSN (optional)
2919b032f27cSSam Leffler 	 *	[tlv] HT capabilities
2920b032f27cSSam Leffler 	 *	[tlv] HT information
2921ac0b7d32SAdrian Chadd 	 *	[tlv] VHT capabilities
2922ac0b7d32SAdrian Chadd 	 *	[tlv] VHT information
2923b032f27cSSam Leffler 	 *	[tlv] WPA (optional)
2924b032f27cSSam Leffler 	 *	[tlv] WME (optional)
2925b032f27cSSam Leffler 	 *	[tlv] Vendor OUI HT capabilities (optional)
2926b032f27cSSam Leffler 	 *	[tlv] Vendor OUI HT information (optional)
2927b032f27cSSam Leffler 	 *	[tlv] Atheros capabilities
2928b032f27cSSam Leffler 	 *	[tlv] AppIE's (optional)
292959aa14a9SRui Paulo 	 *	[tlv] Mesh ID (MBSS)
293059aa14a9SRui Paulo 	 *	[tlv] Mesh Conf (MBSS)
2931b032f27cSSam Leffler 	 */
2932b032f27cSSam Leffler 	m = ieee80211_getmgtframe(&frm,
2933b032f27cSSam Leffler 		 ic->ic_headroom + sizeof(struct ieee80211_frame),
2934b032f27cSSam Leffler 		 8
2935b032f27cSSam Leffler 	       + sizeof(uint16_t)
2936b032f27cSSam Leffler 	       + sizeof(uint16_t)
2937b032f27cSSam Leffler 	       + 2 + IEEE80211_NWID_LEN
2938b032f27cSSam Leffler 	       + 2 + IEEE80211_RATE_SIZE
2939b032f27cSSam Leffler 	       + 7	/* max(7,3) */
2940b032f27cSSam Leffler 	       + IEEE80211_COUNTRY_MAX_SIZE
2941b032f27cSSam Leffler 	       + 3
2942b032f27cSSam Leffler 	       + sizeof(struct ieee80211_csa_ie)
294332b0e64bSAdrian Chadd 	       + sizeof(struct ieee80211_quiet_ie)
2944b032f27cSSam Leffler 	       + 3
2945b032f27cSSam Leffler 	       + 2 + (IEEE80211_RATE_MAXSIZE - IEEE80211_RATE_SIZE)
2946688fe74dSSam Leffler 	       + sizeof(struct ieee80211_ie_wpa)
2947b032f27cSSam Leffler 	       + sizeof(struct ieee80211_ie_htcap)
2948b032f27cSSam Leffler 	       + sizeof(struct ieee80211_ie_htinfo)
2949b032f27cSSam Leffler 	       + sizeof(struct ieee80211_ie_wpa)
2950b032f27cSSam Leffler 	       + sizeof(struct ieee80211_wme_param)
2951b032f27cSSam Leffler 	       + 4 + sizeof(struct ieee80211_ie_htcap)
2952b032f27cSSam Leffler 	       + 4 + sizeof(struct ieee80211_ie_htinfo)
2953ac0b7d32SAdrian Chadd 	       +  sizeof(struct ieee80211_ie_vhtcap)
2954ac0b7d32SAdrian Chadd 	       +  sizeof(struct ieee80211_ie_vht_operation)
2955616190d0SSam Leffler #ifdef IEEE80211_SUPPORT_SUPERG
2956b032f27cSSam Leffler 	       + sizeof(struct ieee80211_ath_ie)
2957616190d0SSam Leffler #endif
295859aa14a9SRui Paulo #ifdef IEEE80211_SUPPORT_MESH
295959aa14a9SRui Paulo 	       + 2 + IEEE80211_MESHID_LEN
296059aa14a9SRui Paulo 	       + sizeof(struct ieee80211_meshconf_ie)
296159aa14a9SRui Paulo #endif
2962b032f27cSSam Leffler 	       + (vap->iv_appie_proberesp != NULL ?
2963b032f27cSSam Leffler 			vap->iv_appie_proberesp->ie_len : 0)
2964b032f27cSSam Leffler 	);
2965b032f27cSSam Leffler 	if (m == NULL) {
2966b032f27cSSam Leffler 		vap->iv_stats.is_tx_nobuf++;
2967b032f27cSSam Leffler 		return NULL;
2968b032f27cSSam Leffler 	}
2969b032f27cSSam Leffler 
2970b032f27cSSam Leffler 	memset(frm, 0, 8);	/* timestamp should be filled later */
2971b032f27cSSam Leffler 	frm += 8;
2972b032f27cSSam Leffler 	*(uint16_t *)frm = htole16(bss->ni_intval);
2973b032f27cSSam Leffler 	frm += 2;
297459aa14a9SRui Paulo 	capinfo = ieee80211_getcapinfo(vap, bss->ni_chan);
2975b032f27cSSam Leffler 	*(uint16_t *)frm = htole16(capinfo);
2976b032f27cSSam Leffler 	frm += 2;
2977b032f27cSSam Leffler 
2978b032f27cSSam Leffler 	frm = ieee80211_add_ssid(frm, bss->ni_essid, bss->ni_esslen);
2979b032f27cSSam Leffler 	rs = ieee80211_get_suprates(ic, bss->ni_chan);
2980b032f27cSSam Leffler 	frm = ieee80211_add_rates(frm, rs);
2981b032f27cSSam Leffler 
2982b032f27cSSam Leffler 	if (IEEE80211_IS_CHAN_FHSS(bss->ni_chan)) {
2983b032f27cSSam Leffler 		*frm++ = IEEE80211_ELEMID_FHPARMS;
2984b032f27cSSam Leffler 		*frm++ = 5;
2985b032f27cSSam Leffler 		*frm++ = bss->ni_fhdwell & 0x00ff;
2986b032f27cSSam Leffler 		*frm++ = (bss->ni_fhdwell >> 8) & 0x00ff;
2987b032f27cSSam Leffler 		*frm++ = IEEE80211_FH_CHANSET(
2988b032f27cSSam Leffler 		    ieee80211_chan2ieee(ic, bss->ni_chan));
2989b032f27cSSam Leffler 		*frm++ = IEEE80211_FH_CHANPAT(
2990b032f27cSSam Leffler 		    ieee80211_chan2ieee(ic, bss->ni_chan));
2991b032f27cSSam Leffler 		*frm++ = bss->ni_fhindex;
2992b032f27cSSam Leffler 	} else {
2993b032f27cSSam Leffler 		*frm++ = IEEE80211_ELEMID_DSPARMS;
2994b032f27cSSam Leffler 		*frm++ = 1;
2995b032f27cSSam Leffler 		*frm++ = ieee80211_chan2ieee(ic, bss->ni_chan);
2996b032f27cSSam Leffler 	}
2997b032f27cSSam Leffler 
2998b032f27cSSam Leffler 	if (vap->iv_opmode == IEEE80211_M_IBSS) {
2999b032f27cSSam Leffler 		*frm++ = IEEE80211_ELEMID_IBSSPARMS;
3000b032f27cSSam Leffler 		*frm++ = 2;
3001b032f27cSSam Leffler 		*frm++ = 0; *frm++ = 0;		/* TODO: ATIM window */
3002b032f27cSSam Leffler 	}
3003b032f27cSSam Leffler 	if ((vap->iv_flags & IEEE80211_F_DOTH) ||
3004b032f27cSSam Leffler 	    (vap->iv_flags_ext & IEEE80211_FEXT_DOTD))
3005b032f27cSSam Leffler 		frm = ieee80211_add_countryie(frm, ic);
3006b032f27cSSam Leffler 	if (vap->iv_flags & IEEE80211_F_DOTH) {
3007b032f27cSSam Leffler 		if (IEEE80211_IS_CHAN_5GHZ(bss->ni_chan))
3008b032f27cSSam Leffler 			frm = ieee80211_add_powerconstraint(frm, vap);
3009b032f27cSSam Leffler 		if (ic->ic_flags & IEEE80211_F_CSAPENDING)
3010b032f27cSSam Leffler 			frm = ieee80211_add_csa(frm, vap);
3011b032f27cSSam Leffler 	}
301232b0e64bSAdrian Chadd 	if (vap->iv_flags & IEEE80211_F_DOTH) {
301332b0e64bSAdrian Chadd 		if (IEEE80211_IS_CHAN_DFS(ic->ic_bsschan) &&
301432b0e64bSAdrian Chadd 		    (vap->iv_flags_ext & IEEE80211_FEXT_DFS)) {
301532b0e64bSAdrian Chadd 			if (vap->iv_quiet)
3016ce4552cdSAdrian Chadd 				frm = ieee80211_add_quiet(frm, vap, 0);
301732b0e64bSAdrian Chadd 		}
301832b0e64bSAdrian Chadd 	}
3019b032f27cSSam Leffler 	if (IEEE80211_IS_CHAN_ANYG(bss->ni_chan))
3020b032f27cSSam Leffler 		frm = ieee80211_add_erp(frm, ic);
3021b032f27cSSam Leffler 	frm = ieee80211_add_xrates(frm, rs);
3022d8df5f3dSRui Paulo 	frm = ieee80211_add_rsn(frm, vap);
3023b032f27cSSam Leffler 	/*
3024b032f27cSSam Leffler 	 * NB: legacy 11b clients do not get certain ie's.
3025b032f27cSSam Leffler 	 *     The caller identifies such clients by passing
3026b032f27cSSam Leffler 	 *     a token in legacy to us.  Could expand this to be
3027b032f27cSSam Leffler 	 *     any legacy client for stuff like HT ie's.
3028b032f27cSSam Leffler 	 */
3029b032f27cSSam Leffler 	if (IEEE80211_IS_CHAN_HT(bss->ni_chan) &&
3030b032f27cSSam Leffler 	    legacy != IEEE80211_SEND_LEGACY_11B) {
3031b032f27cSSam Leffler 		frm = ieee80211_add_htcap(frm, bss);
3032b032f27cSSam Leffler 		frm = ieee80211_add_htinfo(frm, bss);
3033b032f27cSSam Leffler 	}
3034ac0b7d32SAdrian Chadd 	if (IEEE80211_IS_CHAN_VHT(bss->ni_chan) &&
3035ac0b7d32SAdrian Chadd 	    legacy != IEEE80211_SEND_LEGACY_11B) {
3036ac0b7d32SAdrian Chadd 		frm = ieee80211_add_vhtcap(frm, bss);
3037ac0b7d32SAdrian Chadd 		frm = ieee80211_add_vhtinfo(frm, bss);
3038ac0b7d32SAdrian Chadd 	}
3039d8df5f3dSRui Paulo 	frm = ieee80211_add_wpa(frm, vap);
3040b032f27cSSam Leffler 	if (vap->iv_flags & IEEE80211_F_WME)
3041b032f27cSSam Leffler 		frm = ieee80211_add_wme_param(frm, &ic->ic_wme);
3042b032f27cSSam Leffler 	if (IEEE80211_IS_CHAN_HT(bss->ni_chan) &&
30432bfc8a91SSam Leffler 	    (vap->iv_flags_ht & IEEE80211_FHT_HTCOMPAT) &&
3044b032f27cSSam Leffler 	    legacy != IEEE80211_SEND_LEGACY_11B) {
3045b032f27cSSam Leffler 		frm = ieee80211_add_htcap_vendor(frm, bss);
3046b032f27cSSam Leffler 		frm = ieee80211_add_htinfo_vendor(frm, bss);
3047b032f27cSSam Leffler 	}
3048616190d0SSam Leffler #ifdef IEEE80211_SUPPORT_SUPERG
30494207227cSSam Leffler 	if ((vap->iv_flags & IEEE80211_F_ATHEROS) &&
30504207227cSSam Leffler 	    legacy != IEEE80211_SEND_LEGACY_11B)
30514207227cSSam Leffler 		frm = ieee80211_add_athcaps(frm, bss);
3052616190d0SSam Leffler #endif
3053b032f27cSSam Leffler 	if (vap->iv_appie_proberesp != NULL)
3054b032f27cSSam Leffler 		frm = add_appie(frm, vap->iv_appie_proberesp);
305559aa14a9SRui Paulo #ifdef IEEE80211_SUPPORT_MESH
305659aa14a9SRui Paulo 	if (vap->iv_opmode == IEEE80211_M_MBSS) {
305759aa14a9SRui Paulo 		frm = ieee80211_add_meshid(frm, vap);
305859aa14a9SRui Paulo 		frm = ieee80211_add_meshconf(frm, vap);
305959aa14a9SRui Paulo 	}
306059aa14a9SRui Paulo #endif
3061b032f27cSSam Leffler 	m->m_pkthdr.len = m->m_len = frm - mtod(m, uint8_t *);
3062b032f27cSSam Leffler 
3063b032f27cSSam Leffler 	return m;
3064b032f27cSSam Leffler }
3065b032f27cSSam Leffler 
3066b032f27cSSam Leffler /*
3067b032f27cSSam Leffler  * Send a probe response frame to the specified mac address.
3068b032f27cSSam Leffler  * This does not go through the normal mgt frame api so we
3069b032f27cSSam Leffler  * can specify the destination address and re-use the bss node
3070b032f27cSSam Leffler  * for the sta reference.
3071b032f27cSSam Leffler  */
3072b032f27cSSam Leffler int
3073b032f27cSSam Leffler ieee80211_send_proberesp(struct ieee80211vap *vap,
3074b032f27cSSam Leffler 	const uint8_t da[IEEE80211_ADDR_LEN], int legacy)
3075b032f27cSSam Leffler {
3076b032f27cSSam Leffler 	struct ieee80211_node *bss = vap->iv_bss;
3077b032f27cSSam Leffler 	struct ieee80211com *ic = vap->iv_ic;
3078b032f27cSSam Leffler 	struct mbuf *m;
30795cda6006SAdrian Chadd 	int ret;
3080b032f27cSSam Leffler 
3081b032f27cSSam Leffler 	if (vap->iv_state == IEEE80211_S_CAC) {
3082b032f27cSSam Leffler 		IEEE80211_NOTE(vap, IEEE80211_MSG_OUTPUT, bss,
3083b032f27cSSam Leffler 		    "block %s frame in CAC state", "probe response");
3084b032f27cSSam Leffler 		vap->iv_stats.is_tx_badstate++;
3085b032f27cSSam Leffler 		return EIO;		/* XXX */
3086b032f27cSSam Leffler 	}
3087b032f27cSSam Leffler 
3088b032f27cSSam Leffler 	/*
3089b032f27cSSam Leffler 	 * Hold a reference on the node so it doesn't go away until after
3090b032f27cSSam Leffler 	 * the xmit is complete all the way in the driver.  On error we
3091b032f27cSSam Leffler 	 * will remove our reference.
3092b032f27cSSam Leffler 	 */
3093b032f27cSSam Leffler 	IEEE80211_DPRINTF(vap, IEEE80211_MSG_NODE,
3094b032f27cSSam Leffler 	    "ieee80211_ref_node (%s:%u) %p<%s> refcnt %d\n",
3095b032f27cSSam Leffler 	    __func__, __LINE__, bss, ether_sprintf(bss->ni_macaddr),
3096b032f27cSSam Leffler 	    ieee80211_node_refcnt(bss)+1);
3097b032f27cSSam Leffler 	ieee80211_ref_node(bss);
3098b032f27cSSam Leffler 
3099b032f27cSSam Leffler 	m = ieee80211_alloc_proberesp(bss, legacy);
3100b032f27cSSam Leffler 	if (m == NULL) {
3101b032f27cSSam Leffler 		ieee80211_free_node(bss);
3102b032f27cSSam Leffler 		return ENOMEM;
3103b032f27cSSam Leffler 	}
3104b032f27cSSam Leffler 
3105eb1b1807SGleb Smirnoff 	M_PREPEND(m, sizeof(struct ieee80211_frame), M_NOWAIT);
3106b032f27cSSam Leffler 	KASSERT(m != NULL, ("no room for header"));
3107b032f27cSSam Leffler 
31085cda6006SAdrian Chadd 	IEEE80211_TX_LOCK(ic);
31099e80b1dfSSam Leffler 	ieee80211_send_setup(bss, m,
3110b032f27cSSam Leffler 	     IEEE80211_FC0_TYPE_MGT | IEEE80211_FC0_SUBTYPE_PROBE_RESP,
31118ac160cdSSam Leffler 	     IEEE80211_NONQOS_TID, vap->iv_myaddr, da, bss->ni_bssid);
3112b032f27cSSam Leffler 	/* XXX power management? */
3113c1af44bdSSam Leffler 	m->m_flags |= M_ENCAP;		/* mark encapsulated */
3114b032f27cSSam Leffler 
3115b032f27cSSam Leffler 	M_WME_SETAC(m, WME_AC_BE);
3116b032f27cSSam Leffler 
3117b032f27cSSam Leffler 	IEEE80211_DPRINTF(vap, IEEE80211_MSG_DEBUG | IEEE80211_MSG_DUMPPKTS,
3118b032f27cSSam Leffler 	    "send probe resp on channel %u to %s%s\n",
3119b032f27cSSam Leffler 	    ieee80211_chan2ieee(ic, ic->ic_curchan), ether_sprintf(da),
3120b032f27cSSam Leffler 	    legacy ? " <legacy>" : "");
3121b032f27cSSam Leffler 	IEEE80211_NODE_STAT(bss, tx_mgmt);
3122b032f27cSSam Leffler 
31235cda6006SAdrian Chadd 	ret = ieee80211_raw_output(vap, bss, m, NULL);
31245cda6006SAdrian Chadd 	IEEE80211_TX_UNLOCK(ic);
31255cda6006SAdrian Chadd 	return (ret);
3126b032f27cSSam Leffler }
3127b032f27cSSam Leffler 
3128b032f27cSSam Leffler /*
3129b032f27cSSam Leffler  * Allocate and build a RTS (Request To Send) control frame.
3130b032f27cSSam Leffler  */
3131b032f27cSSam Leffler struct mbuf *
3132b032f27cSSam Leffler ieee80211_alloc_rts(struct ieee80211com *ic,
3133b032f27cSSam Leffler 	const uint8_t ra[IEEE80211_ADDR_LEN],
3134b032f27cSSam Leffler 	const uint8_t ta[IEEE80211_ADDR_LEN],
3135b032f27cSSam Leffler 	uint16_t dur)
3136b032f27cSSam Leffler {
3137b032f27cSSam Leffler 	struct ieee80211_frame_rts *rts;
3138b032f27cSSam Leffler 	struct mbuf *m;
3139b032f27cSSam Leffler 
3140b032f27cSSam Leffler 	/* XXX honor ic_headroom */
3141eb1b1807SGleb Smirnoff 	m = m_gethdr(M_NOWAIT, MT_DATA);
3142b032f27cSSam Leffler 	if (m != NULL) {
3143b032f27cSSam Leffler 		rts = mtod(m, struct ieee80211_frame_rts *);
3144b032f27cSSam Leffler 		rts->i_fc[0] = IEEE80211_FC0_VERSION_0 |
3145b032f27cSSam Leffler 			IEEE80211_FC0_TYPE_CTL | IEEE80211_FC0_SUBTYPE_RTS;
3146b032f27cSSam Leffler 		rts->i_fc[1] = IEEE80211_FC1_DIR_NODS;
3147b032f27cSSam Leffler 		*(u_int16_t *)rts->i_dur = htole16(dur);
3148b032f27cSSam Leffler 		IEEE80211_ADDR_COPY(rts->i_ra, ra);
3149b032f27cSSam Leffler 		IEEE80211_ADDR_COPY(rts->i_ta, ta);
3150b032f27cSSam Leffler 
3151b032f27cSSam Leffler 		m->m_pkthdr.len = m->m_len = sizeof(struct ieee80211_frame_rts);
3152b032f27cSSam Leffler 	}
3153b032f27cSSam Leffler 	return m;
3154b032f27cSSam Leffler }
3155b032f27cSSam Leffler 
3156b032f27cSSam Leffler /*
3157b032f27cSSam Leffler  * Allocate and build a CTS (Clear To Send) control frame.
3158b032f27cSSam Leffler  */
3159b032f27cSSam Leffler struct mbuf *
3160b032f27cSSam Leffler ieee80211_alloc_cts(struct ieee80211com *ic,
3161b032f27cSSam Leffler 	const uint8_t ra[IEEE80211_ADDR_LEN], uint16_t dur)
3162b032f27cSSam Leffler {
3163b032f27cSSam Leffler 	struct ieee80211_frame_cts *cts;
3164b032f27cSSam Leffler 	struct mbuf *m;
3165b032f27cSSam Leffler 
3166b032f27cSSam Leffler 	/* XXX honor ic_headroom */
3167eb1b1807SGleb Smirnoff 	m = m_gethdr(M_NOWAIT, MT_DATA);
3168b032f27cSSam Leffler 	if (m != NULL) {
3169b032f27cSSam Leffler 		cts = mtod(m, struct ieee80211_frame_cts *);
3170b032f27cSSam Leffler 		cts->i_fc[0] = IEEE80211_FC0_VERSION_0 |
3171b032f27cSSam Leffler 			IEEE80211_FC0_TYPE_CTL | IEEE80211_FC0_SUBTYPE_CTS;
3172b032f27cSSam Leffler 		cts->i_fc[1] = IEEE80211_FC1_DIR_NODS;
3173b032f27cSSam Leffler 		*(u_int16_t *)cts->i_dur = htole16(dur);
3174b032f27cSSam Leffler 		IEEE80211_ADDR_COPY(cts->i_ra, ra);
3175b032f27cSSam Leffler 
3176b032f27cSSam Leffler 		m->m_pkthdr.len = m->m_len = sizeof(struct ieee80211_frame_cts);
3177b032f27cSSam Leffler 	}
3178b032f27cSSam Leffler 	return m;
3179b032f27cSSam Leffler }
3180b032f27cSSam Leffler 
3181d1b67106SAndriy Voskoboinyk /*
3182d1b67106SAndriy Voskoboinyk  * Wrapper for CTS/RTS frame allocation.
3183d1b67106SAndriy Voskoboinyk  */
3184d1b67106SAndriy Voskoboinyk struct mbuf *
3185d1b67106SAndriy Voskoboinyk ieee80211_alloc_prot(struct ieee80211_node *ni, const struct mbuf *m,
3186d1b67106SAndriy Voskoboinyk     uint8_t rate, int prot)
3187d1b67106SAndriy Voskoboinyk {
3188d1b67106SAndriy Voskoboinyk 	struct ieee80211com *ic = ni->ni_ic;
3189d1b67106SAndriy Voskoboinyk 	const struct ieee80211_frame *wh;
3190d1b67106SAndriy Voskoboinyk 	struct mbuf *mprot;
3191d1b67106SAndriy Voskoboinyk 	uint16_t dur;
3192d1b67106SAndriy Voskoboinyk 	int pktlen, isshort;
3193d1b67106SAndriy Voskoboinyk 
3194d1b67106SAndriy Voskoboinyk 	KASSERT(prot == IEEE80211_PROT_RTSCTS ||
3195d1b67106SAndriy Voskoboinyk 	    prot == IEEE80211_PROT_CTSONLY,
3196d1b67106SAndriy Voskoboinyk 	    ("wrong protection type %d", prot));
3197d1b67106SAndriy Voskoboinyk 
3198d1b67106SAndriy Voskoboinyk 	wh = mtod(m, const struct ieee80211_frame *);
3199d1b67106SAndriy Voskoboinyk 	pktlen = m->m_pkthdr.len + IEEE80211_CRC_LEN;
3200d1b67106SAndriy Voskoboinyk 	isshort = (ic->ic_flags & IEEE80211_F_SHPREAMBLE) != 0;
3201d1b67106SAndriy Voskoboinyk 	dur = ieee80211_compute_duration(ic->ic_rt, pktlen, rate, isshort)
3202d1b67106SAndriy Voskoboinyk 	    + ieee80211_ack_duration(ic->ic_rt, rate, isshort);
3203d1b67106SAndriy Voskoboinyk 
3204d1b67106SAndriy Voskoboinyk 	if (prot == IEEE80211_PROT_RTSCTS) {
3205d1b67106SAndriy Voskoboinyk 		/* NB: CTS is the same size as an ACK */
3206d1b67106SAndriy Voskoboinyk 		dur += ieee80211_ack_duration(ic->ic_rt, rate, isshort);
3207d1b67106SAndriy Voskoboinyk 		mprot = ieee80211_alloc_rts(ic, wh->i_addr1, wh->i_addr2, dur);
3208d1b67106SAndriy Voskoboinyk 	} else
3209d1b67106SAndriy Voskoboinyk 		mprot = ieee80211_alloc_cts(ic, ni->ni_vap->iv_myaddr, dur);
3210d1b67106SAndriy Voskoboinyk 
3211d1b67106SAndriy Voskoboinyk 	return (mprot);
3212d1b67106SAndriy Voskoboinyk }
3213d1b67106SAndriy Voskoboinyk 
321468e8e04eSSam Leffler static void
321568e8e04eSSam Leffler ieee80211_tx_mgt_timeout(void *arg)
321668e8e04eSSam Leffler {
3217e94527beSAdrian Chadd 	struct ieee80211vap *vap = arg;
321868e8e04eSSam Leffler 
3219e94527beSAdrian Chadd 	IEEE80211_LOCK(vap->iv_ic);
3220b032f27cSSam Leffler 	if (vap->iv_state != IEEE80211_S_INIT &&
3221b032f27cSSam Leffler 	    (vap->iv_ic->ic_flags & IEEE80211_F_SCAN) == 0) {
322268e8e04eSSam Leffler 		/*
322368e8e04eSSam Leffler 		 * NB: it's safe to specify a timeout as the reason here;
322468e8e04eSSam Leffler 		 *     it'll only be used in the right state.
322568e8e04eSSam Leffler 		 */
3226e94527beSAdrian Chadd 		ieee80211_new_state_locked(vap, IEEE80211_S_SCAN,
322768e8e04eSSam Leffler 			IEEE80211_SCAN_FAIL_TIMEOUT);
322868e8e04eSSam Leffler 	}
3229e94527beSAdrian Chadd 	IEEE80211_UNLOCK(vap->iv_ic);
323068e8e04eSSam Leffler }
323168e8e04eSSam Leffler 
3232e94527beSAdrian Chadd /*
3233e94527beSAdrian Chadd  * This is the callback set on net80211-sourced transmitted
3234e94527beSAdrian Chadd  * authentication request frames.
3235e94527beSAdrian Chadd  *
3236e94527beSAdrian Chadd  * This does a couple of things:
3237e94527beSAdrian Chadd  *
3238e94527beSAdrian Chadd  * + If the frame transmitted was a success, it schedules a future
3239e94527beSAdrian Chadd  *   event which will transition the interface to scan.
3240e94527beSAdrian Chadd  *   If a state transition _then_ occurs before that event occurs,
3241e94527beSAdrian Chadd  *   said state transition will cancel this callout.
3242e94527beSAdrian Chadd  *
3243e94527beSAdrian Chadd  * + If the frame transmit was a failure, it immediately schedules
3244e94527beSAdrian Chadd  *   the transition back to scan.
3245e94527beSAdrian Chadd  */
324668e8e04eSSam Leffler static void
324768e8e04eSSam Leffler ieee80211_tx_mgt_cb(struct ieee80211_node *ni, void *arg, int status)
324868e8e04eSSam Leffler {
3249b032f27cSSam Leffler 	struct ieee80211vap *vap = ni->ni_vap;
325068e8e04eSSam Leffler 	enum ieee80211_state ostate = (enum ieee80211_state) arg;
325168e8e04eSSam Leffler 
325268e8e04eSSam Leffler 	/*
325368e8e04eSSam Leffler 	 * Frame transmit completed; arrange timer callback.  If
3254a4641f4eSPedro F. Giffuni 	 * transmit was successfully we wait for response.  Otherwise
325568e8e04eSSam Leffler 	 * we arrange an immediate callback instead of doing the
325668e8e04eSSam Leffler 	 * callback directly since we don't know what state the driver
325768e8e04eSSam Leffler 	 * is in (e.g. what locks it is holding).  This work should
325868e8e04eSSam Leffler 	 * not be too time-critical and not happen too often so the
325968e8e04eSSam Leffler 	 * added overhead is acceptable.
326068e8e04eSSam Leffler 	 *
326168e8e04eSSam Leffler 	 * XXX what happens if !acked but response shows up before callback?
326268e8e04eSSam Leffler 	 */
3263e94527beSAdrian Chadd 	if (vap->iv_state == ostate) {
3264b032f27cSSam Leffler 		callout_reset(&vap->iv_mgtsend,
326568e8e04eSSam Leffler 			status == 0 ? IEEE80211_TRANS_WAIT*hz : 0,
3266e94527beSAdrian Chadd 			ieee80211_tx_mgt_timeout, vap);
3267e94527beSAdrian Chadd 	}
326868e8e04eSSam Leffler }
326968e8e04eSSam Leffler 
3270b032f27cSSam Leffler static void
3271b032f27cSSam Leffler ieee80211_beacon_construct(struct mbuf *m, uint8_t *frm,
3272210ab3c2SAdrian Chadd 	struct ieee80211_node *ni)
32738a1b9b6aSSam Leffler {
3274b032f27cSSam Leffler 	struct ieee80211vap *vap = ni->ni_vap;
3275210ab3c2SAdrian Chadd 	struct ieee80211_beacon_offsets *bo = &vap->iv_bcn_off;
3276b105a069SSam Leffler 	struct ieee80211com *ic = ni->ni_ic;
3277b032f27cSSam Leffler 	struct ieee80211_rateset *rs = &ni->ni_rates;
327868e8e04eSSam Leffler 	uint16_t capinfo;
32798a1b9b6aSSam Leffler 
32808a1b9b6aSSam Leffler 	/*
32818a1b9b6aSSam Leffler 	 * beacon frame format
328251172f62SAdrian Chadd 	 *
328351172f62SAdrian Chadd 	 * TODO: update to 802.11-2012; a lot of stuff has changed;
328451172f62SAdrian Chadd 	 * vendor extensions should be at the end, etc.
328551172f62SAdrian Chadd 	 *
32868a1b9b6aSSam Leffler 	 *	[8] time stamp
32878a1b9b6aSSam Leffler 	 *	[2] beacon interval
32888a1b9b6aSSam Leffler 	 *	[2] cabability information
32898a1b9b6aSSam Leffler 	 *	[tlv] ssid
32908a1b9b6aSSam Leffler 	 *	[tlv] supported rates
32918a1b9b6aSSam Leffler 	 *	[3] parameter set (DS)
3292b032f27cSSam Leffler 	 *	[8] CF parameter set (optional)
32938a1b9b6aSSam Leffler 	 *	[tlv] parameter set (IBSS/TIM)
3294b032f27cSSam Leffler 	 *	[tlv] country (optional)
3295b032f27cSSam Leffler 	 *	[3] power control (optional)
3296b032f27cSSam Leffler 	 *	[5] channel switch announcement (CSA) (optional)
329751172f62SAdrian Chadd 	 * XXX TODO: Quiet
329851172f62SAdrian Chadd 	 * XXX TODO: IBSS DFS
329951172f62SAdrian Chadd 	 * XXX TODO: TPC report
33008a1b9b6aSSam Leffler 	 *	[tlv] extended rate phy (ERP)
33018a1b9b6aSSam Leffler 	 *	[tlv] extended supported rates
3302688fe74dSSam Leffler 	 *	[tlv] RSN parameters
330351172f62SAdrian Chadd 	 * XXX TODO: BSSLOAD
330451172f62SAdrian Chadd 	 * (XXX EDCA parameter set, QoS capability?)
330551172f62SAdrian Chadd 	 * XXX TODO: AP channel report
330651172f62SAdrian Chadd 	 *
330768e8e04eSSam Leffler 	 *	[tlv] HT capabilities
330868e8e04eSSam Leffler 	 *	[tlv] HT information
330951172f62SAdrian Chadd 	 *	XXX TODO: 20/40 BSS coexistence
331051172f62SAdrian Chadd 	 * Mesh:
331151172f62SAdrian Chadd 	 * XXX TODO: Meshid
331251172f62SAdrian Chadd 	 * XXX TODO: mesh config
331351172f62SAdrian Chadd 	 * XXX TODO: mesh awake window
331451172f62SAdrian Chadd 	 * XXX TODO: beacon timing (mesh, etc)
331551172f62SAdrian Chadd 	 * XXX TODO: MCCAOP Advertisement Overview
331651172f62SAdrian Chadd 	 * XXX TODO: MCCAOP Advertisement
331751172f62SAdrian Chadd 	 * XXX TODO: Mesh channel switch parameters
331851172f62SAdrian Chadd 	 * VHT:
331951172f62SAdrian Chadd 	 * XXX TODO: VHT capabilities
332051172f62SAdrian Chadd 	 * XXX TODO: VHT operation
332151172f62SAdrian Chadd 	 * XXX TODO: VHT transmit power envelope
332251172f62SAdrian Chadd 	 * XXX TODO: channel switch wrapper element
332351172f62SAdrian Chadd 	 * XXX TODO: extended BSS load element
332451172f62SAdrian Chadd 	 *
3325b032f27cSSam Leffler 	 * XXX Vendor-specific OIDs (e.g. Atheros)
3326b032f27cSSam Leffler 	 *	[tlv] WPA parameters
3327b032f27cSSam Leffler 	 *	[tlv] WME parameters
332868e8e04eSSam Leffler 	 *	[tlv] Vendor OUI HT capabilities (optional)
332968e8e04eSSam Leffler 	 *	[tlv] Vendor OUI HT information (optional)
33304207227cSSam Leffler 	 *	[tlv] Atheros capabilities (optional)
333110ad9a77SSam Leffler 	 *	[tlv] TDMA parameters (optional)
333259aa14a9SRui Paulo 	 *	[tlv] Mesh ID (MBSS)
333359aa14a9SRui Paulo 	 *	[tlv] Mesh Conf (MBSS)
3334b032f27cSSam Leffler 	 *	[tlv] application data (optional)
33358a1b9b6aSSam Leffler 	 */
33368a1b9b6aSSam Leffler 
33371b6167d2SSam Leffler 	memset(bo, 0, sizeof(*bo));
33381b6167d2SSam Leffler 
33398a1b9b6aSSam Leffler 	memset(frm, 0, 8);	/* XXX timestamp is set by hardware/driver */
33408a1b9b6aSSam Leffler 	frm += 8;
334168e8e04eSSam Leffler 	*(uint16_t *)frm = htole16(ni->ni_intval);
33428a1b9b6aSSam Leffler 	frm += 2;
334359aa14a9SRui Paulo 	capinfo = ieee80211_getcapinfo(vap, ni->ni_chan);
334468e8e04eSSam Leffler 	bo->bo_caps = (uint16_t *)frm;
334568e8e04eSSam Leffler 	*(uint16_t *)frm = htole16(capinfo);
33468a1b9b6aSSam Leffler 	frm += 2;
33478a1b9b6aSSam Leffler 	*frm++ = IEEE80211_ELEMID_SSID;
3348b032f27cSSam Leffler 	if ((vap->iv_flags & IEEE80211_F_HIDESSID) == 0) {
33498a1b9b6aSSam Leffler 		*frm++ = ni->ni_esslen;
33508a1b9b6aSSam Leffler 		memcpy(frm, ni->ni_essid, ni->ni_esslen);
33518a1b9b6aSSam Leffler 		frm += ni->ni_esslen;
33528a1b9b6aSSam Leffler 	} else
33538a1b9b6aSSam Leffler 		*frm++ = 0;
33548a1b9b6aSSam Leffler 	frm = ieee80211_add_rates(frm, rs);
3355b032f27cSSam Leffler 	if (!IEEE80211_IS_CHAN_FHSS(ni->ni_chan)) {
33568a1b9b6aSSam Leffler 		*frm++ = IEEE80211_ELEMID_DSPARMS;
33578a1b9b6aSSam Leffler 		*frm++ = 1;
3358b032f27cSSam Leffler 		*frm++ = ieee80211_chan2ieee(ic, ni->ni_chan);
3359b032f27cSSam Leffler 	}
3360b032f27cSSam Leffler 	if (ic->ic_flags & IEEE80211_F_PCF) {
3361b032f27cSSam Leffler 		bo->bo_cfp = frm;
3362b032f27cSSam Leffler 		frm = ieee80211_add_cfparms(frm, ic);
33638a1b9b6aSSam Leffler 	}
33648a1b9b6aSSam Leffler 	bo->bo_tim = frm;
3365b032f27cSSam Leffler 	if (vap->iv_opmode == IEEE80211_M_IBSS) {
33668a1b9b6aSSam Leffler 		*frm++ = IEEE80211_ELEMID_IBSSPARMS;
33678a1b9b6aSSam Leffler 		*frm++ = 2;
33688a1b9b6aSSam Leffler 		*frm++ = 0; *frm++ = 0;		/* TODO: ATIM window */
33698a1b9b6aSSam Leffler 		bo->bo_tim_len = 0;
337059aa14a9SRui Paulo 	} else if (vap->iv_opmode == IEEE80211_M_HOSTAP ||
337159aa14a9SRui Paulo 	    vap->iv_opmode == IEEE80211_M_MBSS) {
337259aa14a9SRui Paulo 		/* TIM IE is the same for Mesh and Hostap */
33738a1b9b6aSSam Leffler 		struct ieee80211_tim_ie *tie = (struct ieee80211_tim_ie *) frm;
33748a1b9b6aSSam Leffler 
33758a1b9b6aSSam Leffler 		tie->tim_ie = IEEE80211_ELEMID_TIM;
33768a1b9b6aSSam Leffler 		tie->tim_len = 4;	/* length */
33778a1b9b6aSSam Leffler 		tie->tim_count = 0;	/* DTIM count */
3378b032f27cSSam Leffler 		tie->tim_period = vap->iv_dtim_period;	/* DTIM period */
33798a1b9b6aSSam Leffler 		tie->tim_bitctl = 0;	/* bitmap control */
33808a1b9b6aSSam Leffler 		tie->tim_bitmap[0] = 0;	/* Partial Virtual Bitmap */
33818a1b9b6aSSam Leffler 		frm += sizeof(struct ieee80211_tim_ie);
33828a1b9b6aSSam Leffler 		bo->bo_tim_len = 1;
33838a1b9b6aSSam Leffler 	}
3384b105a069SSam Leffler 	bo->bo_tim_trailer = frm;
3385b032f27cSSam Leffler 	if ((vap->iv_flags & IEEE80211_F_DOTH) ||
3386b032f27cSSam Leffler 	    (vap->iv_flags_ext & IEEE80211_FEXT_DOTD))
3387b032f27cSSam Leffler 		frm = ieee80211_add_countryie(frm, ic);
3388b032f27cSSam Leffler 	if (vap->iv_flags & IEEE80211_F_DOTH) {
3389b032f27cSSam Leffler 		if (IEEE80211_IS_CHAN_5GHZ(ni->ni_chan))
3390b032f27cSSam Leffler 			frm = ieee80211_add_powerconstraint(frm, vap);
3391b032f27cSSam Leffler 		bo->bo_csa = frm;
3392b032f27cSSam Leffler 		if (ic->ic_flags & IEEE80211_F_CSAPENDING)
3393b032f27cSSam Leffler 			frm = ieee80211_add_csa(frm, vap);
3394b032f27cSSam Leffler 	} else
3395b032f27cSSam Leffler 		bo->bo_csa = frm;
339632b0e64bSAdrian Chadd 
33974d3dcce5SAdrian Chadd 	bo->bo_quiet = NULL;
339832b0e64bSAdrian Chadd 	if (vap->iv_flags & IEEE80211_F_DOTH) {
339932b0e64bSAdrian Chadd 		if (IEEE80211_IS_CHAN_DFS(ic->ic_bsschan) &&
34004d3dcce5SAdrian Chadd 		    (vap->iv_flags_ext & IEEE80211_FEXT_DFS) &&
34014d3dcce5SAdrian Chadd 		    (vap->iv_quiet == 1)) {
34024d3dcce5SAdrian Chadd 			/*
34034d3dcce5SAdrian Chadd 			 * We only insert the quiet IE offset if
34044d3dcce5SAdrian Chadd 			 * the quiet IE is enabled.  Otherwise don't
34054d3dcce5SAdrian Chadd 			 * put it here or we'll just overwrite
34064d3dcce5SAdrian Chadd 			 * some other beacon contents.
34074d3dcce5SAdrian Chadd 			 */
34084d3dcce5SAdrian Chadd 			if (vap->iv_quiet) {
34094d3dcce5SAdrian Chadd 				bo->bo_quiet = frm;
3410ce4552cdSAdrian Chadd 				frm = ieee80211_add_quiet(frm,vap, 0);
341132b0e64bSAdrian Chadd 			}
34124d3dcce5SAdrian Chadd 		}
34134d3dcce5SAdrian Chadd 	}
341432b0e64bSAdrian Chadd 
3415b032f27cSSam Leffler 	if (IEEE80211_IS_CHAN_ANYG(ni->ni_chan)) {
34160912bac9SSam Leffler 		bo->bo_erp = frm;
34178a1b9b6aSSam Leffler 		frm = ieee80211_add_erp(frm, ic);
34181b6167d2SSam Leffler 	}
341968e8e04eSSam Leffler 	frm = ieee80211_add_xrates(frm, rs);
3420d8df5f3dSRui Paulo 	frm = ieee80211_add_rsn(frm, vap);
3421b032f27cSSam Leffler 	if (IEEE80211_IS_CHAN_HT(ni->ni_chan)) {
342268e8e04eSSam Leffler 		frm = ieee80211_add_htcap(frm, ni);
342368e8e04eSSam Leffler 		bo->bo_htinfo = frm;
342468e8e04eSSam Leffler 		frm = ieee80211_add_htinfo(frm, ni);
34251b6167d2SSam Leffler 	}
342651172f62SAdrian Chadd 
342751172f62SAdrian Chadd 	if (IEEE80211_IS_CHAN_VHT(ni->ni_chan)) {
342851172f62SAdrian Chadd 		frm = ieee80211_add_vhtcap(frm, ni);
342951172f62SAdrian Chadd 		bo->bo_vhtinfo = frm;
343051172f62SAdrian Chadd 		frm = ieee80211_add_vhtinfo(frm, ni);
343151172f62SAdrian Chadd 		/* Transmit power envelope */
343251172f62SAdrian Chadd 		/* Channel switch wrapper element */
343351172f62SAdrian Chadd 		/* Extended bss load element */
343451172f62SAdrian Chadd 	}
343551172f62SAdrian Chadd 
3436d8df5f3dSRui Paulo 	frm = ieee80211_add_wpa(frm, vap);
3437b032f27cSSam Leffler 	if (vap->iv_flags & IEEE80211_F_WME) {
34381b6167d2SSam Leffler 		bo->bo_wme = frm;
34391b6167d2SSam Leffler 		frm = ieee80211_add_wme_param(frm, &ic->ic_wme);
34401b6167d2SSam Leffler 	}
3441b032f27cSSam Leffler 	if (IEEE80211_IS_CHAN_HT(ni->ni_chan) &&
34422bfc8a91SSam Leffler 	    (vap->iv_flags_ht & IEEE80211_FHT_HTCOMPAT)) {
344368e8e04eSSam Leffler 		frm = ieee80211_add_htcap_vendor(frm, ni);
344468e8e04eSSam Leffler 		frm = ieee80211_add_htinfo_vendor(frm, ni);
34450912bac9SSam Leffler 	}
344651172f62SAdrian Chadd 
34474207227cSSam Leffler #ifdef IEEE80211_SUPPORT_SUPERG
34484207227cSSam Leffler 	if (vap->iv_flags & IEEE80211_F_ATHEROS) {
34494207227cSSam Leffler 		bo->bo_ath = frm;
34504207227cSSam Leffler 		frm = ieee80211_add_athcaps(frm, ni);
34514207227cSSam Leffler 	}
34524207227cSSam Leffler #endif
345310ad9a77SSam Leffler #ifdef IEEE80211_SUPPORT_TDMA
345410ad9a77SSam Leffler 	if (vap->iv_caps & IEEE80211_C_TDMA) {
345510ad9a77SSam Leffler 		bo->bo_tdma = frm;
345610ad9a77SSam Leffler 		frm = ieee80211_add_tdma(frm, vap);
345710ad9a77SSam Leffler 	}
345810ad9a77SSam Leffler #endif
3459b032f27cSSam Leffler 	if (vap->iv_appie_beacon != NULL) {
3460b032f27cSSam Leffler 		bo->bo_appie = frm;
3461b032f27cSSam Leffler 		bo->bo_appie_len = vap->iv_appie_beacon->ie_len;
3462b032f27cSSam Leffler 		frm = add_appie(frm, vap->iv_appie_beacon);
3463b032f27cSSam Leffler 	}
346451172f62SAdrian Chadd 
346551172f62SAdrian Chadd 	/* XXX TODO: move meshid/meshconf up to before vendor extensions? */
346659aa14a9SRui Paulo #ifdef IEEE80211_SUPPORT_MESH
346759aa14a9SRui Paulo 	if (vap->iv_opmode == IEEE80211_M_MBSS) {
346859aa14a9SRui Paulo 		frm = ieee80211_add_meshid(frm, vap);
3469d093681cSRui Paulo 		bo->bo_meshconf = frm;
347059aa14a9SRui Paulo 		frm = ieee80211_add_meshconf(frm, vap);
347159aa14a9SRui Paulo 	}
347259aa14a9SRui Paulo #endif
3473b105a069SSam Leffler 	bo->bo_tim_trailer_len = frm - bo->bo_tim_trailer;
3474b032f27cSSam Leffler 	bo->bo_csa_trailer_len = frm - bo->bo_csa;
347568e8e04eSSam Leffler 	m->m_pkthdr.len = m->m_len = frm - mtod(m, uint8_t *);
3476b032f27cSSam Leffler }
3477b032f27cSSam Leffler 
3478b032f27cSSam Leffler /*
3479b032f27cSSam Leffler  * Allocate a beacon frame and fillin the appropriate bits.
3480b032f27cSSam Leffler  */
3481b032f27cSSam Leffler struct mbuf *
3482210ab3c2SAdrian Chadd ieee80211_beacon_alloc(struct ieee80211_node *ni)
3483b032f27cSSam Leffler {
3484b032f27cSSam Leffler 	struct ieee80211vap *vap = ni->ni_vap;
3485b032f27cSSam Leffler 	struct ieee80211com *ic = ni->ni_ic;
3486b032f27cSSam Leffler 	struct ifnet *ifp = vap->iv_ifp;
3487b032f27cSSam Leffler 	struct ieee80211_frame *wh;
3488b032f27cSSam Leffler 	struct mbuf *m;
3489b032f27cSSam Leffler 	int pktlen;
3490b032f27cSSam Leffler 	uint8_t *frm;
3491b032f27cSSam Leffler 
3492b032f27cSSam Leffler 	/*
34934d3dcce5SAdrian Chadd 	 * Update the "We're putting the quiet IE in the beacon" state.
34944d3dcce5SAdrian Chadd 	 */
34954d3dcce5SAdrian Chadd 	if (vap->iv_quiet == 1)
34964d3dcce5SAdrian Chadd 		vap->iv_flags_ext |= IEEE80211_FEXT_QUIET_IE;
34974d3dcce5SAdrian Chadd 	else if (vap->iv_quiet == 0)
34984d3dcce5SAdrian Chadd 		vap->iv_flags_ext &= ~IEEE80211_FEXT_QUIET_IE;
34994d3dcce5SAdrian Chadd 
35004d3dcce5SAdrian Chadd 	/*
3501b032f27cSSam Leffler 	 * beacon frame format
350251172f62SAdrian Chadd 	 *
350351172f62SAdrian Chadd 	 * Note: This needs updating for 802.11-2012.
350451172f62SAdrian Chadd 	 *
3505b032f27cSSam Leffler 	 *	[8] time stamp
3506b032f27cSSam Leffler 	 *	[2] beacon interval
3507b032f27cSSam Leffler 	 *	[2] cabability information
3508b032f27cSSam Leffler 	 *	[tlv] ssid
3509b032f27cSSam Leffler 	 *	[tlv] supported rates
3510b032f27cSSam Leffler 	 *	[3] parameter set (DS)
3511b032f27cSSam Leffler 	 *	[8] CF parameter set (optional)
3512b032f27cSSam Leffler 	 *	[tlv] parameter set (IBSS/TIM)
3513b032f27cSSam Leffler 	 *	[tlv] country (optional)
3514b032f27cSSam Leffler 	 *	[3] power control (optional)
3515b032f27cSSam Leffler 	 *	[5] channel switch announcement (CSA) (optional)
3516b032f27cSSam Leffler 	 *	[tlv] extended rate phy (ERP)
3517b032f27cSSam Leffler 	 *	[tlv] extended supported rates
3518b032f27cSSam Leffler 	 *	[tlv] RSN parameters
3519b032f27cSSam Leffler 	 *	[tlv] HT capabilities
3520b032f27cSSam Leffler 	 *	[tlv] HT information
352151172f62SAdrian Chadd 	 *	[tlv] VHT capabilities
352251172f62SAdrian Chadd 	 *	[tlv] VHT operation
3523b032f27cSSam Leffler 	 *	[tlv] Vendor OUI HT capabilities (optional)
3524b032f27cSSam Leffler 	 *	[tlv] Vendor OUI HT information (optional)
3525b032f27cSSam Leffler 	 * XXX Vendor-specific OIDs (e.g. Atheros)
3526b032f27cSSam Leffler 	 *	[tlv] WPA parameters
3527b032f27cSSam Leffler 	 *	[tlv] WME parameters
352810ad9a77SSam Leffler 	 *	[tlv] TDMA parameters (optional)
352959aa14a9SRui Paulo 	 *	[tlv] Mesh ID (MBSS)
353059aa14a9SRui Paulo 	 *	[tlv] Mesh Conf (MBSS)
3531b032f27cSSam Leffler 	 *	[tlv] application data (optional)
3532b032f27cSSam Leffler 	 * NB: we allocate the max space required for the TIM bitmap.
3533b032f27cSSam Leffler 	 * XXX how big is this?
3534b032f27cSSam Leffler 	 */
3535b032f27cSSam Leffler 	pktlen =   8					/* time stamp */
3536b032f27cSSam Leffler 		 + sizeof(uint16_t)			/* beacon interval */
3537b032f27cSSam Leffler 		 + sizeof(uint16_t)			/* capabilities */
3538b032f27cSSam Leffler 		 + 2 + ni->ni_esslen			/* ssid */
3539b032f27cSSam Leffler 	         + 2 + IEEE80211_RATE_SIZE		/* supported rates */
3540b032f27cSSam Leffler 	         + 2 + 1				/* DS parameters */
3541b032f27cSSam Leffler 		 + 2 + 6				/* CF parameters */
3542b032f27cSSam Leffler 		 + 2 + 4 + vap->iv_tim_len		/* DTIM/IBSSPARMS */
3543b032f27cSSam Leffler 		 + IEEE80211_COUNTRY_MAX_SIZE		/* country */
3544b032f27cSSam Leffler 		 + 2 + 1				/* power control */
3545b032f27cSSam Leffler 		 + sizeof(struct ieee80211_csa_ie)	/* CSA */
354632b0e64bSAdrian Chadd 		 + sizeof(struct ieee80211_quiet_ie)	/* Quiet */
3547b032f27cSSam Leffler 		 + 2 + 1				/* ERP */
3548b032f27cSSam Leffler 	         + 2 + (IEEE80211_RATE_MAXSIZE - IEEE80211_RATE_SIZE)
3549b032f27cSSam Leffler 		 + (vap->iv_caps & IEEE80211_C_WPA ?	/* WPA 1+2 */
3550b032f27cSSam Leffler 			2*sizeof(struct ieee80211_ie_wpa) : 0)
3551b032f27cSSam Leffler 		 /* XXX conditional? */
3552b032f27cSSam Leffler 		 + 4+2*sizeof(struct ieee80211_ie_htcap)/* HT caps */
3553b032f27cSSam Leffler 		 + 4+2*sizeof(struct ieee80211_ie_htinfo)/* HT info */
355451172f62SAdrian Chadd 		 + sizeof(struct ieee80211_ie_vhtcap)/* VHT caps */
355551172f62SAdrian Chadd 		 + sizeof(struct ieee80211_ie_vht_operation)/* VHT info */
3556b032f27cSSam Leffler 		 + (vap->iv_caps & IEEE80211_C_WME ?	/* WME */
3557b032f27cSSam Leffler 			sizeof(struct ieee80211_wme_param) : 0)
35584207227cSSam Leffler #ifdef IEEE80211_SUPPORT_SUPERG
35594207227cSSam Leffler 		 + sizeof(struct ieee80211_ath_ie)	/* ATH */
35604207227cSSam Leffler #endif
356110ad9a77SSam Leffler #ifdef IEEE80211_SUPPORT_TDMA
356210ad9a77SSam Leffler 		 + (vap->iv_caps & IEEE80211_C_TDMA ?	/* TDMA */
356310ad9a77SSam Leffler 			sizeof(struct ieee80211_tdma_param) : 0)
356410ad9a77SSam Leffler #endif
356559aa14a9SRui Paulo #ifdef IEEE80211_SUPPORT_MESH
356659aa14a9SRui Paulo 		 + 2 + ni->ni_meshidlen
356759aa14a9SRui Paulo 		 + sizeof(struct ieee80211_meshconf_ie)
356859aa14a9SRui Paulo #endif
3569b032f27cSSam Leffler 		 + IEEE80211_MAX_APPIE
3570b032f27cSSam Leffler 		 ;
3571b032f27cSSam Leffler 	m = ieee80211_getmgtframe(&frm,
3572b032f27cSSam Leffler 		ic->ic_headroom + sizeof(struct ieee80211_frame), pktlen);
3573b032f27cSSam Leffler 	if (m == NULL) {
3574b032f27cSSam Leffler 		IEEE80211_DPRINTF(vap, IEEE80211_MSG_ANY,
3575b032f27cSSam Leffler 			"%s: cannot get buf; size %u\n", __func__, pktlen);
3576b032f27cSSam Leffler 		vap->iv_stats.is_tx_nobuf++;
3577b032f27cSSam Leffler 		return NULL;
3578b032f27cSSam Leffler 	}
3579210ab3c2SAdrian Chadd 	ieee80211_beacon_construct(m, frm, ni);
35808a1b9b6aSSam Leffler 
3581eb1b1807SGleb Smirnoff 	M_PREPEND(m, sizeof(struct ieee80211_frame), M_NOWAIT);
35828a1b9b6aSSam Leffler 	KASSERT(m != NULL, ("no space for 802.11 header?"));
35838a1b9b6aSSam Leffler 	wh = mtod(m, struct ieee80211_frame *);
35848a1b9b6aSSam Leffler 	wh->i_fc[0] = IEEE80211_FC0_VERSION_0 | IEEE80211_FC0_TYPE_MGT |
35858a1b9b6aSSam Leffler 	    IEEE80211_FC0_SUBTYPE_BEACON;
35868a1b9b6aSSam Leffler 	wh->i_fc[1] = IEEE80211_FC1_DIR_NODS;
358768e8e04eSSam Leffler 	*(uint16_t *)wh->i_dur = 0;
35888a1b9b6aSSam Leffler 	IEEE80211_ADDR_COPY(wh->i_addr1, ifp->if_broadcastaddr);
3589b032f27cSSam Leffler 	IEEE80211_ADDR_COPY(wh->i_addr2, vap->iv_myaddr);
35908a1b9b6aSSam Leffler 	IEEE80211_ADDR_COPY(wh->i_addr3, ni->ni_bssid);
359168e8e04eSSam Leffler 	*(uint16_t *)wh->i_seq = 0;
35928a1b9b6aSSam Leffler 
35938a1b9b6aSSam Leffler 	return m;
35948a1b9b6aSSam Leffler }
35958a1b9b6aSSam Leffler 
35968a1b9b6aSSam Leffler /*
35978a1b9b6aSSam Leffler  * Update the dynamic parts of a beacon frame based on the current state.
35988a1b9b6aSSam Leffler  */
35998a1b9b6aSSam Leffler int
3600210ab3c2SAdrian Chadd ieee80211_beacon_update(struct ieee80211_node *ni, struct mbuf *m, int mcast)
36018a1b9b6aSSam Leffler {
3602b032f27cSSam Leffler 	struct ieee80211vap *vap = ni->ni_vap;
3603210ab3c2SAdrian Chadd 	struct ieee80211_beacon_offsets *bo = &vap->iv_bcn_off;
3604b105a069SSam Leffler 	struct ieee80211com *ic = ni->ni_ic;
36058a1b9b6aSSam Leffler 	int len_changed = 0;
360668e8e04eSSam Leffler 	uint16_t capinfo;
3607fa3324c9SAdrian Chadd 	struct ieee80211_frame *wh;
3608fa3324c9SAdrian Chadd 	ieee80211_seq seqno;
36098a1b9b6aSSam Leffler 
3610b032f27cSSam Leffler 	IEEE80211_LOCK(ic);
3611b032f27cSSam Leffler 	/*
3612b032f27cSSam Leffler 	 * Handle 11h channel change when we've reached the count.
3613b032f27cSSam Leffler 	 * We must recalculate the beacon frame contents to account
3614b032f27cSSam Leffler 	 * for the new channel.  Note we do this only for the first
3615b032f27cSSam Leffler 	 * vap that reaches this point; subsequent vaps just update
3616b032f27cSSam Leffler 	 * their beacon state to reflect the recalculated channel.
3617b032f27cSSam Leffler 	 */
3618b032f27cSSam Leffler 	if (isset(bo->bo_flags, IEEE80211_BEACON_CSA) &&
3619b032f27cSSam Leffler 	    vap->iv_csa_count == ic->ic_csa_count) {
3620b032f27cSSam Leffler 		vap->iv_csa_count = 0;
3621b032f27cSSam Leffler 		/*
3622b032f27cSSam Leffler 		 * Effect channel change before reconstructing the beacon
3623b032f27cSSam Leffler 		 * frame contents as many places reference ni_chan.
3624b032f27cSSam Leffler 		 */
3625b032f27cSSam Leffler 		if (ic->ic_csa_newchan != NULL)
3626b032f27cSSam Leffler 			ieee80211_csa_completeswitch(ic);
3627b032f27cSSam Leffler 		/*
3628b032f27cSSam Leffler 		 * NB: ieee80211_beacon_construct clears all pending
3629b032f27cSSam Leffler 		 * updates in bo_flags so we don't need to explicitly
3630b032f27cSSam Leffler 		 * clear IEEE80211_BEACON_CSA.
3631b032f27cSSam Leffler 		 */
3632b032f27cSSam Leffler 		ieee80211_beacon_construct(m,
3633210ab3c2SAdrian Chadd 		    mtod(m, uint8_t*) + sizeof(struct ieee80211_frame), ni);
3634b032f27cSSam Leffler 
3635b032f27cSSam Leffler 		/* XXX do WME aggressive mode processing? */
3636b032f27cSSam Leffler 		IEEE80211_UNLOCK(ic);
3637b032f27cSSam Leffler 		return 1;		/* just assume length changed */
3638b032f27cSSam Leffler 	}
3639b032f27cSSam Leffler 
36404d3dcce5SAdrian Chadd 	/*
36414d3dcce5SAdrian Chadd 	 * Handle the quiet time element being added and removed.
36424d3dcce5SAdrian Chadd 	 * Again, for now we just cheat and reconstruct the whole
36434d3dcce5SAdrian Chadd 	 * beacon - that way the gap is provided as appropriate.
36444d3dcce5SAdrian Chadd 	 *
36454d3dcce5SAdrian Chadd 	 * So, track whether we have already added the IE versus
36464d3dcce5SAdrian Chadd 	 * whether we want to be adding the IE.
36474d3dcce5SAdrian Chadd 	 */
36484d3dcce5SAdrian Chadd 	if ((vap->iv_flags_ext & IEEE80211_FEXT_QUIET_IE) &&
36494d3dcce5SAdrian Chadd 	    (vap->iv_quiet == 0)) {
36504d3dcce5SAdrian Chadd 		/*
36514d3dcce5SAdrian Chadd 		 * Quiet time beacon IE enabled, but it's disabled;
36524d3dcce5SAdrian Chadd 		 * recalc
36534d3dcce5SAdrian Chadd 		 */
36544d3dcce5SAdrian Chadd 		vap->iv_flags_ext &= ~IEEE80211_FEXT_QUIET_IE;
36554d3dcce5SAdrian Chadd 		ieee80211_beacon_construct(m,
36564d3dcce5SAdrian Chadd 		    mtod(m, uint8_t*) + sizeof(struct ieee80211_frame), ni);
36574d3dcce5SAdrian Chadd 		/* XXX do WME aggressive mode processing? */
36584d3dcce5SAdrian Chadd 		IEEE80211_UNLOCK(ic);
36594d3dcce5SAdrian Chadd 		return 1;		/* just assume length changed */
36604d3dcce5SAdrian Chadd 	}
36614d3dcce5SAdrian Chadd 
36624d3dcce5SAdrian Chadd 	if (((vap->iv_flags_ext & IEEE80211_FEXT_QUIET_IE) == 0) &&
36634d3dcce5SAdrian Chadd 	    (vap->iv_quiet == 1)) {
36644d3dcce5SAdrian Chadd 		/*
36654d3dcce5SAdrian Chadd 		 * Quiet time beacon IE disabled, but it's now enabled;
36664d3dcce5SAdrian Chadd 		 * recalc
36674d3dcce5SAdrian Chadd 		 */
36684d3dcce5SAdrian Chadd 		vap->iv_flags_ext |= IEEE80211_FEXT_QUIET_IE;
36694d3dcce5SAdrian Chadd 		ieee80211_beacon_construct(m,
36704d3dcce5SAdrian Chadd 		    mtod(m, uint8_t*) + sizeof(struct ieee80211_frame), ni);
36714d3dcce5SAdrian Chadd 		/* XXX do WME aggressive mode processing? */
36724d3dcce5SAdrian Chadd 		IEEE80211_UNLOCK(ic);
36734d3dcce5SAdrian Chadd 		return 1;		/* just assume length changed */
36744d3dcce5SAdrian Chadd 	}
36754d3dcce5SAdrian Chadd 
3676fa3324c9SAdrian Chadd 	wh = mtod(m, struct ieee80211_frame *);
367751172f62SAdrian Chadd 
367851172f62SAdrian Chadd 	/*
367951172f62SAdrian Chadd 	 * XXX TODO Strictly speaking this should be incremented with the TX
368051172f62SAdrian Chadd 	 * lock held so as to serialise access to the non-qos TID sequence
368151172f62SAdrian Chadd 	 * number space.
368251172f62SAdrian Chadd 	 *
368351172f62SAdrian Chadd 	 * If the driver identifies it does its own TX seqno management then
368451172f62SAdrian Chadd 	 * we can skip this (and still not do the TX seqno.)
368551172f62SAdrian Chadd 	 */
3686fa3324c9SAdrian Chadd 	seqno = ni->ni_txseqs[IEEE80211_NONQOS_TID]++;
3687fa3324c9SAdrian Chadd 	*(uint16_t *)&wh->i_seq[0] =
3688fa3324c9SAdrian Chadd 		htole16(seqno << IEEE80211_SEQ_SEQ_SHIFT);
3689fa3324c9SAdrian Chadd 	M_SEQNO_SET(m, seqno);
3690fa3324c9SAdrian Chadd 
36918a1b9b6aSSam Leffler 	/* XXX faster to recalculate entirely or just changes? */
369259aa14a9SRui Paulo 	capinfo = ieee80211_getcapinfo(vap, ni->ni_chan);
36938a1b9b6aSSam Leffler 	*bo->bo_caps = htole16(capinfo);
36948a1b9b6aSSam Leffler 
3695b032f27cSSam Leffler 	if (vap->iv_flags & IEEE80211_F_WME) {
36968a1b9b6aSSam Leffler 		struct ieee80211_wme_state *wme = &ic->ic_wme;
36978a1b9b6aSSam Leffler 
36988a1b9b6aSSam Leffler 		/*
3699a4641f4eSPedro F. Giffuni 		 * Check for aggressive mode change.  When there is
37008a1b9b6aSSam Leffler 		 * significant high priority traffic in the BSS
37018a1b9b6aSSam Leffler 		 * throttle back BE traffic by using conservative
3702a4641f4eSPedro F. Giffuni 		 * parameters.  Otherwise BE uses aggressive params
37038a1b9b6aSSam Leffler 		 * to optimize performance of legacy/non-QoS traffic.
37048a1b9b6aSSam Leffler 		 */
37058a1b9b6aSSam Leffler 		if (wme->wme_flags & WME_F_AGGRMODE) {
37068a1b9b6aSSam Leffler 			if (wme->wme_hipri_traffic >
37078a1b9b6aSSam Leffler 			    wme->wme_hipri_switch_thresh) {
3708b032f27cSSam Leffler 				IEEE80211_DPRINTF(vap, IEEE80211_MSG_WME,
37098a1b9b6aSSam Leffler 				    "%s: traffic %u, disable aggressive mode\n",
37108a1b9b6aSSam Leffler 				    __func__, wme->wme_hipri_traffic);
37118a1b9b6aSSam Leffler 				wme->wme_flags &= ~WME_F_AGGRMODE;
3712b032f27cSSam Leffler 				ieee80211_wme_updateparams_locked(vap);
37138a1b9b6aSSam Leffler 				wme->wme_hipri_traffic =
37148a1b9b6aSSam Leffler 					wme->wme_hipri_switch_hysteresis;
37158a1b9b6aSSam Leffler 			} else
37168a1b9b6aSSam Leffler 				wme->wme_hipri_traffic = 0;
37178a1b9b6aSSam Leffler 		} else {
37188a1b9b6aSSam Leffler 			if (wme->wme_hipri_traffic <=
37198a1b9b6aSSam Leffler 			    wme->wme_hipri_switch_thresh) {
3720b032f27cSSam Leffler 				IEEE80211_DPRINTF(vap, IEEE80211_MSG_WME,
37218a1b9b6aSSam Leffler 				    "%s: traffic %u, enable aggressive mode\n",
37228a1b9b6aSSam Leffler 				    __func__, wme->wme_hipri_traffic);
37238a1b9b6aSSam Leffler 				wme->wme_flags |= WME_F_AGGRMODE;
3724b032f27cSSam Leffler 				ieee80211_wme_updateparams_locked(vap);
37258a1b9b6aSSam Leffler 				wme->wme_hipri_traffic = 0;
37268a1b9b6aSSam Leffler 			} else
37278a1b9b6aSSam Leffler 				wme->wme_hipri_traffic =
37288a1b9b6aSSam Leffler 					wme->wme_hipri_switch_hysteresis;
37298a1b9b6aSSam Leffler 		}
3730b105a069SSam Leffler 		if (isset(bo->bo_flags, IEEE80211_BEACON_WME)) {
37318a1b9b6aSSam Leffler 			(void) ieee80211_add_wme_param(bo->bo_wme, wme);
3732b105a069SSam Leffler 			clrbit(bo->bo_flags, IEEE80211_BEACON_WME);
37338a1b9b6aSSam Leffler 		}
37348a1b9b6aSSam Leffler 	}
37358a1b9b6aSSam Leffler 
3736b105a069SSam Leffler 	if (isset(bo->bo_flags,  IEEE80211_BEACON_HTINFO)) {
3737b032f27cSSam Leffler 		ieee80211_ht_update_beacon(vap, bo);
3738b105a069SSam Leffler 		clrbit(bo->bo_flags, IEEE80211_BEACON_HTINFO);
373968e8e04eSSam Leffler 	}
374010ad9a77SSam Leffler #ifdef IEEE80211_SUPPORT_TDMA
374110ad9a77SSam Leffler 	if (vap->iv_caps & IEEE80211_C_TDMA) {
374210ad9a77SSam Leffler 		/*
374310ad9a77SSam Leffler 		 * NB: the beacon is potentially updated every TBTT.
374410ad9a77SSam Leffler 		 */
374510ad9a77SSam Leffler 		ieee80211_tdma_update_beacon(vap, bo);
374610ad9a77SSam Leffler 	}
374710ad9a77SSam Leffler #endif
3748d093681cSRui Paulo #ifdef IEEE80211_SUPPORT_MESH
3749d093681cSRui Paulo 	if (vap->iv_opmode == IEEE80211_M_MBSS)
3750d093681cSRui Paulo 		ieee80211_mesh_update_beacon(vap, bo);
3751d093681cSRui Paulo #endif
3752d093681cSRui Paulo 
375359aa14a9SRui Paulo 	if (vap->iv_opmode == IEEE80211_M_HOSTAP ||
375459aa14a9SRui Paulo 	    vap->iv_opmode == IEEE80211_M_MBSS) {	/* NB: no IBSS support*/
37558a1b9b6aSSam Leffler 		struct ieee80211_tim_ie *tie =
37568a1b9b6aSSam Leffler 			(struct ieee80211_tim_ie *) bo->bo_tim;
3757b105a069SSam Leffler 		if (isset(bo->bo_flags, IEEE80211_BEACON_TIM)) {
37588a1b9b6aSSam Leffler 			u_int timlen, timoff, i;
37598a1b9b6aSSam Leffler 			/*
37608a1b9b6aSSam Leffler 			 * ATIM/DTIM needs updating.  If it fits in the
37618a1b9b6aSSam Leffler 			 * current space allocated then just copy in the
37628a1b9b6aSSam Leffler 			 * new bits.  Otherwise we need to move any trailing
37638a1b9b6aSSam Leffler 			 * data to make room.  Note that we know there is
37648a1b9b6aSSam Leffler 			 * contiguous space because ieee80211_beacon_allocate
37658a1b9b6aSSam Leffler 			 * insures there is space in the mbuf to write a
3766b032f27cSSam Leffler 			 * maximal-size virtual bitmap (based on iv_max_aid).
37678a1b9b6aSSam Leffler 			 */
37688a1b9b6aSSam Leffler 			/*
37698a1b9b6aSSam Leffler 			 * Calculate the bitmap size and offset, copy any
37708a1b9b6aSSam Leffler 			 * trailer out of the way, and then copy in the
37718a1b9b6aSSam Leffler 			 * new bitmap and update the information element.
37728a1b9b6aSSam Leffler 			 * Note that the tim bitmap must contain at least
37738a1b9b6aSSam Leffler 			 * one byte and any offset must be even.
37748a1b9b6aSSam Leffler 			 */
3775b032f27cSSam Leffler 			if (vap->iv_ps_pending != 0) {
37768a1b9b6aSSam Leffler 				timoff = 128;		/* impossibly large */
3777b032f27cSSam Leffler 				for (i = 0; i < vap->iv_tim_len; i++)
3778b032f27cSSam Leffler 					if (vap->iv_tim_bitmap[i]) {
37798a1b9b6aSSam Leffler 						timoff = i &~ 1;
37808a1b9b6aSSam Leffler 						break;
37818a1b9b6aSSam Leffler 					}
37828a1b9b6aSSam Leffler 				KASSERT(timoff != 128, ("tim bitmap empty!"));
3783b032f27cSSam Leffler 				for (i = vap->iv_tim_len-1; i >= timoff; i--)
3784b032f27cSSam Leffler 					if (vap->iv_tim_bitmap[i])
37858a1b9b6aSSam Leffler 						break;
37868a1b9b6aSSam Leffler 				timlen = 1 + (i - timoff);
37878a1b9b6aSSam Leffler 			} else {
37888a1b9b6aSSam Leffler 				timoff = 0;
37898a1b9b6aSSam Leffler 				timlen = 1;
37908a1b9b6aSSam Leffler 			}
379151172f62SAdrian Chadd 
379251172f62SAdrian Chadd 			/*
379351172f62SAdrian Chadd 			 * TODO: validate this!
379451172f62SAdrian Chadd 			 */
37958a1b9b6aSSam Leffler 			if (timlen != bo->bo_tim_len) {
37968a1b9b6aSSam Leffler 				/* copy up/down trailer */
37970912bac9SSam Leffler 				int adjust = tie->tim_bitmap+timlen
3798b105a069SSam Leffler 					   - bo->bo_tim_trailer;
3799b105a069SSam Leffler 				ovbcopy(bo->bo_tim_trailer,
3800b105a069SSam Leffler 				    bo->bo_tim_trailer+adjust,
3801b105a069SSam Leffler 				    bo->bo_tim_trailer_len);
3802b105a069SSam Leffler 				bo->bo_tim_trailer += adjust;
38030912bac9SSam Leffler 				bo->bo_erp += adjust;
380468e8e04eSSam Leffler 				bo->bo_htinfo += adjust;
380551172f62SAdrian Chadd 				bo->bo_vhtinfo += adjust;
380602e69b54SBernhard Schmidt #ifdef IEEE80211_SUPPORT_SUPERG
38074207227cSSam Leffler 				bo->bo_ath += adjust;
38084207227cSSam Leffler #endif
380902e69b54SBernhard Schmidt #ifdef IEEE80211_SUPPORT_TDMA
381092e870edSSam Leffler 				bo->bo_tdma += adjust;
381192e870edSSam Leffler #endif
381202e69b54SBernhard Schmidt #ifdef IEEE80211_SUPPORT_MESH
3813d093681cSRui Paulo 				bo->bo_meshconf += adjust;
3814d093681cSRui Paulo #endif
3815b032f27cSSam Leffler 				bo->bo_appie += adjust;
3816b032f27cSSam Leffler 				bo->bo_wme += adjust;
3817b032f27cSSam Leffler 				bo->bo_csa += adjust;
381832b0e64bSAdrian Chadd 				bo->bo_quiet += adjust;
38198a1b9b6aSSam Leffler 				bo->bo_tim_len = timlen;
38208a1b9b6aSSam Leffler 
38218a1b9b6aSSam Leffler 				/* update information element */
38228a1b9b6aSSam Leffler 				tie->tim_len = 3 + timlen;
38238a1b9b6aSSam Leffler 				tie->tim_bitctl = timoff;
38248a1b9b6aSSam Leffler 				len_changed = 1;
38258a1b9b6aSSam Leffler 			}
3826b032f27cSSam Leffler 			memcpy(tie->tim_bitmap, vap->iv_tim_bitmap + timoff,
38278a1b9b6aSSam Leffler 				bo->bo_tim_len);
38288a1b9b6aSSam Leffler 
3829b105a069SSam Leffler 			clrbit(bo->bo_flags, IEEE80211_BEACON_TIM);
38308a1b9b6aSSam Leffler 
3831b032f27cSSam Leffler 			IEEE80211_DPRINTF(vap, IEEE80211_MSG_POWER,
38328a1b9b6aSSam Leffler 				"%s: TIM updated, pending %u, off %u, len %u\n",
3833b032f27cSSam Leffler 				__func__, vap->iv_ps_pending, timoff, timlen);
38348a1b9b6aSSam Leffler 		}
38358a1b9b6aSSam Leffler 		/* count down DTIM period */
38368a1b9b6aSSam Leffler 		if (tie->tim_count == 0)
38378a1b9b6aSSam Leffler 			tie->tim_count = tie->tim_period - 1;
38388a1b9b6aSSam Leffler 		else
38398a1b9b6aSSam Leffler 			tie->tim_count--;
38408a1b9b6aSSam Leffler 		/* update state for buffered multicast frames on DTIM */
3841a196b35fSSam Leffler 		if (mcast && tie->tim_count == 0)
38428a1b9b6aSSam Leffler 			tie->tim_bitctl |= 1;
38438a1b9b6aSSam Leffler 		else
38448a1b9b6aSSam Leffler 			tie->tim_bitctl &= ~1;
3845b032f27cSSam Leffler 		if (isset(bo->bo_flags, IEEE80211_BEACON_CSA)) {
3846b032f27cSSam Leffler 			struct ieee80211_csa_ie *csa =
3847b032f27cSSam Leffler 			    (struct ieee80211_csa_ie *) bo->bo_csa;
3848b032f27cSSam Leffler 
3849b032f27cSSam Leffler 			/*
3850b032f27cSSam Leffler 			 * Insert or update CSA ie.  If we're just starting
3851b032f27cSSam Leffler 			 * to count down to the channel switch then we need
3852b032f27cSSam Leffler 			 * to insert the CSA ie.  Otherwise we just need to
3853b032f27cSSam Leffler 			 * drop the count.  The actual change happens above
3854b032f27cSSam Leffler 			 * when the vap's count reaches the target count.
3855b032f27cSSam Leffler 			 */
3856b032f27cSSam Leffler 			if (vap->iv_csa_count == 0) {
3857b032f27cSSam Leffler 				memmove(&csa[1], csa, bo->bo_csa_trailer_len);
3858b032f27cSSam Leffler 				bo->bo_erp += sizeof(*csa);
3859d01b3c26SSam Leffler 				bo->bo_htinfo += sizeof(*csa);
386051172f62SAdrian Chadd 				bo->bo_vhtinfo += sizeof(*csa);
3861b032f27cSSam Leffler 				bo->bo_wme += sizeof(*csa);
386202e69b54SBernhard Schmidt #ifdef IEEE80211_SUPPORT_SUPERG
38634207227cSSam Leffler 				bo->bo_ath += sizeof(*csa);
38644207227cSSam Leffler #endif
386502e69b54SBernhard Schmidt #ifdef IEEE80211_SUPPORT_TDMA
386692e870edSSam Leffler 				bo->bo_tdma += sizeof(*csa);
386792e870edSSam Leffler #endif
386802e69b54SBernhard Schmidt #ifdef IEEE80211_SUPPORT_MESH
3869d093681cSRui Paulo 				bo->bo_meshconf += sizeof(*csa);
3870d093681cSRui Paulo #endif
3871b032f27cSSam Leffler 				bo->bo_appie += sizeof(*csa);
3872b032f27cSSam Leffler 				bo->bo_csa_trailer_len += sizeof(*csa);
387332b0e64bSAdrian Chadd 				bo->bo_quiet += sizeof(*csa);
3874b032f27cSSam Leffler 				bo->bo_tim_trailer_len += sizeof(*csa);
3875b032f27cSSam Leffler 				m->m_len += sizeof(*csa);
3876b032f27cSSam Leffler 				m->m_pkthdr.len += sizeof(*csa);
3877b032f27cSSam Leffler 
3878b032f27cSSam Leffler 				ieee80211_add_csa(bo->bo_csa, vap);
3879b032f27cSSam Leffler 			} else
3880b032f27cSSam Leffler 				csa->csa_count--;
3881b032f27cSSam Leffler 			vap->iv_csa_count++;
3882b032f27cSSam Leffler 			/* NB: don't clear IEEE80211_BEACON_CSA */
3883b032f27cSSam Leffler 		}
38844d3dcce5SAdrian Chadd 
38854d3dcce5SAdrian Chadd 		/*
38864d3dcce5SAdrian Chadd 		 * Only add the quiet time IE if we've enabled it
38874d3dcce5SAdrian Chadd 		 * as appropriate.
38884d3dcce5SAdrian Chadd 		 */
388932b0e64bSAdrian Chadd 		if (IEEE80211_IS_CHAN_DFS(ic->ic_bsschan) &&
389032b0e64bSAdrian Chadd 		    (vap->iv_flags_ext & IEEE80211_FEXT_DFS)) {
38914d3dcce5SAdrian Chadd 			if (vap->iv_quiet &&
38924d3dcce5SAdrian Chadd 			    (vap->iv_flags_ext & IEEE80211_FEXT_QUIET_IE)) {
3893ce4552cdSAdrian Chadd 				ieee80211_add_quiet(bo->bo_quiet, vap, 1);
389432b0e64bSAdrian Chadd 			}
38954d3dcce5SAdrian Chadd 		}
3896b105a069SSam Leffler 		if (isset(bo->bo_flags, IEEE80211_BEACON_ERP)) {
38970912bac9SSam Leffler 			/*
38980912bac9SSam Leffler 			 * ERP element needs updating.
38990912bac9SSam Leffler 			 */
39000912bac9SSam Leffler 			(void) ieee80211_add_erp(bo->bo_erp, ic);
3901b105a069SSam Leffler 			clrbit(bo->bo_flags, IEEE80211_BEACON_ERP);
39020912bac9SSam Leffler 		}
39034207227cSSam Leffler #ifdef IEEE80211_SUPPORT_SUPERG
39044207227cSSam Leffler 		if (isset(bo->bo_flags,  IEEE80211_BEACON_ATH)) {
39054207227cSSam Leffler 			ieee80211_add_athcaps(bo->bo_ath, ni);
39064207227cSSam Leffler 			clrbit(bo->bo_flags, IEEE80211_BEACON_ATH);
39074207227cSSam Leffler 		}
39084207227cSSam Leffler #endif
39098a1b9b6aSSam Leffler 	}
3910b032f27cSSam Leffler 	if (isset(bo->bo_flags, IEEE80211_BEACON_APPIE)) {
3911b032f27cSSam Leffler 		const struct ieee80211_appie *aie = vap->iv_appie_beacon;
3912b032f27cSSam Leffler 		int aielen;
3913b032f27cSSam Leffler 		uint8_t *frm;
3914b032f27cSSam Leffler 
3915b032f27cSSam Leffler 		aielen = 0;
3916b032f27cSSam Leffler 		if (aie != NULL)
3917b032f27cSSam Leffler 			aielen += aie->ie_len;
3918b032f27cSSam Leffler 		if (aielen != bo->bo_appie_len) {
3919b032f27cSSam Leffler 			/* copy up/down trailer */
3920b032f27cSSam Leffler 			int adjust = aielen - bo->bo_appie_len;
3921b032f27cSSam Leffler 			ovbcopy(bo->bo_tim_trailer, bo->bo_tim_trailer+adjust,
3922b032f27cSSam Leffler 				bo->bo_tim_trailer_len);
3923b032f27cSSam Leffler 			bo->bo_tim_trailer += adjust;
3924b032f27cSSam Leffler 			bo->bo_appie += adjust;
3925b032f27cSSam Leffler 			bo->bo_appie_len = aielen;
3926b032f27cSSam Leffler 
3927b032f27cSSam Leffler 			len_changed = 1;
3928b032f27cSSam Leffler 		}
3929b032f27cSSam Leffler 		frm = bo->bo_appie;
3930b032f27cSSam Leffler 		if (aie != NULL)
3931b032f27cSSam Leffler 			frm  = add_appie(frm, aie);
3932b032f27cSSam Leffler 		clrbit(bo->bo_flags, IEEE80211_BEACON_APPIE);
3933b032f27cSSam Leffler 	}
3934b032f27cSSam Leffler 	IEEE80211_UNLOCK(ic);
39358a1b9b6aSSam Leffler 
39368a1b9b6aSSam Leffler 	return len_changed;
39378a1b9b6aSSam Leffler }
393874b4c76eSAdrian Chadd 
393974b4c76eSAdrian Chadd /*
394074b4c76eSAdrian Chadd  * Do Ethernet-LLC encapsulation for each payload in a fast frame
394174b4c76eSAdrian Chadd  * tunnel encapsulation.  The frame is assumed to have an Ethernet
394274b4c76eSAdrian Chadd  * header at the front that must be stripped before prepending the
394374b4c76eSAdrian Chadd  * LLC followed by the Ethernet header passed in (with an Ethernet
394474b4c76eSAdrian Chadd  * type that specifies the payload size).
394574b4c76eSAdrian Chadd  */
394674b4c76eSAdrian Chadd struct mbuf *
394774b4c76eSAdrian Chadd ieee80211_ff_encap1(struct ieee80211vap *vap, struct mbuf *m,
394874b4c76eSAdrian Chadd 	const struct ether_header *eh)
394974b4c76eSAdrian Chadd {
395074b4c76eSAdrian Chadd 	struct llc *llc;
395174b4c76eSAdrian Chadd 	uint16_t payload;
395274b4c76eSAdrian Chadd 
395374b4c76eSAdrian Chadd 	/* XXX optimize by combining m_adj+M_PREPEND */
395474b4c76eSAdrian Chadd 	m_adj(m, sizeof(struct ether_header) - sizeof(struct llc));
395574b4c76eSAdrian Chadd 	llc = mtod(m, struct llc *);
395674b4c76eSAdrian Chadd 	llc->llc_dsap = llc->llc_ssap = LLC_SNAP_LSAP;
395774b4c76eSAdrian Chadd 	llc->llc_control = LLC_UI;
395874b4c76eSAdrian Chadd 	llc->llc_snap.org_code[0] = 0;
395974b4c76eSAdrian Chadd 	llc->llc_snap.org_code[1] = 0;
396074b4c76eSAdrian Chadd 	llc->llc_snap.org_code[2] = 0;
396174b4c76eSAdrian Chadd 	llc->llc_snap.ether_type = eh->ether_type;
396274b4c76eSAdrian Chadd 	payload = m->m_pkthdr.len;		/* NB: w/o Ethernet header */
396374b4c76eSAdrian Chadd 
396474b4c76eSAdrian Chadd 	M_PREPEND(m, sizeof(struct ether_header), M_NOWAIT);
396574b4c76eSAdrian Chadd 	if (m == NULL) {		/* XXX cannot happen */
396674b4c76eSAdrian Chadd 		IEEE80211_DPRINTF(vap, IEEE80211_MSG_SUPERG,
396774b4c76eSAdrian Chadd 			"%s: no space for ether_header\n", __func__);
396874b4c76eSAdrian Chadd 		vap->iv_stats.is_tx_nobuf++;
396974b4c76eSAdrian Chadd 		return NULL;
397074b4c76eSAdrian Chadd 	}
397174b4c76eSAdrian Chadd 	ETHER_HEADER_COPY(mtod(m, void *), eh);
397274b4c76eSAdrian Chadd 	mtod(m, struct ether_header *)->ether_type = htons(payload);
397374b4c76eSAdrian Chadd 	return m;
397474b4c76eSAdrian Chadd }
397536ee7775SAdrian Chadd 
397636ee7775SAdrian Chadd /*
397736ee7775SAdrian Chadd  * Complete an mbuf transmission.
397836ee7775SAdrian Chadd  *
397936ee7775SAdrian Chadd  * For now, this simply processes a completed frame after the
398036ee7775SAdrian Chadd  * driver has completed it's transmission and/or retransmission.
398136ee7775SAdrian Chadd  * It assumes the frame is an 802.11 encapsulated frame.
398236ee7775SAdrian Chadd  *
398336ee7775SAdrian Chadd  * Later on it will grow to become the exit path for a given frame
398436ee7775SAdrian Chadd  * from the driver and, depending upon how it's been encapsulated
398536ee7775SAdrian Chadd  * and already transmitted, it may end up doing A-MPDU retransmission,
398636ee7775SAdrian Chadd  * power save requeuing, etc.
398736ee7775SAdrian Chadd  *
398836ee7775SAdrian Chadd  * In order for the above to work, the driver entry point to this
398936ee7775SAdrian Chadd  * must not hold any driver locks.  Thus, the driver needs to delay
399036ee7775SAdrian Chadd  * any actual mbuf completion until it can release said locks.
399136ee7775SAdrian Chadd  *
399236ee7775SAdrian Chadd  * This frees the mbuf and if the mbuf has a node reference,
399336ee7775SAdrian Chadd  * the node reference will be freed.
399436ee7775SAdrian Chadd  */
399536ee7775SAdrian Chadd void
399636ee7775SAdrian Chadd ieee80211_tx_complete(struct ieee80211_node *ni, struct mbuf *m, int status)
399736ee7775SAdrian Chadd {
399836ee7775SAdrian Chadd 
399936ee7775SAdrian Chadd 	if (ni != NULL) {
40007a79cebfSGleb Smirnoff 		struct ifnet *ifp = ni->ni_vap->iv_ifp;
40017a79cebfSGleb Smirnoff 
40027a79cebfSGleb Smirnoff 		if (status == 0) {
40037a79cebfSGleb Smirnoff 			if_inc_counter(ifp, IFCOUNTER_OBYTES, m->m_pkthdr.len);
40047a79cebfSGleb Smirnoff 			if_inc_counter(ifp, IFCOUNTER_OPACKETS, 1);
40057a79cebfSGleb Smirnoff 			if (m->m_flags & M_MCAST)
40067a79cebfSGleb Smirnoff 				if_inc_counter(ifp, IFCOUNTER_OMCASTS, 1);
40077a79cebfSGleb Smirnoff 		} else
40087a79cebfSGleb Smirnoff 			if_inc_counter(ifp, IFCOUNTER_OERRORS, 1);
400936ee7775SAdrian Chadd 		if (m->m_flags & M_TXCB)
401036ee7775SAdrian Chadd 			ieee80211_process_callback(ni, m, status);
401136ee7775SAdrian Chadd 		ieee80211_free_node(ni);
401236ee7775SAdrian Chadd 	}
401336ee7775SAdrian Chadd 	m_freem(m);
401436ee7775SAdrian Chadd }
4015