xref: /freebsd/sys/net80211/ieee80211_output.c (revision dea4512157f45a2026320a5f306dac409692682d)
11a1e1d21SSam Leffler /*-
27535e66aSSam Leffler  * Copyright (c) 2001 Atsushi Onoe
310ad9a77SSam Leffler  * Copyright (c) 2002-2009 Sam Leffler, Errno Consulting
41a1e1d21SSam Leffler  * All rights reserved.
51a1e1d21SSam Leffler  *
61a1e1d21SSam Leffler  * Redistribution and use in source and binary forms, with or without
71a1e1d21SSam Leffler  * modification, are permitted provided that the following conditions
81a1e1d21SSam Leffler  * are met:
91a1e1d21SSam Leffler  * 1. Redistributions of source code must retain the above copyright
107535e66aSSam Leffler  *    notice, this list of conditions and the following disclaimer.
117535e66aSSam Leffler  * 2. Redistributions in binary form must reproduce the above copyright
127535e66aSSam Leffler  *    notice, this list of conditions and the following disclaimer in the
137535e66aSSam Leffler  *    documentation and/or other materials provided with the distribution.
141a1e1d21SSam Leffler  *
157535e66aSSam Leffler  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
167535e66aSSam Leffler  * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
177535e66aSSam Leffler  * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
187535e66aSSam Leffler  * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
197535e66aSSam Leffler  * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
207535e66aSSam Leffler  * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
217535e66aSSam Leffler  * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
227535e66aSSam Leffler  * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
237535e66aSSam Leffler  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
247535e66aSSam Leffler  * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
251a1e1d21SSam Leffler  */
261a1e1d21SSam Leffler 
271a1e1d21SSam Leffler #include <sys/cdefs.h>
281a1e1d21SSam Leffler __FBSDID("$FreeBSD$");
291a1e1d21SSam Leffler 
301a1e1d21SSam Leffler #include "opt_inet.h"
31e755a73dSSam Leffler #include "opt_inet6.h"
32b032f27cSSam Leffler #include "opt_wlan.h"
331a1e1d21SSam Leffler 
341a1e1d21SSam Leffler #include <sys/param.h>
351a1e1d21SSam Leffler #include <sys/systm.h>
361a1e1d21SSam Leffler #include <sys/mbuf.h>
371a1e1d21SSam Leffler #include <sys/kernel.h>
381a1e1d21SSam Leffler #include <sys/endian.h>
391a1e1d21SSam Leffler 
408a1b9b6aSSam Leffler #include <sys/socket.h>
411a1e1d21SSam Leffler 
421a1e1d21SSam Leffler #include <net/bpf.h>
438a1b9b6aSSam Leffler #include <net/ethernet.h>
448a1b9b6aSSam Leffler #include <net/if.h>
4576039bc8SGleb Smirnoff #include <net/if_var.h>
468a1b9b6aSSam Leffler #include <net/if_llc.h>
478a1b9b6aSSam Leffler #include <net/if_media.h>
488a1b9b6aSSam Leffler #include <net/if_vlan_var.h>
498a1b9b6aSSam Leffler 
508a1b9b6aSSam Leffler #include <net80211/ieee80211_var.h>
5168e8e04eSSam Leffler #include <net80211/ieee80211_regdomain.h>
52616190d0SSam Leffler #ifdef IEEE80211_SUPPORT_SUPERG
53616190d0SSam Leffler #include <net80211/ieee80211_superg.h>
54616190d0SSam Leffler #endif
5510ad9a77SSam Leffler #ifdef IEEE80211_SUPPORT_TDMA
5610ad9a77SSam Leffler #include <net80211/ieee80211_tdma.h>
5710ad9a77SSam Leffler #endif
58b032f27cSSam Leffler #include <net80211/ieee80211_wds.h>
5959aa14a9SRui Paulo #include <net80211/ieee80211_mesh.h>
601a1e1d21SSam Leffler 
618355d59dSBjoern A. Zeeb #if defined(INET) || defined(INET6)
621a1e1d21SSam Leffler #include <netinet/in.h>
638355d59dSBjoern A. Zeeb #endif
648355d59dSBjoern A. Zeeb 
658355d59dSBjoern A. Zeeb #ifdef INET
661a1e1d21SSam Leffler #include <netinet/if_ether.h>
678a1b9b6aSSam Leffler #include <netinet/in_systm.h>
688a1b9b6aSSam Leffler #include <netinet/ip.h>
698a1b9b6aSSam Leffler #endif
70e755a73dSSam Leffler #ifdef INET6
71e755a73dSSam Leffler #include <netinet/ip6.h>
72e755a73dSSam Leffler #endif
738a1b9b6aSSam Leffler 
74c27b9cdbSRobert Watson #include <security/mac/mac_framework.h>
75c27b9cdbSRobert Watson 
7668e8e04eSSam Leffler #define	ETHER_HEADER_COPY(dst, src) \
7768e8e04eSSam Leffler 	memcpy(dst, src, sizeof(struct ether_header))
7868e8e04eSSam Leffler 
7959aa14a9SRui Paulo /* unalligned little endian access */
8059aa14a9SRui Paulo #define LE_WRITE_2(p, v) do {				\
8159aa14a9SRui Paulo 	((uint8_t *)(p))[0] = (v) & 0xff;		\
8259aa14a9SRui Paulo 	((uint8_t *)(p))[1] = ((v) >> 8) & 0xff;	\
8359aa14a9SRui Paulo } while (0)
8459aa14a9SRui Paulo #define LE_WRITE_4(p, v) do {				\
8559aa14a9SRui Paulo 	((uint8_t *)(p))[0] = (v) & 0xff;		\
8659aa14a9SRui Paulo 	((uint8_t *)(p))[1] = ((v) >> 8) & 0xff;	\
8759aa14a9SRui Paulo 	((uint8_t *)(p))[2] = ((v) >> 16) & 0xff;	\
8859aa14a9SRui Paulo 	((uint8_t *)(p))[3] = ((v) >> 24) & 0xff;	\
8959aa14a9SRui Paulo } while (0)
9059aa14a9SRui Paulo 
91b032f27cSSam Leffler static int ieee80211_fragment(struct ieee80211vap *, struct mbuf *,
9268e8e04eSSam Leffler 	u_int hdrsize, u_int ciphdrsize, u_int mtu);
9368e8e04eSSam Leffler static	void ieee80211_tx_mgt_cb(struct ieee80211_node *, void *, int);
9468e8e04eSSam Leffler 
958a1b9b6aSSam Leffler #ifdef IEEE80211_DEBUG
968a1b9b6aSSam Leffler /*
978a1b9b6aSSam Leffler  * Decide if an outbound management frame should be
988a1b9b6aSSam Leffler  * printed when debugging is enabled.  This filters some
998a1b9b6aSSam Leffler  * of the less interesting frames that come frequently
1008a1b9b6aSSam Leffler  * (e.g. beacons).
1018a1b9b6aSSam Leffler  */
1028a1b9b6aSSam Leffler static __inline int
103b032f27cSSam Leffler doprint(struct ieee80211vap *vap, int subtype)
1048a1b9b6aSSam Leffler {
1058a1b9b6aSSam Leffler 	switch (subtype) {
1068a1b9b6aSSam Leffler 	case IEEE80211_FC0_SUBTYPE_PROBE_RESP:
107b032f27cSSam Leffler 		return (vap->iv_opmode == IEEE80211_M_IBSS);
1088a1b9b6aSSam Leffler 	}
1098a1b9b6aSSam Leffler 	return 1;
1108a1b9b6aSSam Leffler }
1111a1e1d21SSam Leffler #endif
1121a1e1d21SSam Leffler 
1130a915fadSSam Leffler /*
114363a2c3cSAdrian Chadd  * Transmit a frame to the given destination on the given VAP.
115363a2c3cSAdrian Chadd  *
116363a2c3cSAdrian Chadd  * It's up to the caller to figure out the details of who this
117363a2c3cSAdrian Chadd  * is going to and resolving the node.
118363a2c3cSAdrian Chadd  *
119363a2c3cSAdrian Chadd  * This routine takes care of queuing it for power save,
120363a2c3cSAdrian Chadd  * A-MPDU state stuff, fast-frames state stuff, encapsulation
121363a2c3cSAdrian Chadd  * if required, then passing it up to the driver layer.
122363a2c3cSAdrian Chadd  *
123363a2c3cSAdrian Chadd  * This routine (for now) consumes the mbuf and frees the node
124363a2c3cSAdrian Chadd  * reference; it ideally will return a TX status which reflects
125363a2c3cSAdrian Chadd  * whether the mbuf was consumed or not, so the caller can
126363a2c3cSAdrian Chadd  * free the mbuf (if appropriate) and the node reference (again,
127363a2c3cSAdrian Chadd  * if appropriate.)
128363a2c3cSAdrian Chadd  */
129363a2c3cSAdrian Chadd int
130363a2c3cSAdrian Chadd ieee80211_vap_pkt_send_dest(struct ieee80211vap *vap, struct mbuf *m,
131363a2c3cSAdrian Chadd     struct ieee80211_node *ni)
132363a2c3cSAdrian Chadd {
133363a2c3cSAdrian Chadd 	struct ieee80211com *ic = vap->iv_ic;
134363a2c3cSAdrian Chadd 	struct ifnet *ifp = vap->iv_ifp;
135363a2c3cSAdrian Chadd 	int error;
136363a2c3cSAdrian Chadd 
137363a2c3cSAdrian Chadd 	if ((ni->ni_flags & IEEE80211_NODE_PWR_MGT) &&
138363a2c3cSAdrian Chadd 	    (m->m_flags & M_PWR_SAV) == 0) {
139363a2c3cSAdrian Chadd 		/*
140363a2c3cSAdrian Chadd 		 * Station in power save mode; pass the frame
141363a2c3cSAdrian Chadd 		 * to the 802.11 layer and continue.  We'll get
142363a2c3cSAdrian Chadd 		 * the frame back when the time is right.
143363a2c3cSAdrian Chadd 		 * XXX lose WDS vap linkage?
144363a2c3cSAdrian Chadd 		 */
145363a2c3cSAdrian Chadd 		(void) ieee80211_pwrsave(ni, m);
146363a2c3cSAdrian Chadd 		ieee80211_free_node(ni);
147c6d5b600SAdrian Chadd 
148c6d5b600SAdrian Chadd 		/*
149c6d5b600SAdrian Chadd 		 * We queued it fine, so tell the upper layer
150c6d5b600SAdrian Chadd 		 * that we consumed it.
151c6d5b600SAdrian Chadd 		 */
152c6d5b600SAdrian Chadd 		return (0);
153363a2c3cSAdrian Chadd 	}
154363a2c3cSAdrian Chadd 	/* calculate priority so drivers can find the tx queue */
155363a2c3cSAdrian Chadd 	if (ieee80211_classify(ni, m)) {
156363a2c3cSAdrian Chadd 		IEEE80211_DISCARD_MAC(vap, IEEE80211_MSG_OUTPUT,
157363a2c3cSAdrian Chadd 		    ni->ni_macaddr, NULL,
158363a2c3cSAdrian Chadd 		    "%s", "classification failure");
159363a2c3cSAdrian Chadd 		vap->iv_stats.is_tx_classify++;
160*dea45121SGleb Smirnoff 		if_inc_counter(ifp, IFCOUNTER_OERRORS, 1);
161363a2c3cSAdrian Chadd 		m_freem(m);
162363a2c3cSAdrian Chadd 		ieee80211_free_node(ni);
163c6d5b600SAdrian Chadd 
164363a2c3cSAdrian Chadd 		/* XXX better status? */
165c6d5b600SAdrian Chadd 		return (0);
166363a2c3cSAdrian Chadd 	}
167363a2c3cSAdrian Chadd 	/*
168363a2c3cSAdrian Chadd 	 * Stash the node pointer.  Note that we do this after
169363a2c3cSAdrian Chadd 	 * any call to ieee80211_dwds_mcast because that code
170363a2c3cSAdrian Chadd 	 * uses any existing value for rcvif to identify the
171363a2c3cSAdrian Chadd 	 * interface it (might have been) received on.
172363a2c3cSAdrian Chadd 	 */
173363a2c3cSAdrian Chadd 	m->m_pkthdr.rcvif = (void *)ni;
174363a2c3cSAdrian Chadd 
175363a2c3cSAdrian Chadd 	BPF_MTAP(ifp, m);		/* 802.3 tx */
176363a2c3cSAdrian Chadd 
177363a2c3cSAdrian Chadd 	/*
178363a2c3cSAdrian Chadd 	 * Check if A-MPDU tx aggregation is setup or if we
179363a2c3cSAdrian Chadd 	 * should try to enable it.  The sta must be associated
180363a2c3cSAdrian Chadd 	 * with HT and A-MPDU enabled for use.  When the policy
181363a2c3cSAdrian Chadd 	 * routine decides we should enable A-MPDU we issue an
182363a2c3cSAdrian Chadd 	 * ADDBA request and wait for a reply.  The frame being
183363a2c3cSAdrian Chadd 	 * encapsulated will go out w/o using A-MPDU, or possibly
184363a2c3cSAdrian Chadd 	 * it might be collected by the driver and held/retransmit.
185363a2c3cSAdrian Chadd 	 * The default ic_ampdu_enable routine handles staggering
186363a2c3cSAdrian Chadd 	 * ADDBA requests in case the receiver NAK's us or we are
187363a2c3cSAdrian Chadd 	 * otherwise unable to establish a BA stream.
188363a2c3cSAdrian Chadd 	 */
189363a2c3cSAdrian Chadd 	if ((ni->ni_flags & IEEE80211_NODE_AMPDU_TX) &&
190363a2c3cSAdrian Chadd 	    (vap->iv_flags_ht & IEEE80211_FHT_AMPDU_TX) &&
191363a2c3cSAdrian Chadd 	    (m->m_flags & M_EAPOL) == 0) {
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 	}
212363a2c3cSAdrian Chadd 
213363a2c3cSAdrian Chadd #ifdef IEEE80211_SUPPORT_SUPERG
214363a2c3cSAdrian Chadd 	else if (IEEE80211_ATH_CAP(vap, ni, IEEE80211_NODE_FF)) {
215363a2c3cSAdrian Chadd 		m = ieee80211_ff_check(ni, m);
216363a2c3cSAdrian Chadd 		if (m == NULL) {
217363a2c3cSAdrian Chadd 			/* NB: any ni ref held on stageq */
21811e0ddb1SAdrian Chadd 			return (0);
219363a2c3cSAdrian Chadd 		}
220363a2c3cSAdrian Chadd 	}
221363a2c3cSAdrian Chadd #endif /* IEEE80211_SUPPORT_SUPERG */
222363a2c3cSAdrian Chadd 
223363a2c3cSAdrian Chadd 	/*
224363a2c3cSAdrian Chadd 	 * Grab the TX lock - serialise the TX process from this
225363a2c3cSAdrian Chadd 	 * point (where TX state is being checked/modified)
226363a2c3cSAdrian Chadd 	 * through to driver queue.
227363a2c3cSAdrian Chadd 	 */
228363a2c3cSAdrian Chadd 	IEEE80211_TX_LOCK(ic);
229363a2c3cSAdrian Chadd 
230363a2c3cSAdrian Chadd 	if (__predict_true((vap->iv_caps & IEEE80211_C_8023ENCAP) == 0)) {
231363a2c3cSAdrian Chadd 		/*
232363a2c3cSAdrian Chadd 		 * Encapsulate the packet in prep for transmission.
233363a2c3cSAdrian Chadd 		 */
234363a2c3cSAdrian Chadd 		m = ieee80211_encap(vap, ni, m);
235363a2c3cSAdrian Chadd 		if (m == NULL) {
236363a2c3cSAdrian Chadd 			/* NB: stat+msg handled in ieee80211_encap */
237363a2c3cSAdrian Chadd 			IEEE80211_TX_UNLOCK(ic);
238363a2c3cSAdrian Chadd 			ieee80211_free_node(ni);
239363a2c3cSAdrian Chadd 			/* XXX better status? */
240363a2c3cSAdrian Chadd 			return (ENOBUFS);
241363a2c3cSAdrian Chadd 		}
242363a2c3cSAdrian Chadd 	}
243e7495198SAdrian Chadd 	error = ieee80211_parent_xmitpkt(ic, m);
244363a2c3cSAdrian Chadd 
245363a2c3cSAdrian Chadd 	/*
246363a2c3cSAdrian Chadd 	 * Unlock at this point - no need to hold it across
247363a2c3cSAdrian Chadd 	 * ieee80211_free_node() (ie, the comlock)
248363a2c3cSAdrian Chadd 	 */
249363a2c3cSAdrian Chadd 	IEEE80211_TX_UNLOCK(ic);
250363a2c3cSAdrian Chadd 	if (error != 0) {
251363a2c3cSAdrian Chadd 		/* NB: IFQ_HANDOFF reclaims mbuf */
252363a2c3cSAdrian Chadd 		ieee80211_free_node(ni);
253363a2c3cSAdrian Chadd 	} else {
254*dea45121SGleb Smirnoff 		if_inc_counter(ifp, IFCOUNTER_OPACKETS, 1);
255363a2c3cSAdrian Chadd 	}
256363a2c3cSAdrian Chadd 	ic->ic_lastdata = ticks;
257363a2c3cSAdrian Chadd 
258363a2c3cSAdrian Chadd 	return (0);
259363a2c3cSAdrian Chadd }
260363a2c3cSAdrian Chadd 
261363a2c3cSAdrian Chadd 
262363a2c3cSAdrian Chadd 
263363a2c3cSAdrian Chadd /*
2645cda6006SAdrian Chadd  * Send the given mbuf through the given vap.
2655cda6006SAdrian Chadd  *
2665cda6006SAdrian Chadd  * This consumes the mbuf regardless of whether the transmit
2675cda6006SAdrian Chadd  * was successful or not.
2685cda6006SAdrian Chadd  *
2695cda6006SAdrian Chadd  * This does none of the initial checks that ieee80211_start()
2705cda6006SAdrian Chadd  * does (eg CAC timeout, interface wakeup) - the caller must
2715cda6006SAdrian Chadd  * do this first.
2725cda6006SAdrian Chadd  */
2735cda6006SAdrian Chadd static int
2745cda6006SAdrian Chadd ieee80211_start_pkt(struct ieee80211vap *vap, struct mbuf *m)
2755cda6006SAdrian Chadd {
2765cda6006SAdrian Chadd #define	IS_DWDS(vap) \
2775cda6006SAdrian Chadd 	(vap->iv_opmode == IEEE80211_M_WDS && \
2785cda6006SAdrian Chadd 	 (vap->iv_flags_ext & IEEE80211_FEXT_WDSLEGACY) == 0)
2795cda6006SAdrian Chadd 	struct ieee80211com *ic = vap->iv_ic;
2805cda6006SAdrian Chadd 	struct ifnet *ifp = vap->iv_ifp;
2815cda6006SAdrian Chadd 	struct ieee80211_node *ni;
2825cda6006SAdrian Chadd 	struct ether_header *eh;
2835cda6006SAdrian Chadd 
2845cda6006SAdrian Chadd 	/*
2855cda6006SAdrian Chadd 	 * Cancel any background scan.
2865cda6006SAdrian Chadd 	 */
2875cda6006SAdrian Chadd 	if (ic->ic_flags & IEEE80211_F_SCAN)
2885cda6006SAdrian Chadd 		ieee80211_cancel_anyscan(vap);
2895cda6006SAdrian Chadd 	/*
2905cda6006SAdrian Chadd 	 * Find the node for the destination so we can do
2915cda6006SAdrian Chadd 	 * things like power save and fast frames aggregation.
2925cda6006SAdrian Chadd 	 *
2935cda6006SAdrian Chadd 	 * NB: past this point various code assumes the first
2945cda6006SAdrian Chadd 	 *     mbuf has the 802.3 header present (and contiguous).
2955cda6006SAdrian Chadd 	 */
2965cda6006SAdrian Chadd 	ni = NULL;
2975cda6006SAdrian Chadd 	if (m->m_len < sizeof(struct ether_header) &&
2985cda6006SAdrian Chadd 	   (m = m_pullup(m, sizeof(struct ether_header))) == NULL) {
2995cda6006SAdrian Chadd 		IEEE80211_DPRINTF(vap, IEEE80211_MSG_OUTPUT,
3005cda6006SAdrian Chadd 		    "discard frame, %s\n", "m_pullup failed");
3015cda6006SAdrian Chadd 		vap->iv_stats.is_tx_nobuf++;	/* XXX */
302*dea45121SGleb Smirnoff 		if_inc_counter(ifp, IFCOUNTER_OERRORS, 1);
3035cda6006SAdrian Chadd 		return (ENOBUFS);
3045cda6006SAdrian Chadd 	}
3055cda6006SAdrian Chadd 	eh = mtod(m, struct ether_header *);
3065cda6006SAdrian Chadd 	if (ETHER_IS_MULTICAST(eh->ether_dhost)) {
3075cda6006SAdrian Chadd 		if (IS_DWDS(vap)) {
3085cda6006SAdrian Chadd 			/*
3095cda6006SAdrian Chadd 			 * Only unicast frames from the above go out
3105cda6006SAdrian Chadd 			 * DWDS vaps; multicast frames are handled by
3115cda6006SAdrian Chadd 			 * dispatching the frame as it comes through
3125cda6006SAdrian Chadd 			 * the AP vap (see below).
3135cda6006SAdrian Chadd 			 */
3145cda6006SAdrian Chadd 			IEEE80211_DISCARD_MAC(vap, IEEE80211_MSG_WDS,
3155cda6006SAdrian Chadd 			    eh->ether_dhost, "mcast", "%s", "on DWDS");
3165cda6006SAdrian Chadd 			vap->iv_stats.is_dwds_mcast++;
3175cda6006SAdrian Chadd 			m_freem(m);
3185cda6006SAdrian Chadd 			/* XXX better status? */
3195cda6006SAdrian Chadd 			return (ENOBUFS);
3205cda6006SAdrian Chadd 		}
3215cda6006SAdrian Chadd 		if (vap->iv_opmode == IEEE80211_M_HOSTAP) {
3225cda6006SAdrian Chadd 			/*
3235cda6006SAdrian Chadd 			 * Spam DWDS vap's w/ multicast traffic.
3245cda6006SAdrian Chadd 			 */
3255cda6006SAdrian Chadd 			/* XXX only if dwds in use? */
3265cda6006SAdrian Chadd 			ieee80211_dwds_mcast(vap, m);
3275cda6006SAdrian Chadd 		}
3285cda6006SAdrian Chadd 	}
3295cda6006SAdrian Chadd #ifdef IEEE80211_SUPPORT_MESH
3305cda6006SAdrian Chadd 	if (vap->iv_opmode != IEEE80211_M_MBSS) {
3315cda6006SAdrian Chadd #endif
3325cda6006SAdrian Chadd 		ni = ieee80211_find_txnode(vap, eh->ether_dhost);
3335cda6006SAdrian Chadd 		if (ni == NULL) {
3345cda6006SAdrian Chadd 			/* NB: ieee80211_find_txnode does stat+msg */
335*dea45121SGleb Smirnoff 			if_inc_counter(ifp, IFCOUNTER_OERRORS, 1);
3365cda6006SAdrian Chadd 			m_freem(m);
3375cda6006SAdrian Chadd 			/* XXX better status? */
3385cda6006SAdrian Chadd 			return (ENOBUFS);
3395cda6006SAdrian Chadd 		}
3405cda6006SAdrian Chadd 		if (ni->ni_associd == 0 &&
3415cda6006SAdrian Chadd 		    (ni->ni_flags & IEEE80211_NODE_ASSOCID)) {
3425cda6006SAdrian Chadd 			IEEE80211_DISCARD_MAC(vap, IEEE80211_MSG_OUTPUT,
3435cda6006SAdrian Chadd 			    eh->ether_dhost, NULL,
3445cda6006SAdrian Chadd 			    "sta not associated (type 0x%04x)",
3455cda6006SAdrian Chadd 			    htons(eh->ether_type));
3465cda6006SAdrian Chadd 			vap->iv_stats.is_tx_notassoc++;
347*dea45121SGleb Smirnoff 			if_inc_counter(ifp, IFCOUNTER_OERRORS, 1);
3485cda6006SAdrian Chadd 			m_freem(m);
3495cda6006SAdrian Chadd 			ieee80211_free_node(ni);
3505cda6006SAdrian Chadd 			/* XXX better status? */
3515cda6006SAdrian Chadd 			return (ENOBUFS);
3525cda6006SAdrian Chadd 		}
3535cda6006SAdrian Chadd #ifdef IEEE80211_SUPPORT_MESH
3545cda6006SAdrian Chadd 	} else {
3555cda6006SAdrian Chadd 		if (!IEEE80211_ADDR_EQ(eh->ether_shost, vap->iv_myaddr)) {
3565cda6006SAdrian Chadd 			/*
3575cda6006SAdrian Chadd 			 * Proxy station only if configured.
3585cda6006SAdrian Chadd 			 */
3595cda6006SAdrian Chadd 			if (!ieee80211_mesh_isproxyena(vap)) {
3605cda6006SAdrian Chadd 				IEEE80211_DISCARD_MAC(vap,
3615cda6006SAdrian Chadd 				    IEEE80211_MSG_OUTPUT |
3625cda6006SAdrian Chadd 				    IEEE80211_MSG_MESH,
3635cda6006SAdrian Chadd 				    eh->ether_dhost, NULL,
3645cda6006SAdrian Chadd 				    "%s", "proxy not enabled");
3655cda6006SAdrian Chadd 				vap->iv_stats.is_mesh_notproxy++;
366*dea45121SGleb Smirnoff 				if_inc_counter(ifp, IFCOUNTER_OERRORS, 1);
3675cda6006SAdrian Chadd 				m_freem(m);
3685cda6006SAdrian Chadd 				/* XXX better status? */
3695cda6006SAdrian Chadd 				return (ENOBUFS);
3705cda6006SAdrian Chadd 			}
3715cda6006SAdrian Chadd 			IEEE80211_DPRINTF(vap, IEEE80211_MSG_OUTPUT,
3725cda6006SAdrian Chadd 			    "forward frame from DS SA(%6D), DA(%6D)\n",
3735cda6006SAdrian Chadd 			    eh->ether_shost, ":",
3745cda6006SAdrian Chadd 			    eh->ether_dhost, ":");
3755cda6006SAdrian Chadd 			ieee80211_mesh_proxy_check(vap, eh->ether_shost);
3765cda6006SAdrian Chadd 		}
3775cda6006SAdrian Chadd 		ni = ieee80211_mesh_discover(vap, eh->ether_dhost, m);
3785cda6006SAdrian Chadd 		if (ni == NULL) {
3795cda6006SAdrian Chadd 			/*
3805cda6006SAdrian Chadd 			 * NB: ieee80211_mesh_discover holds/disposes
3815cda6006SAdrian Chadd 			 * frame (e.g. queueing on path discovery).
3825cda6006SAdrian Chadd 			 */
383*dea45121SGleb Smirnoff 			if_inc_counter(ifp, IFCOUNTER_OERRORS, 1);
3845cda6006SAdrian Chadd 			/* XXX better status? */
3855cda6006SAdrian Chadd 			return (ENOBUFS);
3865cda6006SAdrian Chadd 		}
3875cda6006SAdrian Chadd 	}
3885cda6006SAdrian Chadd #endif
389363a2c3cSAdrian Chadd 
3905cda6006SAdrian Chadd 	/*
391363a2c3cSAdrian Chadd 	 * We've resolved the sender, so attempt to transmit it.
3925cda6006SAdrian Chadd 	 */
393ddd9ebbcSAdrian Chadd 
394ddd9ebbcSAdrian Chadd 	if (vap->iv_state == IEEE80211_S_SLEEP) {
395ddd9ebbcSAdrian Chadd 		/*
396ddd9ebbcSAdrian Chadd 		 * In power save; queue frame and then  wakeup device
397ddd9ebbcSAdrian Chadd 		 * for transmit.
398ddd9ebbcSAdrian Chadd 		 */
399ddd9ebbcSAdrian Chadd 		ic->ic_lastdata = ticks;
400ddd9ebbcSAdrian Chadd 		(void) ieee80211_pwrsave(ni, m);
401ddd9ebbcSAdrian Chadd 		ieee80211_free_node(ni);
402ddd9ebbcSAdrian Chadd 		ieee80211_new_state(vap, IEEE80211_S_RUN, 0);
403ddd9ebbcSAdrian Chadd 		return (0);
404ddd9ebbcSAdrian Chadd 	}
405ddd9ebbcSAdrian Chadd 
406363a2c3cSAdrian Chadd 	if (ieee80211_vap_pkt_send_dest(vap, m, ni) != 0)
4075cda6006SAdrian Chadd 		return (ENOBUFS);
4085cda6006SAdrian Chadd 	return (0);
4095cda6006SAdrian Chadd #undef	IS_DWDS
4105cda6006SAdrian Chadd }
4115cda6006SAdrian Chadd 
4125cda6006SAdrian Chadd /*
413b032f27cSSam Leffler  * Start method for vap's.  All packets from the stack come
414b032f27cSSam Leffler  * through here.  We handle common processing of the packets
415b032f27cSSam Leffler  * before dispatching them to the underlying device.
4161df885c8SAdrian Chadd  *
4171df885c8SAdrian Chadd  * if_transmit() requires that the mbuf be consumed by this call
4181df885c8SAdrian Chadd  * regardless of the return condition.
419b032f27cSSam Leffler  */
420e7495198SAdrian Chadd int
421e7495198SAdrian Chadd ieee80211_vap_transmit(struct ifnet *ifp, struct mbuf *m)
422b032f27cSSam Leffler {
423b032f27cSSam Leffler 	struct ieee80211vap *vap = ifp->if_softc;
424b032f27cSSam Leffler 	struct ieee80211com *ic = vap->iv_ic;
425b032f27cSSam Leffler 	struct ifnet *parent = ic->ic_ifp;
426b032f27cSSam Leffler 
427b032f27cSSam Leffler 	/* NB: parent must be up and running */
428b032f27cSSam Leffler 	if (!IFNET_IS_UP_RUNNING(parent)) {
429b032f27cSSam Leffler 		IEEE80211_DPRINTF(vap, IEEE80211_MSG_OUTPUT,
430b032f27cSSam Leffler 		    "%s: ignore queue, parent %s not up+running\n",
431b032f27cSSam Leffler 		    __func__, parent->if_xname);
432b032f27cSSam Leffler 		/* XXX stat */
4331df885c8SAdrian Chadd 		m_freem(m);
434e7495198SAdrian Chadd 		return (EINVAL);
435b032f27cSSam Leffler 	}
436ddd9ebbcSAdrian Chadd 
437b032f27cSSam Leffler 	/*
438b032f27cSSam Leffler 	 * No data frames go out unless we're running.
439b032f27cSSam Leffler 	 * Note in particular this covers CAC and CSA
440b032f27cSSam Leffler 	 * states (though maybe we should check muting
441b032f27cSSam Leffler 	 * for CSA).
442b032f27cSSam Leffler 	 */
443ddd9ebbcSAdrian Chadd 	if (vap->iv_state != IEEE80211_S_RUN &&
444ddd9ebbcSAdrian Chadd 	    vap->iv_state != IEEE80211_S_SLEEP) {
445b032f27cSSam Leffler 		IEEE80211_LOCK(ic);
446b032f27cSSam Leffler 		/* re-check under the com lock to avoid races */
447ddd9ebbcSAdrian Chadd 		if (vap->iv_state != IEEE80211_S_RUN &&
448ddd9ebbcSAdrian Chadd 		    vap->iv_state != IEEE80211_S_SLEEP) {
449b032f27cSSam Leffler 			IEEE80211_DPRINTF(vap, IEEE80211_MSG_OUTPUT,
450b032f27cSSam Leffler 			    "%s: ignore queue, in %s state\n",
451b032f27cSSam Leffler 			    __func__, ieee80211_state_name[vap->iv_state]);
452b032f27cSSam Leffler 			vap->iv_stats.is_tx_badstate++;
453b032f27cSSam Leffler 			IEEE80211_UNLOCK(ic);
45470e0b5acSAdrian Chadd 			ifp->if_drv_flags |= IFF_DRV_OACTIVE;
4551df885c8SAdrian Chadd 			m_freem(m);
456e7495198SAdrian Chadd 			return (EINVAL);
457b032f27cSSam Leffler 		}
458b032f27cSSam Leffler 		IEEE80211_UNLOCK(ic);
459b032f27cSSam Leffler 	}
4605cda6006SAdrian Chadd 
461b032f27cSSam Leffler 	/*
462b032f27cSSam Leffler 	 * Sanitize mbuf flags for net80211 use.  We cannot
463927ef5ffSSam Leffler 	 * clear M_PWR_SAV or M_MORE_DATA because these may
464927ef5ffSSam Leffler 	 * be set for frames that are re-submitted from the
465927ef5ffSSam Leffler 	 * power save queue.
466b032f27cSSam Leffler 	 *
467b032f27cSSam Leffler 	 * NB: This must be done before ieee80211_classify as
468b032f27cSSam Leffler 	 *     it marks EAPOL in frames with M_EAPOL.
469b032f27cSSam Leffler 	 */
470927ef5ffSSam Leffler 	m->m_flags &= ~(M_80211_TX - M_PWR_SAV - M_MORE_DATA);
471e7495198SAdrian Chadd 
472b032f27cSSam Leffler 	/*
4735cda6006SAdrian Chadd 	 * Bump to the packet transmission path.
474e7495198SAdrian Chadd 	 * The mbuf will be consumed here.
475b032f27cSSam Leffler 	 */
476e7495198SAdrian Chadd 	return (ieee80211_start_pkt(vap, m));
477b032f27cSSam Leffler }
478e7495198SAdrian Chadd 
479e7495198SAdrian Chadd void
480e7495198SAdrian Chadd ieee80211_vap_qflush(struct ifnet *ifp)
481e7495198SAdrian Chadd {
482e7495198SAdrian Chadd 
483e7495198SAdrian Chadd 	/* Empty for now */
484b032f27cSSam Leffler }
485b032f27cSSam Leffler 
486168f582eSSam Leffler /*
4875cda6006SAdrian Chadd  * 802.11 raw output routine.
488ddd9ebbcSAdrian Chadd  *
489ddd9ebbcSAdrian Chadd  * XXX TODO: this (and other send routines) should correctly
490ddd9ebbcSAdrian Chadd  * XXX keep the pwr mgmt bit set if it decides to call into the
491ddd9ebbcSAdrian Chadd  * XXX driver to send a frame whilst the state is SLEEP.
492ddd9ebbcSAdrian Chadd  *
493ddd9ebbcSAdrian Chadd  * Otherwise the peer may decide that we're awake and flood us
494ddd9ebbcSAdrian Chadd  * with traffic we are still too asleep to receive!
495168f582eSSam Leffler  */
4965cda6006SAdrian Chadd int
4975cda6006SAdrian Chadd ieee80211_raw_output(struct ieee80211vap *vap, struct ieee80211_node *ni,
4985cda6006SAdrian Chadd     struct mbuf *m, const struct ieee80211_bpf_params *params)
4995cda6006SAdrian Chadd {
5005cda6006SAdrian Chadd 	struct ieee80211com *ic = vap->iv_ic;
501168f582eSSam Leffler 
5025cda6006SAdrian Chadd 	return (ic->ic_raw_xmit(ni, m, params));
503b032f27cSSam Leffler }
504b032f27cSSam Leffler 
505b032f27cSSam Leffler /*
506b032f27cSSam Leffler  * 802.11 output routine. This is (currently) used only to
507b032f27cSSam Leffler  * connect bpf write calls to the 802.11 layer for injecting
508fad788b1SSam Leffler  * raw 802.11 frames.
509b032f27cSSam Leffler  */
510cc80eae5SAdrian Chadd #if __FreeBSD_version >= 1000031
511b032f27cSSam Leffler int
512b032f27cSSam Leffler ieee80211_output(struct ifnet *ifp, struct mbuf *m,
51347e8d432SGleb Smirnoff 	const struct sockaddr *dst, struct route *ro)
514cc80eae5SAdrian Chadd #else
515cc80eae5SAdrian Chadd int
516cc80eae5SAdrian Chadd ieee80211_output(struct ifnet *ifp, struct mbuf *m,
517cc80eae5SAdrian Chadd 	struct sockaddr *dst, struct route *ro)
518cc80eae5SAdrian Chadd #endif
519b032f27cSSam Leffler {
520b032f27cSSam Leffler #define senderr(e) do { error = (e); goto bad;} while (0)
521b032f27cSSam Leffler 	struct ieee80211_node *ni = NULL;
5228ed1835dSSam Leffler 	struct ieee80211vap *vap;
523b032f27cSSam Leffler 	struct ieee80211_frame *wh;
5245cda6006SAdrian Chadd 	struct ieee80211com *ic = NULL;
525b032f27cSSam Leffler 	int error;
5265cda6006SAdrian Chadd 	int ret;
527b032f27cSSam Leffler 
5288ed1835dSSam Leffler 	if (ifp->if_drv_flags & IFF_DRV_OACTIVE) {
5298ed1835dSSam Leffler 		/*
5308ed1835dSSam Leffler 		 * Short-circuit requests if the vap is marked OACTIVE
5318ed1835dSSam Leffler 		 * as this can happen because a packet came down through
5328ed1835dSSam Leffler 		 * ieee80211_start before the vap entered RUN state in
5338ed1835dSSam Leffler 		 * which case it's ok to just drop the frame.  This
5348ed1835dSSam Leffler 		 * should not be necessary but callers of if_output don't
5358ed1835dSSam Leffler 		 * check OACTIVE.
5368ed1835dSSam Leffler 		 */
5378ed1835dSSam Leffler 		senderr(ENETDOWN);
5388ed1835dSSam Leffler 	}
5398ed1835dSSam Leffler 	vap = ifp->if_softc;
5405cda6006SAdrian Chadd 	ic = vap->iv_ic;
541b032f27cSSam Leffler 	/*
542b032f27cSSam Leffler 	 * Hand to the 802.3 code if not tagged as
543b032f27cSSam Leffler 	 * a raw 802.11 frame.
544b032f27cSSam Leffler 	 */
545b032f27cSSam Leffler 	if (dst->sa_family != AF_IEEE80211)
546279aa3d4SKip Macy 		return vap->iv_output(ifp, m, dst, ro);
547b032f27cSSam Leffler #ifdef MAC
548c27b9cdbSRobert Watson 	error = mac_ifnet_check_transmit(ifp, m);
549b032f27cSSam Leffler 	if (error)
550b032f27cSSam Leffler 		senderr(error);
551b032f27cSSam Leffler #endif
552b032f27cSSam Leffler 	if (ifp->if_flags & IFF_MONITOR)
553b032f27cSSam Leffler 		senderr(ENETDOWN);
554b032f27cSSam Leffler 	if (!IFNET_IS_UP_RUNNING(ifp))
555b032f27cSSam Leffler 		senderr(ENETDOWN);
556b032f27cSSam Leffler 	if (vap->iv_state == IEEE80211_S_CAC) {
557b032f27cSSam Leffler 		IEEE80211_DPRINTF(vap,
558b032f27cSSam Leffler 		    IEEE80211_MSG_OUTPUT | IEEE80211_MSG_DOTH,
559b032f27cSSam Leffler 		    "block %s frame in CAC state\n", "raw data");
560b032f27cSSam Leffler 		vap->iv_stats.is_tx_badstate++;
561b032f27cSSam Leffler 		senderr(EIO);		/* XXX */
5620d9aed8aSBernhard Schmidt 	} else if (vap->iv_state == IEEE80211_S_SCAN)
5630d9aed8aSBernhard Schmidt 		senderr(EIO);
564b032f27cSSam Leffler 	/* XXX bypass bridge, pfil, carp, etc. */
565b032f27cSSam Leffler 
566b032f27cSSam Leffler 	if (m->m_pkthdr.len < sizeof(struct ieee80211_frame_ack))
567b032f27cSSam Leffler 		senderr(EIO);	/* XXX */
568b032f27cSSam Leffler 	wh = mtod(m, struct ieee80211_frame *);
569b032f27cSSam Leffler 	if ((wh->i_fc[0] & IEEE80211_FC0_VERSION_MASK) !=
570b032f27cSSam Leffler 	    IEEE80211_FC0_VERSION_0)
571b032f27cSSam Leffler 		senderr(EIO);	/* XXX */
572b032f27cSSam Leffler 
573b032f27cSSam Leffler 	/* locate destination node */
574b032f27cSSam Leffler 	switch (wh->i_fc[1] & IEEE80211_FC1_DIR_MASK) {
575b032f27cSSam Leffler 	case IEEE80211_FC1_DIR_NODS:
576b032f27cSSam Leffler 	case IEEE80211_FC1_DIR_FROMDS:
577b032f27cSSam Leffler 		ni = ieee80211_find_txnode(vap, wh->i_addr1);
578b032f27cSSam Leffler 		break;
579b032f27cSSam Leffler 	case IEEE80211_FC1_DIR_TODS:
580b032f27cSSam Leffler 	case IEEE80211_FC1_DIR_DSTODS:
581b032f27cSSam Leffler 		if (m->m_pkthdr.len < sizeof(struct ieee80211_frame))
582b032f27cSSam Leffler 			senderr(EIO);	/* XXX */
583b032f27cSSam Leffler 		ni = ieee80211_find_txnode(vap, wh->i_addr3);
584b032f27cSSam Leffler 		break;
585b032f27cSSam Leffler 	default:
586b032f27cSSam Leffler 		senderr(EIO);	/* XXX */
587b032f27cSSam Leffler 	}
588b032f27cSSam Leffler 	if (ni == NULL) {
589b032f27cSSam Leffler 		/*
590b032f27cSSam Leffler 		 * Permit packets w/ bpf params through regardless
591b032f27cSSam Leffler 		 * (see below about sa_len).
592b032f27cSSam Leffler 		 */
593b032f27cSSam Leffler 		if (dst->sa_len == 0)
594b032f27cSSam Leffler 			senderr(EHOSTUNREACH);
595b032f27cSSam Leffler 		ni = ieee80211_ref_node(vap->iv_bss);
596b032f27cSSam Leffler 	}
597b032f27cSSam Leffler 
598b032f27cSSam Leffler 	/*
599b032f27cSSam Leffler 	 * Sanitize mbuf for net80211 flags leaked from above.
600b032f27cSSam Leffler 	 *
601b032f27cSSam Leffler 	 * NB: This must be done before ieee80211_classify as
602b032f27cSSam Leffler 	 *     it marks EAPOL in frames with M_EAPOL.
603b032f27cSSam Leffler 	 */
604b032f27cSSam Leffler 	m->m_flags &= ~M_80211_TX;
605b032f27cSSam Leffler 
606b032f27cSSam Leffler 	/* calculate priority so drivers can find the tx queue */
607b032f27cSSam Leffler 	/* XXX assumes an 802.3 frame */
608b032f27cSSam Leffler 	if (ieee80211_classify(ni, m))
609b032f27cSSam Leffler 		senderr(EIO);		/* XXX */
610b032f27cSSam Leffler 
611*dea45121SGleb Smirnoff 	if_inc_counter(ifp, IFCOUNTER_OPACKETS, 1);
6120e910c94SSam Leffler 	IEEE80211_NODE_STAT(ni, tx_data);
6130e910c94SSam Leffler 	if (IEEE80211_IS_MULTICAST(wh->i_addr1)) {
6140e910c94SSam Leffler 		IEEE80211_NODE_STAT(ni, tx_mcast);
6150e910c94SSam Leffler 		m->m_flags |= M_MCAST;
6160e910c94SSam Leffler 	} else
6170e910c94SSam Leffler 		IEEE80211_NODE_STAT(ni, tx_ucast);
6180e910c94SSam Leffler 	/* NB: ieee80211_encap does not include 802.11 header */
6190e910c94SSam Leffler 	IEEE80211_NODE_STAT_ADD(ni, tx_bytes, m->m_pkthdr.len);
620b032f27cSSam Leffler 
6215cda6006SAdrian Chadd 	IEEE80211_TX_LOCK(ic);
6225cda6006SAdrian Chadd 
623b032f27cSSam Leffler 	/*
624b032f27cSSam Leffler 	 * NB: DLT_IEEE802_11_RADIO identifies the parameters are
625b032f27cSSam Leffler 	 * present by setting the sa_len field of the sockaddr (yes,
626b032f27cSSam Leffler 	 * this is a hack).
627b032f27cSSam Leffler 	 * NB: we assume sa_data is suitably aligned to cast.
628b032f27cSSam Leffler 	 */
6295cda6006SAdrian Chadd 	ret = ieee80211_raw_output(vap, ni, m,
630b032f27cSSam Leffler 	    (const struct ieee80211_bpf_params *)(dst->sa_len ?
631b032f27cSSam Leffler 		dst->sa_data : NULL));
6325cda6006SAdrian Chadd 	IEEE80211_TX_UNLOCK(ic);
6335cda6006SAdrian Chadd 	return (ret);
634b032f27cSSam Leffler bad:
635b032f27cSSam Leffler 	if (m != NULL)
636b032f27cSSam Leffler 		m_freem(m);
637b032f27cSSam Leffler 	if (ni != NULL)
638b032f27cSSam Leffler 		ieee80211_free_node(ni);
639*dea45121SGleb Smirnoff 	if_inc_counter(ifp, IFCOUNTER_OERRORS, 1);
640b032f27cSSam Leffler 	return error;
641b032f27cSSam Leffler #undef senderr
642b032f27cSSam Leffler }
643b032f27cSSam Leffler 
644b032f27cSSam Leffler /*
645add59d08SSam Leffler  * Set the direction field and address fields of an outgoing
6460e66722dSSam Leffler  * frame.  Note this should be called early on in constructing
6470e66722dSSam Leffler  * a frame as it sets i_fc[1]; other bits can then be or'd in.
648add59d08SSam Leffler  */
64959aa14a9SRui Paulo void
650b032f27cSSam Leffler ieee80211_send_setup(
651add59d08SSam Leffler 	struct ieee80211_node *ni,
6529e80b1dfSSam Leffler 	struct mbuf *m,
6538ac160cdSSam Leffler 	int type, int tid,
65468e8e04eSSam Leffler 	const uint8_t sa[IEEE80211_ADDR_LEN],
65568e8e04eSSam Leffler 	const uint8_t da[IEEE80211_ADDR_LEN],
65668e8e04eSSam Leffler 	const uint8_t bssid[IEEE80211_ADDR_LEN])
657add59d08SSam Leffler {
658add59d08SSam Leffler #define	WH4(wh)	((struct ieee80211_frame_addr4 *)wh)
65959aa14a9SRui Paulo 	struct ieee80211vap *vap = ni->ni_vap;
66050cfec0eSBernhard Schmidt 	struct ieee80211_tx_ampdu *tap;
6619e80b1dfSSam Leffler 	struct ieee80211_frame *wh = mtod(m, struct ieee80211_frame *);
6629e80b1dfSSam Leffler 	ieee80211_seq seqno;
663add59d08SSam Leffler 
6646ce4aeb8SAdrian Chadd 	IEEE80211_TX_LOCK_ASSERT(ni->ni_ic);
6655cda6006SAdrian Chadd 
666add59d08SSam Leffler 	wh->i_fc[0] = IEEE80211_FC0_VERSION_0 | type;
667add59d08SSam Leffler 	if ((type & IEEE80211_FC0_TYPE_MASK) == IEEE80211_FC0_TYPE_DATA) {
668b032f27cSSam Leffler 		switch (vap->iv_opmode) {
669add59d08SSam Leffler 		case IEEE80211_M_STA:
670add59d08SSam Leffler 			wh->i_fc[1] = IEEE80211_FC1_DIR_TODS;
671add59d08SSam Leffler 			IEEE80211_ADDR_COPY(wh->i_addr1, bssid);
672add59d08SSam Leffler 			IEEE80211_ADDR_COPY(wh->i_addr2, sa);
673add59d08SSam Leffler 			IEEE80211_ADDR_COPY(wh->i_addr3, da);
674add59d08SSam Leffler 			break;
675add59d08SSam Leffler 		case IEEE80211_M_IBSS:
676add59d08SSam Leffler 		case IEEE80211_M_AHDEMO:
677add59d08SSam Leffler 			wh->i_fc[1] = IEEE80211_FC1_DIR_NODS;
678add59d08SSam Leffler 			IEEE80211_ADDR_COPY(wh->i_addr1, da);
679add59d08SSam Leffler 			IEEE80211_ADDR_COPY(wh->i_addr2, sa);
680add59d08SSam Leffler 			IEEE80211_ADDR_COPY(wh->i_addr3, bssid);
681add59d08SSam Leffler 			break;
682add59d08SSam Leffler 		case IEEE80211_M_HOSTAP:
683add59d08SSam Leffler 			wh->i_fc[1] = IEEE80211_FC1_DIR_FROMDS;
684add59d08SSam Leffler 			IEEE80211_ADDR_COPY(wh->i_addr1, da);
685add59d08SSam Leffler 			IEEE80211_ADDR_COPY(wh->i_addr2, bssid);
686add59d08SSam Leffler 			IEEE80211_ADDR_COPY(wh->i_addr3, sa);
687add59d08SSam Leffler 			break;
68868e8e04eSSam Leffler 		case IEEE80211_M_WDS:
68968e8e04eSSam Leffler 			wh->i_fc[1] = IEEE80211_FC1_DIR_DSTODS;
690b032f27cSSam Leffler 			IEEE80211_ADDR_COPY(wh->i_addr1, da);
691b032f27cSSam Leffler 			IEEE80211_ADDR_COPY(wh->i_addr2, vap->iv_myaddr);
69268e8e04eSSam Leffler 			IEEE80211_ADDR_COPY(wh->i_addr3, da);
69368e8e04eSSam Leffler 			IEEE80211_ADDR_COPY(WH4(wh)->i_addr4, sa);
69468e8e04eSSam Leffler 			break;
69559aa14a9SRui Paulo 		case IEEE80211_M_MBSS:
69659aa14a9SRui Paulo #ifdef IEEE80211_SUPPORT_MESH
69759aa14a9SRui Paulo 			if (IEEE80211_IS_MULTICAST(da)) {
69859aa14a9SRui Paulo 				wh->i_fc[1] = IEEE80211_FC1_DIR_FROMDS;
69959aa14a9SRui Paulo 				/* XXX next hop */
70059aa14a9SRui Paulo 				IEEE80211_ADDR_COPY(wh->i_addr1, da);
70159aa14a9SRui Paulo 				IEEE80211_ADDR_COPY(wh->i_addr2,
70259aa14a9SRui Paulo 				    vap->iv_myaddr);
70359aa14a9SRui Paulo 			} else {
70459aa14a9SRui Paulo 				wh->i_fc[1] = IEEE80211_FC1_DIR_DSTODS;
70559aa14a9SRui Paulo 				IEEE80211_ADDR_COPY(wh->i_addr1, da);
70659aa14a9SRui Paulo 				IEEE80211_ADDR_COPY(wh->i_addr2,
70759aa14a9SRui Paulo 				    vap->iv_myaddr);
70859aa14a9SRui Paulo 				IEEE80211_ADDR_COPY(wh->i_addr3, da);
70959aa14a9SRui Paulo 				IEEE80211_ADDR_COPY(WH4(wh)->i_addr4, sa);
71059aa14a9SRui Paulo 			}
71159aa14a9SRui Paulo #endif
71259aa14a9SRui Paulo 			break;
713add59d08SSam Leffler 		case IEEE80211_M_MONITOR:	/* NB: to quiet compiler */
714add59d08SSam Leffler 			break;
715add59d08SSam Leffler 		}
716add59d08SSam Leffler 	} else {
717add59d08SSam Leffler 		wh->i_fc[1] = IEEE80211_FC1_DIR_NODS;
718add59d08SSam Leffler 		IEEE80211_ADDR_COPY(wh->i_addr1, da);
719add59d08SSam Leffler 		IEEE80211_ADDR_COPY(wh->i_addr2, sa);
72059aa14a9SRui Paulo #ifdef IEEE80211_SUPPORT_MESH
72159aa14a9SRui Paulo 		if (vap->iv_opmode == IEEE80211_M_MBSS)
72259aa14a9SRui Paulo 			IEEE80211_ADDR_COPY(wh->i_addr3, sa);
72359aa14a9SRui Paulo 		else
72459aa14a9SRui Paulo #endif
725add59d08SSam Leffler 			IEEE80211_ADDR_COPY(wh->i_addr3, bssid);
726add59d08SSam Leffler 	}
72768e8e04eSSam Leffler 	*(uint16_t *)&wh->i_dur[0] = 0;
7289e80b1dfSSam Leffler 
7292aa563dfSAdrian Chadd 	tap = &ni->ni_tx_ampdu[tid];
73050cfec0eSBernhard Schmidt 	if (tid != IEEE80211_NONQOS_TID && IEEE80211_AMPDU_RUNNING(tap))
73150cfec0eSBernhard Schmidt 		m->m_flags |= M_AMPDU_MPDU;
73250cfec0eSBernhard Schmidt 	else {
7339e80b1dfSSam Leffler 		seqno = ni->ni_txseqs[tid]++;
73450cfec0eSBernhard Schmidt 		*(uint16_t *)&wh->i_seq[0] =
73550cfec0eSBernhard Schmidt 		    htole16(seqno << IEEE80211_SEQ_SEQ_SHIFT);
7369a841c7fSSam Leffler 		M_SEQNO_SET(m, seqno);
73750cfec0eSBernhard Schmidt 	}
7389e80b1dfSSam Leffler 
7399e80b1dfSSam Leffler 	if (IEEE80211_IS_MULTICAST(wh->i_addr1))
7409e80b1dfSSam Leffler 		m->m_flags |= M_MCAST;
741add59d08SSam Leffler #undef WH4
742add59d08SSam Leffler }
743add59d08SSam Leffler 
744add59d08SSam Leffler /*
7450a915fadSSam Leffler  * Send a management frame to the specified node.  The node pointer
7460a915fadSSam Leffler  * must have a reference as the pointer will be passed to the driver
7470a915fadSSam Leffler  * and potentially held for a long time.  If the frame is successfully
7480a915fadSSam Leffler  * dispatched to the driver, then it is responsible for freeing the
749b032f27cSSam Leffler  * reference (and potentially free'ing up any associated storage);
750b032f27cSSam Leffler  * otherwise deal with reclaiming any reference (on error).
7510a915fadSSam Leffler  */
75268e8e04eSSam Leffler int
7538ac160cdSSam Leffler ieee80211_mgmt_output(struct ieee80211_node *ni, struct mbuf *m, int type,
7548ac160cdSSam Leffler 	struct ieee80211_bpf_params *params)
7551a1e1d21SSam Leffler {
756b032f27cSSam Leffler 	struct ieee80211vap *vap = ni->ni_vap;
757b032f27cSSam Leffler 	struct ieee80211com *ic = ni->ni_ic;
7581a1e1d21SSam Leffler 	struct ieee80211_frame *wh;
7595cda6006SAdrian Chadd 	int ret;
7601a1e1d21SSam Leffler 
7610a915fadSSam Leffler 	KASSERT(ni != NULL, ("null node"));
7621a1e1d21SSam Leffler 
763b032f27cSSam Leffler 	if (vap->iv_state == IEEE80211_S_CAC) {
764b032f27cSSam Leffler 		IEEE80211_NOTE(vap, IEEE80211_MSG_OUTPUT | IEEE80211_MSG_DOTH,
765b032f27cSSam Leffler 		    ni, "block %s frame in CAC state",
766b032f27cSSam Leffler 			ieee80211_mgt_subtype_name[
767b032f27cSSam Leffler 			    (type & IEEE80211_FC0_SUBTYPE_MASK) >>
768b032f27cSSam Leffler 				IEEE80211_FC0_SUBTYPE_SHIFT]);
769b032f27cSSam Leffler 		vap->iv_stats.is_tx_badstate++;
770b032f27cSSam Leffler 		ieee80211_free_node(ni);
771b032f27cSSam Leffler 		m_freem(m);
772b032f27cSSam Leffler 		return EIO;		/* XXX */
773b032f27cSSam Leffler 	}
774b032f27cSSam Leffler 
775eb1b1807SGleb Smirnoff 	M_PREPEND(m, sizeof(struct ieee80211_frame), M_NOWAIT);
776b032f27cSSam Leffler 	if (m == NULL) {
777b032f27cSSam Leffler 		ieee80211_free_node(ni);
7781a1e1d21SSam Leffler 		return ENOMEM;
779b032f27cSSam Leffler 	}
7800a915fadSSam Leffler 
7815cda6006SAdrian Chadd 	IEEE80211_TX_LOCK(ic);
7825cda6006SAdrian Chadd 
7831a1e1d21SSam Leffler 	wh = mtod(m, struct ieee80211_frame *);
7849e80b1dfSSam Leffler 	ieee80211_send_setup(ni, m,
7858ac160cdSSam Leffler 	     IEEE80211_FC0_TYPE_MGT | type, IEEE80211_NONQOS_TID,
786b032f27cSSam Leffler 	     vap->iv_myaddr, ni->ni_macaddr, ni->ni_bssid);
7878ac160cdSSam Leffler 	if (params->ibp_flags & IEEE80211_BPF_CRYPTO) {
788b032f27cSSam Leffler 		IEEE80211_NOTE_MAC(vap, IEEE80211_MSG_AUTH, wh->i_addr1,
789b032f27cSSam Leffler 		    "encrypting frame (%s)", __func__);
7905945b5f5SKevin Lo 		wh->i_fc[1] |= IEEE80211_FC1_PROTECTED;
7918a1b9b6aSSam Leffler 	}
792c1af44bdSSam Leffler 	m->m_flags |= M_ENCAP;		/* mark encapsulated */
7938ac160cdSSam Leffler 
7948ac160cdSSam Leffler 	KASSERT(type != IEEE80211_FC0_SUBTYPE_PROBE_RESP, ("probe response?"));
7958ac160cdSSam Leffler 	M_WME_SETAC(m, params->ibp_pri);
7968ac160cdSSam Leffler 
7978a1b9b6aSSam Leffler #ifdef IEEE80211_DEBUG
7988a1b9b6aSSam Leffler 	/* avoid printing too many frames */
799b032f27cSSam Leffler 	if ((ieee80211_msg_debug(vap) && doprint(vap, type)) ||
800b032f27cSSam Leffler 	    ieee80211_msg_dumppkts(vap)) {
8018a1b9b6aSSam Leffler 		printf("[%s] send %s on channel %u\n",
8028a1b9b6aSSam Leffler 		    ether_sprintf(wh->i_addr1),
8038a1b9b6aSSam Leffler 		    ieee80211_mgt_subtype_name[
8048a1b9b6aSSam Leffler 			(type & IEEE80211_FC0_SUBTYPE_MASK) >>
8058a1b9b6aSSam Leffler 				IEEE80211_FC0_SUBTYPE_SHIFT],
806b5c99415SSam Leffler 		    ieee80211_chan2ieee(ic, ic->ic_curchan));
8078a1b9b6aSSam Leffler 	}
8088a1b9b6aSSam Leffler #endif
8098a1b9b6aSSam Leffler 	IEEE80211_NODE_STAT(ni, tx_mgmt);
81068e8e04eSSam Leffler 
8115cda6006SAdrian Chadd 	ret = ieee80211_raw_output(vap, ni, m, params);
8125cda6006SAdrian Chadd 	IEEE80211_TX_UNLOCK(ic);
8135cda6006SAdrian Chadd 	return (ret);
814246b5467SSam Leffler }
815246b5467SSam Leffler 
816246b5467SSam Leffler /*
8176683931eSSam Leffler  * Send a null data frame to the specified node.  If the station
8186683931eSSam Leffler  * is setup for QoS then a QoS Null Data frame is constructed.
8196683931eSSam Leffler  * If this is a WDS station then a 4-address frame is constructed.
82019ad2dd7SSam Leffler  *
82119ad2dd7SSam Leffler  * NB: the caller is assumed to have setup a node reference
82219ad2dd7SSam Leffler  *     for use; this is necessary to deal with a race condition
823b032f27cSSam Leffler  *     when probing for inactive stations.  Like ieee80211_mgmt_output
824b032f27cSSam Leffler  *     we must cleanup any node reference on error;  however we
825b032f27cSSam Leffler  *     can safely just unref it as we know it will never be the
826b032f27cSSam Leffler  *     last reference to the node.
8278a1b9b6aSSam Leffler  */
8288a1b9b6aSSam Leffler int
829f62121ceSSam Leffler ieee80211_send_nulldata(struct ieee80211_node *ni)
8308a1b9b6aSSam Leffler {
831b032f27cSSam Leffler 	struct ieee80211vap *vap = ni->ni_vap;
832f62121ceSSam Leffler 	struct ieee80211com *ic = ni->ni_ic;
8338a1b9b6aSSam Leffler 	struct mbuf *m;
8348a1b9b6aSSam Leffler 	struct ieee80211_frame *wh;
8356683931eSSam Leffler 	int hdrlen;
8366683931eSSam Leffler 	uint8_t *frm;
8375cda6006SAdrian Chadd 	int ret;
8388a1b9b6aSSam Leffler 
839b032f27cSSam Leffler 	if (vap->iv_state == IEEE80211_S_CAC) {
840b032f27cSSam Leffler 		IEEE80211_NOTE(vap, IEEE80211_MSG_OUTPUT | IEEE80211_MSG_DOTH,
841b032f27cSSam Leffler 		    ni, "block %s frame in CAC state", "null data");
842b032f27cSSam Leffler 		ieee80211_unref_node(&ni);
843b032f27cSSam Leffler 		vap->iv_stats.is_tx_badstate++;
844b032f27cSSam Leffler 		return EIO;		/* XXX */
845b032f27cSSam Leffler 	}
846b032f27cSSam Leffler 
8476683931eSSam Leffler 	if (ni->ni_flags & (IEEE80211_NODE_QOS|IEEE80211_NODE_HT))
8486683931eSSam Leffler 		hdrlen = sizeof(struct ieee80211_qosframe);
8496683931eSSam Leffler 	else
8506683931eSSam Leffler 		hdrlen = sizeof(struct ieee80211_frame);
8516683931eSSam Leffler 	/* NB: only WDS vap's get 4-address frames */
8526683931eSSam Leffler 	if (vap->iv_opmode == IEEE80211_M_WDS)
8536683931eSSam Leffler 		hdrlen += IEEE80211_ADDR_LEN;
8546683931eSSam Leffler 	if (ic->ic_flags & IEEE80211_F_DATAPAD)
8556683931eSSam Leffler 		hdrlen = roundup(hdrlen, sizeof(uint32_t));
8566683931eSSam Leffler 
8576683931eSSam Leffler 	m = ieee80211_getmgtframe(&frm, ic->ic_headroom + hdrlen, 0);
8588a1b9b6aSSam Leffler 	if (m == NULL) {
8598a1b9b6aSSam Leffler 		/* XXX debug msg */
86019ad2dd7SSam Leffler 		ieee80211_unref_node(&ni);
861b032f27cSSam Leffler 		vap->iv_stats.is_tx_nobuf++;
8628a1b9b6aSSam Leffler 		return ENOMEM;
8638a1b9b6aSSam Leffler 	}
8646683931eSSam Leffler 	KASSERT(M_LEADINGSPACE(m) >= hdrlen,
8656683931eSSam Leffler 	    ("leading space %zd", M_LEADINGSPACE(m)));
866eb1b1807SGleb Smirnoff 	M_PREPEND(m, hdrlen, M_NOWAIT);
8676683931eSSam Leffler 	if (m == NULL) {
8686683931eSSam Leffler 		/* NB: cannot happen */
8696683931eSSam Leffler 		ieee80211_free_node(ni);
8706683931eSSam Leffler 		return ENOMEM;
8716683931eSSam Leffler 	}
8728a1b9b6aSSam Leffler 
8735cda6006SAdrian Chadd 	IEEE80211_TX_LOCK(ic);
8745cda6006SAdrian Chadd 
8756683931eSSam Leffler 	wh = mtod(m, struct ieee80211_frame *);		/* NB: a little lie */
8766683931eSSam Leffler 	if (ni->ni_flags & IEEE80211_NODE_QOS) {
8776683931eSSam Leffler 		const int tid = WME_AC_TO_TID(WME_AC_BE);
8786683931eSSam Leffler 		uint8_t *qos;
8796683931eSSam Leffler 
8809e80b1dfSSam Leffler 		ieee80211_send_setup(ni, m,
8816683931eSSam Leffler 		    IEEE80211_FC0_TYPE_DATA | IEEE80211_FC0_SUBTYPE_QOS_NULL,
8826683931eSSam Leffler 		    tid, vap->iv_myaddr, ni->ni_macaddr, ni->ni_bssid);
8836683931eSSam Leffler 
8846683931eSSam Leffler 		if (vap->iv_opmode == IEEE80211_M_WDS)
8856683931eSSam Leffler 			qos = ((struct ieee80211_qosframe_addr4 *) wh)->i_qos;
8866683931eSSam Leffler 		else
8876683931eSSam Leffler 			qos = ((struct ieee80211_qosframe *) wh)->i_qos;
8886683931eSSam Leffler 		qos[0] = tid & IEEE80211_QOS_TID;
8896683931eSSam Leffler 		if (ic->ic_wme.wme_wmeChanParams.cap_wmeParams[WME_AC_BE].wmep_noackPolicy)
8906683931eSSam Leffler 			qos[0] |= IEEE80211_QOS_ACKPOLICY_NOACK;
8916683931eSSam Leffler 		qos[1] = 0;
8926683931eSSam Leffler 	} else {
8939e80b1dfSSam Leffler 		ieee80211_send_setup(ni, m,
894add59d08SSam Leffler 		    IEEE80211_FC0_TYPE_DATA | IEEE80211_FC0_SUBTYPE_NODATA,
8958ac160cdSSam Leffler 		    IEEE80211_NONQOS_TID,
896b032f27cSSam Leffler 		    vap->iv_myaddr, ni->ni_macaddr, ni->ni_bssid);
8976683931eSSam Leffler 	}
898b032f27cSSam Leffler 	if (vap->iv_opmode != IEEE80211_M_WDS) {
899add59d08SSam Leffler 		/* NB: power management bit is never sent by an AP */
900add59d08SSam Leffler 		if ((ni->ni_flags & IEEE80211_NODE_PWR_MGT) &&
901b032f27cSSam Leffler 		    vap->iv_opmode != IEEE80211_M_HOSTAP)
902add59d08SSam Leffler 			wh->i_fc[1] |= IEEE80211_FC1_PWR_MGT;
903b032f27cSSam Leffler 	}
9046683931eSSam Leffler 	m->m_len = m->m_pkthdr.len = hdrlen;
905c1af44bdSSam Leffler 	m->m_flags |= M_ENCAP;		/* mark encapsulated */
9066683931eSSam Leffler 
907bb239ce9SSam Leffler 	M_WME_SETAC(m, WME_AC_BE);
9088a1b9b6aSSam Leffler 
9098a1b9b6aSSam Leffler 	IEEE80211_NODE_STAT(ni, tx_data);
9108a1b9b6aSSam Leffler 
911b032f27cSSam Leffler 	IEEE80211_NOTE(vap, IEEE80211_MSG_DEBUG | IEEE80211_MSG_DUMPPKTS, ni,
9126683931eSSam Leffler 	    "send %snull data frame on channel %u, pwr mgt %s",
9136683931eSSam Leffler 	    ni->ni_flags & IEEE80211_NODE_QOS ? "QoS " : "",
914b5c99415SSam Leffler 	    ieee80211_chan2ieee(ic, ic->ic_curchan),
915add59d08SSam Leffler 	    wh->i_fc[1] & IEEE80211_FC1_PWR_MGT ? "ena" : "dis");
916add59d08SSam Leffler 
9175cda6006SAdrian Chadd 	ret = ieee80211_raw_output(vap, ni, m, NULL);
9185cda6006SAdrian Chadd 	IEEE80211_TX_UNLOCK(ic);
9195cda6006SAdrian Chadd 	return (ret);
9208a1b9b6aSSam Leffler }
9218a1b9b6aSSam Leffler 
9228a1b9b6aSSam Leffler /*
9238a1b9b6aSSam Leffler  * Assign priority to a frame based on any vlan tag assigned
9248a1b9b6aSSam Leffler  * to the station and/or any Diffserv setting in an IP header.
9258a1b9b6aSSam Leffler  * Finally, if an ACM policy is setup (in station mode) it's
9268a1b9b6aSSam Leffler  * applied.
9278a1b9b6aSSam Leffler  */
9288a1b9b6aSSam Leffler int
929b032f27cSSam Leffler ieee80211_classify(struct ieee80211_node *ni, struct mbuf *m)
9308a1b9b6aSSam Leffler {
931b032f27cSSam Leffler 	const struct ether_header *eh = mtod(m, struct ether_header *);
9328a1b9b6aSSam Leffler 	int v_wme_ac, d_wme_ac, ac;
9338a1b9b6aSSam Leffler 
934b032f27cSSam Leffler 	/*
935b032f27cSSam Leffler 	 * Always promote PAE/EAPOL frames to high priority.
936b032f27cSSam Leffler 	 */
937b032f27cSSam Leffler 	if (eh->ether_type == htons(ETHERTYPE_PAE)) {
938b032f27cSSam Leffler 		/* NB: mark so others don't need to check header */
939b032f27cSSam Leffler 		m->m_flags |= M_EAPOL;
940b032f27cSSam Leffler 		ac = WME_AC_VO;
941b032f27cSSam Leffler 		goto done;
942b032f27cSSam Leffler 	}
943b032f27cSSam Leffler 	/*
944b032f27cSSam Leffler 	 * Non-qos traffic goes to BE.
945b032f27cSSam Leffler 	 */
9468a1b9b6aSSam Leffler 	if ((ni->ni_flags & IEEE80211_NODE_QOS) == 0) {
9478a1b9b6aSSam Leffler 		ac = WME_AC_BE;
9488a1b9b6aSSam Leffler 		goto done;
9498a1b9b6aSSam Leffler 	}
9508a1b9b6aSSam Leffler 
9518a1b9b6aSSam Leffler 	/*
9528a1b9b6aSSam Leffler 	 * If node has a vlan tag then all traffic
9538a1b9b6aSSam Leffler 	 * to it must have a matching tag.
9548a1b9b6aSSam Leffler 	 */
9558a1b9b6aSSam Leffler 	v_wme_ac = 0;
9568a1b9b6aSSam Leffler 	if (ni->ni_vlan != 0) {
95778ba57b9SAndre Oppermann 		 if ((m->m_flags & M_VLANTAG) == 0) {
9588a1b9b6aSSam Leffler 			IEEE80211_NODE_STAT(ni, tx_novlantag);
9598a1b9b6aSSam Leffler 			return 1;
9608a1b9b6aSSam Leffler 		}
96178ba57b9SAndre Oppermann 		if (EVL_VLANOFTAG(m->m_pkthdr.ether_vtag) !=
9628a1b9b6aSSam Leffler 		    EVL_VLANOFTAG(ni->ni_vlan)) {
9638a1b9b6aSSam Leffler 			IEEE80211_NODE_STAT(ni, tx_vlanmismatch);
9648a1b9b6aSSam Leffler 			return 1;
9658a1b9b6aSSam Leffler 		}
9668a1b9b6aSSam Leffler 		/* map vlan priority to AC */
967f4558c9aSSam Leffler 		v_wme_ac = TID_TO_WME_AC(EVL_PRIOFTAG(ni->ni_vlan));
9688a1b9b6aSSam Leffler 	}
9698a1b9b6aSSam Leffler 
970e755a73dSSam Leffler 	/* XXX m_copydata may be too slow for fast path */
9718a1b9b6aSSam Leffler #ifdef INET
9728a1b9b6aSSam Leffler 	if (eh->ether_type == htons(ETHERTYPE_IP)) {
973f4558c9aSSam Leffler 		uint8_t tos;
9748a1b9b6aSSam Leffler 		/*
975f4558c9aSSam Leffler 		 * IP frame, map the DSCP bits from the TOS field.
9768a1b9b6aSSam Leffler 		 */
977f4558c9aSSam Leffler 		/* NB: ip header may not be in first mbuf */
978f4558c9aSSam Leffler 		m_copydata(m, sizeof(struct ether_header) +
979f4558c9aSSam Leffler 		    offsetof(struct ip, ip_tos), sizeof(tos), &tos);
980f4558c9aSSam Leffler 		tos >>= 5;		/* NB: ECN + low 3 bits of DSCP */
981f4558c9aSSam Leffler 		d_wme_ac = TID_TO_WME_AC(tos);
9828a1b9b6aSSam Leffler 	} else {
9838a1b9b6aSSam Leffler #endif /* INET */
984e755a73dSSam Leffler #ifdef INET6
985e755a73dSSam Leffler 	if (eh->ether_type == htons(ETHERTYPE_IPV6)) {
986e755a73dSSam Leffler 		uint32_t flow;
987e755a73dSSam Leffler 		uint8_t tos;
988e755a73dSSam Leffler 		/*
9896ffd0ca9SBjoern A. Zeeb 		 * IPv6 frame, map the DSCP bits from the traffic class field.
990e755a73dSSam Leffler 		 */
991e755a73dSSam Leffler 		m_copydata(m, sizeof(struct ether_header) +
992e755a73dSSam Leffler 		    offsetof(struct ip6_hdr, ip6_flow), sizeof(flow),
993e755a73dSSam Leffler 		    (caddr_t) &flow);
994e755a73dSSam Leffler 		tos = (uint8_t)(ntohl(flow) >> 20);
995e755a73dSSam Leffler 		tos >>= 5;		/* NB: ECN + low 3 bits of DSCP */
996e755a73dSSam Leffler 		d_wme_ac = TID_TO_WME_AC(tos);
997e755a73dSSam Leffler 	} else {
998e755a73dSSam Leffler #endif /* INET6 */
9998a1b9b6aSSam Leffler 		d_wme_ac = WME_AC_BE;
1000e755a73dSSam Leffler #ifdef INET6
1001e755a73dSSam Leffler 	}
1002e755a73dSSam Leffler #endif
10038a1b9b6aSSam Leffler #ifdef INET
10048a1b9b6aSSam Leffler 	}
10058a1b9b6aSSam Leffler #endif
10068a1b9b6aSSam Leffler 	/*
10078a1b9b6aSSam Leffler 	 * Use highest priority AC.
10088a1b9b6aSSam Leffler 	 */
10098a1b9b6aSSam Leffler 	if (v_wme_ac > d_wme_ac)
10108a1b9b6aSSam Leffler 		ac = v_wme_ac;
10118a1b9b6aSSam Leffler 	else
10128a1b9b6aSSam Leffler 		ac = d_wme_ac;
10138a1b9b6aSSam Leffler 
10148a1b9b6aSSam Leffler 	/*
10158a1b9b6aSSam Leffler 	 * Apply ACM policy.
10168a1b9b6aSSam Leffler 	 */
1017b032f27cSSam Leffler 	if (ni->ni_vap->iv_opmode == IEEE80211_M_STA) {
10188a1b9b6aSSam Leffler 		static const int acmap[4] = {
10198a1b9b6aSSam Leffler 			WME_AC_BK,	/* WME_AC_BE */
10208a1b9b6aSSam Leffler 			WME_AC_BK,	/* WME_AC_BK */
10218a1b9b6aSSam Leffler 			WME_AC_BE,	/* WME_AC_VI */
10228a1b9b6aSSam Leffler 			WME_AC_VI,	/* WME_AC_VO */
10238a1b9b6aSSam Leffler 		};
1024b032f27cSSam Leffler 		struct ieee80211com *ic = ni->ni_ic;
1025b032f27cSSam Leffler 
10268a1b9b6aSSam Leffler 		while (ac != WME_AC_BK &&
10278a1b9b6aSSam Leffler 		    ic->ic_wme.wme_wmeBssChanParams.cap_wmeParams[ac].wmep_acm)
10288a1b9b6aSSam Leffler 			ac = acmap[ac];
10298a1b9b6aSSam Leffler 	}
10308a1b9b6aSSam Leffler done:
10318a1b9b6aSSam Leffler 	M_WME_SETAC(m, ac);
10328a1b9b6aSSam Leffler 	return 0;
10338a1b9b6aSSam Leffler }
10348a1b9b6aSSam Leffler 
10358a1b9b6aSSam Leffler /*
10365e923d2eSSam Leffler  * Insure there is sufficient contiguous space to encapsulate the
10375e923d2eSSam Leffler  * 802.11 data frame.  If room isn't already there, arrange for it.
10385e923d2eSSam Leffler  * Drivers and cipher modules assume we have done the necessary work
10395e923d2eSSam Leffler  * and fail rudely if they don't find the space they need.
10405e923d2eSSam Leffler  */
1041616190d0SSam Leffler struct mbuf *
1042b032f27cSSam Leffler ieee80211_mbuf_adjust(struct ieee80211vap *vap, int hdrsize,
10435e923d2eSSam Leffler 	struct ieee80211_key *key, struct mbuf *m)
10445e923d2eSSam Leffler {
1045ab96db10SSam Leffler #define	TO_BE_RECLAIMED	(sizeof(struct ether_header) - sizeof(struct llc))
1046b032f27cSSam Leffler 	int needed_space = vap->iv_ic->ic_headroom + hdrsize;
10475e923d2eSSam Leffler 
10485e923d2eSSam Leffler 	if (key != NULL) {
10495e923d2eSSam Leffler 		/* XXX belongs in crypto code? */
10505e923d2eSSam Leffler 		needed_space += key->wk_cipher->ic_header;
10515e923d2eSSam Leffler 		/* XXX frags */
105283a244dbSSam Leffler 		/*
105383a244dbSSam Leffler 		 * When crypto is being done in the host we must insure
105483a244dbSSam Leffler 		 * the data are writable for the cipher routines; clone
105583a244dbSSam Leffler 		 * a writable mbuf chain.
105683a244dbSSam Leffler 		 * XXX handle SWMIC specially
105783a244dbSSam Leffler 		 */
10585c1f7f19SSam Leffler 		if (key->wk_flags & (IEEE80211_KEY_SWENCRYPT|IEEE80211_KEY_SWENMIC)) {
105983a244dbSSam Leffler 			m = m_unshare(m, M_NOWAIT);
106083a244dbSSam Leffler 			if (m == NULL) {
1061b032f27cSSam Leffler 				IEEE80211_DPRINTF(vap, IEEE80211_MSG_OUTPUT,
106283a244dbSSam Leffler 				    "%s: cannot get writable mbuf\n", __func__);
1063b032f27cSSam Leffler 				vap->iv_stats.is_tx_nobuf++; /* XXX new stat */
106483a244dbSSam Leffler 				return NULL;
106583a244dbSSam Leffler 			}
106683a244dbSSam Leffler 		}
10675e923d2eSSam Leffler 	}
10685e923d2eSSam Leffler 	/*
10695e923d2eSSam Leffler 	 * We know we are called just before stripping an Ethernet
10705e923d2eSSam Leffler 	 * header and prepending an LLC header.  This means we know
10715e923d2eSSam Leffler 	 * there will be
1072ab96db10SSam Leffler 	 *	sizeof(struct ether_header) - sizeof(struct llc)
10735e923d2eSSam Leffler 	 * bytes recovered to which we need additional space for the
10745e923d2eSSam Leffler 	 * 802.11 header and any crypto header.
10755e923d2eSSam Leffler 	 */
10765e923d2eSSam Leffler 	/* XXX check trailing space and copy instead? */
10775e923d2eSSam Leffler 	if (M_LEADINGSPACE(m) < needed_space - TO_BE_RECLAIMED) {
10785e923d2eSSam Leffler 		struct mbuf *n = m_gethdr(M_NOWAIT, m->m_type);
10795e923d2eSSam Leffler 		if (n == NULL) {
1080b032f27cSSam Leffler 			IEEE80211_DPRINTF(vap, IEEE80211_MSG_OUTPUT,
10815e923d2eSSam Leffler 			    "%s: cannot expand storage\n", __func__);
1082b032f27cSSam Leffler 			vap->iv_stats.is_tx_nobuf++;
10835e923d2eSSam Leffler 			m_freem(m);
10845e923d2eSSam Leffler 			return NULL;
10855e923d2eSSam Leffler 		}
10865e923d2eSSam Leffler 		KASSERT(needed_space <= MHLEN,
1087d7b5c50bSAlfred Perlstein 		    ("not enough room, need %u got %d\n", needed_space, MHLEN));
10885e923d2eSSam Leffler 		/*
10895e923d2eSSam Leffler 		 * Setup new mbuf to have leading space to prepend the
10905e923d2eSSam Leffler 		 * 802.11 header and any crypto header bits that are
10915e923d2eSSam Leffler 		 * required (the latter are added when the driver calls
10925e923d2eSSam Leffler 		 * back to ieee80211_crypto_encap to do crypto encapsulation).
10935e923d2eSSam Leffler 		 */
10945e923d2eSSam Leffler 		/* NB: must be first 'cuz it clobbers m_data */
10955e923d2eSSam Leffler 		m_move_pkthdr(n, m);
10965e923d2eSSam Leffler 		n->m_len = 0;			/* NB: m_gethdr does not set */
10975e923d2eSSam Leffler 		n->m_data += needed_space;
10985e923d2eSSam Leffler 		/*
10995e923d2eSSam Leffler 		 * Pull up Ethernet header to create the expected layout.
11005e923d2eSSam Leffler 		 * We could use m_pullup but that's overkill (i.e. we don't
11015e923d2eSSam Leffler 		 * need the actual data) and it cannot fail so do it inline
11025e923d2eSSam Leffler 		 * for speed.
11035e923d2eSSam Leffler 		 */
11045e923d2eSSam Leffler 		/* NB: struct ether_header is known to be contiguous */
11055e923d2eSSam Leffler 		n->m_len += sizeof(struct ether_header);
11065e923d2eSSam Leffler 		m->m_len -= sizeof(struct ether_header);
11075e923d2eSSam Leffler 		m->m_data += sizeof(struct ether_header);
11085e923d2eSSam Leffler 		/*
11095e923d2eSSam Leffler 		 * Replace the head of the chain.
11105e923d2eSSam Leffler 		 */
11115e923d2eSSam Leffler 		n->m_next = m;
11125e923d2eSSam Leffler 		m = n;
11135e923d2eSSam Leffler 	}
11145e923d2eSSam Leffler 	return m;
11155e923d2eSSam Leffler #undef TO_BE_RECLAIMED
11165e923d2eSSam Leffler }
11175e923d2eSSam Leffler 
11185e923d2eSSam Leffler /*
11195e923d2eSSam Leffler  * Return the transmit key to use in sending a unicast frame.
11205e923d2eSSam Leffler  * If a unicast key is set we use that.  When no unicast key is set
11215e923d2eSSam Leffler  * we fall back to the default transmit key.
11228a1b9b6aSSam Leffler  */
11238a1b9b6aSSam Leffler static __inline struct ieee80211_key *
1124b032f27cSSam Leffler ieee80211_crypto_getucastkey(struct ieee80211vap *vap,
1125b032f27cSSam Leffler 	struct ieee80211_node *ni)
11268a1b9b6aSSam Leffler {
1127cda15ce1SSam Leffler 	if (IEEE80211_KEY_UNDEFINED(&ni->ni_ucastkey)) {
1128b032f27cSSam Leffler 		if (vap->iv_def_txkey == IEEE80211_KEYIX_NONE ||
1129b032f27cSSam Leffler 		    IEEE80211_KEY_UNDEFINED(&vap->iv_nw_keys[vap->iv_def_txkey]))
11308a1b9b6aSSam Leffler 			return NULL;
1131b032f27cSSam Leffler 		return &vap->iv_nw_keys[vap->iv_def_txkey];
11328a1b9b6aSSam Leffler 	} else {
11338a1b9b6aSSam Leffler 		return &ni->ni_ucastkey;
11348a1b9b6aSSam Leffler 	}
11355e923d2eSSam Leffler }
11365e923d2eSSam Leffler 
11375e923d2eSSam Leffler /*
11385e923d2eSSam Leffler  * Return the transmit key to use in sending a multicast frame.
11395e923d2eSSam Leffler  * Multicast traffic always uses the group key which is installed as
11405e923d2eSSam Leffler  * the default tx key.
11415e923d2eSSam Leffler  */
11425e923d2eSSam Leffler static __inline struct ieee80211_key *
1143b032f27cSSam Leffler ieee80211_crypto_getmcastkey(struct ieee80211vap *vap,
1144b032f27cSSam Leffler 	struct ieee80211_node *ni)
11455e923d2eSSam Leffler {
1146b032f27cSSam Leffler 	if (vap->iv_def_txkey == IEEE80211_KEYIX_NONE ||
1147b032f27cSSam Leffler 	    IEEE80211_KEY_UNDEFINED(&vap->iv_nw_keys[vap->iv_def_txkey]))
11485e923d2eSSam Leffler 		return NULL;
1149b032f27cSSam Leffler 	return &vap->iv_nw_keys[vap->iv_def_txkey];
11508a1b9b6aSSam Leffler }
11518a1b9b6aSSam Leffler 
11528a1b9b6aSSam Leffler /*
11538a1b9b6aSSam Leffler  * Encapsulate an outbound data frame.  The mbuf chain is updated.
11548a1b9b6aSSam Leffler  * If an error is encountered NULL is returned.  The caller is required
11558a1b9b6aSSam Leffler  * to provide a node reference and pullup the ethernet header in the
11568a1b9b6aSSam Leffler  * first mbuf.
1157b032f27cSSam Leffler  *
1158b032f27cSSam Leffler  * NB: Packet is assumed to be processed by ieee80211_classify which
1159b032f27cSSam Leffler  *     marked EAPOL frames w/ M_EAPOL.
11600a915fadSSam Leffler  */
11611a1e1d21SSam Leffler struct mbuf *
1162339ccfb3SSam Leffler ieee80211_encap(struct ieee80211vap *vap, struct ieee80211_node *ni,
1163339ccfb3SSam Leffler     struct mbuf *m)
11641a1e1d21SSam Leffler {
1165b032f27cSSam Leffler #define	WH4(wh)	((struct ieee80211_frame_addr4 *)(wh))
11663c314f6dSMonthadar Al Jaberi #define MC01(mc)	((struct ieee80211_meshcntl_ae01 *)mc)
1167b032f27cSSam Leffler 	struct ieee80211com *ic = ni->ni_ic;
116859aa14a9SRui Paulo #ifdef IEEE80211_SUPPORT_MESH
116959aa14a9SRui Paulo 	struct ieee80211_mesh_state *ms = vap->iv_mesh;
1170c104cff2SRui Paulo 	struct ieee80211_meshcntl_ae10 *mc;
11713c314f6dSMonthadar Al Jaberi 	struct ieee80211_mesh_route *rt = NULL;
11723c314f6dSMonthadar Al Jaberi 	int dir = -1;
117359aa14a9SRui Paulo #endif
11741a1e1d21SSam Leffler 	struct ether_header eh;
11751a1e1d21SSam Leffler 	struct ieee80211_frame *wh;
11768a1b9b6aSSam Leffler 	struct ieee80211_key *key;
11771a1e1d21SSam Leffler 	struct llc *llc;
1178616190d0SSam Leffler 	int hdrsize, hdrspace, datalen, addqos, txfrag, is4addr;
11799e80b1dfSSam Leffler 	ieee80211_seq seqno;
118059aa14a9SRui Paulo 	int meshhdrsize, meshae;
118159aa14a9SRui Paulo 	uint8_t *qos;
11821a1e1d21SSam Leffler 
11835cda6006SAdrian Chadd 	IEEE80211_TX_LOCK_ASSERT(ic);
11845cda6006SAdrian Chadd 
118568e8e04eSSam Leffler 	/*
118668e8e04eSSam Leffler 	 * Copy existing Ethernet header to a safe place.  The
118768e8e04eSSam Leffler 	 * rest of the code assumes it's ok to strip it when
118868e8e04eSSam Leffler 	 * reorganizing state for the final encapsulation.
118968e8e04eSSam Leffler 	 */
11908a1b9b6aSSam Leffler 	KASSERT(m->m_len >= sizeof(eh), ("no ethernet header!"));
1191b032f27cSSam Leffler 	ETHER_HEADER_COPY(&eh, mtod(m, caddr_t));
11921a1e1d21SSam Leffler 
11938a1b9b6aSSam Leffler 	/*
11948a1b9b6aSSam Leffler 	 * Insure space for additional headers.  First identify
11958a1b9b6aSSam Leffler 	 * transmit key to use in calculating any buffer adjustments
11968a1b9b6aSSam Leffler 	 * required.  This is also used below to do privacy
11978a1b9b6aSSam Leffler 	 * encapsulation work.  Then calculate the 802.11 header
11988a1b9b6aSSam Leffler 	 * size and any padding required by the driver.
11998a1b9b6aSSam Leffler 	 *
12008a1b9b6aSSam Leffler 	 * Note key may be NULL if we fall back to the default
12018a1b9b6aSSam Leffler 	 * transmit key and that is not set.  In that case the
12028a1b9b6aSSam Leffler 	 * buffer may not be expanded as needed by the cipher
12038a1b9b6aSSam Leffler 	 * routines, but they will/should discard it.
12048a1b9b6aSSam Leffler 	 */
1205b032f27cSSam Leffler 	if (vap->iv_flags & IEEE80211_F_PRIVACY) {
1206b032f27cSSam Leffler 		if (vap->iv_opmode == IEEE80211_M_STA ||
1207b032f27cSSam Leffler 		    !IEEE80211_IS_MULTICAST(eh.ether_dhost) ||
1208b032f27cSSam Leffler 		    (vap->iv_opmode == IEEE80211_M_WDS &&
1209b032f27cSSam Leffler 		     (vap->iv_flags_ext & IEEE80211_FEXT_WDSLEGACY)))
1210b032f27cSSam Leffler 			key = ieee80211_crypto_getucastkey(vap, ni);
12115e923d2eSSam Leffler 		else
1212b032f27cSSam Leffler 			key = ieee80211_crypto_getmcastkey(vap, ni);
1213b032f27cSSam Leffler 		if (key == NULL && (m->m_flags & M_EAPOL) == 0) {
1214b032f27cSSam Leffler 			IEEE80211_NOTE_MAC(vap, IEEE80211_MSG_CRYPTO,
1215b032f27cSSam Leffler 			    eh.ether_dhost,
1216b032f27cSSam Leffler 			    "no default transmit key (%s) deftxkey %u",
1217b032f27cSSam Leffler 			    __func__, vap->iv_def_txkey);
1218b032f27cSSam Leffler 			vap->iv_stats.is_tx_nodefkey++;
1219d72c7253SSam Leffler 			goto bad;
12208a1b9b6aSSam Leffler 		}
12218a1b9b6aSSam Leffler 	} else
12228a1b9b6aSSam Leffler 		key = NULL;
12235e923d2eSSam Leffler 	/*
12245e923d2eSSam Leffler 	 * XXX Some ap's don't handle QoS-encapsulated EAPOL
12255e923d2eSSam Leffler 	 * frames so suppress use.  This may be an issue if other
12265e923d2eSSam Leffler 	 * ap's require all data frames to be QoS-encapsulated
12275e923d2eSSam Leffler 	 * once negotiated in which case we'll need to make this
12285e923d2eSSam Leffler 	 * configurable.
122991216c71SAdrian Chadd 	 * NB: mesh data frames are QoS.
12305e923d2eSSam Leffler 	 */
123191216c71SAdrian Chadd 	addqos = ((ni->ni_flags & (IEEE80211_NODE_QOS|IEEE80211_NODE_HT)) ||
123291216c71SAdrian Chadd 	    (vap->iv_opmode == IEEE80211_M_MBSS)) &&
1233b032f27cSSam Leffler 	    (m->m_flags & M_EAPOL) == 0;
12345e923d2eSSam Leffler 	if (addqos)
12358a1b9b6aSSam Leffler 		hdrsize = sizeof(struct ieee80211_qosframe);
12368a1b9b6aSSam Leffler 	else
12378a1b9b6aSSam Leffler 		hdrsize = sizeof(struct ieee80211_frame);
123859aa14a9SRui Paulo #ifdef IEEE80211_SUPPORT_MESH
123959aa14a9SRui Paulo 	if (vap->iv_opmode == IEEE80211_M_MBSS) {
124059aa14a9SRui Paulo 		/*
124159aa14a9SRui Paulo 		 * Mesh data frames are encapsulated according to the
124259aa14a9SRui Paulo 		 * rules of Section 11B.8.5 (p.139 of D3.0 spec).
124359aa14a9SRui Paulo 		 * o Group Addressed data (aka multicast) originating
124459aa14a9SRui Paulo 		 *   at the local sta are sent w/ 3-address format and
124559aa14a9SRui Paulo 		 *   address extension mode 00
124659aa14a9SRui Paulo 		 * o Individually Addressed data (aka unicast) originating
124759aa14a9SRui Paulo 		 *   at the local sta are sent w/ 4-address format and
124859aa14a9SRui Paulo 		 *   address extension mode 00
124959aa14a9SRui Paulo 		 * o Group Addressed data forwarded from a non-mesh sta are
125059aa14a9SRui Paulo 		 *   sent w/ 3-address format and address extension mode 01
125159aa14a9SRui Paulo 		 * o Individually Address data from another sta are sent
125259aa14a9SRui Paulo 		 *   w/ 4-address format and address extension mode 10
125359aa14a9SRui Paulo 		 */
125459aa14a9SRui Paulo 		is4addr = 0;		/* NB: don't use, disable */
12553c314f6dSMonthadar Al Jaberi 		if (!IEEE80211_IS_MULTICAST(eh.ether_dhost)) {
12563c314f6dSMonthadar Al Jaberi 			rt = ieee80211_mesh_rt_find(vap, eh.ether_dhost);
12573c314f6dSMonthadar Al Jaberi 			KASSERT(rt != NULL, ("route is NULL"));
12583c314f6dSMonthadar Al Jaberi 			dir = IEEE80211_FC1_DIR_DSTODS;
12593c314f6dSMonthadar Al Jaberi 			hdrsize += IEEE80211_ADDR_LEN;
12603c314f6dSMonthadar Al Jaberi 			if (rt->rt_flags & IEEE80211_MESHRT_FLAGS_PROXY) {
12613c314f6dSMonthadar Al Jaberi 				if (IEEE80211_ADDR_EQ(rt->rt_mesh_gate,
12623c314f6dSMonthadar Al Jaberi 				    vap->iv_myaddr)) {
12633c314f6dSMonthadar Al Jaberi 					IEEE80211_NOTE_MAC(vap,
12643c314f6dSMonthadar Al Jaberi 					    IEEE80211_MSG_MESH,
12653c314f6dSMonthadar Al Jaberi 					    eh.ether_dhost,
12663c314f6dSMonthadar Al Jaberi 					    "%s", "trying to send to ourself");
12673c314f6dSMonthadar Al Jaberi 					goto bad;
12683c314f6dSMonthadar Al Jaberi 				}
12693c314f6dSMonthadar Al Jaberi 				meshae = IEEE80211_MESH_AE_10;
12703c314f6dSMonthadar Al Jaberi 				meshhdrsize =
12713c314f6dSMonthadar Al Jaberi 				    sizeof(struct ieee80211_meshcntl_ae10);
127259aa14a9SRui Paulo 			} else {
12733c314f6dSMonthadar Al Jaberi 				meshae = IEEE80211_MESH_AE_00;
12743c314f6dSMonthadar Al Jaberi 				meshhdrsize =
12753c314f6dSMonthadar Al Jaberi 				    sizeof(struct ieee80211_meshcntl);
12763c314f6dSMonthadar Al Jaberi 			}
12773c314f6dSMonthadar Al Jaberi 		} else {
12783c314f6dSMonthadar Al Jaberi 			dir = IEEE80211_FC1_DIR_FROMDS;
12793c314f6dSMonthadar Al Jaberi 			if (!IEEE80211_ADDR_EQ(eh.ether_shost, vap->iv_myaddr)) {
12803c314f6dSMonthadar Al Jaberi 				/* proxy group */
12813c314f6dSMonthadar Al Jaberi 				meshae = IEEE80211_MESH_AE_01;
12823c314f6dSMonthadar Al Jaberi 				meshhdrsize =
12833c314f6dSMonthadar Al Jaberi 				    sizeof(struct ieee80211_meshcntl_ae01);
12843c314f6dSMonthadar Al Jaberi 			} else {
12853c314f6dSMonthadar Al Jaberi 				/* group */
12863c314f6dSMonthadar Al Jaberi 				meshae = IEEE80211_MESH_AE_00;
12873c314f6dSMonthadar Al Jaberi 				meshhdrsize = sizeof(struct ieee80211_meshcntl);
12883c314f6dSMonthadar Al Jaberi 			}
128959aa14a9SRui Paulo 		}
129059aa14a9SRui Paulo 	} else {
129159aa14a9SRui Paulo #endif
1292b032f27cSSam Leffler 		/*
1293b032f27cSSam Leffler 		 * 4-address frames need to be generated for:
12946437e6daSSam Leffler 		 * o packets sent through a WDS vap (IEEE80211_M_WDS)
1295f2a6a13cSSam Leffler 		 * o packets sent through a vap marked for relaying
1296f2a6a13cSSam Leffler 		 *   (e.g. a station operating with dynamic WDS)
1297b032f27cSSam Leffler 		 */
12986437e6daSSam Leffler 		is4addr = vap->iv_opmode == IEEE80211_M_WDS ||
1299f2a6a13cSSam Leffler 		    ((vap->iv_flags_ext & IEEE80211_FEXT_4ADDR) &&
1300b032f27cSSam Leffler 		     !IEEE80211_ADDR_EQ(eh.ether_shost, vap->iv_myaddr));
1301b032f27cSSam Leffler 		if (is4addr)
1302b032f27cSSam Leffler 			hdrsize += IEEE80211_ADDR_LEN;
130359aa14a9SRui Paulo 		meshhdrsize = meshae = 0;
130459aa14a9SRui Paulo #ifdef IEEE80211_SUPPORT_MESH
130559aa14a9SRui Paulo 	}
130659aa14a9SRui Paulo #endif
1307b032f27cSSam Leffler 	/*
1308b032f27cSSam Leffler 	 * Honor driver DATAPAD requirement.
1309b032f27cSSam Leffler 	 */
13108a1b9b6aSSam Leffler 	if (ic->ic_flags & IEEE80211_F_DATAPAD)
1311b032f27cSSam Leffler 		hdrspace = roundup(hdrsize, sizeof(uint32_t));
1312b032f27cSSam Leffler 	else
1313b032f27cSSam Leffler 		hdrspace = hdrsize;
131468e8e04eSSam Leffler 
1315616190d0SSam Leffler 	if (__predict_true((m->m_flags & M_FF) == 0)) {
131668e8e04eSSam Leffler 		/*
131768e8e04eSSam Leffler 		 * Normal frame.
131868e8e04eSSam Leffler 		 */
131959aa14a9SRui Paulo 		m = ieee80211_mbuf_adjust(vap, hdrspace + meshhdrsize, key, m);
13208a1b9b6aSSam Leffler 		if (m == NULL) {
13218a1b9b6aSSam Leffler 			/* NB: ieee80211_mbuf_adjust handles msgs+statistics */
13220a915fadSSam Leffler 			goto bad;
13230a915fadSSam Leffler 		}
132468e8e04eSSam Leffler 		/* NB: this could be optimized 'cuz of ieee80211_mbuf_adjust */
1325ab96db10SSam Leffler 		m_adj(m, sizeof(struct ether_header) - sizeof(struct llc));
13261a1e1d21SSam Leffler 		llc = mtod(m, struct llc *);
13271a1e1d21SSam Leffler 		llc->llc_dsap = llc->llc_ssap = LLC_SNAP_LSAP;
13281a1e1d21SSam Leffler 		llc->llc_control = LLC_UI;
13291a1e1d21SSam Leffler 		llc->llc_snap.org_code[0] = 0;
13301a1e1d21SSam Leffler 		llc->llc_snap.org_code[1] = 0;
13311a1e1d21SSam Leffler 		llc->llc_snap.org_code[2] = 0;
13321a1e1d21SSam Leffler 		llc->llc_snap.ether_type = eh.ether_type;
1333616190d0SSam Leffler 	} else {
1334616190d0SSam Leffler #ifdef IEEE80211_SUPPORT_SUPERG
1335339ccfb3SSam Leffler 		/*
1336339ccfb3SSam Leffler 		 * Aggregated frame.
1337339ccfb3SSam Leffler 		 */
133859aa14a9SRui Paulo 		m = ieee80211_ff_encap(vap, m, hdrspace + meshhdrsize, key);
1339616190d0SSam Leffler 		if (m == NULL)
1340616190d0SSam Leffler #endif
1341616190d0SSam Leffler 			goto bad;
134268e8e04eSSam Leffler 	}
13438a1b9b6aSSam Leffler 	datalen = m->m_pkthdr.len;		/* NB: w/o 802.11 header */
13448a1b9b6aSSam Leffler 
1345eb1b1807SGleb Smirnoff 	M_PREPEND(m, hdrspace + meshhdrsize, M_NOWAIT);
13461be50176SSam Leffler 	if (m == NULL) {
1347b032f27cSSam Leffler 		vap->iv_stats.is_tx_nobuf++;
13480a915fadSSam Leffler 		goto bad;
13491be50176SSam Leffler 	}
13501a1e1d21SSam Leffler 	wh = mtod(m, struct ieee80211_frame *);
13511a1e1d21SSam Leffler 	wh->i_fc[0] = IEEE80211_FC0_VERSION_0 | IEEE80211_FC0_TYPE_DATA;
135268e8e04eSSam Leffler 	*(uint16_t *)wh->i_dur = 0;
135359aa14a9SRui Paulo 	qos = NULL;	/* NB: quiet compiler */
1354b032f27cSSam Leffler 	if (is4addr) {
1355b032f27cSSam Leffler 		wh->i_fc[1] = IEEE80211_FC1_DIR_DSTODS;
1356b032f27cSSam Leffler 		IEEE80211_ADDR_COPY(wh->i_addr1, ni->ni_macaddr);
1357b032f27cSSam Leffler 		IEEE80211_ADDR_COPY(wh->i_addr2, vap->iv_myaddr);
1358b032f27cSSam Leffler 		IEEE80211_ADDR_COPY(wh->i_addr3, eh.ether_dhost);
1359b032f27cSSam Leffler 		IEEE80211_ADDR_COPY(WH4(wh)->i_addr4, eh.ether_shost);
1360b032f27cSSam Leffler 	} else switch (vap->iv_opmode) {
13611a1e1d21SSam Leffler 	case IEEE80211_M_STA:
13621a1e1d21SSam Leffler 		wh->i_fc[1] = IEEE80211_FC1_DIR_TODS;
13631a1e1d21SSam Leffler 		IEEE80211_ADDR_COPY(wh->i_addr1, ni->ni_bssid);
13641a1e1d21SSam Leffler 		IEEE80211_ADDR_COPY(wh->i_addr2, eh.ether_shost);
13651a1e1d21SSam Leffler 		IEEE80211_ADDR_COPY(wh->i_addr3, eh.ether_dhost);
13661a1e1d21SSam Leffler 		break;
13671a1e1d21SSam Leffler 	case IEEE80211_M_IBSS:
13681a1e1d21SSam Leffler 	case IEEE80211_M_AHDEMO:
13691a1e1d21SSam Leffler 		wh->i_fc[1] = IEEE80211_FC1_DIR_NODS;
13701a1e1d21SSam Leffler 		IEEE80211_ADDR_COPY(wh->i_addr1, eh.ether_dhost);
13711a1e1d21SSam Leffler 		IEEE80211_ADDR_COPY(wh->i_addr2, eh.ether_shost);
1372a8b16e87SSam Leffler 		/*
1373b032f27cSSam Leffler 		 * NB: always use the bssid from iv_bss as the
1374a8b16e87SSam Leffler 		 *     neighbor's may be stale after an ibss merge
1375a8b16e87SSam Leffler 		 */
1376b032f27cSSam Leffler 		IEEE80211_ADDR_COPY(wh->i_addr3, vap->iv_bss->ni_bssid);
13771a1e1d21SSam Leffler 		break;
13781a1e1d21SSam Leffler 	case IEEE80211_M_HOSTAP:
13791a1e1d21SSam Leffler 		wh->i_fc[1] = IEEE80211_FC1_DIR_FROMDS;
13801a1e1d21SSam Leffler 		IEEE80211_ADDR_COPY(wh->i_addr1, eh.ether_dhost);
13811a1e1d21SSam Leffler 		IEEE80211_ADDR_COPY(wh->i_addr2, ni->ni_bssid);
13821a1e1d21SSam Leffler 		IEEE80211_ADDR_COPY(wh->i_addr3, eh.ether_shost);
13831a1e1d21SSam Leffler 		break;
138459aa14a9SRui Paulo #ifdef IEEE80211_SUPPORT_MESH
138559aa14a9SRui Paulo 	case IEEE80211_M_MBSS:
138659aa14a9SRui Paulo 		/* NB: offset by hdrspace to deal with DATAPAD */
1387c104cff2SRui Paulo 		mc = (struct ieee80211_meshcntl_ae10 *)
138859aa14a9SRui Paulo 		     (mtod(m, uint8_t *) + hdrspace);
13893c314f6dSMonthadar Al Jaberi 		wh->i_fc[1] = dir;
139059aa14a9SRui Paulo 		switch (meshae) {
13913c314f6dSMonthadar Al Jaberi 		case IEEE80211_MESH_AE_00:	/* no proxy */
139259aa14a9SRui Paulo 			mc->mc_flags = 0;
13933c314f6dSMonthadar Al Jaberi 			if (dir == IEEE80211_FC1_DIR_DSTODS) { /* ucast */
13943c314f6dSMonthadar Al Jaberi 				IEEE80211_ADDR_COPY(wh->i_addr1,
13953c314f6dSMonthadar Al Jaberi 				    ni->ni_macaddr);
13963c314f6dSMonthadar Al Jaberi 				IEEE80211_ADDR_COPY(wh->i_addr2,
13973c314f6dSMonthadar Al Jaberi 				    vap->iv_myaddr);
13983c314f6dSMonthadar Al Jaberi 				IEEE80211_ADDR_COPY(wh->i_addr3,
13993c314f6dSMonthadar Al Jaberi 				    eh.ether_dhost);
14003c314f6dSMonthadar Al Jaberi 				IEEE80211_ADDR_COPY(WH4(wh)->i_addr4,
14013c314f6dSMonthadar Al Jaberi 				    eh.ether_shost);
14023c314f6dSMonthadar Al Jaberi 				qos =((struct ieee80211_qosframe_addr4 *)
14033c314f6dSMonthadar Al Jaberi 				    wh)->i_qos;
14043c314f6dSMonthadar Al Jaberi 			} else if (dir == IEEE80211_FC1_DIR_FROMDS) {
14053c314f6dSMonthadar Al Jaberi 				 /* mcast */
14063c314f6dSMonthadar Al Jaberi 				IEEE80211_ADDR_COPY(wh->i_addr1,
14073c314f6dSMonthadar Al Jaberi 				    eh.ether_dhost);
14083c314f6dSMonthadar Al Jaberi 				IEEE80211_ADDR_COPY(wh->i_addr2,
14093c314f6dSMonthadar Al Jaberi 				    vap->iv_myaddr);
14103c314f6dSMonthadar Al Jaberi 				IEEE80211_ADDR_COPY(wh->i_addr3,
14113c314f6dSMonthadar Al Jaberi 				    eh.ether_shost);
14123c314f6dSMonthadar Al Jaberi 				qos = ((struct ieee80211_qosframe *)
14133c314f6dSMonthadar Al Jaberi 				    wh)->i_qos;
14143c314f6dSMonthadar Al Jaberi 			}
141559aa14a9SRui Paulo 			break;
14163c314f6dSMonthadar Al Jaberi 		case IEEE80211_MESH_AE_01:	/* mcast, proxy */
141759aa14a9SRui Paulo 			wh->i_fc[1] = IEEE80211_FC1_DIR_FROMDS;
141859aa14a9SRui Paulo 			IEEE80211_ADDR_COPY(wh->i_addr1, eh.ether_dhost);
141959aa14a9SRui Paulo 			IEEE80211_ADDR_COPY(wh->i_addr2, vap->iv_myaddr);
1420c104cff2SRui Paulo 			IEEE80211_ADDR_COPY(wh->i_addr3, vap->iv_myaddr);
142159aa14a9SRui Paulo 			mc->mc_flags = 1;
14223c314f6dSMonthadar Al Jaberi 			IEEE80211_ADDR_COPY(MC01(mc)->mc_addr4,
14233c314f6dSMonthadar Al Jaberi 			    eh.ether_shost);
142459aa14a9SRui Paulo 			qos = ((struct ieee80211_qosframe *) wh)->i_qos;
142559aa14a9SRui Paulo 			break;
14263c314f6dSMonthadar Al Jaberi 		case IEEE80211_MESH_AE_10:	/* ucast, proxy */
14273c314f6dSMonthadar Al Jaberi 			KASSERT(rt != NULL, ("route is NULL"));
14283c314f6dSMonthadar Al Jaberi 			IEEE80211_ADDR_COPY(wh->i_addr1, rt->rt_nexthop);
142959aa14a9SRui Paulo 			IEEE80211_ADDR_COPY(wh->i_addr2, vap->iv_myaddr);
14303c314f6dSMonthadar Al Jaberi 			IEEE80211_ADDR_COPY(wh->i_addr3, rt->rt_mesh_gate);
1431c104cff2SRui Paulo 			IEEE80211_ADDR_COPY(WH4(wh)->i_addr4, vap->iv_myaddr);
14323c314f6dSMonthadar Al Jaberi 			mc->mc_flags = IEEE80211_MESH_AE_10;
14333c314f6dSMonthadar Al Jaberi 			IEEE80211_ADDR_COPY(mc->mc_addr5, eh.ether_dhost);
14343c314f6dSMonthadar Al Jaberi 			IEEE80211_ADDR_COPY(mc->mc_addr6, eh.ether_shost);
143559aa14a9SRui Paulo 			qos = ((struct ieee80211_qosframe_addr4 *) wh)->i_qos;
143659aa14a9SRui Paulo 			break;
143759aa14a9SRui Paulo 		default:
143859aa14a9SRui Paulo 			KASSERT(0, ("meshae %d", meshae));
143959aa14a9SRui Paulo 			break;
144059aa14a9SRui Paulo 		}
144159aa14a9SRui Paulo 		mc->mc_ttl = ms->ms_ttl;
144259aa14a9SRui Paulo 		ms->ms_seq++;
144359aa14a9SRui Paulo 		LE_WRITE_4(mc->mc_seq, ms->ms_seq);
144459aa14a9SRui Paulo 		break;
144559aa14a9SRui Paulo #endif
1446b032f27cSSam Leffler 	case IEEE80211_M_WDS:		/* NB: is4addr should always be true */
144759aa14a9SRui Paulo 	default:
14480a915fadSSam Leffler 		goto bad;
14491a1e1d21SSam Leffler 	}
1450bc5627d9SSam Leffler 	if (m->m_flags & M_MORE_DATA)
1451bc5627d9SSam Leffler 		wh->i_fc[1] |= IEEE80211_FC1_MORE_DATA;
14525e923d2eSSam Leffler 	if (addqos) {
14538a1b9b6aSSam Leffler 		int ac, tid;
14548a1b9b6aSSam Leffler 
1455b032f27cSSam Leffler 		if (is4addr) {
1456b032f27cSSam Leffler 			qos = ((struct ieee80211_qosframe_addr4 *) wh)->i_qos;
145759aa14a9SRui Paulo 		/* NB: mesh case handled earlier */
145859aa14a9SRui Paulo 		} else if (vap->iv_opmode != IEEE80211_M_MBSS)
1459b032f27cSSam Leffler 			qos = ((struct ieee80211_qosframe *) wh)->i_qos;
14608a1b9b6aSSam Leffler 		ac = M_WME_GETAC(m);
14618a1b9b6aSSam Leffler 		/* map from access class/queue to 11e header priorty value */
14628a1b9b6aSSam Leffler 		tid = WME_AC_TO_TID(ac);
1463b032f27cSSam Leffler 		qos[0] = tid & IEEE80211_QOS_TID;
14648a1b9b6aSSam Leffler 		if (ic->ic_wme.wme_wmeChanParams.cap_wmeParams[ac].wmep_noackPolicy)
1465b032f27cSSam Leffler 			qos[0] |= IEEE80211_QOS_ACKPOLICY_NOACK;
146691216c71SAdrian Chadd #ifdef IEEE80211_SUPPORT_MESH
1467d566999aSMonthadar Al Jaberi 		if (vap->iv_opmode == IEEE80211_M_MBSS)
1468d566999aSMonthadar Al Jaberi 			qos[1] = IEEE80211_QOS_MC;
1469d566999aSMonthadar Al Jaberi 		else
147091216c71SAdrian Chadd #endif
1471b032f27cSSam Leffler 			qos[1] = 0;
1472b032f27cSSam Leffler 		wh->i_fc[0] |= IEEE80211_FC0_SUBTYPE_QOS;
14738a1b9b6aSSam Leffler 
147445f856e3SSam Leffler 		if ((m->m_flags & M_AMPDU_MPDU) == 0) {
147545f856e3SSam Leffler 			/*
147645f856e3SSam Leffler 			 * NB: don't assign a sequence # to potential
147745f856e3SSam Leffler 			 * aggregates; we expect this happens at the
147845f856e3SSam Leffler 			 * point the frame comes off any aggregation q
147945f856e3SSam Leffler 			 * as otherwise we may introduce holes in the
148045f856e3SSam Leffler 			 * BA sequence space and/or make window accouting
148145f856e3SSam Leffler 			 * more difficult.
148245f856e3SSam Leffler 			 *
148345f856e3SSam Leffler 			 * XXX may want to control this with a driver
148445f856e3SSam Leffler 			 * capability; this may also change when we pull
148545f856e3SSam Leffler 			 * aggregation up into net80211
148645f856e3SSam Leffler 			 */
14879e80b1dfSSam Leffler 			seqno = ni->ni_txseqs[tid]++;
148868e8e04eSSam Leffler 			*(uint16_t *)wh->i_seq =
14899e80b1dfSSam Leffler 			    htole16(seqno << IEEE80211_SEQ_SEQ_SHIFT);
14909a841c7fSSam Leffler 			M_SEQNO_SET(m, seqno);
149145f856e3SSam Leffler 		}
14928a1b9b6aSSam Leffler 	} else {
14939e80b1dfSSam Leffler 		seqno = ni->ni_txseqs[IEEE80211_NONQOS_TID]++;
149468e8e04eSSam Leffler 		*(uint16_t *)wh->i_seq =
14959e80b1dfSSam Leffler 		    htole16(seqno << IEEE80211_SEQ_SEQ_SHIFT);
14969a841c7fSSam Leffler 		M_SEQNO_SET(m, seqno);
14978a1b9b6aSSam Leffler 	}
14989a841c7fSSam Leffler 
149959aa14a9SRui Paulo 
150068e8e04eSSam Leffler 	/* check if xmit fragmentation is required */
1501b032f27cSSam Leffler 	txfrag = (m->m_pkthdr.len > vap->iv_fragthreshold &&
150268e8e04eSSam Leffler 	    !IEEE80211_IS_MULTICAST(wh->i_addr1) &&
1503b032f27cSSam Leffler 	    (vap->iv_caps & IEEE80211_C_TXFRAG) &&
1504e9cfc1f5SSam Leffler 	    (m->m_flags & (M_FF | M_AMPDU_MPDU)) == 0);
15055e923d2eSSam Leffler 	if (key != NULL) {
15065e923d2eSSam Leffler 		/*
15075e923d2eSSam Leffler 		 * IEEE 802.1X: send EAPOL frames always in the clear.
15085e923d2eSSam Leffler 		 * WPA/WPA2: encrypt EAPOL keys when pairwise keys are set.
15095e923d2eSSam Leffler 		 */
1510b032f27cSSam Leffler 		if ((m->m_flags & M_EAPOL) == 0 ||
1511b032f27cSSam Leffler 		    ((vap->iv_flags & IEEE80211_F_WPA) &&
1512b032f27cSSam Leffler 		     (vap->iv_opmode == IEEE80211_M_STA ?
1513cda15ce1SSam Leffler 		      !IEEE80211_KEY_UNDEFINED(key) :
1514cda15ce1SSam Leffler 		      !IEEE80211_KEY_UNDEFINED(&ni->ni_ucastkey)))) {
15155945b5f5SKevin Lo 			wh->i_fc[1] |= IEEE80211_FC1_PROTECTED;
1516b032f27cSSam Leffler 			if (!ieee80211_crypto_enmic(vap, key, m, txfrag)) {
1517b032f27cSSam Leffler 				IEEE80211_NOTE_MAC(vap, IEEE80211_MSG_OUTPUT,
1518b032f27cSSam Leffler 				    eh.ether_dhost,
1519b032f27cSSam Leffler 				    "%s", "enmic failed, discard frame");
1520b032f27cSSam Leffler 				vap->iv_stats.is_crypto_enmicfail++;
15215e923d2eSSam Leffler 				goto bad;
15225e923d2eSSam Leffler 			}
15235e923d2eSSam Leffler 		}
15245e923d2eSSam Leffler 	}
1525b032f27cSSam Leffler 	if (txfrag && !ieee80211_fragment(vap, m, hdrsize,
1526b032f27cSSam Leffler 	    key != NULL ? key->wk_cipher->ic_header : 0, vap->iv_fragthreshold))
152768e8e04eSSam Leffler 		goto bad;
15288a1b9b6aSSam Leffler 
1529c1af44bdSSam Leffler 	m->m_flags |= M_ENCAP;		/* mark encapsulated */
1530c1af44bdSSam Leffler 
15318a1b9b6aSSam Leffler 	IEEE80211_NODE_STAT(ni, tx_data);
15329e80b1dfSSam Leffler 	if (IEEE80211_IS_MULTICAST(wh->i_addr1)) {
1533b6e9b119SSam Leffler 		IEEE80211_NODE_STAT(ni, tx_mcast);
15349e80b1dfSSam Leffler 		m->m_flags |= M_MCAST;
15359e80b1dfSSam Leffler 	} else
1536b6e9b119SSam Leffler 		IEEE80211_NODE_STAT(ni, tx_ucast);
15378a1b9b6aSSam Leffler 	IEEE80211_NODE_STAT_ADD(ni, tx_bytes, datalen);
15388a1b9b6aSSam Leffler 
15391a1e1d21SSam Leffler 	return m;
15400a915fadSSam Leffler bad:
15410a915fadSSam Leffler 	if (m != NULL)
15420a915fadSSam Leffler 		m_freem(m);
15430a915fadSSam Leffler 	return NULL;
1544b032f27cSSam Leffler #undef WH4
15453c314f6dSMonthadar Al Jaberi #undef MC01
15461a1e1d21SSam Leffler }
15471a1e1d21SSam Leffler 
15481a1e1d21SSam Leffler /*
154968e8e04eSSam Leffler  * Fragment the frame according to the specified mtu.
155068e8e04eSSam Leffler  * The size of the 802.11 header (w/o padding) is provided
155168e8e04eSSam Leffler  * so we don't need to recalculate it.  We create a new
155268e8e04eSSam Leffler  * mbuf for each fragment and chain it through m_nextpkt;
155368e8e04eSSam Leffler  * we might be able to optimize this by reusing the original
155468e8e04eSSam Leffler  * packet's mbufs but that is significantly more complicated.
155568e8e04eSSam Leffler  */
155668e8e04eSSam Leffler static int
1557b032f27cSSam Leffler ieee80211_fragment(struct ieee80211vap *vap, struct mbuf *m0,
155868e8e04eSSam Leffler 	u_int hdrsize, u_int ciphdrsize, u_int mtu)
155968e8e04eSSam Leffler {
15608d46c25dSAdrian Chadd 	struct ieee80211com *ic = vap->iv_ic;
156168e8e04eSSam Leffler 	struct ieee80211_frame *wh, *whf;
156268e8e04eSSam Leffler 	struct mbuf *m, *prev, *next;
156368e8e04eSSam Leffler 	u_int totalhdrsize, fragno, fragsize, off, remainder, payload;
15648d46c25dSAdrian Chadd 	u_int hdrspace;
156568e8e04eSSam Leffler 
156668e8e04eSSam Leffler 	KASSERT(m0->m_nextpkt == NULL, ("mbuf already chained?"));
156768e8e04eSSam Leffler 	KASSERT(m0->m_pkthdr.len > mtu,
156868e8e04eSSam Leffler 		("pktlen %u mtu %u", m0->m_pkthdr.len, mtu));
156968e8e04eSSam Leffler 
15708d46c25dSAdrian Chadd 	/*
15718d46c25dSAdrian Chadd 	 * Honor driver DATAPAD requirement.
15728d46c25dSAdrian Chadd 	 */
15738d46c25dSAdrian Chadd 	if (ic->ic_flags & IEEE80211_F_DATAPAD)
15748d46c25dSAdrian Chadd 		hdrspace = roundup(hdrsize, sizeof(uint32_t));
15758d46c25dSAdrian Chadd 	else
15768d46c25dSAdrian Chadd 		hdrspace = hdrsize;
15778d46c25dSAdrian Chadd 
157868e8e04eSSam Leffler 	wh = mtod(m0, struct ieee80211_frame *);
157968e8e04eSSam Leffler 	/* NB: mark the first frag; it will be propagated below */
158068e8e04eSSam Leffler 	wh->i_fc[1] |= IEEE80211_FC1_MORE_FRAG;
15818d46c25dSAdrian Chadd 	totalhdrsize = hdrspace + ciphdrsize;
158268e8e04eSSam Leffler 	fragno = 1;
158368e8e04eSSam Leffler 	off = mtu - ciphdrsize;
158468e8e04eSSam Leffler 	remainder = m0->m_pkthdr.len - off;
158568e8e04eSSam Leffler 	prev = m0;
158668e8e04eSSam Leffler 	do {
158768e8e04eSSam Leffler 		fragsize = totalhdrsize + remainder;
158868e8e04eSSam Leffler 		if (fragsize > mtu)
158968e8e04eSSam Leffler 			fragsize = mtu;
1590b032f27cSSam Leffler 		/* XXX fragsize can be >2048! */
159168e8e04eSSam Leffler 		KASSERT(fragsize < MCLBYTES,
159268e8e04eSSam Leffler 			("fragment size %u too big!", fragsize));
159368e8e04eSSam Leffler 		if (fragsize > MHLEN)
1594eb1b1807SGleb Smirnoff 			m = m_getcl(M_NOWAIT, MT_DATA, M_PKTHDR);
159568e8e04eSSam Leffler 		else
1596eb1b1807SGleb Smirnoff 			m = m_gethdr(M_NOWAIT, MT_DATA);
159768e8e04eSSam Leffler 		if (m == NULL)
159868e8e04eSSam Leffler 			goto bad;
159968e8e04eSSam Leffler 		/* leave room to prepend any cipher header */
160068e8e04eSSam Leffler 		m_align(m, fragsize - ciphdrsize);
160168e8e04eSSam Leffler 
160268e8e04eSSam Leffler 		/*
160368e8e04eSSam Leffler 		 * Form the header in the fragment.  Note that since
160468e8e04eSSam Leffler 		 * we mark the first fragment with the MORE_FRAG bit
160568e8e04eSSam Leffler 		 * it automatically is propagated to each fragment; we
160668e8e04eSSam Leffler 		 * need only clear it on the last fragment (done below).
160791216c71SAdrian Chadd 		 * NB: frag 1+ dont have Mesh Control field present.
160868e8e04eSSam Leffler 		 */
160968e8e04eSSam Leffler 		whf = mtod(m, struct ieee80211_frame *);
161068e8e04eSSam Leffler 		memcpy(whf, wh, hdrsize);
161191216c71SAdrian Chadd #ifdef IEEE80211_SUPPORT_MESH
161291216c71SAdrian Chadd 		if (vap->iv_opmode == IEEE80211_M_MBSS) {
161391216c71SAdrian Chadd 			if (IEEE80211_IS_DSTODS(wh))
161491216c71SAdrian Chadd 				((struct ieee80211_qosframe_addr4 *)
161591216c71SAdrian Chadd 				    whf)->i_qos[1] &= ~IEEE80211_QOS_MC;
161691216c71SAdrian Chadd 			else
161791216c71SAdrian Chadd 				((struct ieee80211_qosframe *)
161891216c71SAdrian Chadd 				    whf)->i_qos[1] &= ~IEEE80211_QOS_MC;
161991216c71SAdrian Chadd 		}
162091216c71SAdrian Chadd #endif
162168e8e04eSSam Leffler 		*(uint16_t *)&whf->i_seq[0] |= htole16(
162268e8e04eSSam Leffler 			(fragno & IEEE80211_SEQ_FRAG_MASK) <<
162368e8e04eSSam Leffler 				IEEE80211_SEQ_FRAG_SHIFT);
162468e8e04eSSam Leffler 		fragno++;
162568e8e04eSSam Leffler 
162668e8e04eSSam Leffler 		payload = fragsize - totalhdrsize;
162768e8e04eSSam Leffler 		/* NB: destination is known to be contiguous */
16288d46c25dSAdrian Chadd 
16298d46c25dSAdrian Chadd 		m_copydata(m0, off, payload, mtod(m, uint8_t *) + hdrspace);
16308d46c25dSAdrian Chadd 		m->m_len = hdrspace + payload;
16318d46c25dSAdrian Chadd 		m->m_pkthdr.len = hdrspace + payload;
163268e8e04eSSam Leffler 		m->m_flags |= M_FRAG;
163368e8e04eSSam Leffler 
163468e8e04eSSam Leffler 		/* chain up the fragment */
163568e8e04eSSam Leffler 		prev->m_nextpkt = m;
163668e8e04eSSam Leffler 		prev = m;
163768e8e04eSSam Leffler 
163868e8e04eSSam Leffler 		/* deduct fragment just formed */
163968e8e04eSSam Leffler 		remainder -= payload;
164068e8e04eSSam Leffler 		off += payload;
164168e8e04eSSam Leffler 	} while (remainder != 0);
164251cec121SWeongyo Jeong 
164351cec121SWeongyo Jeong 	/* set the last fragment */
164451cec121SWeongyo Jeong 	m->m_flags |= M_LASTFRAG;
164568e8e04eSSam Leffler 	whf->i_fc[1] &= ~IEEE80211_FC1_MORE_FRAG;
164668e8e04eSSam Leffler 
164768e8e04eSSam Leffler 	/* strip first mbuf now that everything has been copied */
164868e8e04eSSam Leffler 	m_adj(m0, -(m0->m_pkthdr.len - (mtu - ciphdrsize)));
164968e8e04eSSam Leffler 	m0->m_flags |= M_FIRSTFRAG | M_FRAG;
165068e8e04eSSam Leffler 
1651b032f27cSSam Leffler 	vap->iv_stats.is_tx_fragframes++;
1652b032f27cSSam Leffler 	vap->iv_stats.is_tx_frags += fragno-1;
165368e8e04eSSam Leffler 
165468e8e04eSSam Leffler 	return 1;
165568e8e04eSSam Leffler bad:
165668e8e04eSSam Leffler 	/* reclaim fragments but leave original frame for caller to free */
165768e8e04eSSam Leffler 	for (m = m0->m_nextpkt; m != NULL; m = next) {
165868e8e04eSSam Leffler 		next = m->m_nextpkt;
165968e8e04eSSam Leffler 		m->m_nextpkt = NULL;		/* XXX paranoid */
166068e8e04eSSam Leffler 		m_freem(m);
166168e8e04eSSam Leffler 	}
166268e8e04eSSam Leffler 	m0->m_nextpkt = NULL;
166368e8e04eSSam Leffler 	return 0;
166468e8e04eSSam Leffler }
166568e8e04eSSam Leffler 
166668e8e04eSSam Leffler /*
16671a1e1d21SSam Leffler  * Add a supported rates element id to a frame.
16681a1e1d21SSam Leffler  */
166959aa14a9SRui Paulo uint8_t *
167068e8e04eSSam Leffler ieee80211_add_rates(uint8_t *frm, const struct ieee80211_rateset *rs)
16711a1e1d21SSam Leffler {
16721a1e1d21SSam Leffler 	int nrates;
16731a1e1d21SSam Leffler 
16741a1e1d21SSam Leffler 	*frm++ = IEEE80211_ELEMID_RATES;
16751a1e1d21SSam Leffler 	nrates = rs->rs_nrates;
16761a1e1d21SSam Leffler 	if (nrates > IEEE80211_RATE_SIZE)
16771a1e1d21SSam Leffler 		nrates = IEEE80211_RATE_SIZE;
16781a1e1d21SSam Leffler 	*frm++ = nrates;
16791a1e1d21SSam Leffler 	memcpy(frm, rs->rs_rates, nrates);
16801a1e1d21SSam Leffler 	return frm + nrates;
16811a1e1d21SSam Leffler }
16821a1e1d21SSam Leffler 
16831a1e1d21SSam Leffler /*
16841a1e1d21SSam Leffler  * Add an extended supported rates element id to a frame.
16851a1e1d21SSam Leffler  */
168659aa14a9SRui Paulo uint8_t *
168768e8e04eSSam Leffler ieee80211_add_xrates(uint8_t *frm, const struct ieee80211_rateset *rs)
16881a1e1d21SSam Leffler {
16891a1e1d21SSam Leffler 	/*
16901a1e1d21SSam Leffler 	 * Add an extended supported rates element if operating in 11g mode.
16911a1e1d21SSam Leffler 	 */
16921a1e1d21SSam Leffler 	if (rs->rs_nrates > IEEE80211_RATE_SIZE) {
16931a1e1d21SSam Leffler 		int nrates = rs->rs_nrates - IEEE80211_RATE_SIZE;
16941a1e1d21SSam Leffler 		*frm++ = IEEE80211_ELEMID_XRATES;
16951a1e1d21SSam Leffler 		*frm++ = nrates;
16961a1e1d21SSam Leffler 		memcpy(frm, rs->rs_rates + IEEE80211_RATE_SIZE, nrates);
16971a1e1d21SSam Leffler 		frm += nrates;
16981a1e1d21SSam Leffler 	}
16991a1e1d21SSam Leffler 	return frm;
17001a1e1d21SSam Leffler }
17011a1e1d21SSam Leffler 
17021a1e1d21SSam Leffler /*
1703b032f27cSSam Leffler  * Add an ssid element to a frame.
17041a1e1d21SSam Leffler  */
170568e8e04eSSam Leffler static uint8_t *
170668e8e04eSSam Leffler ieee80211_add_ssid(uint8_t *frm, const uint8_t *ssid, u_int len)
17071a1e1d21SSam Leffler {
17081a1e1d21SSam Leffler 	*frm++ = IEEE80211_ELEMID_SSID;
17091a1e1d21SSam Leffler 	*frm++ = len;
17101a1e1d21SSam Leffler 	memcpy(frm, ssid, len);
17111a1e1d21SSam Leffler 	return frm + len;
17121a1e1d21SSam Leffler }
17131a1e1d21SSam Leffler 
17148a1b9b6aSSam Leffler /*
17158a1b9b6aSSam Leffler  * Add an erp element to a frame.
17168a1b9b6aSSam Leffler  */
171768e8e04eSSam Leffler static uint8_t *
171868e8e04eSSam Leffler ieee80211_add_erp(uint8_t *frm, struct ieee80211com *ic)
17191a1e1d21SSam Leffler {
172068e8e04eSSam Leffler 	uint8_t erp;
17211a1e1d21SSam Leffler 
17228a1b9b6aSSam Leffler 	*frm++ = IEEE80211_ELEMID_ERP;
17238a1b9b6aSSam Leffler 	*frm++ = 1;
17248a1b9b6aSSam Leffler 	erp = 0;
17258a1b9b6aSSam Leffler 	if (ic->ic_nonerpsta != 0)
17268a1b9b6aSSam Leffler 		erp |= IEEE80211_ERP_NON_ERP_PRESENT;
17278a1b9b6aSSam Leffler 	if (ic->ic_flags & IEEE80211_F_USEPROT)
17288a1b9b6aSSam Leffler 		erp |= IEEE80211_ERP_USE_PROTECTION;
17298a1b9b6aSSam Leffler 	if (ic->ic_flags & IEEE80211_F_USEBARKER)
17308a1b9b6aSSam Leffler 		erp |= IEEE80211_ERP_LONG_PREAMBLE;
17318a1b9b6aSSam Leffler 	*frm++ = erp;
17328a1b9b6aSSam Leffler 	return frm;
17331a1e1d21SSam Leffler }
17341a1e1d21SSam Leffler 
17358a1b9b6aSSam Leffler /*
1736b032f27cSSam Leffler  * Add a CFParams element to a frame.
17378a1b9b6aSSam Leffler  */
173868e8e04eSSam Leffler static uint8_t *
1739b032f27cSSam Leffler ieee80211_add_cfparms(uint8_t *frm, struct ieee80211com *ic)
17408a1b9b6aSSam Leffler {
1741b032f27cSSam Leffler #define	ADDSHORT(frm, v) do {	\
174259aa14a9SRui Paulo 	LE_WRITE_2(frm, v);	\
1743b032f27cSSam Leffler 	frm += 2;		\
1744b032f27cSSam Leffler } while (0)
1745b032f27cSSam Leffler 	*frm++ = IEEE80211_ELEMID_CFPARMS;
1746b032f27cSSam Leffler 	*frm++ = 6;
1747b032f27cSSam Leffler 	*frm++ = 0;		/* CFP count */
1748b032f27cSSam Leffler 	*frm++ = 2;		/* CFP period */
1749b032f27cSSam Leffler 	ADDSHORT(frm, 0);	/* CFP MaxDuration (TU) */
1750b032f27cSSam Leffler 	ADDSHORT(frm, 0);	/* CFP CurRemaining (TU) */
17518a1b9b6aSSam Leffler 	return frm;
1752b032f27cSSam Leffler #undef ADDSHORT
1753b032f27cSSam Leffler }
1754b032f27cSSam Leffler 
1755b032f27cSSam Leffler static __inline uint8_t *
1756b032f27cSSam Leffler add_appie(uint8_t *frm, const struct ieee80211_appie *ie)
1757b032f27cSSam Leffler {
1758b032f27cSSam Leffler 	memcpy(frm, ie->ie_data, ie->ie_len);
1759b032f27cSSam Leffler 	return frm + ie->ie_len;
1760b032f27cSSam Leffler }
1761b032f27cSSam Leffler 
1762b032f27cSSam Leffler static __inline uint8_t *
1763b032f27cSSam Leffler add_ie(uint8_t *frm, const uint8_t *ie)
1764b032f27cSSam Leffler {
1765b032f27cSSam Leffler 	memcpy(frm, ie, 2 + ie[1]);
1766b032f27cSSam Leffler 	return frm + 2 + ie[1];
17678a1b9b6aSSam Leffler }
17688a1b9b6aSSam Leffler 
17698a1b9b6aSSam Leffler #define	WME_OUI_BYTES		0x00, 0x50, 0xf2
17708a1b9b6aSSam Leffler /*
17718a1b9b6aSSam Leffler  * Add a WME information element to a frame.
17728a1b9b6aSSam Leffler  */
177368e8e04eSSam Leffler static uint8_t *
177468e8e04eSSam Leffler ieee80211_add_wme_info(uint8_t *frm, struct ieee80211_wme_state *wme)
17758a1b9b6aSSam Leffler {
17768a1b9b6aSSam Leffler 	static const struct ieee80211_wme_info info = {
17778a1b9b6aSSam Leffler 		.wme_id		= IEEE80211_ELEMID_VENDOR,
17788a1b9b6aSSam Leffler 		.wme_len	= sizeof(struct ieee80211_wme_info) - 2,
17798a1b9b6aSSam Leffler 		.wme_oui	= { WME_OUI_BYTES },
17808a1b9b6aSSam Leffler 		.wme_type	= WME_OUI_TYPE,
17818a1b9b6aSSam Leffler 		.wme_subtype	= WME_INFO_OUI_SUBTYPE,
17828a1b9b6aSSam Leffler 		.wme_version	= WME_VERSION,
17838a1b9b6aSSam Leffler 		.wme_info	= 0,
17848a1b9b6aSSam Leffler 	};
17858a1b9b6aSSam Leffler 	memcpy(frm, &info, sizeof(info));
17868a1b9b6aSSam Leffler 	return frm + sizeof(info);
17878a1b9b6aSSam Leffler }
17888a1b9b6aSSam Leffler 
17898a1b9b6aSSam Leffler /*
17908a1b9b6aSSam Leffler  * Add a WME parameters element to a frame.
17918a1b9b6aSSam Leffler  */
179268e8e04eSSam Leffler static uint8_t *
179368e8e04eSSam Leffler ieee80211_add_wme_param(uint8_t *frm, struct ieee80211_wme_state *wme)
17948a1b9b6aSSam Leffler {
17958a1b9b6aSSam Leffler #define	SM(_v, _f)	(((_v) << _f##_S) & _f)
17968a1b9b6aSSam Leffler #define	ADDSHORT(frm, v) do {	\
179759aa14a9SRui Paulo 	LE_WRITE_2(frm, v);	\
17988a1b9b6aSSam Leffler 	frm += 2;		\
17998a1b9b6aSSam Leffler } while (0)
18008a1b9b6aSSam Leffler 	/* NB: this works 'cuz a param has an info at the front */
18018a1b9b6aSSam Leffler 	static const struct ieee80211_wme_info param = {
18028a1b9b6aSSam Leffler 		.wme_id		= IEEE80211_ELEMID_VENDOR,
18038a1b9b6aSSam Leffler 		.wme_len	= sizeof(struct ieee80211_wme_param) - 2,
18048a1b9b6aSSam Leffler 		.wme_oui	= { WME_OUI_BYTES },
18058a1b9b6aSSam Leffler 		.wme_type	= WME_OUI_TYPE,
18068a1b9b6aSSam Leffler 		.wme_subtype	= WME_PARAM_OUI_SUBTYPE,
18078a1b9b6aSSam Leffler 		.wme_version	= WME_VERSION,
18088a1b9b6aSSam Leffler 	};
18098a1b9b6aSSam Leffler 	int i;
18108a1b9b6aSSam Leffler 
18118a1b9b6aSSam Leffler 	memcpy(frm, &param, sizeof(param));
18128a1b9b6aSSam Leffler 	frm += __offsetof(struct ieee80211_wme_info, wme_info);
18138a1b9b6aSSam Leffler 	*frm++ = wme->wme_bssChanParams.cap_info;	/* AC info */
18148a1b9b6aSSam Leffler 	*frm++ = 0;					/* reserved field */
18158a1b9b6aSSam Leffler 	for (i = 0; i < WME_NUM_AC; i++) {
18168a1b9b6aSSam Leffler 		const struct wmeParams *ac =
18178a1b9b6aSSam Leffler 		       &wme->wme_bssChanParams.cap_wmeParams[i];
18188a1b9b6aSSam Leffler 		*frm++ = SM(i, WME_PARAM_ACI)
18198a1b9b6aSSam Leffler 		       | SM(ac->wmep_acm, WME_PARAM_ACM)
18208a1b9b6aSSam Leffler 		       | SM(ac->wmep_aifsn, WME_PARAM_AIFSN)
18218a1b9b6aSSam Leffler 		       ;
18228a1b9b6aSSam Leffler 		*frm++ = SM(ac->wmep_logcwmax, WME_PARAM_LOGCWMAX)
18238a1b9b6aSSam Leffler 		       | SM(ac->wmep_logcwmin, WME_PARAM_LOGCWMIN)
18248a1b9b6aSSam Leffler 		       ;
18258a1b9b6aSSam Leffler 		ADDSHORT(frm, ac->wmep_txopLimit);
18268a1b9b6aSSam Leffler 	}
18278a1b9b6aSSam Leffler 	return frm;
18288a1b9b6aSSam Leffler #undef SM
18298a1b9b6aSSam Leffler #undef ADDSHORT
18308a1b9b6aSSam Leffler }
18318a1b9b6aSSam Leffler #undef WME_OUI_BYTES
18328a1b9b6aSSam Leffler 
18330a915fadSSam Leffler /*
1834b032f27cSSam Leffler  * Add an 11h Power Constraint element to a frame.
1835b032f27cSSam Leffler  */
1836b032f27cSSam Leffler static uint8_t *
1837b032f27cSSam Leffler ieee80211_add_powerconstraint(uint8_t *frm, struct ieee80211vap *vap)
1838b032f27cSSam Leffler {
1839b032f27cSSam Leffler 	const struct ieee80211_channel *c = vap->iv_bss->ni_chan;
1840b032f27cSSam Leffler 	/* XXX per-vap tx power limit? */
1841b032f27cSSam Leffler 	int8_t limit = vap->iv_ic->ic_txpowlimit / 2;
1842b032f27cSSam Leffler 
1843b032f27cSSam Leffler 	frm[0] = IEEE80211_ELEMID_PWRCNSTR;
1844b032f27cSSam Leffler 	frm[1] = 1;
1845b032f27cSSam Leffler 	frm[2] = c->ic_maxregpower > limit ?  c->ic_maxregpower - limit : 0;
1846b032f27cSSam Leffler 	return frm + 3;
1847b032f27cSSam Leffler }
1848b032f27cSSam Leffler 
1849b032f27cSSam Leffler /*
1850b032f27cSSam Leffler  * Add an 11h Power Capability element to a frame.
1851b032f27cSSam Leffler  */
1852b032f27cSSam Leffler static uint8_t *
1853b032f27cSSam Leffler ieee80211_add_powercapability(uint8_t *frm, const struct ieee80211_channel *c)
1854b032f27cSSam Leffler {
1855b032f27cSSam Leffler 	frm[0] = IEEE80211_ELEMID_PWRCAP;
1856b032f27cSSam Leffler 	frm[1] = 2;
1857b032f27cSSam Leffler 	frm[2] = c->ic_minpower;
1858b032f27cSSam Leffler 	frm[3] = c->ic_maxpower;
1859b032f27cSSam Leffler 	return frm + 4;
1860b032f27cSSam Leffler }
1861b032f27cSSam Leffler 
1862b032f27cSSam Leffler /*
1863b032f27cSSam Leffler  * Add an 11h Supported Channels element to a frame.
1864b032f27cSSam Leffler  */
1865b032f27cSSam Leffler static uint8_t *
1866b032f27cSSam Leffler ieee80211_add_supportedchannels(uint8_t *frm, struct ieee80211com *ic)
1867b032f27cSSam Leffler {
1868b032f27cSSam Leffler 	static const int ielen = 26;
1869b032f27cSSam Leffler 
1870b032f27cSSam Leffler 	frm[0] = IEEE80211_ELEMID_SUPPCHAN;
1871b032f27cSSam Leffler 	frm[1] = ielen;
1872b032f27cSSam Leffler 	/* XXX not correct */
1873b032f27cSSam Leffler 	memcpy(frm+2, ic->ic_chan_avail, ielen);
1874b032f27cSSam Leffler 	return frm + 2 + ielen;
1875b032f27cSSam Leffler }
1876b032f27cSSam Leffler 
1877b032f27cSSam Leffler /*
187832b0e64bSAdrian Chadd  * Add an 11h Quiet time element to a frame.
187932b0e64bSAdrian Chadd  */
188032b0e64bSAdrian Chadd static uint8_t *
188132b0e64bSAdrian Chadd ieee80211_add_quiet(uint8_t *frm, struct ieee80211vap *vap)
188232b0e64bSAdrian Chadd {
188332b0e64bSAdrian Chadd 	struct ieee80211_quiet_ie *quiet = (struct ieee80211_quiet_ie *) frm;
188432b0e64bSAdrian Chadd 
188532b0e64bSAdrian Chadd 	quiet->quiet_ie = IEEE80211_ELEMID_QUIET;
188632b0e64bSAdrian Chadd 	quiet->len = 6;
188732b0e64bSAdrian Chadd 	if (vap->iv_quiet_count_value == 1)
188832b0e64bSAdrian Chadd 		vap->iv_quiet_count_value = vap->iv_quiet_count;
188932b0e64bSAdrian Chadd 	else if (vap->iv_quiet_count_value > 1)
189032b0e64bSAdrian Chadd 		vap->iv_quiet_count_value--;
189132b0e64bSAdrian Chadd 
189232b0e64bSAdrian Chadd 	if (vap->iv_quiet_count_value == 0) {
189332b0e64bSAdrian Chadd 		/* value 0 is reserved as per 802.11h standerd */
189432b0e64bSAdrian Chadd 		vap->iv_quiet_count_value = 1;
189532b0e64bSAdrian Chadd 	}
189632b0e64bSAdrian Chadd 
189732b0e64bSAdrian Chadd 	quiet->tbttcount = vap->iv_quiet_count_value;
189832b0e64bSAdrian Chadd 	quiet->period = vap->iv_quiet_period;
189932b0e64bSAdrian Chadd 	quiet->duration = htole16(vap->iv_quiet_duration);
190032b0e64bSAdrian Chadd 	quiet->offset = htole16(vap->iv_quiet_offset);
190132b0e64bSAdrian Chadd 	return frm + sizeof(*quiet);
190232b0e64bSAdrian Chadd }
190332b0e64bSAdrian Chadd 
190432b0e64bSAdrian Chadd /*
1905b032f27cSSam Leffler  * Add an 11h Channel Switch Announcement element to a frame.
1906b032f27cSSam Leffler  * Note that we use the per-vap CSA count to adjust the global
1907b032f27cSSam Leffler  * counter so we can use this routine to form probe response
1908b032f27cSSam Leffler  * frames and get the current count.
1909b032f27cSSam Leffler  */
1910b032f27cSSam Leffler static uint8_t *
1911b032f27cSSam Leffler ieee80211_add_csa(uint8_t *frm, struct ieee80211vap *vap)
1912b032f27cSSam Leffler {
1913b032f27cSSam Leffler 	struct ieee80211com *ic = vap->iv_ic;
1914b032f27cSSam Leffler 	struct ieee80211_csa_ie *csa = (struct ieee80211_csa_ie *) frm;
1915b032f27cSSam Leffler 
1916c70761e6SSam Leffler 	csa->csa_ie = IEEE80211_ELEMID_CSA;
1917b032f27cSSam Leffler 	csa->csa_len = 3;
1918b032f27cSSam Leffler 	csa->csa_mode = 1;		/* XXX force quiet on channel */
1919b032f27cSSam Leffler 	csa->csa_newchan = ieee80211_chan2ieee(ic, ic->ic_csa_newchan);
1920b032f27cSSam Leffler 	csa->csa_count = ic->ic_csa_count - vap->iv_csa_count;
1921b032f27cSSam Leffler 	return frm + sizeof(*csa);
1922b032f27cSSam Leffler }
1923b032f27cSSam Leffler 
1924b032f27cSSam Leffler /*
1925b032f27cSSam Leffler  * Add an 11h country information element to a frame.
1926b032f27cSSam Leffler  */
1927b032f27cSSam Leffler static uint8_t *
1928b032f27cSSam Leffler ieee80211_add_countryie(uint8_t *frm, struct ieee80211com *ic)
1929b032f27cSSam Leffler {
1930b032f27cSSam Leffler 
1931b032f27cSSam Leffler 	if (ic->ic_countryie == NULL ||
1932b032f27cSSam Leffler 	    ic->ic_countryie_chan != ic->ic_bsschan) {
1933b032f27cSSam Leffler 		/*
1934b032f27cSSam Leffler 		 * Handle lazy construction of ie.  This is done on
1935b032f27cSSam Leffler 		 * first use and after a channel change that requires
1936b032f27cSSam Leffler 		 * re-calculation.
1937b032f27cSSam Leffler 		 */
1938b032f27cSSam Leffler 		if (ic->ic_countryie != NULL)
1939b032f27cSSam Leffler 			free(ic->ic_countryie, M_80211_NODE_IE);
1940b032f27cSSam Leffler 		ic->ic_countryie = ieee80211_alloc_countryie(ic);
1941b032f27cSSam Leffler 		if (ic->ic_countryie == NULL)
1942b032f27cSSam Leffler 			return frm;
1943b032f27cSSam Leffler 		ic->ic_countryie_chan = ic->ic_bsschan;
1944b032f27cSSam Leffler 	}
1945b032f27cSSam Leffler 	return add_appie(frm, ic->ic_countryie);
1946b032f27cSSam Leffler }
1947b032f27cSSam Leffler 
1948d8df5f3dSRui Paulo uint8_t *
1949d8df5f3dSRui Paulo ieee80211_add_wpa(uint8_t *frm, const struct ieee80211vap *vap)
1950d8df5f3dSRui Paulo {
1951d8df5f3dSRui Paulo 	if (vap->iv_flags & IEEE80211_F_WPA1 && vap->iv_wpa_ie != NULL)
1952d8df5f3dSRui Paulo 		return (add_ie(frm, vap->iv_wpa_ie));
1953d8df5f3dSRui Paulo 	else {
1954d8df5f3dSRui Paulo 		/* XXX else complain? */
1955d8df5f3dSRui Paulo 		return (frm);
1956d8df5f3dSRui Paulo 	}
1957d8df5f3dSRui Paulo }
1958d8df5f3dSRui Paulo 
1959d8df5f3dSRui Paulo uint8_t *
1960d8df5f3dSRui Paulo ieee80211_add_rsn(uint8_t *frm, const struct ieee80211vap *vap)
1961d8df5f3dSRui Paulo {
1962d8df5f3dSRui Paulo 	if (vap->iv_flags & IEEE80211_F_WPA2 && vap->iv_rsn_ie != NULL)
1963d8df5f3dSRui Paulo 		return (add_ie(frm, vap->iv_rsn_ie));
1964d8df5f3dSRui Paulo 	else {
1965d8df5f3dSRui Paulo 		/* XXX else complain? */
1966d8df5f3dSRui Paulo 		return (frm);
1967d8df5f3dSRui Paulo 	}
1968d8df5f3dSRui Paulo }
1969d8df5f3dSRui Paulo 
1970d8df5f3dSRui Paulo uint8_t *
1971d8df5f3dSRui Paulo ieee80211_add_qos(uint8_t *frm, const struct ieee80211_node *ni)
1972d8df5f3dSRui Paulo {
1973d8df5f3dSRui Paulo 	if (ni->ni_flags & IEEE80211_NODE_QOS) {
1974d8df5f3dSRui Paulo 		*frm++ = IEEE80211_ELEMID_QOS;
1975d8df5f3dSRui Paulo 		*frm++ = 1;
1976d8df5f3dSRui Paulo 		*frm++ = 0;
1977d8df5f3dSRui Paulo 	}
1978d8df5f3dSRui Paulo 
1979d8df5f3dSRui Paulo 	return (frm);
1980d8df5f3dSRui Paulo }
1981d8df5f3dSRui Paulo 
1982b032f27cSSam Leffler /*
1983af8418dcSSam Leffler  * Send a probe request frame with the specified ssid
1984af8418dcSSam Leffler  * and any optional information element data.
1985af8418dcSSam Leffler  */
1986af8418dcSSam Leffler int
1987af8418dcSSam Leffler ieee80211_send_probereq(struct ieee80211_node *ni,
198868e8e04eSSam Leffler 	const uint8_t sa[IEEE80211_ADDR_LEN],
198968e8e04eSSam Leffler 	const uint8_t da[IEEE80211_ADDR_LEN],
199068e8e04eSSam Leffler 	const uint8_t bssid[IEEE80211_ADDR_LEN],
1991b032f27cSSam Leffler 	const uint8_t *ssid, size_t ssidlen)
1992af8418dcSSam Leffler {
1993b032f27cSSam Leffler 	struct ieee80211vap *vap = ni->ni_vap;
1994af8418dcSSam Leffler 	struct ieee80211com *ic = ni->ni_ic;
199516d7cbb1SSam Leffler 	const struct ieee80211_txparam *tp;
199616d7cbb1SSam Leffler 	struct ieee80211_bpf_params params;
1997af8418dcSSam Leffler 	struct ieee80211_frame *wh;
199841b3c790SSam Leffler 	const struct ieee80211_rateset *rs;
1999af8418dcSSam Leffler 	struct mbuf *m;
200068e8e04eSSam Leffler 	uint8_t *frm;
20015cda6006SAdrian Chadd 	int ret;
2002af8418dcSSam Leffler 
2003b032f27cSSam Leffler 	if (vap->iv_state == IEEE80211_S_CAC) {
2004b032f27cSSam Leffler 		IEEE80211_NOTE(vap, IEEE80211_MSG_OUTPUT, ni,
2005b032f27cSSam Leffler 		    "block %s frame in CAC state", "probe request");
2006b032f27cSSam Leffler 		vap->iv_stats.is_tx_badstate++;
2007b032f27cSSam Leffler 		return EIO;		/* XXX */
2008b032f27cSSam Leffler 	}
2009b032f27cSSam Leffler 
2010af8418dcSSam Leffler 	/*
2011af8418dcSSam Leffler 	 * Hold a reference on the node so it doesn't go away until after
2012af8418dcSSam Leffler 	 * the xmit is complete all the way in the driver.  On error we
2013af8418dcSSam Leffler 	 * will remove our reference.
2014af8418dcSSam Leffler 	 */
2015b032f27cSSam Leffler 	IEEE80211_DPRINTF(vap, IEEE80211_MSG_NODE,
2016af8418dcSSam Leffler 		"ieee80211_ref_node (%s:%u) %p<%s> refcnt %d\n",
2017af8418dcSSam Leffler 		__func__, __LINE__,
2018af8418dcSSam Leffler 		ni, ether_sprintf(ni->ni_macaddr),
2019af8418dcSSam Leffler 		ieee80211_node_refcnt(ni)+1);
2020af8418dcSSam Leffler 	ieee80211_ref_node(ni);
2021af8418dcSSam Leffler 
2022af8418dcSSam Leffler 	/*
2023af8418dcSSam Leffler 	 * prreq frame format
2024af8418dcSSam Leffler 	 *	[tlv] ssid
2025af8418dcSSam Leffler 	 *	[tlv] supported rates
2026b032f27cSSam Leffler 	 *	[tlv] RSN (optional)
2027af8418dcSSam Leffler 	 *	[tlv] extended supported rates
2028b032f27cSSam Leffler 	 *	[tlv] WPA (optional)
2029af8418dcSSam Leffler 	 *	[tlv] user-specified ie's
2030af8418dcSSam Leffler 	 */
2031af8418dcSSam Leffler 	m = ieee80211_getmgtframe(&frm,
203268e8e04eSSam Leffler 		 ic->ic_headroom + sizeof(struct ieee80211_frame),
2033af8418dcSSam Leffler 	       	 2 + IEEE80211_NWID_LEN
2034af8418dcSSam Leffler 	       + 2 + IEEE80211_RATE_SIZE
2035b032f27cSSam Leffler 	       + sizeof(struct ieee80211_ie_wpa)
2036af8418dcSSam Leffler 	       + 2 + (IEEE80211_RATE_MAXSIZE - IEEE80211_RATE_SIZE)
2037b032f27cSSam Leffler 	       + sizeof(struct ieee80211_ie_wpa)
2038b032f27cSSam Leffler 	       + (vap->iv_appie_probereq != NULL ?
2039b032f27cSSam Leffler 		   vap->iv_appie_probereq->ie_len : 0)
2040af8418dcSSam Leffler 	);
2041af8418dcSSam Leffler 	if (m == NULL) {
2042b032f27cSSam Leffler 		vap->iv_stats.is_tx_nobuf++;
2043af8418dcSSam Leffler 		ieee80211_free_node(ni);
2044af8418dcSSam Leffler 		return ENOMEM;
2045af8418dcSSam Leffler 	}
2046af8418dcSSam Leffler 
2047af8418dcSSam Leffler 	frm = ieee80211_add_ssid(frm, ssid, ssidlen);
204841b3c790SSam Leffler 	rs = ieee80211_get_suprates(ic, ic->ic_curchan);
204941b3c790SSam Leffler 	frm = ieee80211_add_rates(frm, rs);
2050d8df5f3dSRui Paulo 	frm = ieee80211_add_rsn(frm, vap);
2051b032f27cSSam Leffler 	frm = ieee80211_add_xrates(frm, rs);
2052d8df5f3dSRui Paulo 	frm = ieee80211_add_wpa(frm, vap);
2053b032f27cSSam Leffler 	if (vap->iv_appie_probereq != NULL)
2054b032f27cSSam Leffler 		frm = add_appie(frm, vap->iv_appie_probereq);
205568e8e04eSSam Leffler 	m->m_pkthdr.len = m->m_len = frm - mtod(m, uint8_t *);
2056af8418dcSSam Leffler 
205716d7cbb1SSam Leffler 	KASSERT(M_LEADINGSPACE(m) >= sizeof(struct ieee80211_frame),
205816d7cbb1SSam Leffler 	    ("leading space %zd", M_LEADINGSPACE(m)));
2059eb1b1807SGleb Smirnoff 	M_PREPEND(m, sizeof(struct ieee80211_frame), M_NOWAIT);
206016d7cbb1SSam Leffler 	if (m == NULL) {
206116d7cbb1SSam Leffler 		/* NB: cannot happen */
206216d7cbb1SSam Leffler 		ieee80211_free_node(ni);
2063af8418dcSSam Leffler 		return ENOMEM;
206416d7cbb1SSam Leffler 	}
2065af8418dcSSam Leffler 
20665cda6006SAdrian Chadd 	IEEE80211_TX_LOCK(ic);
2067af8418dcSSam Leffler 	wh = mtod(m, struct ieee80211_frame *);
20689e80b1dfSSam Leffler 	ieee80211_send_setup(ni, m,
2069af8418dcSSam Leffler 	     IEEE80211_FC0_TYPE_MGT | IEEE80211_FC0_SUBTYPE_PROBE_REQ,
20708ac160cdSSam Leffler 	     IEEE80211_NONQOS_TID, sa, da, bssid);
2071af8418dcSSam Leffler 	/* XXX power management? */
2072c1af44bdSSam Leffler 	m->m_flags |= M_ENCAP;		/* mark encapsulated */
2073af8418dcSSam Leffler 
2074b032f27cSSam Leffler 	M_WME_SETAC(m, WME_AC_BE);
2075b032f27cSSam Leffler 
2076af8418dcSSam Leffler 	IEEE80211_NODE_STAT(ni, tx_probereq);
2077af8418dcSSam Leffler 	IEEE80211_NODE_STAT(ni, tx_mgmt);
2078af8418dcSSam Leffler 
2079b032f27cSSam Leffler 	IEEE80211_DPRINTF(vap, IEEE80211_MSG_DEBUG | IEEE80211_MSG_DUMPPKTS,
2080b032f27cSSam Leffler 	    "send probe req on channel %u bssid %s ssid \"%.*s\"\n",
2081b032f27cSSam Leffler 	    ieee80211_chan2ieee(ic, ic->ic_curchan), ether_sprintf(bssid),
2082b032f27cSSam Leffler 	    ssidlen, ssid);
2083af8418dcSSam Leffler 
208416d7cbb1SSam Leffler 	memset(&params, 0, sizeof(params));
208516d7cbb1SSam Leffler 	params.ibp_pri = M_WME_GETAC(m);
208616d7cbb1SSam Leffler 	tp = &vap->iv_txparms[ieee80211_chan2mode(ic->ic_curchan)];
208716d7cbb1SSam Leffler 	params.ibp_rate0 = tp->mgmtrate;
208816d7cbb1SSam Leffler 	if (IEEE80211_IS_MULTICAST(da)) {
208916d7cbb1SSam Leffler 		params.ibp_flags |= IEEE80211_BPF_NOACK;
209016d7cbb1SSam Leffler 		params.ibp_try0 = 1;
209116d7cbb1SSam Leffler 	} else
209216d7cbb1SSam Leffler 		params.ibp_try0 = tp->maxretry;
209316d7cbb1SSam Leffler 	params.ibp_power = ni->ni_txpower;
20945cda6006SAdrian Chadd 	ret = ieee80211_raw_output(vap, ni, m, &params);
20955cda6006SAdrian Chadd 	IEEE80211_TX_UNLOCK(ic);
20965cda6006SAdrian Chadd 	return (ret);
2097af8418dcSSam Leffler }
2098af8418dcSSam Leffler 
2099af8418dcSSam Leffler /*
2100667dad55SSam Leffler  * Calculate capability information for mgt frames.
2101667dad55SSam Leffler  */
210259aa14a9SRui Paulo uint16_t
210359aa14a9SRui Paulo ieee80211_getcapinfo(struct ieee80211vap *vap, struct ieee80211_channel *chan)
2104667dad55SSam Leffler {
2105b032f27cSSam Leffler 	struct ieee80211com *ic = vap->iv_ic;
210668e8e04eSSam Leffler 	uint16_t capinfo;
2107667dad55SSam Leffler 
2108b032f27cSSam Leffler 	KASSERT(vap->iv_opmode != IEEE80211_M_STA, ("station mode"));
2109667dad55SSam Leffler 
2110b032f27cSSam Leffler 	if (vap->iv_opmode == IEEE80211_M_HOSTAP)
2111667dad55SSam Leffler 		capinfo = IEEE80211_CAPINFO_ESS;
2112b032f27cSSam Leffler 	else if (vap->iv_opmode == IEEE80211_M_IBSS)
2113667dad55SSam Leffler 		capinfo = IEEE80211_CAPINFO_IBSS;
2114667dad55SSam Leffler 	else
2115667dad55SSam Leffler 		capinfo = 0;
2116b032f27cSSam Leffler 	if (vap->iv_flags & IEEE80211_F_PRIVACY)
2117667dad55SSam Leffler 		capinfo |= IEEE80211_CAPINFO_PRIVACY;
2118667dad55SSam Leffler 	if ((ic->ic_flags & IEEE80211_F_SHPREAMBLE) &&
2119667dad55SSam Leffler 	    IEEE80211_IS_CHAN_2GHZ(chan))
2120667dad55SSam Leffler 		capinfo |= IEEE80211_CAPINFO_SHORT_PREAMBLE;
2121667dad55SSam Leffler 	if (ic->ic_flags & IEEE80211_F_SHSLOT)
2122667dad55SSam Leffler 		capinfo |= IEEE80211_CAPINFO_SHORT_SLOTTIME;
2123b032f27cSSam Leffler 	if (IEEE80211_IS_CHAN_5GHZ(chan) && (vap->iv_flags & IEEE80211_F_DOTH))
2124b032f27cSSam Leffler 		capinfo |= IEEE80211_CAPINFO_SPECTRUM_MGMT;
2125667dad55SSam Leffler 	return capinfo;
2126667dad55SSam Leffler }
2127667dad55SSam Leffler 
2128667dad55SSam Leffler /*
21290a915fadSSam Leffler  * Send a management frame.  The node is for the destination (or ic_bss
21300a915fadSSam Leffler  * when in station mode).  Nodes other than ic_bss have their reference
21310a915fadSSam Leffler  * count bumped to reflect our use for an indeterminant time.
21320a915fadSSam Leffler  */
21331a1e1d21SSam Leffler int
2134b032f27cSSam Leffler ieee80211_send_mgmt(struct ieee80211_node *ni, int type, int arg)
21351a1e1d21SSam Leffler {
21361b6167d2SSam Leffler #define	HTFLAGS (IEEE80211_NODE_HT | IEEE80211_NODE_HTCOMPAT)
2137b032f27cSSam Leffler #define	senderr(_x, _v)	do { vap->iv_stats._v++; ret = _x; goto bad; } while (0)
2138b032f27cSSam Leffler 	struct ieee80211vap *vap = ni->ni_vap;
2139b032f27cSSam Leffler 	struct ieee80211com *ic = ni->ni_ic;
2140b032f27cSSam Leffler 	struct ieee80211_node *bss = vap->iv_bss;
21418ac160cdSSam Leffler 	struct ieee80211_bpf_params params;
21421a1e1d21SSam Leffler 	struct mbuf *m;
214368e8e04eSSam Leffler 	uint8_t *frm;
214468e8e04eSSam Leffler 	uint16_t capinfo;
214568e8e04eSSam Leffler 	int has_challenge, is_shared_key, ret, status;
21461a1e1d21SSam Leffler 
21470a915fadSSam Leffler 	KASSERT(ni != NULL, ("null node"));
21480a915fadSSam Leffler 
21490a915fadSSam Leffler 	/*
21500a915fadSSam Leffler 	 * Hold a reference on the node so it doesn't go away until after
21510a915fadSSam Leffler 	 * the xmit is complete all the way in the driver.  On error we
21520a915fadSSam Leffler 	 * will remove our reference.
21530a915fadSSam Leffler 	 */
2154b032f27cSSam Leffler 	IEEE80211_DPRINTF(vap, IEEE80211_MSG_NODE,
215549a15236SSam Leffler 		"ieee80211_ref_node (%s:%u) %p<%s> refcnt %d\n",
21568a1b9b6aSSam Leffler 		__func__, __LINE__,
215749a15236SSam Leffler 		ni, ether_sprintf(ni->ni_macaddr),
21588a1b9b6aSSam Leffler 		ieee80211_node_refcnt(ni)+1);
21590a915fadSSam Leffler 	ieee80211_ref_node(ni);
21608a1b9b6aSSam Leffler 
21618ac160cdSSam Leffler 	memset(&params, 0, sizeof(params));
21621a1e1d21SSam Leffler 	switch (type) {
21631a1e1d21SSam Leffler 
21641a1e1d21SSam Leffler 	case IEEE80211_FC0_SUBTYPE_AUTH:
21658a1b9b6aSSam Leffler 		status = arg >> 16;
21668a1b9b6aSSam Leffler 		arg &= 0xffff;
21678a1b9b6aSSam Leffler 		has_challenge = ((arg == IEEE80211_AUTH_SHARED_CHALLENGE ||
21688a1b9b6aSSam Leffler 		    arg == IEEE80211_AUTH_SHARED_RESPONSE) &&
21698a1b9b6aSSam Leffler 		    ni->ni_challenge != NULL);
21708a1b9b6aSSam Leffler 
21718a1b9b6aSSam Leffler 		/*
21728a1b9b6aSSam Leffler 		 * Deduce whether we're doing open authentication or
21738a1b9b6aSSam Leffler 		 * shared key authentication.  We do the latter if
21748a1b9b6aSSam Leffler 		 * we're in the middle of a shared key authentication
21758a1b9b6aSSam Leffler 		 * handshake or if we're initiating an authentication
21768a1b9b6aSSam Leffler 		 * request and configured to use shared key.
21778a1b9b6aSSam Leffler 		 */
21788a1b9b6aSSam Leffler 		is_shared_key = has_challenge ||
21798a1b9b6aSSam Leffler 		     arg >= IEEE80211_AUTH_SHARED_RESPONSE ||
21808a1b9b6aSSam Leffler 		     (arg == IEEE80211_AUTH_SHARED_REQUEST &&
2181b032f27cSSam Leffler 		      bss->ni_authmode == IEEE80211_AUTH_SHARED);
21828a1b9b6aSSam Leffler 
21838a1b9b6aSSam Leffler 		m = ieee80211_getmgtframe(&frm,
218468e8e04eSSam Leffler 			  ic->ic_headroom + sizeof(struct ieee80211_frame),
218568e8e04eSSam Leffler 			  3 * sizeof(uint16_t)
21868a1b9b6aSSam Leffler 			+ (has_challenge && status == IEEE80211_STATUS_SUCCESS ?
218768e8e04eSSam Leffler 				sizeof(uint16_t)+IEEE80211_CHALLENGE_LEN : 0)
21888a1b9b6aSSam Leffler 		);
21891a1e1d21SSam Leffler 		if (m == NULL)
21908a1b9b6aSSam Leffler 			senderr(ENOMEM, is_tx_nobuf);
21918a1b9b6aSSam Leffler 
219268e8e04eSSam Leffler 		((uint16_t *)frm)[0] =
21938a1b9b6aSSam Leffler 		    (is_shared_key) ? htole16(IEEE80211_AUTH_ALG_SHARED)
21948a1b9b6aSSam Leffler 		                    : htole16(IEEE80211_AUTH_ALG_OPEN);
219568e8e04eSSam Leffler 		((uint16_t *)frm)[1] = htole16(arg);	/* sequence number */
219668e8e04eSSam Leffler 		((uint16_t *)frm)[2] = htole16(status);/* status */
21978a1b9b6aSSam Leffler 
21988a1b9b6aSSam Leffler 		if (has_challenge && status == IEEE80211_STATUS_SUCCESS) {
219968e8e04eSSam Leffler 			((uint16_t *)frm)[3] =
22008a1b9b6aSSam Leffler 			    htole16((IEEE80211_CHALLENGE_LEN << 8) |
22018a1b9b6aSSam Leffler 			    IEEE80211_ELEMID_CHALLENGE);
220268e8e04eSSam Leffler 			memcpy(&((uint16_t *)frm)[4], ni->ni_challenge,
22038a1b9b6aSSam Leffler 			    IEEE80211_CHALLENGE_LEN);
22048a1b9b6aSSam Leffler 			m->m_pkthdr.len = m->m_len =
220568e8e04eSSam Leffler 				4 * sizeof(uint16_t) + IEEE80211_CHALLENGE_LEN;
22068a1b9b6aSSam Leffler 			if (arg == IEEE80211_AUTH_SHARED_RESPONSE) {
2207b032f27cSSam Leffler 				IEEE80211_NOTE(vap, IEEE80211_MSG_AUTH, ni,
2208b032f27cSSam Leffler 				    "request encrypt frame (%s)", __func__);
22098ac160cdSSam Leffler 				/* mark frame for encryption */
22108ac160cdSSam Leffler 				params.ibp_flags |= IEEE80211_BPF_CRYPTO;
22118a1b9b6aSSam Leffler 			}
22128a1b9b6aSSam Leffler 		} else
221368e8e04eSSam Leffler 			m->m_pkthdr.len = m->m_len = 3 * sizeof(uint16_t);
22148a1b9b6aSSam Leffler 
22158a1b9b6aSSam Leffler 		/* XXX not right for shared key */
22168a1b9b6aSSam Leffler 		if (status == IEEE80211_STATUS_SUCCESS)
22178a1b9b6aSSam Leffler 			IEEE80211_NODE_STAT(ni, tx_auth);
22188a1b9b6aSSam Leffler 		else
22198a1b9b6aSSam Leffler 			IEEE80211_NODE_STAT(ni, tx_auth_fail);
22208a1b9b6aSSam Leffler 
2221b032f27cSSam Leffler 		if (vap->iv_opmode == IEEE80211_M_STA)
222268e8e04eSSam Leffler 			ieee80211_add_callback(m, ieee80211_tx_mgt_cb,
2223b032f27cSSam Leffler 				(void *) vap->iv_state);
22241a1e1d21SSam Leffler 		break;
22251a1e1d21SSam Leffler 
22261a1e1d21SSam Leffler 	case IEEE80211_FC0_SUBTYPE_DEAUTH:
2227b032f27cSSam Leffler 		IEEE80211_NOTE(vap, IEEE80211_MSG_AUTH, ni,
2228b032f27cSSam Leffler 		    "send station deauthenticate (reason %d)", arg);
222968e8e04eSSam Leffler 		m = ieee80211_getmgtframe(&frm,
223068e8e04eSSam Leffler 			ic->ic_headroom + sizeof(struct ieee80211_frame),
223168e8e04eSSam Leffler 			sizeof(uint16_t));
22321a1e1d21SSam Leffler 		if (m == NULL)
22338a1b9b6aSSam Leffler 			senderr(ENOMEM, is_tx_nobuf);
223468e8e04eSSam Leffler 		*(uint16_t *)frm = htole16(arg);	/* reason */
223568e8e04eSSam Leffler 		m->m_pkthdr.len = m->m_len = sizeof(uint16_t);
22368a1b9b6aSSam Leffler 
22378a1b9b6aSSam Leffler 		IEEE80211_NODE_STAT(ni, tx_deauth);
22388a1b9b6aSSam Leffler 		IEEE80211_NODE_STAT_SET(ni, tx_deauth_code, arg);
22398a1b9b6aSSam Leffler 
2240e4918ecdSSam Leffler 		ieee80211_node_unauthorize(ni);		/* port closed */
22411a1e1d21SSam Leffler 		break;
22421a1e1d21SSam Leffler 
22431a1e1d21SSam Leffler 	case IEEE80211_FC0_SUBTYPE_ASSOC_REQ:
22441a1e1d21SSam Leffler 	case IEEE80211_FC0_SUBTYPE_REASSOC_REQ:
22451a1e1d21SSam Leffler 		/*
22461a1e1d21SSam Leffler 		 * asreq frame format
22471a1e1d21SSam Leffler 		 *	[2] capability information
22481a1e1d21SSam Leffler 		 *	[2] listen interval
22491a1e1d21SSam Leffler 		 *	[6*] current AP address (reassoc only)
22501a1e1d21SSam Leffler 		 *	[tlv] ssid
22511a1e1d21SSam Leffler 		 *	[tlv] supported rates
22521a1e1d21SSam Leffler 		 *	[tlv] extended supported rates
2253b032f27cSSam Leffler 		 *	[4] power capability (optional)
2254b032f27cSSam Leffler 		 *	[28] supported channels (optional)
225568e8e04eSSam Leffler 		 *	[tlv] HT capabilities
2256b032f27cSSam Leffler 		 *	[tlv] WME (optional)
225768e8e04eSSam Leffler 		 *	[tlv] Vendor OUI HT capabilities (optional)
225868e8e04eSSam Leffler 		 *	[tlv] Atheros capabilities (if negotiated)
2259b032f27cSSam Leffler 		 *	[tlv] AppIE's (optional)
22601a1e1d21SSam Leffler 		 */
22618a1b9b6aSSam Leffler 		m = ieee80211_getmgtframe(&frm,
226268e8e04eSSam Leffler 			 ic->ic_headroom + sizeof(struct ieee80211_frame),
226368e8e04eSSam Leffler 			 sizeof(uint16_t)
226468e8e04eSSam Leffler 		       + sizeof(uint16_t)
22651a1e1d21SSam Leffler 		       + IEEE80211_ADDR_LEN
22668a1b9b6aSSam Leffler 		       + 2 + IEEE80211_NWID_LEN
22671a1e1d21SSam Leffler 		       + 2 + IEEE80211_RATE_SIZE
22688a1b9b6aSSam Leffler 		       + 2 + (IEEE80211_RATE_MAXSIZE - IEEE80211_RATE_SIZE)
2269b032f27cSSam Leffler 		       + 4
2270b032f27cSSam Leffler 		       + 2 + 26
22718a1b9b6aSSam Leffler 		       + sizeof(struct ieee80211_wme_info)
2272b032f27cSSam Leffler 		       + sizeof(struct ieee80211_ie_htcap)
2273b032f27cSSam Leffler 		       + 4 + sizeof(struct ieee80211_ie_htcap)
2274616190d0SSam Leffler #ifdef IEEE80211_SUPPORT_SUPERG
227568e8e04eSSam Leffler 		       + sizeof(struct ieee80211_ath_ie)
2276616190d0SSam Leffler #endif
2277b032f27cSSam Leffler 		       + (vap->iv_appie_wpa != NULL ?
2278b032f27cSSam Leffler 				vap->iv_appie_wpa->ie_len : 0)
2279b032f27cSSam Leffler 		       + (vap->iv_appie_assocreq != NULL ?
2280b032f27cSSam Leffler 				vap->iv_appie_assocreq->ie_len : 0)
22818a1b9b6aSSam Leffler 		);
22821a1e1d21SSam Leffler 		if (m == NULL)
22838a1b9b6aSSam Leffler 			senderr(ENOMEM, is_tx_nobuf);
22841a1e1d21SSam Leffler 
2285b032f27cSSam Leffler 		KASSERT(vap->iv_opmode == IEEE80211_M_STA,
2286b032f27cSSam Leffler 		    ("wrong mode %u", vap->iv_opmode));
2287667dad55SSam Leffler 		capinfo = IEEE80211_CAPINFO_ESS;
2288b032f27cSSam Leffler 		if (vap->iv_flags & IEEE80211_F_PRIVACY)
22891a1e1d21SSam Leffler 			capinfo |= IEEE80211_CAPINFO_PRIVACY;
22904f2e09c4SSam Leffler 		/*
22914f2e09c4SSam Leffler 		 * NB: Some 11a AP's reject the request when
22924f2e09c4SSam Leffler 		 *     short premable is set.
22934f2e09c4SSam Leffler 		 */
22944f2e09c4SSam Leffler 		if ((ic->ic_flags & IEEE80211_F_SHPREAMBLE) &&
2295b5c99415SSam Leffler 		    IEEE80211_IS_CHAN_2GHZ(ic->ic_curchan))
22961a1e1d21SSam Leffler 			capinfo |= IEEE80211_CAPINFO_SHORT_PREAMBLE;
229768e8e04eSSam Leffler 		if (IEEE80211_IS_CHAN_ANYG(ic->ic_curchan) &&
22988a1b9b6aSSam Leffler 		    (ic->ic_caps & IEEE80211_C_SHSLOT))
22991a1e1d21SSam Leffler 			capinfo |= IEEE80211_CAPINFO_SHORT_SLOTTIME;
23001b6167d2SSam Leffler 		if ((ni->ni_capinfo & IEEE80211_CAPINFO_SPECTRUM_MGMT) &&
2301b032f27cSSam Leffler 		    (vap->iv_flags & IEEE80211_F_DOTH))
23021b6167d2SSam Leffler 			capinfo |= IEEE80211_CAPINFO_SPECTRUM_MGMT;
230368e8e04eSSam Leffler 		*(uint16_t *)frm = htole16(capinfo);
23041a1e1d21SSam Leffler 		frm += 2;
23051a1e1d21SSam Leffler 
2306b032f27cSSam Leffler 		KASSERT(bss->ni_intval != 0, ("beacon interval is zero!"));
230768e8e04eSSam Leffler 		*(uint16_t *)frm = htole16(howmany(ic->ic_lintval,
2308b032f27cSSam Leffler 						    bss->ni_intval));
23091a1e1d21SSam Leffler 		frm += 2;
23101a1e1d21SSam Leffler 
23111a1e1d21SSam Leffler 		if (type == IEEE80211_FC0_SUBTYPE_REASSOC_REQ) {
2312b032f27cSSam Leffler 			IEEE80211_ADDR_COPY(frm, bss->ni_bssid);
23131a1e1d21SSam Leffler 			frm += IEEE80211_ADDR_LEN;
23141a1e1d21SSam Leffler 		}
23151a1e1d21SSam Leffler 
23161a1e1d21SSam Leffler 		frm = ieee80211_add_ssid(frm, ni->ni_essid, ni->ni_esslen);
23171a1e1d21SSam Leffler 		frm = ieee80211_add_rates(frm, &ni->ni_rates);
2318d8df5f3dSRui Paulo 		frm = ieee80211_add_rsn(frm, vap);
2319b032f27cSSam Leffler 		frm = ieee80211_add_xrates(frm, &ni->ni_rates);
2320b032f27cSSam Leffler 		if (capinfo & IEEE80211_CAPINFO_SPECTRUM_MGMT) {
2321b032f27cSSam Leffler 			frm = ieee80211_add_powercapability(frm,
2322b032f27cSSam Leffler 			    ic->ic_curchan);
2323b032f27cSSam Leffler 			frm = ieee80211_add_supportedchannels(frm, ic);
2324b032f27cSSam Leffler 		}
23252bfc8a91SSam Leffler 		if ((vap->iv_flags_ht & IEEE80211_FHT_HT) &&
2326b032f27cSSam Leffler 		    ni->ni_ies.htcap_ie != NULL &&
2327b032f27cSSam Leffler 		    ni->ni_ies.htcap_ie[0] == IEEE80211_ELEMID_HTCAP)
2328b032f27cSSam Leffler 			frm = ieee80211_add_htcap(frm, ni);
2329d8df5f3dSRui Paulo 		frm = ieee80211_add_wpa(frm, vap);
2330b032f27cSSam Leffler 		if ((ic->ic_flags & IEEE80211_F_WME) &&
2331b032f27cSSam Leffler 		    ni->ni_ies.wme_ie != NULL)
2332b032f27cSSam Leffler 			frm = ieee80211_add_wme_info(frm, &ic->ic_wme);
23332bfc8a91SSam Leffler 		if ((vap->iv_flags_ht & IEEE80211_FHT_HT) &&
2334b032f27cSSam Leffler 		    ni->ni_ies.htcap_ie != NULL &&
2335b032f27cSSam Leffler 		    ni->ni_ies.htcap_ie[0] == IEEE80211_ELEMID_VENDOR)
2336b032f27cSSam Leffler 			frm = ieee80211_add_htcap_vendor(frm, ni);
2337616190d0SSam Leffler #ifdef IEEE80211_SUPPORT_SUPERG
23384207227cSSam Leffler 		if (IEEE80211_ATH_CAP(vap, ni, IEEE80211_F_ATHEROS)) {
2339b032f27cSSam Leffler 			frm = ieee80211_add_ath(frm,
2340b032f27cSSam Leffler 				IEEE80211_ATH_CAP(vap, ni, IEEE80211_F_ATHEROS),
23414207227cSSam Leffler 				((vap->iv_flags & IEEE80211_F_WPA) == 0 &&
23424207227cSSam Leffler 				 ni->ni_authmode != IEEE80211_AUTH_8021X) ?
23434207227cSSam Leffler 				vap->iv_def_txkey : IEEE80211_KEYIX_NONE);
23444207227cSSam Leffler 		}
2345616190d0SSam Leffler #endif /* IEEE80211_SUPPORT_SUPERG */
2346b032f27cSSam Leffler 		if (vap->iv_appie_assocreq != NULL)
2347b032f27cSSam Leffler 			frm = add_appie(frm, vap->iv_appie_assocreq);
234868e8e04eSSam Leffler 		m->m_pkthdr.len = m->m_len = frm - mtod(m, uint8_t *);
23491a1e1d21SSam Leffler 
235068e8e04eSSam Leffler 		ieee80211_add_callback(m, ieee80211_tx_mgt_cb,
2351b032f27cSSam Leffler 			(void *) vap->iv_state);
23521a1e1d21SSam Leffler 		break;
23531a1e1d21SSam Leffler 
23541a1e1d21SSam Leffler 	case IEEE80211_FC0_SUBTYPE_ASSOC_RESP:
23551a1e1d21SSam Leffler 	case IEEE80211_FC0_SUBTYPE_REASSOC_RESP:
23561a1e1d21SSam Leffler 		/*
235768e8e04eSSam Leffler 		 * asresp frame format
23581a1e1d21SSam Leffler 		 *	[2] capability information
23591a1e1d21SSam Leffler 		 *	[2] status
23601a1e1d21SSam Leffler 		 *	[2] association ID
23611a1e1d21SSam Leffler 		 *	[tlv] supported rates
23621a1e1d21SSam Leffler 		 *	[tlv] extended supported rates
2363b032f27cSSam Leffler 		 *	[tlv] HT capabilities (standard, if STA enabled)
2364b032f27cSSam Leffler 		 *	[tlv] HT information (standard, if STA enabled)
2365b032f27cSSam Leffler 		 *	[tlv] WME (if configured and STA enabled)
2366b032f27cSSam Leffler 		 *	[tlv] HT capabilities (vendor OUI, if STA enabled)
2367b032f27cSSam Leffler 		 *	[tlv] HT information (vendor OUI, if STA enabled)
2368b032f27cSSam Leffler 		 *	[tlv] Atheros capabilities (if STA enabled)
2369b032f27cSSam Leffler 		 *	[tlv] AppIE's (optional)
23701a1e1d21SSam Leffler 		 */
23718a1b9b6aSSam Leffler 		m = ieee80211_getmgtframe(&frm,
237268e8e04eSSam Leffler 			 ic->ic_headroom + sizeof(struct ieee80211_frame),
237368e8e04eSSam Leffler 			 sizeof(uint16_t)
237468e8e04eSSam Leffler 		       + sizeof(uint16_t)
237568e8e04eSSam Leffler 		       + sizeof(uint16_t)
23761a1e1d21SSam Leffler 		       + 2 + IEEE80211_RATE_SIZE
23778a1b9b6aSSam Leffler 		       + 2 + (IEEE80211_RATE_MAXSIZE - IEEE80211_RATE_SIZE)
237868e8e04eSSam Leffler 		       + sizeof(struct ieee80211_ie_htcap) + 4
237968e8e04eSSam Leffler 		       + sizeof(struct ieee80211_ie_htinfo) + 4
2380b032f27cSSam Leffler 		       + sizeof(struct ieee80211_wme_param)
2381616190d0SSam Leffler #ifdef IEEE80211_SUPPORT_SUPERG
238268e8e04eSSam Leffler 		       + sizeof(struct ieee80211_ath_ie)
2383616190d0SSam Leffler #endif
2384b032f27cSSam Leffler 		       + (vap->iv_appie_assocresp != NULL ?
2385b032f27cSSam Leffler 				vap->iv_appie_assocresp->ie_len : 0)
23868a1b9b6aSSam Leffler 		);
23871a1e1d21SSam Leffler 		if (m == NULL)
23888a1b9b6aSSam Leffler 			senderr(ENOMEM, is_tx_nobuf);
23891a1e1d21SSam Leffler 
239059aa14a9SRui Paulo 		capinfo = ieee80211_getcapinfo(vap, bss->ni_chan);
239168e8e04eSSam Leffler 		*(uint16_t *)frm = htole16(capinfo);
23921a1e1d21SSam Leffler 		frm += 2;
23931a1e1d21SSam Leffler 
239468e8e04eSSam Leffler 		*(uint16_t *)frm = htole16(arg);	/* status */
23951a1e1d21SSam Leffler 		frm += 2;
23961a1e1d21SSam Leffler 
23978a1b9b6aSSam Leffler 		if (arg == IEEE80211_STATUS_SUCCESS) {
239868e8e04eSSam Leffler 			*(uint16_t *)frm = htole16(ni->ni_associd);
23998a1b9b6aSSam Leffler 			IEEE80211_NODE_STAT(ni, tx_assoc);
24008a1b9b6aSSam Leffler 		} else
24018a1b9b6aSSam Leffler 			IEEE80211_NODE_STAT(ni, tx_assoc_fail);
24021a1e1d21SSam Leffler 		frm += 2;
24031a1e1d21SSam Leffler 
24041a1e1d21SSam Leffler 		frm = ieee80211_add_rates(frm, &ni->ni_rates);
24051a1e1d21SSam Leffler 		frm = ieee80211_add_xrates(frm, &ni->ni_rates);
240668e8e04eSSam Leffler 		/* NB: respond according to what we received */
24071b6167d2SSam Leffler 		if ((ni->ni_flags & HTFLAGS) == IEEE80211_NODE_HT) {
240868e8e04eSSam Leffler 			frm = ieee80211_add_htcap(frm, ni);
240968e8e04eSSam Leffler 			frm = ieee80211_add_htinfo(frm, ni);
241068e8e04eSSam Leffler 		}
2411b032f27cSSam Leffler 		if ((vap->iv_flags & IEEE80211_F_WME) &&
2412b032f27cSSam Leffler 		    ni->ni_ies.wme_ie != NULL)
24131b6167d2SSam Leffler 			frm = ieee80211_add_wme_param(frm, &ic->ic_wme);
24141b6167d2SSam Leffler 		if ((ni->ni_flags & HTFLAGS) == HTFLAGS) {
24151b6167d2SSam Leffler 			frm = ieee80211_add_htcap_vendor(frm, ni);
24161b6167d2SSam Leffler 			frm = ieee80211_add_htinfo_vendor(frm, ni);
241768e8e04eSSam Leffler 		}
2418616190d0SSam Leffler #ifdef IEEE80211_SUPPORT_SUPERG
2419b032f27cSSam Leffler 		if (IEEE80211_ATH_CAP(vap, ni, IEEE80211_F_ATHEROS))
242068e8e04eSSam Leffler 			frm = ieee80211_add_ath(frm,
2421b032f27cSSam Leffler 				IEEE80211_ATH_CAP(vap, ni, IEEE80211_F_ATHEROS),
24224207227cSSam Leffler 				((vap->iv_flags & IEEE80211_F_WPA) == 0 &&
24234207227cSSam Leffler 				 ni->ni_authmode != IEEE80211_AUTH_8021X) ?
24244207227cSSam Leffler 				vap->iv_def_txkey : IEEE80211_KEYIX_NONE);
2425616190d0SSam Leffler #endif /* IEEE80211_SUPPORT_SUPERG */
2426b032f27cSSam Leffler 		if (vap->iv_appie_assocresp != NULL)
2427b032f27cSSam Leffler 			frm = add_appie(frm, vap->iv_appie_assocresp);
242868e8e04eSSam Leffler 		m->m_pkthdr.len = m->m_len = frm - mtod(m, uint8_t *);
24291a1e1d21SSam Leffler 		break;
24301a1e1d21SSam Leffler 
24311a1e1d21SSam Leffler 	case IEEE80211_FC0_SUBTYPE_DISASSOC:
2432b032f27cSSam Leffler 		IEEE80211_NOTE(vap, IEEE80211_MSG_ASSOC, ni,
2433b032f27cSSam Leffler 		    "send station disassociate (reason %d)", arg);
243468e8e04eSSam Leffler 		m = ieee80211_getmgtframe(&frm,
243568e8e04eSSam Leffler 			ic->ic_headroom + sizeof(struct ieee80211_frame),
243668e8e04eSSam Leffler 			sizeof(uint16_t));
24371a1e1d21SSam Leffler 		if (m == NULL)
24388a1b9b6aSSam Leffler 			senderr(ENOMEM, is_tx_nobuf);
243968e8e04eSSam Leffler 		*(uint16_t *)frm = htole16(arg);	/* reason */
244068e8e04eSSam Leffler 		m->m_pkthdr.len = m->m_len = sizeof(uint16_t);
24418a1b9b6aSSam Leffler 
24428a1b9b6aSSam Leffler 		IEEE80211_NODE_STAT(ni, tx_disassoc);
24438a1b9b6aSSam Leffler 		IEEE80211_NODE_STAT_SET(ni, tx_disassoc_code, arg);
24441a1e1d21SSam Leffler 		break;
24451a1e1d21SSam Leffler 
24461a1e1d21SSam Leffler 	default:
2447b032f27cSSam Leffler 		IEEE80211_NOTE(vap, IEEE80211_MSG_ANY, ni,
2448b032f27cSSam Leffler 		    "invalid mgmt frame type %u", type);
24491be50176SSam Leffler 		senderr(EINVAL, is_tx_unknownmgt);
24500a915fadSSam Leffler 		/* NOTREACHED */
24511a1e1d21SSam Leffler 	}
245268e8e04eSSam Leffler 
24538ac160cdSSam Leffler 	/* NB: force non-ProbeResp frames to the highest queue */
24548ac160cdSSam Leffler 	params.ibp_pri = WME_AC_VO;
24558ac160cdSSam Leffler 	params.ibp_rate0 = bss->ni_txparms->mgmtrate;
24568ac160cdSSam Leffler 	/* NB: we know all frames are unicast */
24578ac160cdSSam Leffler 	params.ibp_try0 = bss->ni_txparms->maxretry;
24588ac160cdSSam Leffler 	params.ibp_power = bss->ni_txpower;
24598ac160cdSSam Leffler 	return ieee80211_mgmt_output(ni, m, type, &params);
24600a915fadSSam Leffler bad:
24618a1b9b6aSSam Leffler 	ieee80211_free_node(ni);
24621a1e1d21SSam Leffler 	return ret;
24630a915fadSSam Leffler #undef senderr
24641b6167d2SSam Leffler #undef HTFLAGS
24651a1e1d21SSam Leffler }
24668a1b9b6aSSam Leffler 
2467b032f27cSSam Leffler /*
2468b032f27cSSam Leffler  * Return an mbuf with a probe response frame in it.
2469b032f27cSSam Leffler  * Space is left to prepend and 802.11 header at the
2470b032f27cSSam Leffler  * front but it's left to the caller to fill in.
2471b032f27cSSam Leffler  */
2472b032f27cSSam Leffler struct mbuf *
2473b032f27cSSam Leffler ieee80211_alloc_proberesp(struct ieee80211_node *bss, int legacy)
2474b032f27cSSam Leffler {
2475b032f27cSSam Leffler 	struct ieee80211vap *vap = bss->ni_vap;
2476b032f27cSSam Leffler 	struct ieee80211com *ic = bss->ni_ic;
2477b032f27cSSam Leffler 	const struct ieee80211_rateset *rs;
2478b032f27cSSam Leffler 	struct mbuf *m;
2479b032f27cSSam Leffler 	uint16_t capinfo;
2480b032f27cSSam Leffler 	uint8_t *frm;
2481b032f27cSSam Leffler 
2482b032f27cSSam Leffler 	/*
2483b032f27cSSam Leffler 	 * probe response frame format
2484b032f27cSSam Leffler 	 *	[8] time stamp
2485b032f27cSSam Leffler 	 *	[2] beacon interval
2486b032f27cSSam Leffler 	 *	[2] cabability information
2487b032f27cSSam Leffler 	 *	[tlv] ssid
2488b032f27cSSam Leffler 	 *	[tlv] supported rates
2489b032f27cSSam Leffler 	 *	[tlv] parameter set (FH/DS)
2490b032f27cSSam Leffler 	 *	[tlv] parameter set (IBSS)
2491b032f27cSSam Leffler 	 *	[tlv] country (optional)
2492b032f27cSSam Leffler 	 *	[3] power control (optional)
2493b032f27cSSam Leffler 	 *	[5] channel switch announcement (CSA) (optional)
2494b032f27cSSam Leffler 	 *	[tlv] extended rate phy (ERP)
2495b032f27cSSam Leffler 	 *	[tlv] extended supported rates
2496688fe74dSSam Leffler 	 *	[tlv] RSN (optional)
2497b032f27cSSam Leffler 	 *	[tlv] HT capabilities
2498b032f27cSSam Leffler 	 *	[tlv] HT information
2499b032f27cSSam Leffler 	 *	[tlv] WPA (optional)
2500b032f27cSSam Leffler 	 *	[tlv] WME (optional)
2501b032f27cSSam Leffler 	 *	[tlv] Vendor OUI HT capabilities (optional)
2502b032f27cSSam Leffler 	 *	[tlv] Vendor OUI HT information (optional)
2503b032f27cSSam Leffler 	 *	[tlv] Atheros capabilities
2504b032f27cSSam Leffler 	 *	[tlv] AppIE's (optional)
250559aa14a9SRui Paulo 	 *	[tlv] Mesh ID (MBSS)
250659aa14a9SRui Paulo 	 *	[tlv] Mesh Conf (MBSS)
2507b032f27cSSam Leffler 	 */
2508b032f27cSSam Leffler 	m = ieee80211_getmgtframe(&frm,
2509b032f27cSSam Leffler 		 ic->ic_headroom + sizeof(struct ieee80211_frame),
2510b032f27cSSam Leffler 		 8
2511b032f27cSSam Leffler 	       + sizeof(uint16_t)
2512b032f27cSSam Leffler 	       + sizeof(uint16_t)
2513b032f27cSSam Leffler 	       + 2 + IEEE80211_NWID_LEN
2514b032f27cSSam Leffler 	       + 2 + IEEE80211_RATE_SIZE
2515b032f27cSSam Leffler 	       + 7	/* max(7,3) */
2516b032f27cSSam Leffler 	       + IEEE80211_COUNTRY_MAX_SIZE
2517b032f27cSSam Leffler 	       + 3
2518b032f27cSSam Leffler 	       + sizeof(struct ieee80211_csa_ie)
251932b0e64bSAdrian Chadd 	       + sizeof(struct ieee80211_quiet_ie)
2520b032f27cSSam Leffler 	       + 3
2521b032f27cSSam Leffler 	       + 2 + (IEEE80211_RATE_MAXSIZE - IEEE80211_RATE_SIZE)
2522688fe74dSSam Leffler 	       + sizeof(struct ieee80211_ie_wpa)
2523b032f27cSSam Leffler 	       + sizeof(struct ieee80211_ie_htcap)
2524b032f27cSSam Leffler 	       + sizeof(struct ieee80211_ie_htinfo)
2525b032f27cSSam Leffler 	       + sizeof(struct ieee80211_ie_wpa)
2526b032f27cSSam Leffler 	       + sizeof(struct ieee80211_wme_param)
2527b032f27cSSam Leffler 	       + 4 + sizeof(struct ieee80211_ie_htcap)
2528b032f27cSSam Leffler 	       + 4 + sizeof(struct ieee80211_ie_htinfo)
2529616190d0SSam Leffler #ifdef IEEE80211_SUPPORT_SUPERG
2530b032f27cSSam Leffler 	       + sizeof(struct ieee80211_ath_ie)
2531616190d0SSam Leffler #endif
253259aa14a9SRui Paulo #ifdef IEEE80211_SUPPORT_MESH
253359aa14a9SRui Paulo 	       + 2 + IEEE80211_MESHID_LEN
253459aa14a9SRui Paulo 	       + sizeof(struct ieee80211_meshconf_ie)
253559aa14a9SRui Paulo #endif
2536b032f27cSSam Leffler 	       + (vap->iv_appie_proberesp != NULL ?
2537b032f27cSSam Leffler 			vap->iv_appie_proberesp->ie_len : 0)
2538b032f27cSSam Leffler 	);
2539b032f27cSSam Leffler 	if (m == NULL) {
2540b032f27cSSam Leffler 		vap->iv_stats.is_tx_nobuf++;
2541b032f27cSSam Leffler 		return NULL;
2542b032f27cSSam Leffler 	}
2543b032f27cSSam Leffler 
2544b032f27cSSam Leffler 	memset(frm, 0, 8);	/* timestamp should be filled later */
2545b032f27cSSam Leffler 	frm += 8;
2546b032f27cSSam Leffler 	*(uint16_t *)frm = htole16(bss->ni_intval);
2547b032f27cSSam Leffler 	frm += 2;
254859aa14a9SRui Paulo 	capinfo = ieee80211_getcapinfo(vap, bss->ni_chan);
2549b032f27cSSam Leffler 	*(uint16_t *)frm = htole16(capinfo);
2550b032f27cSSam Leffler 	frm += 2;
2551b032f27cSSam Leffler 
2552b032f27cSSam Leffler 	frm = ieee80211_add_ssid(frm, bss->ni_essid, bss->ni_esslen);
2553b032f27cSSam Leffler 	rs = ieee80211_get_suprates(ic, bss->ni_chan);
2554b032f27cSSam Leffler 	frm = ieee80211_add_rates(frm, rs);
2555b032f27cSSam Leffler 
2556b032f27cSSam Leffler 	if (IEEE80211_IS_CHAN_FHSS(bss->ni_chan)) {
2557b032f27cSSam Leffler 		*frm++ = IEEE80211_ELEMID_FHPARMS;
2558b032f27cSSam Leffler 		*frm++ = 5;
2559b032f27cSSam Leffler 		*frm++ = bss->ni_fhdwell & 0x00ff;
2560b032f27cSSam Leffler 		*frm++ = (bss->ni_fhdwell >> 8) & 0x00ff;
2561b032f27cSSam Leffler 		*frm++ = IEEE80211_FH_CHANSET(
2562b032f27cSSam Leffler 		    ieee80211_chan2ieee(ic, bss->ni_chan));
2563b032f27cSSam Leffler 		*frm++ = IEEE80211_FH_CHANPAT(
2564b032f27cSSam Leffler 		    ieee80211_chan2ieee(ic, bss->ni_chan));
2565b032f27cSSam Leffler 		*frm++ = bss->ni_fhindex;
2566b032f27cSSam Leffler 	} else {
2567b032f27cSSam Leffler 		*frm++ = IEEE80211_ELEMID_DSPARMS;
2568b032f27cSSam Leffler 		*frm++ = 1;
2569b032f27cSSam Leffler 		*frm++ = ieee80211_chan2ieee(ic, bss->ni_chan);
2570b032f27cSSam Leffler 	}
2571b032f27cSSam Leffler 
2572b032f27cSSam Leffler 	if (vap->iv_opmode == IEEE80211_M_IBSS) {
2573b032f27cSSam Leffler 		*frm++ = IEEE80211_ELEMID_IBSSPARMS;
2574b032f27cSSam Leffler 		*frm++ = 2;
2575b032f27cSSam Leffler 		*frm++ = 0; *frm++ = 0;		/* TODO: ATIM window */
2576b032f27cSSam Leffler 	}
2577b032f27cSSam Leffler 	if ((vap->iv_flags & IEEE80211_F_DOTH) ||
2578b032f27cSSam Leffler 	    (vap->iv_flags_ext & IEEE80211_FEXT_DOTD))
2579b032f27cSSam Leffler 		frm = ieee80211_add_countryie(frm, ic);
2580b032f27cSSam Leffler 	if (vap->iv_flags & IEEE80211_F_DOTH) {
2581b032f27cSSam Leffler 		if (IEEE80211_IS_CHAN_5GHZ(bss->ni_chan))
2582b032f27cSSam Leffler 			frm = ieee80211_add_powerconstraint(frm, vap);
2583b032f27cSSam Leffler 		if (ic->ic_flags & IEEE80211_F_CSAPENDING)
2584b032f27cSSam Leffler 			frm = ieee80211_add_csa(frm, vap);
2585b032f27cSSam Leffler 	}
258632b0e64bSAdrian Chadd 	if (vap->iv_flags & IEEE80211_F_DOTH) {
258732b0e64bSAdrian Chadd 		if (IEEE80211_IS_CHAN_DFS(ic->ic_bsschan) &&
258832b0e64bSAdrian Chadd 		    (vap->iv_flags_ext & IEEE80211_FEXT_DFS)) {
258932b0e64bSAdrian Chadd 			if (vap->iv_quiet)
259032b0e64bSAdrian Chadd 				frm = ieee80211_add_quiet(frm, vap);
259132b0e64bSAdrian Chadd 		}
259232b0e64bSAdrian Chadd 	}
2593b032f27cSSam Leffler 	if (IEEE80211_IS_CHAN_ANYG(bss->ni_chan))
2594b032f27cSSam Leffler 		frm = ieee80211_add_erp(frm, ic);
2595b032f27cSSam Leffler 	frm = ieee80211_add_xrates(frm, rs);
2596d8df5f3dSRui Paulo 	frm = ieee80211_add_rsn(frm, vap);
2597b032f27cSSam Leffler 	/*
2598b032f27cSSam Leffler 	 * NB: legacy 11b clients do not get certain ie's.
2599b032f27cSSam Leffler 	 *     The caller identifies such clients by passing
2600b032f27cSSam Leffler 	 *     a token in legacy to us.  Could expand this to be
2601b032f27cSSam Leffler 	 *     any legacy client for stuff like HT ie's.
2602b032f27cSSam Leffler 	 */
2603b032f27cSSam Leffler 	if (IEEE80211_IS_CHAN_HT(bss->ni_chan) &&
2604b032f27cSSam Leffler 	    legacy != IEEE80211_SEND_LEGACY_11B) {
2605b032f27cSSam Leffler 		frm = ieee80211_add_htcap(frm, bss);
2606b032f27cSSam Leffler 		frm = ieee80211_add_htinfo(frm, bss);
2607b032f27cSSam Leffler 	}
2608d8df5f3dSRui Paulo 	frm = ieee80211_add_wpa(frm, vap);
2609b032f27cSSam Leffler 	if (vap->iv_flags & IEEE80211_F_WME)
2610b032f27cSSam Leffler 		frm = ieee80211_add_wme_param(frm, &ic->ic_wme);
2611b032f27cSSam Leffler 	if (IEEE80211_IS_CHAN_HT(bss->ni_chan) &&
26122bfc8a91SSam Leffler 	    (vap->iv_flags_ht & IEEE80211_FHT_HTCOMPAT) &&
2613b032f27cSSam Leffler 	    legacy != IEEE80211_SEND_LEGACY_11B) {
2614b032f27cSSam Leffler 		frm = ieee80211_add_htcap_vendor(frm, bss);
2615b032f27cSSam Leffler 		frm = ieee80211_add_htinfo_vendor(frm, bss);
2616b032f27cSSam Leffler 	}
2617616190d0SSam Leffler #ifdef IEEE80211_SUPPORT_SUPERG
26184207227cSSam Leffler 	if ((vap->iv_flags & IEEE80211_F_ATHEROS) &&
26194207227cSSam Leffler 	    legacy != IEEE80211_SEND_LEGACY_11B)
26204207227cSSam Leffler 		frm = ieee80211_add_athcaps(frm, bss);
2621616190d0SSam Leffler #endif
2622b032f27cSSam Leffler 	if (vap->iv_appie_proberesp != NULL)
2623b032f27cSSam Leffler 		frm = add_appie(frm, vap->iv_appie_proberesp);
262459aa14a9SRui Paulo #ifdef IEEE80211_SUPPORT_MESH
262559aa14a9SRui Paulo 	if (vap->iv_opmode == IEEE80211_M_MBSS) {
262659aa14a9SRui Paulo 		frm = ieee80211_add_meshid(frm, vap);
262759aa14a9SRui Paulo 		frm = ieee80211_add_meshconf(frm, vap);
262859aa14a9SRui Paulo 	}
262959aa14a9SRui Paulo #endif
2630b032f27cSSam Leffler 	m->m_pkthdr.len = m->m_len = frm - mtod(m, uint8_t *);
2631b032f27cSSam Leffler 
2632b032f27cSSam Leffler 	return m;
2633b032f27cSSam Leffler }
2634b032f27cSSam Leffler 
2635b032f27cSSam Leffler /*
2636b032f27cSSam Leffler  * Send a probe response frame to the specified mac address.
2637b032f27cSSam Leffler  * This does not go through the normal mgt frame api so we
2638b032f27cSSam Leffler  * can specify the destination address and re-use the bss node
2639b032f27cSSam Leffler  * for the sta reference.
2640b032f27cSSam Leffler  */
2641b032f27cSSam Leffler int
2642b032f27cSSam Leffler ieee80211_send_proberesp(struct ieee80211vap *vap,
2643b032f27cSSam Leffler 	const uint8_t da[IEEE80211_ADDR_LEN], int legacy)
2644b032f27cSSam Leffler {
2645b032f27cSSam Leffler 	struct ieee80211_node *bss = vap->iv_bss;
2646b032f27cSSam Leffler 	struct ieee80211com *ic = vap->iv_ic;
2647b032f27cSSam Leffler 	struct ieee80211_frame *wh;
2648b032f27cSSam Leffler 	struct mbuf *m;
26495cda6006SAdrian Chadd 	int ret;
2650b032f27cSSam Leffler 
2651b032f27cSSam Leffler 	if (vap->iv_state == IEEE80211_S_CAC) {
2652b032f27cSSam Leffler 		IEEE80211_NOTE(vap, IEEE80211_MSG_OUTPUT, bss,
2653b032f27cSSam Leffler 		    "block %s frame in CAC state", "probe response");
2654b032f27cSSam Leffler 		vap->iv_stats.is_tx_badstate++;
2655b032f27cSSam Leffler 		return EIO;		/* XXX */
2656b032f27cSSam Leffler 	}
2657b032f27cSSam Leffler 
2658b032f27cSSam Leffler 	/*
2659b032f27cSSam Leffler 	 * Hold a reference on the node so it doesn't go away until after
2660b032f27cSSam Leffler 	 * the xmit is complete all the way in the driver.  On error we
2661b032f27cSSam Leffler 	 * will remove our reference.
2662b032f27cSSam Leffler 	 */
2663b032f27cSSam Leffler 	IEEE80211_DPRINTF(vap, IEEE80211_MSG_NODE,
2664b032f27cSSam Leffler 	    "ieee80211_ref_node (%s:%u) %p<%s> refcnt %d\n",
2665b032f27cSSam Leffler 	    __func__, __LINE__, bss, ether_sprintf(bss->ni_macaddr),
2666b032f27cSSam Leffler 	    ieee80211_node_refcnt(bss)+1);
2667b032f27cSSam Leffler 	ieee80211_ref_node(bss);
2668b032f27cSSam Leffler 
2669b032f27cSSam Leffler 	m = ieee80211_alloc_proberesp(bss, legacy);
2670b032f27cSSam Leffler 	if (m == NULL) {
2671b032f27cSSam Leffler 		ieee80211_free_node(bss);
2672b032f27cSSam Leffler 		return ENOMEM;
2673b032f27cSSam Leffler 	}
2674b032f27cSSam Leffler 
2675eb1b1807SGleb Smirnoff 	M_PREPEND(m, sizeof(struct ieee80211_frame), M_NOWAIT);
2676b032f27cSSam Leffler 	KASSERT(m != NULL, ("no room for header"));
2677b032f27cSSam Leffler 
26785cda6006SAdrian Chadd 	IEEE80211_TX_LOCK(ic);
2679b032f27cSSam Leffler 	wh = mtod(m, struct ieee80211_frame *);
26809e80b1dfSSam Leffler 	ieee80211_send_setup(bss, m,
2681b032f27cSSam Leffler 	     IEEE80211_FC0_TYPE_MGT | IEEE80211_FC0_SUBTYPE_PROBE_RESP,
26828ac160cdSSam Leffler 	     IEEE80211_NONQOS_TID, vap->iv_myaddr, da, bss->ni_bssid);
2683b032f27cSSam Leffler 	/* XXX power management? */
2684c1af44bdSSam Leffler 	m->m_flags |= M_ENCAP;		/* mark encapsulated */
2685b032f27cSSam Leffler 
2686b032f27cSSam Leffler 	M_WME_SETAC(m, WME_AC_BE);
2687b032f27cSSam Leffler 
2688b032f27cSSam Leffler 	IEEE80211_DPRINTF(vap, IEEE80211_MSG_DEBUG | IEEE80211_MSG_DUMPPKTS,
2689b032f27cSSam Leffler 	    "send probe resp on channel %u to %s%s\n",
2690b032f27cSSam Leffler 	    ieee80211_chan2ieee(ic, ic->ic_curchan), ether_sprintf(da),
2691b032f27cSSam Leffler 	    legacy ? " <legacy>" : "");
2692b032f27cSSam Leffler 	IEEE80211_NODE_STAT(bss, tx_mgmt);
2693b032f27cSSam Leffler 
26945cda6006SAdrian Chadd 	ret = ieee80211_raw_output(vap, bss, m, NULL);
26955cda6006SAdrian Chadd 	IEEE80211_TX_UNLOCK(ic);
26965cda6006SAdrian Chadd 	return (ret);
2697b032f27cSSam Leffler }
2698b032f27cSSam Leffler 
2699b032f27cSSam Leffler /*
2700b032f27cSSam Leffler  * Allocate and build a RTS (Request To Send) control frame.
2701b032f27cSSam Leffler  */
2702b032f27cSSam Leffler struct mbuf *
2703b032f27cSSam Leffler ieee80211_alloc_rts(struct ieee80211com *ic,
2704b032f27cSSam Leffler 	const uint8_t ra[IEEE80211_ADDR_LEN],
2705b032f27cSSam Leffler 	const uint8_t ta[IEEE80211_ADDR_LEN],
2706b032f27cSSam Leffler 	uint16_t dur)
2707b032f27cSSam Leffler {
2708b032f27cSSam Leffler 	struct ieee80211_frame_rts *rts;
2709b032f27cSSam Leffler 	struct mbuf *m;
2710b032f27cSSam Leffler 
2711b032f27cSSam Leffler 	/* XXX honor ic_headroom */
2712eb1b1807SGleb Smirnoff 	m = m_gethdr(M_NOWAIT, MT_DATA);
2713b032f27cSSam Leffler 	if (m != NULL) {
2714b032f27cSSam Leffler 		rts = mtod(m, struct ieee80211_frame_rts *);
2715b032f27cSSam Leffler 		rts->i_fc[0] = IEEE80211_FC0_VERSION_0 |
2716b032f27cSSam Leffler 			IEEE80211_FC0_TYPE_CTL | IEEE80211_FC0_SUBTYPE_RTS;
2717b032f27cSSam Leffler 		rts->i_fc[1] = IEEE80211_FC1_DIR_NODS;
2718b032f27cSSam Leffler 		*(u_int16_t *)rts->i_dur = htole16(dur);
2719b032f27cSSam Leffler 		IEEE80211_ADDR_COPY(rts->i_ra, ra);
2720b032f27cSSam Leffler 		IEEE80211_ADDR_COPY(rts->i_ta, ta);
2721b032f27cSSam Leffler 
2722b032f27cSSam Leffler 		m->m_pkthdr.len = m->m_len = sizeof(struct ieee80211_frame_rts);
2723b032f27cSSam Leffler 	}
2724b032f27cSSam Leffler 	return m;
2725b032f27cSSam Leffler }
2726b032f27cSSam Leffler 
2727b032f27cSSam Leffler /*
2728b032f27cSSam Leffler  * Allocate and build a CTS (Clear To Send) control frame.
2729b032f27cSSam Leffler  */
2730b032f27cSSam Leffler struct mbuf *
2731b032f27cSSam Leffler ieee80211_alloc_cts(struct ieee80211com *ic,
2732b032f27cSSam Leffler 	const uint8_t ra[IEEE80211_ADDR_LEN], uint16_t dur)
2733b032f27cSSam Leffler {
2734b032f27cSSam Leffler 	struct ieee80211_frame_cts *cts;
2735b032f27cSSam Leffler 	struct mbuf *m;
2736b032f27cSSam Leffler 
2737b032f27cSSam Leffler 	/* XXX honor ic_headroom */
2738eb1b1807SGleb Smirnoff 	m = m_gethdr(M_NOWAIT, MT_DATA);
2739b032f27cSSam Leffler 	if (m != NULL) {
2740b032f27cSSam Leffler 		cts = mtod(m, struct ieee80211_frame_cts *);
2741b032f27cSSam Leffler 		cts->i_fc[0] = IEEE80211_FC0_VERSION_0 |
2742b032f27cSSam Leffler 			IEEE80211_FC0_TYPE_CTL | IEEE80211_FC0_SUBTYPE_CTS;
2743b032f27cSSam Leffler 		cts->i_fc[1] = IEEE80211_FC1_DIR_NODS;
2744b032f27cSSam Leffler 		*(u_int16_t *)cts->i_dur = htole16(dur);
2745b032f27cSSam Leffler 		IEEE80211_ADDR_COPY(cts->i_ra, ra);
2746b032f27cSSam Leffler 
2747b032f27cSSam Leffler 		m->m_pkthdr.len = m->m_len = sizeof(struct ieee80211_frame_cts);
2748b032f27cSSam Leffler 	}
2749b032f27cSSam Leffler 	return m;
2750b032f27cSSam Leffler }
2751b032f27cSSam Leffler 
275268e8e04eSSam Leffler static void
275368e8e04eSSam Leffler ieee80211_tx_mgt_timeout(void *arg)
275468e8e04eSSam Leffler {
2755e94527beSAdrian Chadd 	struct ieee80211vap *vap = arg;
275668e8e04eSSam Leffler 
2757e94527beSAdrian Chadd 	IEEE80211_LOCK(vap->iv_ic);
2758b032f27cSSam Leffler 	if (vap->iv_state != IEEE80211_S_INIT &&
2759b032f27cSSam Leffler 	    (vap->iv_ic->ic_flags & IEEE80211_F_SCAN) == 0) {
276068e8e04eSSam Leffler 		/*
276168e8e04eSSam Leffler 		 * NB: it's safe to specify a timeout as the reason here;
276268e8e04eSSam Leffler 		 *     it'll only be used in the right state.
276368e8e04eSSam Leffler 		 */
2764e94527beSAdrian Chadd 		ieee80211_new_state_locked(vap, IEEE80211_S_SCAN,
276568e8e04eSSam Leffler 			IEEE80211_SCAN_FAIL_TIMEOUT);
276668e8e04eSSam Leffler 	}
2767e94527beSAdrian Chadd 	IEEE80211_UNLOCK(vap->iv_ic);
276868e8e04eSSam Leffler }
276968e8e04eSSam Leffler 
2770e94527beSAdrian Chadd /*
2771e94527beSAdrian Chadd  * This is the callback set on net80211-sourced transmitted
2772e94527beSAdrian Chadd  * authentication request frames.
2773e94527beSAdrian Chadd  *
2774e94527beSAdrian Chadd  * This does a couple of things:
2775e94527beSAdrian Chadd  *
2776e94527beSAdrian Chadd  * + If the frame transmitted was a success, it schedules a future
2777e94527beSAdrian Chadd  *   event which will transition the interface to scan.
2778e94527beSAdrian Chadd  *   If a state transition _then_ occurs before that event occurs,
2779e94527beSAdrian Chadd  *   said state transition will cancel this callout.
2780e94527beSAdrian Chadd  *
2781e94527beSAdrian Chadd  * + If the frame transmit was a failure, it immediately schedules
2782e94527beSAdrian Chadd  *   the transition back to scan.
2783e94527beSAdrian Chadd  */
278468e8e04eSSam Leffler static void
278568e8e04eSSam Leffler ieee80211_tx_mgt_cb(struct ieee80211_node *ni, void *arg, int status)
278668e8e04eSSam Leffler {
2787b032f27cSSam Leffler 	struct ieee80211vap *vap = ni->ni_vap;
278868e8e04eSSam Leffler 	enum ieee80211_state ostate = (enum ieee80211_state) arg;
278968e8e04eSSam Leffler 
279068e8e04eSSam Leffler 	/*
279168e8e04eSSam Leffler 	 * Frame transmit completed; arrange timer callback.  If
279268e8e04eSSam Leffler 	 * transmit was successfuly we wait for response.  Otherwise
279368e8e04eSSam Leffler 	 * we arrange an immediate callback instead of doing the
279468e8e04eSSam Leffler 	 * callback directly since we don't know what state the driver
279568e8e04eSSam Leffler 	 * is in (e.g. what locks it is holding).  This work should
279668e8e04eSSam Leffler 	 * not be too time-critical and not happen too often so the
279768e8e04eSSam Leffler 	 * added overhead is acceptable.
279868e8e04eSSam Leffler 	 *
279968e8e04eSSam Leffler 	 * XXX what happens if !acked but response shows up before callback?
280068e8e04eSSam Leffler 	 */
2801e94527beSAdrian Chadd 	if (vap->iv_state == ostate) {
2802b032f27cSSam Leffler 		callout_reset(&vap->iv_mgtsend,
280368e8e04eSSam Leffler 			status == 0 ? IEEE80211_TRANS_WAIT*hz : 0,
2804e94527beSAdrian Chadd 			ieee80211_tx_mgt_timeout, vap);
2805e94527beSAdrian Chadd 	}
280668e8e04eSSam Leffler }
280768e8e04eSSam Leffler 
2808b032f27cSSam Leffler static void
2809b032f27cSSam Leffler ieee80211_beacon_construct(struct mbuf *m, uint8_t *frm,
2810b032f27cSSam Leffler 	struct ieee80211_beacon_offsets *bo, struct ieee80211_node *ni)
28118a1b9b6aSSam Leffler {
2812b032f27cSSam Leffler 	struct ieee80211vap *vap = ni->ni_vap;
2813b105a069SSam Leffler 	struct ieee80211com *ic = ni->ni_ic;
2814b032f27cSSam Leffler 	struct ieee80211_rateset *rs = &ni->ni_rates;
281568e8e04eSSam Leffler 	uint16_t capinfo;
28168a1b9b6aSSam Leffler 
28178a1b9b6aSSam Leffler 	/*
28188a1b9b6aSSam Leffler 	 * beacon frame format
28198a1b9b6aSSam Leffler 	 *	[8] time stamp
28208a1b9b6aSSam Leffler 	 *	[2] beacon interval
28218a1b9b6aSSam Leffler 	 *	[2] cabability information
28228a1b9b6aSSam Leffler 	 *	[tlv] ssid
28238a1b9b6aSSam Leffler 	 *	[tlv] supported rates
28248a1b9b6aSSam Leffler 	 *	[3] parameter set (DS)
2825b032f27cSSam Leffler 	 *	[8] CF parameter set (optional)
28268a1b9b6aSSam Leffler 	 *	[tlv] parameter set (IBSS/TIM)
2827b032f27cSSam Leffler 	 *	[tlv] country (optional)
2828b032f27cSSam Leffler 	 *	[3] power control (optional)
2829b032f27cSSam Leffler 	 *	[5] channel switch announcement (CSA) (optional)
28308a1b9b6aSSam Leffler 	 *	[tlv] extended rate phy (ERP)
28318a1b9b6aSSam Leffler 	 *	[tlv] extended supported rates
2832688fe74dSSam Leffler 	 *	[tlv] RSN parameters
283368e8e04eSSam Leffler 	 *	[tlv] HT capabilities
283468e8e04eSSam Leffler 	 *	[tlv] HT information
2835b032f27cSSam Leffler 	 * XXX Vendor-specific OIDs (e.g. Atheros)
2836b032f27cSSam Leffler 	 *	[tlv] WPA parameters
2837b032f27cSSam Leffler 	 *	[tlv] WME parameters
283868e8e04eSSam Leffler 	 *	[tlv] Vendor OUI HT capabilities (optional)
283968e8e04eSSam Leffler 	 *	[tlv] Vendor OUI HT information (optional)
28404207227cSSam Leffler 	 *	[tlv] Atheros capabilities (optional)
284110ad9a77SSam Leffler 	 *	[tlv] TDMA parameters (optional)
284259aa14a9SRui Paulo 	 *	[tlv] Mesh ID (MBSS)
284359aa14a9SRui Paulo 	 *	[tlv] Mesh Conf (MBSS)
2844b032f27cSSam Leffler 	 *	[tlv] application data (optional)
28458a1b9b6aSSam Leffler 	 */
28468a1b9b6aSSam Leffler 
28471b6167d2SSam Leffler 	memset(bo, 0, sizeof(*bo));
28481b6167d2SSam Leffler 
28498a1b9b6aSSam Leffler 	memset(frm, 0, 8);	/* XXX timestamp is set by hardware/driver */
28508a1b9b6aSSam Leffler 	frm += 8;
285168e8e04eSSam Leffler 	*(uint16_t *)frm = htole16(ni->ni_intval);
28528a1b9b6aSSam Leffler 	frm += 2;
285359aa14a9SRui Paulo 	capinfo = ieee80211_getcapinfo(vap, ni->ni_chan);
285468e8e04eSSam Leffler 	bo->bo_caps = (uint16_t *)frm;
285568e8e04eSSam Leffler 	*(uint16_t *)frm = htole16(capinfo);
28568a1b9b6aSSam Leffler 	frm += 2;
28578a1b9b6aSSam Leffler 	*frm++ = IEEE80211_ELEMID_SSID;
2858b032f27cSSam Leffler 	if ((vap->iv_flags & IEEE80211_F_HIDESSID) == 0) {
28598a1b9b6aSSam Leffler 		*frm++ = ni->ni_esslen;
28608a1b9b6aSSam Leffler 		memcpy(frm, ni->ni_essid, ni->ni_esslen);
28618a1b9b6aSSam Leffler 		frm += ni->ni_esslen;
28628a1b9b6aSSam Leffler 	} else
28638a1b9b6aSSam Leffler 		*frm++ = 0;
28648a1b9b6aSSam Leffler 	frm = ieee80211_add_rates(frm, rs);
2865b032f27cSSam Leffler 	if (!IEEE80211_IS_CHAN_FHSS(ni->ni_chan)) {
28668a1b9b6aSSam Leffler 		*frm++ = IEEE80211_ELEMID_DSPARMS;
28678a1b9b6aSSam Leffler 		*frm++ = 1;
2868b032f27cSSam Leffler 		*frm++ = ieee80211_chan2ieee(ic, ni->ni_chan);
2869b032f27cSSam Leffler 	}
2870b032f27cSSam Leffler 	if (ic->ic_flags & IEEE80211_F_PCF) {
2871b032f27cSSam Leffler 		bo->bo_cfp = frm;
2872b032f27cSSam Leffler 		frm = ieee80211_add_cfparms(frm, ic);
28738a1b9b6aSSam Leffler 	}
28748a1b9b6aSSam Leffler 	bo->bo_tim = frm;
2875b032f27cSSam Leffler 	if (vap->iv_opmode == IEEE80211_M_IBSS) {
28768a1b9b6aSSam Leffler 		*frm++ = IEEE80211_ELEMID_IBSSPARMS;
28778a1b9b6aSSam Leffler 		*frm++ = 2;
28788a1b9b6aSSam Leffler 		*frm++ = 0; *frm++ = 0;		/* TODO: ATIM window */
28798a1b9b6aSSam Leffler 		bo->bo_tim_len = 0;
288059aa14a9SRui Paulo 	} else if (vap->iv_opmode == IEEE80211_M_HOSTAP ||
288159aa14a9SRui Paulo 	    vap->iv_opmode == IEEE80211_M_MBSS) {
288259aa14a9SRui Paulo 		/* TIM IE is the same for Mesh and Hostap */
28838a1b9b6aSSam Leffler 		struct ieee80211_tim_ie *tie = (struct ieee80211_tim_ie *) frm;
28848a1b9b6aSSam Leffler 
28858a1b9b6aSSam Leffler 		tie->tim_ie = IEEE80211_ELEMID_TIM;
28868a1b9b6aSSam Leffler 		tie->tim_len = 4;	/* length */
28878a1b9b6aSSam Leffler 		tie->tim_count = 0;	/* DTIM count */
2888b032f27cSSam Leffler 		tie->tim_period = vap->iv_dtim_period;	/* DTIM period */
28898a1b9b6aSSam Leffler 		tie->tim_bitctl = 0;	/* bitmap control */
28908a1b9b6aSSam Leffler 		tie->tim_bitmap[0] = 0;	/* Partial Virtual Bitmap */
28918a1b9b6aSSam Leffler 		frm += sizeof(struct ieee80211_tim_ie);
28928a1b9b6aSSam Leffler 		bo->bo_tim_len = 1;
28938a1b9b6aSSam Leffler 	}
2894b105a069SSam Leffler 	bo->bo_tim_trailer = frm;
2895b032f27cSSam Leffler 	if ((vap->iv_flags & IEEE80211_F_DOTH) ||
2896b032f27cSSam Leffler 	    (vap->iv_flags_ext & IEEE80211_FEXT_DOTD))
2897b032f27cSSam Leffler 		frm = ieee80211_add_countryie(frm, ic);
2898b032f27cSSam Leffler 	if (vap->iv_flags & IEEE80211_F_DOTH) {
2899b032f27cSSam Leffler 		if (IEEE80211_IS_CHAN_5GHZ(ni->ni_chan))
2900b032f27cSSam Leffler 			frm = ieee80211_add_powerconstraint(frm, vap);
2901b032f27cSSam Leffler 		bo->bo_csa = frm;
2902b032f27cSSam Leffler 		if (ic->ic_flags & IEEE80211_F_CSAPENDING)
2903b032f27cSSam Leffler 			frm = ieee80211_add_csa(frm, vap);
2904b032f27cSSam Leffler 	} else
2905b032f27cSSam Leffler 		bo->bo_csa = frm;
290632b0e64bSAdrian Chadd 
290732b0e64bSAdrian Chadd 	if (vap->iv_flags & IEEE80211_F_DOTH) {
290832b0e64bSAdrian Chadd 		bo->bo_quiet = frm;
290932b0e64bSAdrian Chadd 		if (IEEE80211_IS_CHAN_DFS(ic->ic_bsschan) &&
291032b0e64bSAdrian Chadd 		    (vap->iv_flags_ext & IEEE80211_FEXT_DFS)) {
291132b0e64bSAdrian Chadd 			if (vap->iv_quiet)
291232b0e64bSAdrian Chadd 				frm = ieee80211_add_quiet(frm,vap);
291332b0e64bSAdrian Chadd 		}
291432b0e64bSAdrian Chadd 	} else
291532b0e64bSAdrian Chadd 		bo->bo_quiet = frm;
291632b0e64bSAdrian Chadd 
2917b032f27cSSam Leffler 	if (IEEE80211_IS_CHAN_ANYG(ni->ni_chan)) {
29180912bac9SSam Leffler 		bo->bo_erp = frm;
29198a1b9b6aSSam Leffler 		frm = ieee80211_add_erp(frm, ic);
29201b6167d2SSam Leffler 	}
292168e8e04eSSam Leffler 	frm = ieee80211_add_xrates(frm, rs);
2922d8df5f3dSRui Paulo 	frm = ieee80211_add_rsn(frm, vap);
2923b032f27cSSam Leffler 	if (IEEE80211_IS_CHAN_HT(ni->ni_chan)) {
292468e8e04eSSam Leffler 		frm = ieee80211_add_htcap(frm, ni);
292568e8e04eSSam Leffler 		bo->bo_htinfo = frm;
292668e8e04eSSam Leffler 		frm = ieee80211_add_htinfo(frm, ni);
29271b6167d2SSam Leffler 	}
2928d8df5f3dSRui Paulo 	frm = ieee80211_add_wpa(frm, vap);
2929b032f27cSSam Leffler 	if (vap->iv_flags & IEEE80211_F_WME) {
29301b6167d2SSam Leffler 		bo->bo_wme = frm;
29311b6167d2SSam Leffler 		frm = ieee80211_add_wme_param(frm, &ic->ic_wme);
29321b6167d2SSam Leffler 	}
2933b032f27cSSam Leffler 	if (IEEE80211_IS_CHAN_HT(ni->ni_chan) &&
29342bfc8a91SSam Leffler 	    (vap->iv_flags_ht & IEEE80211_FHT_HTCOMPAT)) {
293568e8e04eSSam Leffler 		frm = ieee80211_add_htcap_vendor(frm, ni);
293668e8e04eSSam Leffler 		frm = ieee80211_add_htinfo_vendor(frm, ni);
29370912bac9SSam Leffler 	}
29384207227cSSam Leffler #ifdef IEEE80211_SUPPORT_SUPERG
29394207227cSSam Leffler 	if (vap->iv_flags & IEEE80211_F_ATHEROS) {
29404207227cSSam Leffler 		bo->bo_ath = frm;
29414207227cSSam Leffler 		frm = ieee80211_add_athcaps(frm, ni);
29424207227cSSam Leffler 	}
29434207227cSSam Leffler #endif
294410ad9a77SSam Leffler #ifdef IEEE80211_SUPPORT_TDMA
294510ad9a77SSam Leffler 	if (vap->iv_caps & IEEE80211_C_TDMA) {
294610ad9a77SSam Leffler 		bo->bo_tdma = frm;
294710ad9a77SSam Leffler 		frm = ieee80211_add_tdma(frm, vap);
294810ad9a77SSam Leffler 	}
294910ad9a77SSam Leffler #endif
2950b032f27cSSam Leffler 	if (vap->iv_appie_beacon != NULL) {
2951b032f27cSSam Leffler 		bo->bo_appie = frm;
2952b032f27cSSam Leffler 		bo->bo_appie_len = vap->iv_appie_beacon->ie_len;
2953b032f27cSSam Leffler 		frm = add_appie(frm, vap->iv_appie_beacon);
2954b032f27cSSam Leffler 	}
295559aa14a9SRui Paulo #ifdef IEEE80211_SUPPORT_MESH
295659aa14a9SRui Paulo 	if (vap->iv_opmode == IEEE80211_M_MBSS) {
295759aa14a9SRui Paulo 		frm = ieee80211_add_meshid(frm, vap);
2958d093681cSRui Paulo 		bo->bo_meshconf = frm;
295959aa14a9SRui Paulo 		frm = ieee80211_add_meshconf(frm, vap);
296059aa14a9SRui Paulo 	}
296159aa14a9SRui Paulo #endif
2962b105a069SSam Leffler 	bo->bo_tim_trailer_len = frm - bo->bo_tim_trailer;
2963b032f27cSSam Leffler 	bo->bo_csa_trailer_len = frm - bo->bo_csa;
296468e8e04eSSam Leffler 	m->m_pkthdr.len = m->m_len = frm - mtod(m, uint8_t *);
2965b032f27cSSam Leffler }
2966b032f27cSSam Leffler 
2967b032f27cSSam Leffler /*
2968b032f27cSSam Leffler  * Allocate a beacon frame and fillin the appropriate bits.
2969b032f27cSSam Leffler  */
2970b032f27cSSam Leffler struct mbuf *
2971b032f27cSSam Leffler ieee80211_beacon_alloc(struct ieee80211_node *ni,
2972b032f27cSSam Leffler 	struct ieee80211_beacon_offsets *bo)
2973b032f27cSSam Leffler {
2974b032f27cSSam Leffler 	struct ieee80211vap *vap = ni->ni_vap;
2975b032f27cSSam Leffler 	struct ieee80211com *ic = ni->ni_ic;
2976b032f27cSSam Leffler 	struct ifnet *ifp = vap->iv_ifp;
2977b032f27cSSam Leffler 	struct ieee80211_frame *wh;
2978b032f27cSSam Leffler 	struct mbuf *m;
2979b032f27cSSam Leffler 	int pktlen;
2980b032f27cSSam Leffler 	uint8_t *frm;
2981b032f27cSSam Leffler 
2982b032f27cSSam Leffler 	/*
2983b032f27cSSam Leffler 	 * beacon frame format
2984b032f27cSSam Leffler 	 *	[8] time stamp
2985b032f27cSSam Leffler 	 *	[2] beacon interval
2986b032f27cSSam Leffler 	 *	[2] cabability information
2987b032f27cSSam Leffler 	 *	[tlv] ssid
2988b032f27cSSam Leffler 	 *	[tlv] supported rates
2989b032f27cSSam Leffler 	 *	[3] parameter set (DS)
2990b032f27cSSam Leffler 	 *	[8] CF parameter set (optional)
2991b032f27cSSam Leffler 	 *	[tlv] parameter set (IBSS/TIM)
2992b032f27cSSam Leffler 	 *	[tlv] country (optional)
2993b032f27cSSam Leffler 	 *	[3] power control (optional)
2994b032f27cSSam Leffler 	 *	[5] channel switch announcement (CSA) (optional)
2995b032f27cSSam Leffler 	 *	[tlv] extended rate phy (ERP)
2996b032f27cSSam Leffler 	 *	[tlv] extended supported rates
2997b032f27cSSam Leffler 	 *	[tlv] RSN parameters
2998b032f27cSSam Leffler 	 *	[tlv] HT capabilities
2999b032f27cSSam Leffler 	 *	[tlv] HT information
3000b032f27cSSam Leffler 	 *	[tlv] Vendor OUI HT capabilities (optional)
3001b032f27cSSam Leffler 	 *	[tlv] Vendor OUI HT information (optional)
3002b032f27cSSam Leffler 	 * XXX Vendor-specific OIDs (e.g. Atheros)
3003b032f27cSSam Leffler 	 *	[tlv] WPA parameters
3004b032f27cSSam Leffler 	 *	[tlv] WME parameters
300510ad9a77SSam Leffler 	 *	[tlv] TDMA parameters (optional)
300659aa14a9SRui Paulo 	 *	[tlv] Mesh ID (MBSS)
300759aa14a9SRui Paulo 	 *	[tlv] Mesh Conf (MBSS)
3008b032f27cSSam Leffler 	 *	[tlv] application data (optional)
3009b032f27cSSam Leffler 	 * NB: we allocate the max space required for the TIM bitmap.
3010b032f27cSSam Leffler 	 * XXX how big is this?
3011b032f27cSSam Leffler 	 */
3012b032f27cSSam Leffler 	pktlen =   8					/* time stamp */
3013b032f27cSSam Leffler 		 + sizeof(uint16_t)			/* beacon interval */
3014b032f27cSSam Leffler 		 + sizeof(uint16_t)			/* capabilities */
3015b032f27cSSam Leffler 		 + 2 + ni->ni_esslen			/* ssid */
3016b032f27cSSam Leffler 	         + 2 + IEEE80211_RATE_SIZE		/* supported rates */
3017b032f27cSSam Leffler 	         + 2 + 1				/* DS parameters */
3018b032f27cSSam Leffler 		 + 2 + 6				/* CF parameters */
3019b032f27cSSam Leffler 		 + 2 + 4 + vap->iv_tim_len		/* DTIM/IBSSPARMS */
3020b032f27cSSam Leffler 		 + IEEE80211_COUNTRY_MAX_SIZE		/* country */
3021b032f27cSSam Leffler 		 + 2 + 1				/* power control */
3022b032f27cSSam Leffler 		 + sizeof(struct ieee80211_csa_ie)	/* CSA */
302332b0e64bSAdrian Chadd 		 + sizeof(struct ieee80211_quiet_ie)	/* Quiet */
3024b032f27cSSam Leffler 		 + 2 + 1				/* ERP */
3025b032f27cSSam Leffler 	         + 2 + (IEEE80211_RATE_MAXSIZE - IEEE80211_RATE_SIZE)
3026b032f27cSSam Leffler 		 + (vap->iv_caps & IEEE80211_C_WPA ?	/* WPA 1+2 */
3027b032f27cSSam Leffler 			2*sizeof(struct ieee80211_ie_wpa) : 0)
3028b032f27cSSam Leffler 		 /* XXX conditional? */
3029b032f27cSSam Leffler 		 + 4+2*sizeof(struct ieee80211_ie_htcap)/* HT caps */
3030b032f27cSSam Leffler 		 + 4+2*sizeof(struct ieee80211_ie_htinfo)/* HT info */
3031b032f27cSSam Leffler 		 + (vap->iv_caps & IEEE80211_C_WME ?	/* WME */
3032b032f27cSSam Leffler 			sizeof(struct ieee80211_wme_param) : 0)
30334207227cSSam Leffler #ifdef IEEE80211_SUPPORT_SUPERG
30344207227cSSam Leffler 		 + sizeof(struct ieee80211_ath_ie)	/* ATH */
30354207227cSSam Leffler #endif
303610ad9a77SSam Leffler #ifdef IEEE80211_SUPPORT_TDMA
303710ad9a77SSam Leffler 		 + (vap->iv_caps & IEEE80211_C_TDMA ?	/* TDMA */
303810ad9a77SSam Leffler 			sizeof(struct ieee80211_tdma_param) : 0)
303910ad9a77SSam Leffler #endif
304059aa14a9SRui Paulo #ifdef IEEE80211_SUPPORT_MESH
304159aa14a9SRui Paulo 		 + 2 + ni->ni_meshidlen
304259aa14a9SRui Paulo 		 + sizeof(struct ieee80211_meshconf_ie)
304359aa14a9SRui Paulo #endif
3044b032f27cSSam Leffler 		 + IEEE80211_MAX_APPIE
3045b032f27cSSam Leffler 		 ;
3046b032f27cSSam Leffler 	m = ieee80211_getmgtframe(&frm,
3047b032f27cSSam Leffler 		ic->ic_headroom + sizeof(struct ieee80211_frame), pktlen);
3048b032f27cSSam Leffler 	if (m == NULL) {
3049b032f27cSSam Leffler 		IEEE80211_DPRINTF(vap, IEEE80211_MSG_ANY,
3050b032f27cSSam Leffler 			"%s: cannot get buf; size %u\n", __func__, pktlen);
3051b032f27cSSam Leffler 		vap->iv_stats.is_tx_nobuf++;
3052b032f27cSSam Leffler 		return NULL;
3053b032f27cSSam Leffler 	}
3054b032f27cSSam Leffler 	ieee80211_beacon_construct(m, frm, bo, ni);
30558a1b9b6aSSam Leffler 
3056eb1b1807SGleb Smirnoff 	M_PREPEND(m, sizeof(struct ieee80211_frame), M_NOWAIT);
30578a1b9b6aSSam Leffler 	KASSERT(m != NULL, ("no space for 802.11 header?"));
30588a1b9b6aSSam Leffler 	wh = mtod(m, struct ieee80211_frame *);
30598a1b9b6aSSam Leffler 	wh->i_fc[0] = IEEE80211_FC0_VERSION_0 | IEEE80211_FC0_TYPE_MGT |
30608a1b9b6aSSam Leffler 	    IEEE80211_FC0_SUBTYPE_BEACON;
30618a1b9b6aSSam Leffler 	wh->i_fc[1] = IEEE80211_FC1_DIR_NODS;
306268e8e04eSSam Leffler 	*(uint16_t *)wh->i_dur = 0;
30638a1b9b6aSSam Leffler 	IEEE80211_ADDR_COPY(wh->i_addr1, ifp->if_broadcastaddr);
3064b032f27cSSam Leffler 	IEEE80211_ADDR_COPY(wh->i_addr2, vap->iv_myaddr);
30658a1b9b6aSSam Leffler 	IEEE80211_ADDR_COPY(wh->i_addr3, ni->ni_bssid);
306668e8e04eSSam Leffler 	*(uint16_t *)wh->i_seq = 0;
30678a1b9b6aSSam Leffler 
30688a1b9b6aSSam Leffler 	return m;
30698a1b9b6aSSam Leffler }
30708a1b9b6aSSam Leffler 
30718a1b9b6aSSam Leffler /*
30728a1b9b6aSSam Leffler  * Update the dynamic parts of a beacon frame based on the current state.
30738a1b9b6aSSam Leffler  */
30748a1b9b6aSSam Leffler int
3075b105a069SSam Leffler ieee80211_beacon_update(struct ieee80211_node *ni,
30768a1b9b6aSSam Leffler 	struct ieee80211_beacon_offsets *bo, struct mbuf *m, int mcast)
30778a1b9b6aSSam Leffler {
3078b032f27cSSam Leffler 	struct ieee80211vap *vap = ni->ni_vap;
3079b105a069SSam Leffler 	struct ieee80211com *ic = ni->ni_ic;
30808a1b9b6aSSam Leffler 	int len_changed = 0;
308168e8e04eSSam Leffler 	uint16_t capinfo;
3082fa3324c9SAdrian Chadd 	struct ieee80211_frame *wh;
3083fa3324c9SAdrian Chadd 	ieee80211_seq seqno;
30848a1b9b6aSSam Leffler 
3085b032f27cSSam Leffler 	IEEE80211_LOCK(ic);
3086b032f27cSSam Leffler 	/*
3087b032f27cSSam Leffler 	 * Handle 11h channel change when we've reached the count.
3088b032f27cSSam Leffler 	 * We must recalculate the beacon frame contents to account
3089b032f27cSSam Leffler 	 * for the new channel.  Note we do this only for the first
3090b032f27cSSam Leffler 	 * vap that reaches this point; subsequent vaps just update
3091b032f27cSSam Leffler 	 * their beacon state to reflect the recalculated channel.
3092b032f27cSSam Leffler 	 */
3093b032f27cSSam Leffler 	if (isset(bo->bo_flags, IEEE80211_BEACON_CSA) &&
3094b032f27cSSam Leffler 	    vap->iv_csa_count == ic->ic_csa_count) {
3095b032f27cSSam Leffler 		vap->iv_csa_count = 0;
3096b032f27cSSam Leffler 		/*
3097b032f27cSSam Leffler 		 * Effect channel change before reconstructing the beacon
3098b032f27cSSam Leffler 		 * frame contents as many places reference ni_chan.
3099b032f27cSSam Leffler 		 */
3100b032f27cSSam Leffler 		if (ic->ic_csa_newchan != NULL)
3101b032f27cSSam Leffler 			ieee80211_csa_completeswitch(ic);
3102b032f27cSSam Leffler 		/*
3103b032f27cSSam Leffler 		 * NB: ieee80211_beacon_construct clears all pending
3104b032f27cSSam Leffler 		 * updates in bo_flags so we don't need to explicitly
3105b032f27cSSam Leffler 		 * clear IEEE80211_BEACON_CSA.
3106b032f27cSSam Leffler 		 */
3107b032f27cSSam Leffler 		ieee80211_beacon_construct(m,
3108b032f27cSSam Leffler 		    mtod(m, uint8_t*) + sizeof(struct ieee80211_frame), bo, ni);
3109b032f27cSSam Leffler 
3110b032f27cSSam Leffler 		/* XXX do WME aggressive mode processing? */
3111b032f27cSSam Leffler 		IEEE80211_UNLOCK(ic);
3112b032f27cSSam Leffler 		return 1;		/* just assume length changed */
3113b032f27cSSam Leffler 	}
3114b032f27cSSam Leffler 
3115fa3324c9SAdrian Chadd 	wh = mtod(m, struct ieee80211_frame *);
3116fa3324c9SAdrian Chadd 	seqno = ni->ni_txseqs[IEEE80211_NONQOS_TID]++;
3117fa3324c9SAdrian Chadd 	*(uint16_t *)&wh->i_seq[0] =
3118fa3324c9SAdrian Chadd 		htole16(seqno << IEEE80211_SEQ_SEQ_SHIFT);
3119fa3324c9SAdrian Chadd 	M_SEQNO_SET(m, seqno);
3120fa3324c9SAdrian Chadd 
31218a1b9b6aSSam Leffler 	/* XXX faster to recalculate entirely or just changes? */
312259aa14a9SRui Paulo 	capinfo = ieee80211_getcapinfo(vap, ni->ni_chan);
31238a1b9b6aSSam Leffler 	*bo->bo_caps = htole16(capinfo);
31248a1b9b6aSSam Leffler 
3125b032f27cSSam Leffler 	if (vap->iv_flags & IEEE80211_F_WME) {
31268a1b9b6aSSam Leffler 		struct ieee80211_wme_state *wme = &ic->ic_wme;
31278a1b9b6aSSam Leffler 
31288a1b9b6aSSam Leffler 		/*
31298a1b9b6aSSam Leffler 		 * Check for agressive mode change.  When there is
31308a1b9b6aSSam Leffler 		 * significant high priority traffic in the BSS
31318a1b9b6aSSam Leffler 		 * throttle back BE traffic by using conservative
31328a1b9b6aSSam Leffler 		 * parameters.  Otherwise BE uses agressive params
31338a1b9b6aSSam Leffler 		 * to optimize performance of legacy/non-QoS traffic.
31348a1b9b6aSSam Leffler 		 */
31358a1b9b6aSSam Leffler 		if (wme->wme_flags & WME_F_AGGRMODE) {
31368a1b9b6aSSam Leffler 			if (wme->wme_hipri_traffic >
31378a1b9b6aSSam Leffler 			    wme->wme_hipri_switch_thresh) {
3138b032f27cSSam Leffler 				IEEE80211_DPRINTF(vap, IEEE80211_MSG_WME,
31398a1b9b6aSSam Leffler 				    "%s: traffic %u, disable aggressive mode\n",
31408a1b9b6aSSam Leffler 				    __func__, wme->wme_hipri_traffic);
31418a1b9b6aSSam Leffler 				wme->wme_flags &= ~WME_F_AGGRMODE;
3142b032f27cSSam Leffler 				ieee80211_wme_updateparams_locked(vap);
31438a1b9b6aSSam Leffler 				wme->wme_hipri_traffic =
31448a1b9b6aSSam Leffler 					wme->wme_hipri_switch_hysteresis;
31458a1b9b6aSSam Leffler 			} else
31468a1b9b6aSSam Leffler 				wme->wme_hipri_traffic = 0;
31478a1b9b6aSSam Leffler 		} else {
31488a1b9b6aSSam Leffler 			if (wme->wme_hipri_traffic <=
31498a1b9b6aSSam Leffler 			    wme->wme_hipri_switch_thresh) {
3150b032f27cSSam Leffler 				IEEE80211_DPRINTF(vap, IEEE80211_MSG_WME,
31518a1b9b6aSSam Leffler 				    "%s: traffic %u, enable aggressive mode\n",
31528a1b9b6aSSam Leffler 				    __func__, wme->wme_hipri_traffic);
31538a1b9b6aSSam Leffler 				wme->wme_flags |= WME_F_AGGRMODE;
3154b032f27cSSam Leffler 				ieee80211_wme_updateparams_locked(vap);
31558a1b9b6aSSam Leffler 				wme->wme_hipri_traffic = 0;
31568a1b9b6aSSam Leffler 			} else
31578a1b9b6aSSam Leffler 				wme->wme_hipri_traffic =
31588a1b9b6aSSam Leffler 					wme->wme_hipri_switch_hysteresis;
31598a1b9b6aSSam Leffler 		}
3160b105a069SSam Leffler 		if (isset(bo->bo_flags, IEEE80211_BEACON_WME)) {
31618a1b9b6aSSam Leffler 			(void) ieee80211_add_wme_param(bo->bo_wme, wme);
3162b105a069SSam Leffler 			clrbit(bo->bo_flags, IEEE80211_BEACON_WME);
31638a1b9b6aSSam Leffler 		}
31648a1b9b6aSSam Leffler 	}
31658a1b9b6aSSam Leffler 
3166b105a069SSam Leffler 	if (isset(bo->bo_flags,  IEEE80211_BEACON_HTINFO)) {
3167b032f27cSSam Leffler 		ieee80211_ht_update_beacon(vap, bo);
3168b105a069SSam Leffler 		clrbit(bo->bo_flags, IEEE80211_BEACON_HTINFO);
316968e8e04eSSam Leffler 	}
317010ad9a77SSam Leffler #ifdef IEEE80211_SUPPORT_TDMA
317110ad9a77SSam Leffler 	if (vap->iv_caps & IEEE80211_C_TDMA) {
317210ad9a77SSam Leffler 		/*
317310ad9a77SSam Leffler 		 * NB: the beacon is potentially updated every TBTT.
317410ad9a77SSam Leffler 		 */
317510ad9a77SSam Leffler 		ieee80211_tdma_update_beacon(vap, bo);
317610ad9a77SSam Leffler 	}
317710ad9a77SSam Leffler #endif
3178d093681cSRui Paulo #ifdef IEEE80211_SUPPORT_MESH
3179d093681cSRui Paulo 	if (vap->iv_opmode == IEEE80211_M_MBSS)
3180d093681cSRui Paulo 		ieee80211_mesh_update_beacon(vap, bo);
3181d093681cSRui Paulo #endif
3182d093681cSRui Paulo 
318359aa14a9SRui Paulo 	if (vap->iv_opmode == IEEE80211_M_HOSTAP ||
318459aa14a9SRui Paulo 	    vap->iv_opmode == IEEE80211_M_MBSS) {	/* NB: no IBSS support*/
31858a1b9b6aSSam Leffler 		struct ieee80211_tim_ie *tie =
31868a1b9b6aSSam Leffler 			(struct ieee80211_tim_ie *) bo->bo_tim;
3187b105a069SSam Leffler 		if (isset(bo->bo_flags, IEEE80211_BEACON_TIM)) {
31888a1b9b6aSSam Leffler 			u_int timlen, timoff, i;
31898a1b9b6aSSam Leffler 			/*
31908a1b9b6aSSam Leffler 			 * ATIM/DTIM needs updating.  If it fits in the
31918a1b9b6aSSam Leffler 			 * current space allocated then just copy in the
31928a1b9b6aSSam Leffler 			 * new bits.  Otherwise we need to move any trailing
31938a1b9b6aSSam Leffler 			 * data to make room.  Note that we know there is
31948a1b9b6aSSam Leffler 			 * contiguous space because ieee80211_beacon_allocate
31958a1b9b6aSSam Leffler 			 * insures there is space in the mbuf to write a
3196b032f27cSSam Leffler 			 * maximal-size virtual bitmap (based on iv_max_aid).
31978a1b9b6aSSam Leffler 			 */
31988a1b9b6aSSam Leffler 			/*
31998a1b9b6aSSam Leffler 			 * Calculate the bitmap size and offset, copy any
32008a1b9b6aSSam Leffler 			 * trailer out of the way, and then copy in the
32018a1b9b6aSSam Leffler 			 * new bitmap and update the information element.
32028a1b9b6aSSam Leffler 			 * Note that the tim bitmap must contain at least
32038a1b9b6aSSam Leffler 			 * one byte and any offset must be even.
32048a1b9b6aSSam Leffler 			 */
3205b032f27cSSam Leffler 			if (vap->iv_ps_pending != 0) {
32068a1b9b6aSSam Leffler 				timoff = 128;		/* impossibly large */
3207b032f27cSSam Leffler 				for (i = 0; i < vap->iv_tim_len; i++)
3208b032f27cSSam Leffler 					if (vap->iv_tim_bitmap[i]) {
32098a1b9b6aSSam Leffler 						timoff = i &~ 1;
32108a1b9b6aSSam Leffler 						break;
32118a1b9b6aSSam Leffler 					}
32128a1b9b6aSSam Leffler 				KASSERT(timoff != 128, ("tim bitmap empty!"));
3213b032f27cSSam Leffler 				for (i = vap->iv_tim_len-1; i >= timoff; i--)
3214b032f27cSSam Leffler 					if (vap->iv_tim_bitmap[i])
32158a1b9b6aSSam Leffler 						break;
32168a1b9b6aSSam Leffler 				timlen = 1 + (i - timoff);
32178a1b9b6aSSam Leffler 			} else {
32188a1b9b6aSSam Leffler 				timoff = 0;
32198a1b9b6aSSam Leffler 				timlen = 1;
32208a1b9b6aSSam Leffler 			}
32218a1b9b6aSSam Leffler 			if (timlen != bo->bo_tim_len) {
32228a1b9b6aSSam Leffler 				/* copy up/down trailer */
32230912bac9SSam Leffler 				int adjust = tie->tim_bitmap+timlen
3224b105a069SSam Leffler 					   - bo->bo_tim_trailer;
3225b105a069SSam Leffler 				ovbcopy(bo->bo_tim_trailer,
3226b105a069SSam Leffler 				    bo->bo_tim_trailer+adjust,
3227b105a069SSam Leffler 				    bo->bo_tim_trailer_len);
3228b105a069SSam Leffler 				bo->bo_tim_trailer += adjust;
32290912bac9SSam Leffler 				bo->bo_erp += adjust;
323068e8e04eSSam Leffler 				bo->bo_htinfo += adjust;
323102e69b54SBernhard Schmidt #ifdef IEEE80211_SUPPORT_SUPERG
32324207227cSSam Leffler 				bo->bo_ath += adjust;
32334207227cSSam Leffler #endif
323402e69b54SBernhard Schmidt #ifdef IEEE80211_SUPPORT_TDMA
323592e870edSSam Leffler 				bo->bo_tdma += adjust;
323692e870edSSam Leffler #endif
323702e69b54SBernhard Schmidt #ifdef IEEE80211_SUPPORT_MESH
3238d093681cSRui Paulo 				bo->bo_meshconf += adjust;
3239d093681cSRui Paulo #endif
3240b032f27cSSam Leffler 				bo->bo_appie += adjust;
3241b032f27cSSam Leffler 				bo->bo_wme += adjust;
3242b032f27cSSam Leffler 				bo->bo_csa += adjust;
324332b0e64bSAdrian Chadd 				bo->bo_quiet += adjust;
32448a1b9b6aSSam Leffler 				bo->bo_tim_len = timlen;
32458a1b9b6aSSam Leffler 
32468a1b9b6aSSam Leffler 				/* update information element */
32478a1b9b6aSSam Leffler 				tie->tim_len = 3 + timlen;
32488a1b9b6aSSam Leffler 				tie->tim_bitctl = timoff;
32498a1b9b6aSSam Leffler 				len_changed = 1;
32508a1b9b6aSSam Leffler 			}
3251b032f27cSSam Leffler 			memcpy(tie->tim_bitmap, vap->iv_tim_bitmap + timoff,
32528a1b9b6aSSam Leffler 				bo->bo_tim_len);
32538a1b9b6aSSam Leffler 
3254b105a069SSam Leffler 			clrbit(bo->bo_flags, IEEE80211_BEACON_TIM);
32558a1b9b6aSSam Leffler 
3256b032f27cSSam Leffler 			IEEE80211_DPRINTF(vap, IEEE80211_MSG_POWER,
32578a1b9b6aSSam Leffler 				"%s: TIM updated, pending %u, off %u, len %u\n",
3258b032f27cSSam Leffler 				__func__, vap->iv_ps_pending, timoff, timlen);
32598a1b9b6aSSam Leffler 		}
32608a1b9b6aSSam Leffler 		/* count down DTIM period */
32618a1b9b6aSSam Leffler 		if (tie->tim_count == 0)
32628a1b9b6aSSam Leffler 			tie->tim_count = tie->tim_period - 1;
32638a1b9b6aSSam Leffler 		else
32648a1b9b6aSSam Leffler 			tie->tim_count--;
32658a1b9b6aSSam Leffler 		/* update state for buffered multicast frames on DTIM */
3266a196b35fSSam Leffler 		if (mcast && tie->tim_count == 0)
32678a1b9b6aSSam Leffler 			tie->tim_bitctl |= 1;
32688a1b9b6aSSam Leffler 		else
32698a1b9b6aSSam Leffler 			tie->tim_bitctl &= ~1;
3270b032f27cSSam Leffler 		if (isset(bo->bo_flags, IEEE80211_BEACON_CSA)) {
3271b032f27cSSam Leffler 			struct ieee80211_csa_ie *csa =
3272b032f27cSSam Leffler 			    (struct ieee80211_csa_ie *) bo->bo_csa;
3273b032f27cSSam Leffler 
3274b032f27cSSam Leffler 			/*
3275b032f27cSSam Leffler 			 * Insert or update CSA ie.  If we're just starting
3276b032f27cSSam Leffler 			 * to count down to the channel switch then we need
3277b032f27cSSam Leffler 			 * to insert the CSA ie.  Otherwise we just need to
3278b032f27cSSam Leffler 			 * drop the count.  The actual change happens above
3279b032f27cSSam Leffler 			 * when the vap's count reaches the target count.
3280b032f27cSSam Leffler 			 */
3281b032f27cSSam Leffler 			if (vap->iv_csa_count == 0) {
3282b032f27cSSam Leffler 				memmove(&csa[1], csa, bo->bo_csa_trailer_len);
3283b032f27cSSam Leffler 				bo->bo_erp += sizeof(*csa);
3284d01b3c26SSam Leffler 				bo->bo_htinfo += sizeof(*csa);
3285b032f27cSSam Leffler 				bo->bo_wme += sizeof(*csa);
328602e69b54SBernhard Schmidt #ifdef IEEE80211_SUPPORT_SUPERG
32874207227cSSam Leffler 				bo->bo_ath += sizeof(*csa);
32884207227cSSam Leffler #endif
328902e69b54SBernhard Schmidt #ifdef IEEE80211_SUPPORT_TDMA
329092e870edSSam Leffler 				bo->bo_tdma += sizeof(*csa);
329192e870edSSam Leffler #endif
329202e69b54SBernhard Schmidt #ifdef IEEE80211_SUPPORT_MESH
3293d093681cSRui Paulo 				bo->bo_meshconf += sizeof(*csa);
3294d093681cSRui Paulo #endif
3295b032f27cSSam Leffler 				bo->bo_appie += sizeof(*csa);
3296b032f27cSSam Leffler 				bo->bo_csa_trailer_len += sizeof(*csa);
329732b0e64bSAdrian Chadd 				bo->bo_quiet += sizeof(*csa);
3298b032f27cSSam Leffler 				bo->bo_tim_trailer_len += sizeof(*csa);
3299b032f27cSSam Leffler 				m->m_len += sizeof(*csa);
3300b032f27cSSam Leffler 				m->m_pkthdr.len += sizeof(*csa);
3301b032f27cSSam Leffler 
3302b032f27cSSam Leffler 				ieee80211_add_csa(bo->bo_csa, vap);
3303b032f27cSSam Leffler 			} else
3304b032f27cSSam Leffler 				csa->csa_count--;
3305b032f27cSSam Leffler 			vap->iv_csa_count++;
3306b032f27cSSam Leffler 			/* NB: don't clear IEEE80211_BEACON_CSA */
3307b032f27cSSam Leffler 		}
330832b0e64bSAdrian Chadd 		if (IEEE80211_IS_CHAN_DFS(ic->ic_bsschan) &&
330932b0e64bSAdrian Chadd 		    (vap->iv_flags_ext & IEEE80211_FEXT_DFS) ){
331032b0e64bSAdrian Chadd 			if (vap->iv_quiet)
331132b0e64bSAdrian Chadd 				ieee80211_add_quiet(bo->bo_quiet, vap);
331232b0e64bSAdrian Chadd 		}
3313b105a069SSam Leffler 		if (isset(bo->bo_flags, IEEE80211_BEACON_ERP)) {
33140912bac9SSam Leffler 			/*
33150912bac9SSam Leffler 			 * ERP element needs updating.
33160912bac9SSam Leffler 			 */
33170912bac9SSam Leffler 			(void) ieee80211_add_erp(bo->bo_erp, ic);
3318b105a069SSam Leffler 			clrbit(bo->bo_flags, IEEE80211_BEACON_ERP);
33190912bac9SSam Leffler 		}
33204207227cSSam Leffler #ifdef IEEE80211_SUPPORT_SUPERG
33214207227cSSam Leffler 		if (isset(bo->bo_flags,  IEEE80211_BEACON_ATH)) {
33224207227cSSam Leffler 			ieee80211_add_athcaps(bo->bo_ath, ni);
33234207227cSSam Leffler 			clrbit(bo->bo_flags, IEEE80211_BEACON_ATH);
33244207227cSSam Leffler 		}
33254207227cSSam Leffler #endif
33268a1b9b6aSSam Leffler 	}
3327b032f27cSSam Leffler 	if (isset(bo->bo_flags, IEEE80211_BEACON_APPIE)) {
3328b032f27cSSam Leffler 		const struct ieee80211_appie *aie = vap->iv_appie_beacon;
3329b032f27cSSam Leffler 		int aielen;
3330b032f27cSSam Leffler 		uint8_t *frm;
3331b032f27cSSam Leffler 
3332b032f27cSSam Leffler 		aielen = 0;
3333b032f27cSSam Leffler 		if (aie != NULL)
3334b032f27cSSam Leffler 			aielen += aie->ie_len;
3335b032f27cSSam Leffler 		if (aielen != bo->bo_appie_len) {
3336b032f27cSSam Leffler 			/* copy up/down trailer */
3337b032f27cSSam Leffler 			int adjust = aielen - bo->bo_appie_len;
3338b032f27cSSam Leffler 			ovbcopy(bo->bo_tim_trailer, bo->bo_tim_trailer+adjust,
3339b032f27cSSam Leffler 				bo->bo_tim_trailer_len);
3340b032f27cSSam Leffler 			bo->bo_tim_trailer += adjust;
3341b032f27cSSam Leffler 			bo->bo_appie += adjust;
3342b032f27cSSam Leffler 			bo->bo_appie_len = aielen;
3343b032f27cSSam Leffler 
3344b032f27cSSam Leffler 			len_changed = 1;
3345b032f27cSSam Leffler 		}
3346b032f27cSSam Leffler 		frm = bo->bo_appie;
3347b032f27cSSam Leffler 		if (aie != NULL)
3348b032f27cSSam Leffler 			frm  = add_appie(frm, aie);
3349b032f27cSSam Leffler 		clrbit(bo->bo_flags, IEEE80211_BEACON_APPIE);
3350b032f27cSSam Leffler 	}
3351b032f27cSSam Leffler 	IEEE80211_UNLOCK(ic);
33528a1b9b6aSSam Leffler 
33538a1b9b6aSSam Leffler 	return len_changed;
33548a1b9b6aSSam Leffler }
335574b4c76eSAdrian Chadd 
335674b4c76eSAdrian Chadd /*
335774b4c76eSAdrian Chadd  * Do Ethernet-LLC encapsulation for each payload in a fast frame
335874b4c76eSAdrian Chadd  * tunnel encapsulation.  The frame is assumed to have an Ethernet
335974b4c76eSAdrian Chadd  * header at the front that must be stripped before prepending the
336074b4c76eSAdrian Chadd  * LLC followed by the Ethernet header passed in (with an Ethernet
336174b4c76eSAdrian Chadd  * type that specifies the payload size).
336274b4c76eSAdrian Chadd  */
336374b4c76eSAdrian Chadd struct mbuf *
336474b4c76eSAdrian Chadd ieee80211_ff_encap1(struct ieee80211vap *vap, struct mbuf *m,
336574b4c76eSAdrian Chadd 	const struct ether_header *eh)
336674b4c76eSAdrian Chadd {
336774b4c76eSAdrian Chadd 	struct llc *llc;
336874b4c76eSAdrian Chadd 	uint16_t payload;
336974b4c76eSAdrian Chadd 
337074b4c76eSAdrian Chadd 	/* XXX optimize by combining m_adj+M_PREPEND */
337174b4c76eSAdrian Chadd 	m_adj(m, sizeof(struct ether_header) - sizeof(struct llc));
337274b4c76eSAdrian Chadd 	llc = mtod(m, struct llc *);
337374b4c76eSAdrian Chadd 	llc->llc_dsap = llc->llc_ssap = LLC_SNAP_LSAP;
337474b4c76eSAdrian Chadd 	llc->llc_control = LLC_UI;
337574b4c76eSAdrian Chadd 	llc->llc_snap.org_code[0] = 0;
337674b4c76eSAdrian Chadd 	llc->llc_snap.org_code[1] = 0;
337774b4c76eSAdrian Chadd 	llc->llc_snap.org_code[2] = 0;
337874b4c76eSAdrian Chadd 	llc->llc_snap.ether_type = eh->ether_type;
337974b4c76eSAdrian Chadd 	payload = m->m_pkthdr.len;		/* NB: w/o Ethernet header */
338074b4c76eSAdrian Chadd 
338174b4c76eSAdrian Chadd 	M_PREPEND(m, sizeof(struct ether_header), M_NOWAIT);
338274b4c76eSAdrian Chadd 	if (m == NULL) {		/* XXX cannot happen */
338374b4c76eSAdrian Chadd 		IEEE80211_DPRINTF(vap, IEEE80211_MSG_SUPERG,
338474b4c76eSAdrian Chadd 			"%s: no space for ether_header\n", __func__);
338574b4c76eSAdrian Chadd 		vap->iv_stats.is_tx_nobuf++;
338674b4c76eSAdrian Chadd 		return NULL;
338774b4c76eSAdrian Chadd 	}
338874b4c76eSAdrian Chadd 	ETHER_HEADER_COPY(mtod(m, void *), eh);
338974b4c76eSAdrian Chadd 	mtod(m, struct ether_header *)->ether_type = htons(payload);
339074b4c76eSAdrian Chadd 	return m;
339174b4c76eSAdrian Chadd }
339236ee7775SAdrian Chadd 
339336ee7775SAdrian Chadd /*
339436ee7775SAdrian Chadd  * Complete an mbuf transmission.
339536ee7775SAdrian Chadd  *
339636ee7775SAdrian Chadd  * For now, this simply processes a completed frame after the
339736ee7775SAdrian Chadd  * driver has completed it's transmission and/or retransmission.
339836ee7775SAdrian Chadd  * It assumes the frame is an 802.11 encapsulated frame.
339936ee7775SAdrian Chadd  *
340036ee7775SAdrian Chadd  * Later on it will grow to become the exit path for a given frame
340136ee7775SAdrian Chadd  * from the driver and, depending upon how it's been encapsulated
340236ee7775SAdrian Chadd  * and already transmitted, it may end up doing A-MPDU retransmission,
340336ee7775SAdrian Chadd  * power save requeuing, etc.
340436ee7775SAdrian Chadd  *
340536ee7775SAdrian Chadd  * In order for the above to work, the driver entry point to this
340636ee7775SAdrian Chadd  * must not hold any driver locks.  Thus, the driver needs to delay
340736ee7775SAdrian Chadd  * any actual mbuf completion until it can release said locks.
340836ee7775SAdrian Chadd  *
340936ee7775SAdrian Chadd  * This frees the mbuf and if the mbuf has a node reference,
341036ee7775SAdrian Chadd  * the node reference will be freed.
341136ee7775SAdrian Chadd  */
341236ee7775SAdrian Chadd void
341336ee7775SAdrian Chadd ieee80211_tx_complete(struct ieee80211_node *ni, struct mbuf *m, int status)
341436ee7775SAdrian Chadd {
341536ee7775SAdrian Chadd 
341636ee7775SAdrian Chadd 	if (ni != NULL) {
341736ee7775SAdrian Chadd 		if (m->m_flags & M_TXCB)
341836ee7775SAdrian Chadd 			ieee80211_process_callback(ni, m, status);
341936ee7775SAdrian Chadd 		ieee80211_free_node(ni);
342036ee7775SAdrian Chadd 	}
342136ee7775SAdrian Chadd 	m_freem(m);
342236ee7775SAdrian Chadd }
3423