ieee80211_output.c revision 172231
1116742Ssam/*-
2116904Ssam * Copyright (c) 2001 Atsushi Onoe
3170360Ssam * Copyright (c) 2002-2007 Sam Leffler, Errno Consulting
4116742Ssam * All rights reserved.
5116742Ssam *
6116742Ssam * Redistribution and use in source and binary forms, with or without
7116742Ssam * modification, are permitted provided that the following conditions
8116742Ssam * are met:
9116742Ssam * 1. Redistributions of source code must retain the above copyright
10116904Ssam *    notice, this list of conditions and the following disclaimer.
11116904Ssam * 2. Redistributions in binary form must reproduce the above copyright
12116904Ssam *    notice, this list of conditions and the following disclaimer in the
13116904Ssam *    documentation and/or other materials provided with the distribution.
14116742Ssam *
15116904Ssam * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
16116904Ssam * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
17116904Ssam * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
18116904Ssam * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
19116904Ssam * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
20116904Ssam * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
21116904Ssam * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
22116904Ssam * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
23116904Ssam * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
24116904Ssam * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
25116742Ssam */
26116742Ssam
27116742Ssam#include <sys/cdefs.h>
28116742Ssam__FBSDID("$FreeBSD: head/sys/net80211/ieee80211_output.c 172231 2007-09-18 21:07:41Z sam $");
29116742Ssam
30116742Ssam#include "opt_inet.h"
31116742Ssam
32116742Ssam#include <sys/param.h>
33116742Ssam#include <sys/systm.h>
34116742Ssam#include <sys/mbuf.h>
35116742Ssam#include <sys/kernel.h>
36116742Ssam#include <sys/endian.h>
37116742Ssam
38138568Ssam#include <sys/socket.h>
39116742Ssam
40138568Ssam#include <net/bpf.h>
41138568Ssam#include <net/ethernet.h>
42116742Ssam#include <net/if.h>
43138568Ssam#include <net/if_llc.h>
44116742Ssam#include <net/if_media.h>
45138568Ssam#include <net/if_vlan_var.h>
46116742Ssam
47116742Ssam#include <net80211/ieee80211_var.h>
48170530Ssam#include <net80211/ieee80211_regdomain.h>
49116742Ssam
50116742Ssam#ifdef INET
51116742Ssam#include <netinet/in.h>
52116742Ssam#include <netinet/if_ether.h>
53138568Ssam#include <netinet/in_systm.h>
54138568Ssam#include <netinet/ip.h>
55116742Ssam#endif
56116742Ssam
57170530Ssam#define	ETHER_HEADER_COPY(dst, src) \
58170530Ssam	memcpy(dst, src, sizeof(struct ether_header))
59170530Ssam
60170530Ssamstatic struct mbuf *ieee80211_encap_fastframe(struct ieee80211com *ic,
61170530Ssam	struct mbuf *m1, const struct ether_header *eh1,
62170530Ssam	struct mbuf *m2, const struct ether_header *eh2);
63170530Ssamstatic int ieee80211_fragment(struct ieee80211com *, struct mbuf *,
64170530Ssam	u_int hdrsize, u_int ciphdrsize, u_int mtu);
65170530Ssamstatic	void ieee80211_tx_mgt_cb(struct ieee80211_node *, void *, int);
66170530Ssam
67138568Ssam#ifdef IEEE80211_DEBUG
68119150Ssam/*
69138568Ssam * Decide if an outbound management frame should be
70138568Ssam * printed when debugging is enabled.  This filters some
71138568Ssam * of the less interesting frames that come frequently
72138568Ssam * (e.g. beacons).
73138568Ssam */
74138568Ssamstatic __inline int
75138568Ssamdoprint(struct ieee80211com *ic, int subtype)
76138568Ssam{
77138568Ssam	switch (subtype) {
78138568Ssam	case IEEE80211_FC0_SUBTYPE_PROBE_RESP:
79138568Ssam		return (ic->ic_opmode == IEEE80211_M_IBSS);
80138568Ssam	}
81138568Ssam	return 1;
82138568Ssam}
83138568Ssam#endif
84138568Ssam
85138568Ssam/*
86148314Ssam * Set the direction field and address fields of an outgoing
87148314Ssam * non-QoS frame.  Note this should be called early on in
88148314Ssam * constructing a frame as it sets i_fc[1]; other bits can
89148314Ssam * then be or'd in.
90148314Ssam */
91148314Ssamstatic void
92148314Ssamieee80211_send_setup(struct ieee80211com *ic,
93148314Ssam	struct ieee80211_node *ni,
94148314Ssam	struct ieee80211_frame *wh,
95148314Ssam	int type,
96170530Ssam	const uint8_t sa[IEEE80211_ADDR_LEN],
97170530Ssam	const uint8_t da[IEEE80211_ADDR_LEN],
98170530Ssam	const uint8_t bssid[IEEE80211_ADDR_LEN])
99148314Ssam{
100148314Ssam#define	WH4(wh)	((struct ieee80211_frame_addr4 *)wh)
101148314Ssam
102148314Ssam	wh->i_fc[0] = IEEE80211_FC0_VERSION_0 | type;
103148314Ssam	if ((type & IEEE80211_FC0_TYPE_MASK) == IEEE80211_FC0_TYPE_DATA) {
104148314Ssam		switch (ic->ic_opmode) {
105148314Ssam		case IEEE80211_M_STA:
106148314Ssam			wh->i_fc[1] = IEEE80211_FC1_DIR_TODS;
107148314Ssam			IEEE80211_ADDR_COPY(wh->i_addr1, bssid);
108148314Ssam			IEEE80211_ADDR_COPY(wh->i_addr2, sa);
109148314Ssam			IEEE80211_ADDR_COPY(wh->i_addr3, da);
110148314Ssam			break;
111148314Ssam		case IEEE80211_M_IBSS:
112148314Ssam		case IEEE80211_M_AHDEMO:
113148314Ssam			wh->i_fc[1] = IEEE80211_FC1_DIR_NODS;
114148314Ssam			IEEE80211_ADDR_COPY(wh->i_addr1, da);
115148314Ssam			IEEE80211_ADDR_COPY(wh->i_addr2, sa);
116148314Ssam			IEEE80211_ADDR_COPY(wh->i_addr3, bssid);
117148314Ssam			break;
118148314Ssam		case IEEE80211_M_HOSTAP:
119148314Ssam			wh->i_fc[1] = IEEE80211_FC1_DIR_FROMDS;
120148314Ssam			IEEE80211_ADDR_COPY(wh->i_addr1, da);
121148314Ssam			IEEE80211_ADDR_COPY(wh->i_addr2, bssid);
122148314Ssam			IEEE80211_ADDR_COPY(wh->i_addr3, sa);
123148314Ssam			break;
124170530Ssam		case IEEE80211_M_WDS:
125170530Ssam			wh->i_fc[1] = IEEE80211_FC1_DIR_DSTODS;
126170530Ssam			/* XXX cheat, bssid holds RA */
127170530Ssam			IEEE80211_ADDR_COPY(wh->i_addr1, bssid);
128170530Ssam			IEEE80211_ADDR_COPY(wh->i_addr2, ic->ic_myaddr);
129170530Ssam			IEEE80211_ADDR_COPY(wh->i_addr3, da);
130170530Ssam			IEEE80211_ADDR_COPY(WH4(wh)->i_addr4, sa);
131170530Ssam			break;
132148314Ssam		case IEEE80211_M_MONITOR:	/* NB: to quiet compiler */
133148314Ssam			break;
134148314Ssam		}
135148314Ssam	} else {
136148314Ssam		wh->i_fc[1] = IEEE80211_FC1_DIR_NODS;
137148314Ssam		IEEE80211_ADDR_COPY(wh->i_addr1, da);
138148314Ssam		IEEE80211_ADDR_COPY(wh->i_addr2, sa);
139148314Ssam		IEEE80211_ADDR_COPY(wh->i_addr3, bssid);
140148314Ssam	}
141170530Ssam	*(uint16_t *)&wh->i_dur[0] = 0;
142148314Ssam	/* NB: use non-QoS tid */
143170530Ssam	*(uint16_t *)&wh->i_seq[0] =
144167439Ssam	    htole16(ni->ni_txseqs[IEEE80211_NONQOS_TID] << IEEE80211_SEQ_SEQ_SHIFT);
145167439Ssam	ni->ni_txseqs[IEEE80211_NONQOS_TID]++;
146148314Ssam#undef WH4
147148314Ssam}
148148314Ssam
149148314Ssam/*
150119150Ssam * Send a management frame to the specified node.  The node pointer
151119150Ssam * must have a reference as the pointer will be passed to the driver
152119150Ssam * and potentially held for a long time.  If the frame is successfully
153119150Ssam * dispatched to the driver, then it is responsible for freeing the
154119150Ssam * reference (and potentially free'ing up any associated storage).
155119150Ssam */
156170530Ssamint
157138568Ssamieee80211_mgmt_output(struct ieee80211com *ic, struct ieee80211_node *ni,
158170530Ssam    struct mbuf *m, int type)
159116742Ssam{
160138568Ssam	struct ifnet *ifp = ic->ic_ifp;
161116742Ssam	struct ieee80211_frame *wh;
162116742Ssam
163119150Ssam	KASSERT(ni != NULL, ("null node"));
164116742Ssam
165119150Ssam	/*
166119150Ssam	 * Yech, hack alert!  We want to pass the node down to the
167119150Ssam	 * driver's start routine.  If we don't do so then the start
168119150Ssam	 * routine must immediately look it up again and that can
169119150Ssam	 * cause a lock order reversal if, for example, this frame
170119150Ssam	 * is being sent because the station is being timedout and
171119150Ssam	 * the frame being sent is a DEAUTH message.  We could stick
172119150Ssam	 * this in an m_tag and tack that on to the mbuf.  However
173119150Ssam	 * that's rather expensive to do for every frame so instead
174119150Ssam	 * we stuff it in the rcvif field since outbound frames do
175119150Ssam	 * not (presently) use this.
176119150Ssam	 */
177116742Ssam	M_PREPEND(m, sizeof(struct ieee80211_frame), M_DONTWAIT);
178116742Ssam	if (m == NULL)
179116742Ssam		return ENOMEM;
180119150Ssam	KASSERT(m->m_pkthdr.rcvif == NULL, ("rcvif not null"));
181119150Ssam	m->m_pkthdr.rcvif = (void *)ni;
182119150Ssam
183116742Ssam	wh = mtod(m, struct ieee80211_frame *);
184148314Ssam	ieee80211_send_setup(ic, ni, wh,
185148314Ssam		IEEE80211_FC0_TYPE_MGT | type,
186148314Ssam		ic->ic_myaddr, ni->ni_macaddr, ni->ni_bssid);
187138568Ssam	if ((m->m_flags & M_LINK0) != 0 && ni->ni_challenge != NULL) {
188138568Ssam		m->m_flags &= ~M_LINK0;
189138568Ssam		IEEE80211_DPRINTF(ic, IEEE80211_MSG_AUTH,
190138568Ssam			"[%s] encrypting frame (%s)\n",
191138568Ssam			ether_sprintf(wh->i_addr1), __func__);
192138568Ssam		wh->i_fc[1] |= IEEE80211_FC1_WEP;
193138568Ssam	}
194172231Ssam	if (ni->ni_flags & IEEE80211_NODE_QOS) {
195172231Ssam		/* NB: force all management frames to the highest queue */
196172231Ssam		M_WME_SETAC(m, WME_AC_VO);
197172231Ssam	} else
198172231Ssam		M_WME_SETAC(m, WME_AC_BE);
199116742Ssam#ifdef IEEE80211_DEBUG
200138568Ssam	/* avoid printing too many frames */
201138568Ssam	if ((ieee80211_msg_debug(ic) && doprint(ic, type)) ||
202138568Ssam	    ieee80211_msg_dumppkts(ic)) {
203138568Ssam		printf("[%s] send %s on channel %u\n",
204138568Ssam		    ether_sprintf(wh->i_addr1),
205138568Ssam		    ieee80211_mgt_subtype_name[
206138568Ssam			(type & IEEE80211_FC0_SUBTYPE_MASK) >>
207138568Ssam				IEEE80211_FC0_SUBTYPE_SHIFT],
208148936Ssam		    ieee80211_chan2ieee(ic, ic->ic_curchan));
209138568Ssam	}
210116742Ssam#endif
211138568Ssam	IEEE80211_NODE_STAT(ni, tx_mgmt);
212116742Ssam	IF_ENQUEUE(&ic->ic_mgtq, m);
213132712Srwatson	if_start(ifp);
214170530Ssam	ifp->if_opackets++;
215170530Ssam
216116742Ssam	return 0;
217116742Ssam}
218116742Ssam
219119150Ssam/*
220160690Ssam * Raw packet transmit stub for legacy drivers.
221160690Ssam * Send the packet through the mgt q so we bypass
222160690Ssam * the normal encapsulation work.
223160690Ssam */
224160690Ssamint
225160690Ssamieee80211_raw_xmit(struct ieee80211_node *ni, struct mbuf *m,
226160690Ssam	const struct ieee80211_bpf_params *params)
227160690Ssam{
228160690Ssam	struct ieee80211com *ic = ni->ni_ic;
229160690Ssam	struct ifnet *ifp = ic->ic_ifp;
230160690Ssam
231160690Ssam	m->m_pkthdr.rcvif = (void *) ni;
232160690Ssam	IF_ENQUEUE(&ic->ic_mgtq, m);
233160690Ssam	if_start(ifp);
234160690Ssam	ifp->if_opackets++;
235160690Ssam
236160690Ssam	return 0;
237160690Ssam}
238160690Ssam
239160690Ssam/*
240160690Ssam * 802.11 output routine. This is (currently) used only to
241160690Ssam * connect bpf write calls to the 802.11 layer for injecting
242160690Ssam * raw 802.11 frames.  Note we locate the ieee80211com from
243160690Ssam * the ifnet using a spare field setup at attach time.  This
244160690Ssam * will go away when the virtual ap support comes in.
245160690Ssam */
246160690Ssamint
247160690Ssamieee80211_output(struct ifnet *ifp, struct mbuf *m,
248160690Ssam	struct sockaddr *dst, struct rtentry *rt0)
249160690Ssam{
250160690Ssam#define senderr(e) do { error = (e); goto bad;} while (0)
251160690Ssam	struct ieee80211com *ic = ifp->if_spare2;	/* XXX */
252160690Ssam	struct ieee80211_node *ni = NULL;
253160690Ssam	struct ieee80211_frame *wh;
254160690Ssam	int error;
255160690Ssam
256160690Ssam	/*
257160690Ssam	 * Hand to the 802.3 code if not tagged as
258160690Ssam	 * a raw 802.11 frame.
259160690Ssam	 */
260160690Ssam	if (dst->sa_family != AF_IEEE80211)
261160690Ssam		return ether_output(ifp, m, dst, rt0);
262160690Ssam#ifdef MAC
263160690Ssam	error = mac_check_ifnet_transmit(ifp, m);
264160690Ssam	if (error)
265160690Ssam		senderr(error);
266160690Ssam#endif
267160690Ssam	if (ifp->if_flags & IFF_MONITOR)
268160690Ssam		senderr(ENETDOWN);
269160690Ssam	if ((ifp->if_flags & IFF_UP) == 0)
270160690Ssam		senderr(ENETDOWN);
271160690Ssam
272160690Ssam	/* XXX bypass bridge, pfil, carp, etc. */
273160690Ssam
274160690Ssam	if (m->m_pkthdr.len < sizeof(struct ieee80211_frame_ack))
275160690Ssam		senderr(EIO);	/* XXX */
276160690Ssam	wh = mtod(m, struct ieee80211_frame *);
277160690Ssam	if ((wh->i_fc[0] & IEEE80211_FC0_VERSION_MASK) !=
278160690Ssam	    IEEE80211_FC0_VERSION_0)
279160690Ssam		senderr(EIO);	/* XXX */
280160690Ssam
281160690Ssam	/* locate destination node */
282160690Ssam	switch (wh->i_fc[1] & IEEE80211_FC1_DIR_MASK) {
283160690Ssam	case IEEE80211_FC1_DIR_NODS:
284160690Ssam	case IEEE80211_FC1_DIR_FROMDS:
285160690Ssam		ni = ieee80211_find_txnode(ic, wh->i_addr1);
286160690Ssam		break;
287160690Ssam	case IEEE80211_FC1_DIR_TODS:
288160690Ssam	case IEEE80211_FC1_DIR_DSTODS:
289160690Ssam		if (m->m_pkthdr.len < sizeof(struct ieee80211_frame))
290160690Ssam			senderr(EIO);	/* XXX */
291160690Ssam		ni = ieee80211_find_txnode(ic, wh->i_addr3);
292160690Ssam		break;
293160690Ssam	default:
294160690Ssam		senderr(EIO);	/* XXX */
295160690Ssam	}
296160690Ssam	if (ni == NULL) {
297160690Ssam		/*
298160690Ssam		 * Permit packets w/ bpf params through regardless
299160690Ssam		 * (see below about sa_len).
300160690Ssam		 */
301160690Ssam		if (dst->sa_len == 0)
302160690Ssam			senderr(EHOSTUNREACH);
303160690Ssam		ni = ieee80211_ref_node(ic->ic_bss);
304160690Ssam	}
305160690Ssam
306160690Ssam	/* XXX ctrl frames should go through */
307160690Ssam	if ((ni->ni_flags & IEEE80211_NODE_PWR_MGT) &&
308160690Ssam	    (m->m_flags & M_PWR_SAV) == 0) {
309160690Ssam		/*
310160690Ssam		 * Station in power save mode; pass the frame
311160690Ssam		 * to the 802.11 layer and continue.  We'll get
312160690Ssam		 * the frame back when the time is right.
313160690Ssam		 */
314170530Ssam		ieee80211_pwrsave(ni, m);
315160690Ssam		error = 0;
316160690Ssam		goto reclaim;
317160690Ssam	}
318160690Ssam
319160690Ssam	/* calculate priority so drivers can find the tx queue */
320160690Ssam	/* XXX assumes an 802.3 frame */
321160690Ssam	if (ieee80211_classify(ic, m, ni))
322160690Ssam		senderr(EIO);		/* XXX */
323160690Ssam
324160690Ssam	BPF_MTAP(ifp, m);
325160690Ssam	/*
326160690Ssam	 * NB: DLT_IEEE802_11_RADIO identifies the parameters are
327160690Ssam	 * present by setting the sa_len field of the sockaddr (yes,
328160690Ssam	 * this is a hack).
329160690Ssam	 * NB: we assume sa_data is suitably aligned to cast.
330160690Ssam	 */
331160690Ssam	return ic->ic_raw_xmit(ni, m, (const struct ieee80211_bpf_params *)
332160690Ssam		(dst->sa_len ? dst->sa_data : NULL));
333160690Ssambad:
334160690Ssam	if (m != NULL)
335160690Ssam		m_freem(m);
336160690Ssamreclaim:
337160690Ssam	if (ni != NULL)
338160690Ssam		ieee80211_free_node(ni);
339160690Ssam	return error;
340160690Ssam#undef senderr
341160690Ssam}
342160690Ssam
343160690Ssam/*
344138568Ssam * Send a null data frame to the specified node.
345148582Ssam *
346148582Ssam * NB: the caller is assumed to have setup a node reference
347148582Ssam *     for use; this is necessary to deal with a race condition
348148582Ssam *     when probing for inactive stations.
349119150Ssam */
350138568Ssamint
351148301Ssamieee80211_send_nulldata(struct ieee80211_node *ni)
352138568Ssam{
353148301Ssam	struct ieee80211com *ic = ni->ni_ic;
354138568Ssam	struct ifnet *ifp = ic->ic_ifp;
355138568Ssam	struct mbuf *m;
356138568Ssam	struct ieee80211_frame *wh;
357138568Ssam
358151967Sandre	MGETHDR(m, M_NOWAIT, MT_DATA);
359138568Ssam	if (m == NULL) {
360138568Ssam		/* XXX debug msg */
361170530Ssam		ieee80211_unref_node(&ni);
362138568Ssam		ic->ic_stats.is_tx_nobuf++;
363138568Ssam		return ENOMEM;
364138568Ssam	}
365170530Ssam	MH_ALIGN(m, sizeof(struct ieee80211_frame));
366148582Ssam	m->m_pkthdr.rcvif = (void *) ni;
367138568Ssam
368138568Ssam	wh = mtod(m, struct ieee80211_frame *);
369148314Ssam	ieee80211_send_setup(ic, ni, wh,
370148314Ssam		IEEE80211_FC0_TYPE_DATA | IEEE80211_FC0_SUBTYPE_NODATA,
371148314Ssam		ic->ic_myaddr, ni->ni_macaddr, ni->ni_bssid);
372148314Ssam	/* NB: power management bit is never sent by an AP */
373148314Ssam	if ((ni->ni_flags & IEEE80211_NODE_PWR_MGT) &&
374170530Ssam	    ic->ic_opmode != IEEE80211_M_HOSTAP &&
375170530Ssam	    ic->ic_opmode != IEEE80211_M_WDS)
376148314Ssam		wh->i_fc[1] |= IEEE80211_FC1_PWR_MGT;
377138568Ssam	m->m_len = m->m_pkthdr.len = sizeof(struct ieee80211_frame);
378172231Ssam	M_WME_SETAC(m, WME_AC_BE);
379138568Ssam
380138568Ssam	IEEE80211_NODE_STAT(ni, tx_data);
381138568Ssam
382148314Ssam	IEEE80211_DPRINTF(ic, IEEE80211_MSG_DEBUG | IEEE80211_MSG_DUMPPKTS,
383148314Ssam	    "[%s] send null data frame on channel %u, pwr mgt %s\n",
384148314Ssam	    ether_sprintf(ni->ni_macaddr),
385148936Ssam	    ieee80211_chan2ieee(ic, ic->ic_curchan),
386148314Ssam	    wh->i_fc[1] & IEEE80211_FC1_PWR_MGT ? "ena" : "dis");
387148314Ssam
388138568Ssam	IF_ENQUEUE(&ic->ic_mgtq, m);		/* cheat */
389138568Ssam	if_start(ifp);
390138568Ssam
391138568Ssam	return 0;
392138568Ssam}
393138568Ssam
394138568Ssam/*
395138568Ssam * Assign priority to a frame based on any vlan tag assigned
396138568Ssam * to the station and/or any Diffserv setting in an IP header.
397138568Ssam * Finally, if an ACM policy is setup (in station mode) it's
398138568Ssam * applied.
399138568Ssam */
400138568Ssamint
401138568Ssamieee80211_classify(struct ieee80211com *ic, struct mbuf *m, struct ieee80211_node *ni)
402138568Ssam{
403138568Ssam	int v_wme_ac, d_wme_ac, ac;
404138568Ssam#ifdef INET
405138568Ssam	struct ether_header *eh;
406138568Ssam#endif
407138568Ssam
408138568Ssam	if ((ni->ni_flags & IEEE80211_NODE_QOS) == 0) {
409138568Ssam		ac = WME_AC_BE;
410138568Ssam		goto done;
411138568Ssam	}
412138568Ssam
413138568Ssam	/*
414138568Ssam	 * If node has a vlan tag then all traffic
415138568Ssam	 * to it must have a matching tag.
416138568Ssam	 */
417138568Ssam	v_wme_ac = 0;
418138568Ssam	if (ni->ni_vlan != 0) {
419162375Sandre		 if ((m->m_flags & M_VLANTAG) == 0) {
420138568Ssam			IEEE80211_NODE_STAT(ni, tx_novlantag);
421138568Ssam			return 1;
422138568Ssam		}
423162375Sandre		if (EVL_VLANOFTAG(m->m_pkthdr.ether_vtag) !=
424138568Ssam		    EVL_VLANOFTAG(ni->ni_vlan)) {
425138568Ssam			IEEE80211_NODE_STAT(ni, tx_vlanmismatch);
426138568Ssam			return 1;
427138568Ssam		}
428138568Ssam		/* map vlan priority to AC */
429138568Ssam		switch (EVL_PRIOFTAG(ni->ni_vlan)) {
430138568Ssam		case 1:
431138568Ssam		case 2:
432138568Ssam			v_wme_ac = WME_AC_BK;
433138568Ssam			break;
434138568Ssam		case 0:
435138568Ssam		case 3:
436138568Ssam			v_wme_ac = WME_AC_BE;
437138568Ssam			break;
438138568Ssam		case 4:
439138568Ssam		case 5:
440138568Ssam			v_wme_ac = WME_AC_VI;
441138568Ssam			break;
442138568Ssam		case 6:
443138568Ssam		case 7:
444138568Ssam			v_wme_ac = WME_AC_VO;
445138568Ssam			break;
446138568Ssam		}
447138568Ssam	}
448138568Ssam
449138568Ssam#ifdef INET
450138568Ssam	eh = mtod(m, struct ether_header *);
451138568Ssam	if (eh->ether_type == htons(ETHERTYPE_IP)) {
452138568Ssam		const struct ip *ip = (struct ip *)
453170530Ssam			(mtod(m, uint8_t *) + sizeof (*eh));
454138568Ssam		/*
455138568Ssam		 * IP frame, map the TOS field.
456138568Ssam		 */
457138568Ssam		switch (ip->ip_tos) {
458138568Ssam		case 0x08:
459138568Ssam		case 0x20:
460138568Ssam			d_wme_ac = WME_AC_BK;	/* background */
461138568Ssam			break;
462138568Ssam		case 0x28:
463138568Ssam		case 0xa0:
464138568Ssam			d_wme_ac = WME_AC_VI;	/* video */
465138568Ssam			break;
466138568Ssam		case 0x30:			/* voice */
467138568Ssam		case 0xe0:
468138568Ssam		case 0x88:			/* XXX UPSD */
469138568Ssam		case 0xb8:
470138568Ssam			d_wme_ac = WME_AC_VO;
471138568Ssam			break;
472138568Ssam		default:
473138568Ssam			d_wme_ac = WME_AC_BE;
474138568Ssam			break;
475138568Ssam		}
476138568Ssam	} else {
477138568Ssam#endif /* INET */
478138568Ssam		d_wme_ac = WME_AC_BE;
479138568Ssam#ifdef INET
480138568Ssam	}
481138568Ssam#endif
482138568Ssam	/*
483138568Ssam	 * Use highest priority AC.
484138568Ssam	 */
485138568Ssam	if (v_wme_ac > d_wme_ac)
486138568Ssam		ac = v_wme_ac;
487138568Ssam	else
488138568Ssam		ac = d_wme_ac;
489138568Ssam
490138568Ssam	/*
491138568Ssam	 * Apply ACM policy.
492138568Ssam	 */
493138568Ssam	if (ic->ic_opmode == IEEE80211_M_STA) {
494138568Ssam		static const int acmap[4] = {
495138568Ssam			WME_AC_BK,	/* WME_AC_BE */
496138568Ssam			WME_AC_BK,	/* WME_AC_BK */
497138568Ssam			WME_AC_BE,	/* WME_AC_VI */
498138568Ssam			WME_AC_VI,	/* WME_AC_VO */
499138568Ssam		};
500138568Ssam		while (ac != WME_AC_BK &&
501138568Ssam		    ic->ic_wme.wme_wmeBssChanParams.cap_wmeParams[ac].wmep_acm)
502138568Ssam			ac = acmap[ac];
503138568Ssam	}
504138568Ssamdone:
505138568Ssam	M_WME_SETAC(m, ac);
506138568Ssam	return 0;
507138568Ssam}
508138568Ssam
509138568Ssam/*
510139527Ssam * Insure there is sufficient contiguous space to encapsulate the
511139527Ssam * 802.11 data frame.  If room isn't already there, arrange for it.
512139527Ssam * Drivers and cipher modules assume we have done the necessary work
513139527Ssam * and fail rudely if they don't find the space they need.
514139527Ssam */
515139527Ssamstatic struct mbuf *
516139527Ssamieee80211_mbuf_adjust(struct ieee80211com *ic, int hdrsize,
517139527Ssam	struct ieee80211_key *key, struct mbuf *m)
518139527Ssam{
519164805Ssam#define	TO_BE_RECLAIMED	(sizeof(struct ether_header) - sizeof(struct llc))
520170530Ssam	int needed_space = ic->ic_headroom + hdrsize;
521139527Ssam
522139527Ssam	if (key != NULL) {
523139527Ssam		/* XXX belongs in crypto code? */
524139527Ssam		needed_space += key->wk_cipher->ic_header;
525139527Ssam		/* XXX frags */
526156758Ssam		/*
527156758Ssam		 * When crypto is being done in the host we must insure
528156758Ssam		 * the data are writable for the cipher routines; clone
529156758Ssam		 * a writable mbuf chain.
530156758Ssam		 * XXX handle SWMIC specially
531156758Ssam		 */
532156758Ssam		if (key->wk_flags & (IEEE80211_KEY_SWCRYPT|IEEE80211_KEY_SWMIC)) {
533156758Ssam			m = m_unshare(m, M_NOWAIT);
534156758Ssam			if (m == NULL) {
535156758Ssam				IEEE80211_DPRINTF(ic, IEEE80211_MSG_OUTPUT,
536156758Ssam				    "%s: cannot get writable mbuf\n", __func__);
537156758Ssam				ic->ic_stats.is_tx_nobuf++; /* XXX new stat */
538156758Ssam				return NULL;
539156758Ssam			}
540156758Ssam		}
541139527Ssam	}
542139527Ssam	/*
543139527Ssam	 * We know we are called just before stripping an Ethernet
544139527Ssam	 * header and prepending an LLC header.  This means we know
545139527Ssam	 * there will be
546164805Ssam	 *	sizeof(struct ether_header) - sizeof(struct llc)
547139527Ssam	 * bytes recovered to which we need additional space for the
548139527Ssam	 * 802.11 header and any crypto header.
549139527Ssam	 */
550139527Ssam	/* XXX check trailing space and copy instead? */
551139527Ssam	if (M_LEADINGSPACE(m) < needed_space - TO_BE_RECLAIMED) {
552139527Ssam		struct mbuf *n = m_gethdr(M_NOWAIT, m->m_type);
553139527Ssam		if (n == NULL) {
554139527Ssam			IEEE80211_DPRINTF(ic, IEEE80211_MSG_OUTPUT,
555139527Ssam			    "%s: cannot expand storage\n", __func__);
556139527Ssam			ic->ic_stats.is_tx_nobuf++;
557139527Ssam			m_freem(m);
558139527Ssam			return NULL;
559139527Ssam		}
560139527Ssam		KASSERT(needed_space <= MHLEN,
561139527Ssam		    ("not enough room, need %u got %zu\n", needed_space, MHLEN));
562139527Ssam		/*
563139527Ssam		 * Setup new mbuf to have leading space to prepend the
564139527Ssam		 * 802.11 header and any crypto header bits that are
565139527Ssam		 * required (the latter are added when the driver calls
566139527Ssam		 * back to ieee80211_crypto_encap to do crypto encapsulation).
567139527Ssam		 */
568139527Ssam		/* NB: must be first 'cuz it clobbers m_data */
569139527Ssam		m_move_pkthdr(n, m);
570139527Ssam		n->m_len = 0;			/* NB: m_gethdr does not set */
571139527Ssam		n->m_data += needed_space;
572139527Ssam		/*
573139527Ssam		 * Pull up Ethernet header to create the expected layout.
574139527Ssam		 * We could use m_pullup but that's overkill (i.e. we don't
575139527Ssam		 * need the actual data) and it cannot fail so do it inline
576139527Ssam		 * for speed.
577139527Ssam		 */
578139527Ssam		/* NB: struct ether_header is known to be contiguous */
579139527Ssam		n->m_len += sizeof(struct ether_header);
580139527Ssam		m->m_len -= sizeof(struct ether_header);
581139527Ssam		m->m_data += sizeof(struct ether_header);
582139527Ssam		/*
583139527Ssam		 * Replace the head of the chain.
584139527Ssam		 */
585139527Ssam		n->m_next = m;
586139527Ssam		m = n;
587139527Ssam	}
588139527Ssam	return m;
589139527Ssam#undef TO_BE_RECLAIMED
590139527Ssam}
591139527Ssam
592139527Ssam/*
593139527Ssam * Return the transmit key to use in sending a unicast frame.
594139527Ssam * If a unicast key is set we use that.  When no unicast key is set
595139527Ssam * we fall back to the default transmit key.
596138568Ssam */
597138568Ssamstatic __inline struct ieee80211_key *
598139527Ssamieee80211_crypto_getucastkey(struct ieee80211com *ic, struct ieee80211_node *ni)
599138568Ssam{
600167432Ssam	if (IEEE80211_KEY_UNDEFINED(&ni->ni_ucastkey)) {
601138568Ssam		if (ic->ic_def_txkey == IEEE80211_KEYIX_NONE ||
602167432Ssam		    IEEE80211_KEY_UNDEFINED(&ic->ic_nw_keys[ic->ic_def_txkey]))
603138568Ssam			return NULL;
604138568Ssam		return &ic->ic_nw_keys[ic->ic_def_txkey];
605138568Ssam	} else {
606138568Ssam		return &ni->ni_ucastkey;
607138568Ssam	}
608138568Ssam}
609138568Ssam
610138568Ssam/*
611139527Ssam * Return the transmit key to use in sending a multicast frame.
612139527Ssam * Multicast traffic always uses the group key which is installed as
613139527Ssam * the default tx key.
614139527Ssam */
615139527Ssamstatic __inline struct ieee80211_key *
616139527Ssamieee80211_crypto_getmcastkey(struct ieee80211com *ic, struct ieee80211_node *ni)
617139527Ssam{
618139527Ssam	if (ic->ic_def_txkey == IEEE80211_KEYIX_NONE ||
619167432Ssam	    IEEE80211_KEY_UNDEFINED(&ic->ic_nw_keys[ic->ic_def_txkey]))
620139527Ssam		return NULL;
621139527Ssam	return &ic->ic_nw_keys[ic->ic_def_txkey];
622139527Ssam}
623139527Ssam
624139527Ssam/*
625138568Ssam * Encapsulate an outbound data frame.  The mbuf chain is updated.
626138568Ssam * If an error is encountered NULL is returned.  The caller is required
627138568Ssam * to provide a node reference and pullup the ethernet header in the
628138568Ssam * first mbuf.
629138568Ssam */
630116742Ssamstruct mbuf *
631138568Ssamieee80211_encap(struct ieee80211com *ic, struct mbuf *m,
632138568Ssam	struct ieee80211_node *ni)
633116742Ssam{
634116742Ssam	struct ether_header eh;
635116742Ssam	struct ieee80211_frame *wh;
636138568Ssam	struct ieee80211_key *key;
637116742Ssam	struct llc *llc;
638170530Ssam	int hdrsize, datalen, addqos, txfrag, isff;
639116742Ssam
640170530Ssam	/*
641170530Ssam	 * Copy existing Ethernet header to a safe place.  The
642170530Ssam	 * rest of the code assumes it's ok to strip it when
643170530Ssam	 * reorganizing state for the final encapsulation.
644170530Ssam	 */
645138568Ssam	KASSERT(m->m_len >= sizeof(eh), ("no ethernet header!"));
646116742Ssam	memcpy(&eh, mtod(m, caddr_t), sizeof(struct ether_header));
647116742Ssam
648138568Ssam	/*
649138568Ssam	 * Insure space for additional headers.  First identify
650138568Ssam	 * transmit key to use in calculating any buffer adjustments
651138568Ssam	 * required.  This is also used below to do privacy
652138568Ssam	 * encapsulation work.  Then calculate the 802.11 header
653138568Ssam	 * size and any padding required by the driver.
654138568Ssam	 *
655138568Ssam	 * Note key may be NULL if we fall back to the default
656138568Ssam	 * transmit key and that is not set.  In that case the
657138568Ssam	 * buffer may not be expanded as needed by the cipher
658138568Ssam	 * routines, but they will/should discard it.
659138568Ssam	 */
660138568Ssam	if (ic->ic_flags & IEEE80211_F_PRIVACY) {
661139527Ssam		if (ic->ic_opmode == IEEE80211_M_STA ||
662139527Ssam		    !IEEE80211_IS_MULTICAST(eh.ether_dhost))
663139527Ssam			key = ieee80211_crypto_getucastkey(ic, ni);
664139527Ssam		else
665139527Ssam			key = ieee80211_crypto_getmcastkey(ic, ni);
666138568Ssam		if (key == NULL && eh.ether_type != htons(ETHERTYPE_PAE)) {
667138568Ssam			IEEE80211_DPRINTF(ic, IEEE80211_MSG_CRYPTO,
668139527Ssam			    "[%s] no default transmit key (%s) deftxkey %u\n",
669139527Ssam			    ether_sprintf(eh.ether_dhost), __func__,
670139527Ssam			    ic->ic_def_txkey);
671139527Ssam			ic->ic_stats.is_tx_nodefkey++;
672171950Ssam			goto bad;
673138568Ssam		}
674138568Ssam	} else
675138568Ssam		key = NULL;
676138568Ssam	/* XXX 4-address format */
677139527Ssam	/*
678139527Ssam	 * XXX Some ap's don't handle QoS-encapsulated EAPOL
679139527Ssam	 * frames so suppress use.  This may be an issue if other
680139527Ssam	 * ap's require all data frames to be QoS-encapsulated
681139527Ssam	 * once negotiated in which case we'll need to make this
682139527Ssam	 * configurable.
683139527Ssam	 */
684170530Ssam	addqos = (ni->ni_flags & (IEEE80211_NODE_QOS|IEEE80211_NODE_HT)) &&
685139527Ssam		 eh.ether_type != htons(ETHERTYPE_PAE);
686139527Ssam	if (addqos)
687138568Ssam		hdrsize = sizeof(struct ieee80211_qosframe);
688138568Ssam	else
689138568Ssam		hdrsize = sizeof(struct ieee80211_frame);
690138568Ssam	if (ic->ic_flags & IEEE80211_F_DATAPAD)
691170530Ssam		hdrsize = roundup(hdrsize, sizeof(uint32_t));
692170530Ssam
693170530Ssam	if ((isff = m->m_flags & M_FF) != 0) {
694170530Ssam		struct mbuf *m2;
695170530Ssam		struct ether_header eh2;
696170530Ssam
697170530Ssam		/*
698170530Ssam		 * Fast frame encapsulation.  There must be two packets
699170530Ssam		 * chained with m_nextpkt.  We do header adjustment for
700170530Ssam		 * each, add the tunnel encapsulation, and then concatenate
701170530Ssam		 * the mbuf chains to form a single frame for transmission.
702170530Ssam		 */
703170530Ssam		m2 = m->m_nextpkt;
704170530Ssam		if (m2 == NULL) {
705170530Ssam			IEEE80211_DPRINTF(ic, IEEE80211_MSG_SUPERG,
706170530Ssam				"%s: only one frame\n", __func__);
707170530Ssam			goto bad;
708170530Ssam		}
709170530Ssam		m->m_nextpkt = NULL;
710170530Ssam		/*
711170530Ssam		 * Include fast frame headers in adjusting header
712170530Ssam		 * layout; this allocates space according to what
713170530Ssam		 * ieee80211_encap_fastframe will do.
714170530Ssam		 */
715170530Ssam		m = ieee80211_mbuf_adjust(ic,
716170530Ssam			hdrsize + sizeof(struct llc) + sizeof(uint32_t) + 2 +
717170530Ssam			    sizeof(struct ether_header),
718170530Ssam			key, m);
719170530Ssam		if (m == NULL) {
720170530Ssam			/* NB: ieee80211_mbuf_adjust handles msgs+statistics */
721170530Ssam			m_freem(m2);
722170530Ssam			goto bad;
723170530Ssam		}
724170530Ssam		/*
725170530Ssam		 * Copy second frame's Ethernet header out of line
726170530Ssam		 * and adjust for encapsulation headers.  Note that
727170530Ssam		 * we make room for padding in case there isn't room
728170530Ssam		 * at the end of first frame.
729170530Ssam		 */
730170530Ssam		KASSERT(m2->m_len >= sizeof(eh2), ("no ethernet header!"));
731170530Ssam		memcpy(&eh2, mtod(m2, caddr_t), sizeof(struct ether_header));
732170530Ssam		m2 = ieee80211_mbuf_adjust(ic,
733170530Ssam			ATH_FF_MAX_HDR_PAD + sizeof(struct ether_header),
734170530Ssam			NULL, m2);
735170530Ssam		if (m2 == NULL) {
736170530Ssam			/* NB: ieee80211_mbuf_adjust handles msgs+statistics */
737170530Ssam			goto bad;
738170530Ssam		}
739170530Ssam		m = ieee80211_encap_fastframe(ic, m, &eh, m2, &eh2);
740170530Ssam		if (m == NULL)
741170530Ssam			goto bad;
742170530Ssam	} else {
743170530Ssam		/*
744170530Ssam		 * Normal frame.
745170530Ssam		 */
746170530Ssam		m = ieee80211_mbuf_adjust(ic, hdrsize, key, m);
747170530Ssam		if (m == NULL) {
748170530Ssam			/* NB: ieee80211_mbuf_adjust handles msgs+statistics */
749170530Ssam			goto bad;
750170530Ssam		}
751170530Ssam		/* NB: this could be optimized 'cuz of ieee80211_mbuf_adjust */
752170530Ssam		m_adj(m, sizeof(struct ether_header) - sizeof(struct llc));
753170530Ssam		llc = mtod(m, struct llc *);
754170530Ssam		llc->llc_dsap = llc->llc_ssap = LLC_SNAP_LSAP;
755170530Ssam		llc->llc_control = LLC_UI;
756170530Ssam		llc->llc_snap.org_code[0] = 0;
757170530Ssam		llc->llc_snap.org_code[1] = 0;
758170530Ssam		llc->llc_snap.org_code[2] = 0;
759170530Ssam		llc->llc_snap.ether_type = eh.ether_type;
760127772Ssam	}
761138568Ssam	datalen = m->m_pkthdr.len;		/* NB: w/o 802.11 header */
762138568Ssam
763138568Ssam	M_PREPEND(m, hdrsize, M_DONTWAIT);
764121180Ssam	if (m == NULL) {
765138568Ssam		ic->ic_stats.is_tx_nobuf++;
766119150Ssam		goto bad;
767121180Ssam	}
768116742Ssam	wh = mtod(m, struct ieee80211_frame *);
769116742Ssam	wh->i_fc[0] = IEEE80211_FC0_VERSION_0 | IEEE80211_FC0_TYPE_DATA;
770170530Ssam	*(uint16_t *)wh->i_dur = 0;
771116742Ssam	switch (ic->ic_opmode) {
772116742Ssam	case IEEE80211_M_STA:
773116742Ssam		wh->i_fc[1] = IEEE80211_FC1_DIR_TODS;
774116742Ssam		IEEE80211_ADDR_COPY(wh->i_addr1, ni->ni_bssid);
775116742Ssam		IEEE80211_ADDR_COPY(wh->i_addr2, eh.ether_shost);
776116742Ssam		IEEE80211_ADDR_COPY(wh->i_addr3, eh.ether_dhost);
777116742Ssam		break;
778116742Ssam	case IEEE80211_M_IBSS:
779116742Ssam	case IEEE80211_M_AHDEMO:
780116742Ssam		wh->i_fc[1] = IEEE80211_FC1_DIR_NODS;
781116742Ssam		IEEE80211_ADDR_COPY(wh->i_addr1, eh.ether_dhost);
782116742Ssam		IEEE80211_ADDR_COPY(wh->i_addr2, eh.ether_shost);
783140636Ssam		/*
784140636Ssam		 * NB: always use the bssid from ic_bss as the
785140636Ssam		 *     neighbor's may be stale after an ibss merge
786140636Ssam		 */
787140636Ssam		IEEE80211_ADDR_COPY(wh->i_addr3, ic->ic_bss->ni_bssid);
788116742Ssam		break;
789116742Ssam	case IEEE80211_M_HOSTAP:
790116742Ssam		wh->i_fc[1] = IEEE80211_FC1_DIR_FROMDS;
791116742Ssam		IEEE80211_ADDR_COPY(wh->i_addr1, eh.ether_dhost);
792116742Ssam		IEEE80211_ADDR_COPY(wh->i_addr2, ni->ni_bssid);
793116742Ssam		IEEE80211_ADDR_COPY(wh->i_addr3, eh.ether_shost);
794116742Ssam		break;
795117817Ssam	case IEEE80211_M_MONITOR:
796170530Ssam	case IEEE80211_M_WDS:
797119150Ssam		goto bad;
798116742Ssam	}
799147789Ssam	if (m->m_flags & M_MORE_DATA)
800147789Ssam		wh->i_fc[1] |= IEEE80211_FC1_MORE_DATA;
801139527Ssam	if (addqos) {
802138568Ssam		struct ieee80211_qosframe *qwh =
803138568Ssam			(struct ieee80211_qosframe *) wh;
804138568Ssam		int ac, tid;
805138568Ssam
806138568Ssam		ac = M_WME_GETAC(m);
807138568Ssam		/* map from access class/queue to 11e header priorty value */
808138568Ssam		tid = WME_AC_TO_TID(ac);
809138568Ssam		qwh->i_qos[0] = tid & IEEE80211_QOS_TID;
810170530Ssam		/*
811170530Ssam		 * Check if A-MPDU tx aggregation is setup or if we
812170530Ssam		 * should try to enable it.  The sta must be associated
813170530Ssam		 * with HT and A-MPDU enabled for use.  On the first
814170530Ssam		 * frame that goes out We issue an ADDBA request and
815170530Ssam		 * wait for a reply.  The frame being encapsulated
816170530Ssam		 * will go out w/o using A-MPDU, or possibly it might
817170530Ssam		 * be collected by the driver and held/retransmit.
818170530Ssam		 * ieee80211_ampdu_request handles staggering requests
819170530Ssam		 * in case the receiver NAK's us or we are otherwise
820170530Ssam		 * unable to establish a BA stream.
821170530Ssam		 */
822170530Ssam		if ((ni->ni_flags & IEEE80211_NODE_HT) &&
823170530Ssam		    (ic->ic_flags_ext & IEEE80211_FEXT_AMPDU_TX)) {
824170530Ssam			struct ieee80211_tx_ampdu *tap = &ni->ni_tx_ampdu[ac];
825170530Ssam
826170530Ssam			if (IEEE80211_AMPDU_RUNNING(tap)) {
827170530Ssam				/*
828170530Ssam				 * Operational, mark frame for aggregation.
829170530Ssam				 */
830170530Ssam				qwh->i_qos[0] |= IEEE80211_QOS_ACKPOLICY_BA;
831170530Ssam			} else if (!IEEE80211_AMPDU_REQUESTED(tap)) {
832170530Ssam				/*
833170530Ssam				 * Not negotiated yet, request service.
834170530Ssam				 */
835170530Ssam				ieee80211_ampdu_request(ni, tap);
836170530Ssam			}
837170530Ssam		}
838170530Ssam		/* XXX works even when BA marked above */
839138568Ssam		if (ic->ic_wme.wme_wmeChanParams.cap_wmeParams[ac].wmep_noackPolicy)
840170530Ssam			qwh->i_qos[0] |= IEEE80211_QOS_ACKPOLICY_NOACK;
841138568Ssam		qwh->i_qos[1] = 0;
842138568Ssam		qwh->i_fc[0] |= IEEE80211_FC0_SUBTYPE_QOS;
843138568Ssam
844170530Ssam		*(uint16_t *)wh->i_seq =
845138568Ssam		    htole16(ni->ni_txseqs[tid] << IEEE80211_SEQ_SEQ_SHIFT);
846138568Ssam		ni->ni_txseqs[tid]++;
847138568Ssam	} else {
848170530Ssam		*(uint16_t *)wh->i_seq =
849167439Ssam		    htole16(ni->ni_txseqs[IEEE80211_NONQOS_TID] << IEEE80211_SEQ_SEQ_SHIFT);
850167439Ssam		ni->ni_txseqs[IEEE80211_NONQOS_TID]++;
851138568Ssam	}
852170530Ssam	/* check if xmit fragmentation is required */
853170530Ssam	txfrag = (m->m_pkthdr.len > ic->ic_fragthreshold &&
854170530Ssam	    !IEEE80211_IS_MULTICAST(wh->i_addr1) &&
855170530Ssam	    !isff);		/* NB: don't fragment ff's */
856139527Ssam	if (key != NULL) {
857139527Ssam		/*
858139527Ssam		 * IEEE 802.1X: send EAPOL frames always in the clear.
859139527Ssam		 * WPA/WPA2: encrypt EAPOL keys when pairwise keys are set.
860139527Ssam		 */
861139527Ssam		if (eh.ether_type != htons(ETHERTYPE_PAE) ||
862139527Ssam		    ((ic->ic_flags & IEEE80211_F_WPA) &&
863141660Ssam		     (ic->ic_opmode == IEEE80211_M_STA ?
864167432Ssam		      !IEEE80211_KEY_UNDEFINED(key) :
865167432Ssam		      !IEEE80211_KEY_UNDEFINED(&ni->ni_ucastkey)))) {
866139527Ssam			wh->i_fc[1] |= IEEE80211_FC1_WEP;
867170530Ssam			if (!ieee80211_crypto_enmic(ic, key, m, txfrag)) {
868139527Ssam				IEEE80211_DPRINTF(ic, IEEE80211_MSG_OUTPUT,
869139527Ssam				    "[%s] enmic failed, discard frame\n",
870139527Ssam				    ether_sprintf(eh.ether_dhost));
871139527Ssam				ic->ic_stats.is_crypto_enmicfail++;
872139527Ssam				goto bad;
873139527Ssam			}
874139527Ssam		}
875139527Ssam	}
876170530Ssam	/*
877170530Ssam	 * NB: frag flags may leak from above; they should only
878170530Ssam	 *     be set on return to the caller if we fragment at
879170530Ssam	 *     the 802.11 layer.
880170530Ssam	 */
881170530Ssam	m->m_flags &= ~(M_FRAG | M_FIRSTFRAG);
882170530Ssam	if (txfrag && !ieee80211_fragment(ic, m, hdrsize,
883170530Ssam	    key != NULL ? key->wk_cipher->ic_header : 0, ic->ic_fragthreshold))
884170530Ssam		goto bad;
885138568Ssam
886138568Ssam	IEEE80211_NODE_STAT(ni, tx_data);
887161144Ssam	if (IEEE80211_IS_MULTICAST(wh->i_addr1))
888161144Ssam		IEEE80211_NODE_STAT(ni, tx_mcast);
889161144Ssam	else
890161144Ssam		IEEE80211_NODE_STAT(ni, tx_ucast);
891138568Ssam	IEEE80211_NODE_STAT_ADD(ni, tx_bytes, datalen);
892138568Ssam
893116742Ssam	return m;
894119150Ssambad:
895119150Ssam	if (m != NULL)
896119150Ssam		m_freem(m);
897119150Ssam	return NULL;
898116742Ssam}
899116742Ssam
900116742Ssam/*
901170530Ssam * Do Ethernet-LLC encapsulation for each payload in a fast frame
902170530Ssam * tunnel encapsulation.  The frame is assumed to have an Ethernet
903170530Ssam * header at the front that must be stripped before prepending the
904170530Ssam * LLC followed by the Ethernet header passed in (with an Ethernet
905170530Ssam * type that specifies the payload size).
906170530Ssam */
907170530Ssamstatic struct mbuf *
908170530Ssamieee80211_encap1(struct ieee80211com *ic, struct mbuf *m,
909170530Ssam	const struct ether_header *eh)
910170530Ssam{
911170530Ssam	struct llc *llc;
912170530Ssam	uint16_t payload;
913170530Ssam
914170530Ssam	/* XXX optimize by combining m_adj+M_PREPEND */
915170530Ssam	m_adj(m, sizeof(struct ether_header) - sizeof(struct llc));
916170530Ssam	llc = mtod(m, struct llc *);
917170530Ssam	llc->llc_dsap = llc->llc_ssap = LLC_SNAP_LSAP;
918170530Ssam	llc->llc_control = LLC_UI;
919170530Ssam	llc->llc_snap.org_code[0] = 0;
920170530Ssam	llc->llc_snap.org_code[1] = 0;
921170530Ssam	llc->llc_snap.org_code[2] = 0;
922170530Ssam	llc->llc_snap.ether_type = eh->ether_type;
923170530Ssam	payload = m->m_pkthdr.len;		/* NB: w/o Ethernet header */
924170530Ssam
925170530Ssam	M_PREPEND(m, sizeof(struct ether_header), M_DONTWAIT);
926170530Ssam	if (m == NULL) {		/* XXX cannot happen */
927170530Ssam		IEEE80211_DPRINTF(ic, IEEE80211_MSG_SUPERG,
928170530Ssam			"%s: no space for ether_header\n", __func__);
929170530Ssam		ic->ic_stats.is_tx_nobuf++;
930170530Ssam		return NULL;
931170530Ssam	}
932170530Ssam	ETHER_HEADER_COPY(mtod(m, void *), eh);
933170530Ssam	mtod(m, struct ether_header *)->ether_type = htons(payload);
934170530Ssam	return m;
935170530Ssam}
936170530Ssam
937170530Ssam/*
938170530Ssam * Do fast frame tunnel encapsulation.  The two frames and
939170530Ssam * Ethernet headers are supplied.  The caller is assumed to
940170530Ssam * have arrange for space in the mbuf chains for encapsulating
941170530Ssam * headers (to avoid major mbuf fragmentation).
942170530Ssam *
943170530Ssam * The encapsulated frame is returned or NULL if there is a
944170530Ssam * problem (should not happen).
945170530Ssam */
946170530Ssamstatic struct mbuf *
947170530Ssamieee80211_encap_fastframe(struct ieee80211com *ic,
948170530Ssam	struct mbuf *m1, const struct ether_header *eh1,
949170530Ssam	struct mbuf *m2, const struct ether_header *eh2)
950170530Ssam{
951170530Ssam	struct llc *llc;
952170530Ssam	struct mbuf *m;
953170530Ssam	int pad;
954170530Ssam
955170530Ssam	/*
956170530Ssam	 * First, each frame gets a standard encapsulation.
957170530Ssam	 */
958170530Ssam	m1 = ieee80211_encap1(ic, m1, eh1);
959170530Ssam	if (m1 == NULL) {
960170530Ssam		m_freem(m2);
961170530Ssam		return NULL;
962170530Ssam	}
963170530Ssam	m2 = ieee80211_encap1(ic, m2, eh2);
964170530Ssam	if (m2 == NULL) {
965170530Ssam		m_freem(m1);
966170530Ssam		return NULL;
967170530Ssam	}
968170530Ssam
969170530Ssam	/*
970170530Ssam	 * Pad leading frame to a 4-byte boundary.  If there
971170530Ssam	 * is space at the end of the first frame, put it
972170530Ssam	 * there; otherwise prepend to the front of the second
973170530Ssam	 * frame.  We know doing the second will always work
974170530Ssam	 * because we reserve space above.  We prefer appending
975170530Ssam	 * as this typically has better DMA alignment properties.
976170530Ssam	 */
977170530Ssam	for (m = m1; m->m_next != NULL; m = m->m_next)
978170530Ssam		;
979170530Ssam	pad = roundup2(m1->m_pkthdr.len, 4) - m1->m_pkthdr.len;
980170530Ssam	if (pad) {
981170530Ssam		if (M_TRAILINGSPACE(m) < pad) {		/* prepend to second */
982170530Ssam			m2->m_data -= pad;
983170530Ssam			m2->m_len += pad;
984170530Ssam			m2->m_pkthdr.len += pad;
985170530Ssam		} else {				/* append to first */
986170530Ssam			m->m_len += pad;
987170530Ssam			m1->m_pkthdr.len += pad;
988170530Ssam		}
989170530Ssam	}
990170530Ssam
991170530Ssam	/*
992170530Ssam	 * Now, stick 'em together and prepend the tunnel headers;
993170530Ssam	 * first the Atheros tunnel header (all zero for now) and
994170530Ssam	 * then a special fast frame LLC.
995170530Ssam	 *
996170530Ssam	 * XXX optimize by prepending together
997170530Ssam	 */
998170530Ssam	m->m_next = m2;			/* NB: last mbuf from above */
999170530Ssam	m1->m_pkthdr.len += m2->m_pkthdr.len;
1000170530Ssam	M_PREPEND(m1, sizeof(uint32_t)+2, M_DONTWAIT);
1001170530Ssam	if (m1 == NULL) {		/* XXX cannot happen */
1002170530Ssam		IEEE80211_DPRINTF(ic, IEEE80211_MSG_SUPERG,
1003170530Ssam			"%s: no space for tunnel header\n", __func__);
1004170530Ssam		ic->ic_stats.is_tx_nobuf++;
1005170530Ssam		return NULL;
1006170530Ssam	}
1007170530Ssam	memset(mtod(m1, void *), 0, sizeof(uint32_t)+2);
1008170530Ssam
1009170530Ssam	M_PREPEND(m1, sizeof(struct llc), M_DONTWAIT);
1010170530Ssam	if (m1 == NULL) {		/* XXX cannot happen */
1011170530Ssam		IEEE80211_DPRINTF(ic, IEEE80211_MSG_SUPERG,
1012170530Ssam			"%s: no space for llc header\n", __func__);
1013170530Ssam		ic->ic_stats.is_tx_nobuf++;
1014170530Ssam		return NULL;
1015170530Ssam	}
1016170530Ssam	llc = mtod(m1, struct llc *);
1017170530Ssam	llc->llc_dsap = llc->llc_ssap = LLC_SNAP_LSAP;
1018170530Ssam	llc->llc_control = LLC_UI;
1019170530Ssam	llc->llc_snap.org_code[0] = ATH_FF_SNAP_ORGCODE_0;
1020170530Ssam	llc->llc_snap.org_code[1] = ATH_FF_SNAP_ORGCODE_1;
1021170530Ssam	llc->llc_snap.org_code[2] = ATH_FF_SNAP_ORGCODE_2;
1022170530Ssam	llc->llc_snap.ether_type = htons(ATH_FF_ETH_TYPE);
1023170530Ssam
1024170530Ssam	ic->ic_stats.is_ff_encap++;
1025170530Ssam
1026170530Ssam	return m1;
1027170530Ssam}
1028170530Ssam
1029170530Ssam/*
1030170530Ssam * Fragment the frame according to the specified mtu.
1031170530Ssam * The size of the 802.11 header (w/o padding) is provided
1032170530Ssam * so we don't need to recalculate it.  We create a new
1033170530Ssam * mbuf for each fragment and chain it through m_nextpkt;
1034170530Ssam * we might be able to optimize this by reusing the original
1035170530Ssam * packet's mbufs but that is significantly more complicated.
1036170530Ssam */
1037170530Ssamstatic int
1038170530Ssamieee80211_fragment(struct ieee80211com *ic, struct mbuf *m0,
1039170530Ssam	u_int hdrsize, u_int ciphdrsize, u_int mtu)
1040170530Ssam{
1041170530Ssam	struct ieee80211_frame *wh, *whf;
1042170530Ssam	struct mbuf *m, *prev, *next;
1043170530Ssam	u_int totalhdrsize, fragno, fragsize, off, remainder, payload;
1044170530Ssam
1045170530Ssam	KASSERT(m0->m_nextpkt == NULL, ("mbuf already chained?"));
1046170530Ssam	KASSERT(m0->m_pkthdr.len > mtu,
1047170530Ssam		("pktlen %u mtu %u", m0->m_pkthdr.len, mtu));
1048170530Ssam
1049170530Ssam	wh = mtod(m0, struct ieee80211_frame *);
1050170530Ssam	/* NB: mark the first frag; it will be propagated below */
1051170530Ssam	wh->i_fc[1] |= IEEE80211_FC1_MORE_FRAG;
1052170530Ssam	totalhdrsize = hdrsize + ciphdrsize;
1053170530Ssam	fragno = 1;
1054170530Ssam	off = mtu - ciphdrsize;
1055170530Ssam	remainder = m0->m_pkthdr.len - off;
1056170530Ssam	prev = m0;
1057170530Ssam	do {
1058170530Ssam		fragsize = totalhdrsize + remainder;
1059170530Ssam		if (fragsize > mtu)
1060170530Ssam			fragsize = mtu;
1061170530Ssam		KASSERT(fragsize < MCLBYTES,
1062170530Ssam			("fragment size %u too big!", fragsize));
1063170530Ssam		if (fragsize > MHLEN)
1064170530Ssam			m = m_getcl(M_DONTWAIT, MT_DATA, M_PKTHDR);
1065170530Ssam		else
1066170530Ssam			m = m_gethdr(M_DONTWAIT, MT_DATA);
1067170530Ssam		if (m == NULL)
1068170530Ssam			goto bad;
1069170530Ssam		/* leave room to prepend any cipher header */
1070170530Ssam		m_align(m, fragsize - ciphdrsize);
1071170530Ssam
1072170530Ssam		/*
1073170530Ssam		 * Form the header in the fragment.  Note that since
1074170530Ssam		 * we mark the first fragment with the MORE_FRAG bit
1075170530Ssam		 * it automatically is propagated to each fragment; we
1076170530Ssam		 * need only clear it on the last fragment (done below).
1077170530Ssam		 */
1078170530Ssam		whf = mtod(m, struct ieee80211_frame *);
1079170530Ssam		memcpy(whf, wh, hdrsize);
1080170530Ssam		*(uint16_t *)&whf->i_seq[0] |= htole16(
1081170530Ssam			(fragno & IEEE80211_SEQ_FRAG_MASK) <<
1082170530Ssam				IEEE80211_SEQ_FRAG_SHIFT);
1083170530Ssam		fragno++;
1084170530Ssam
1085170530Ssam		payload = fragsize - totalhdrsize;
1086170530Ssam		/* NB: destination is known to be contiguous */
1087170530Ssam		m_copydata(m0, off, payload, mtod(m, uint8_t *) + hdrsize);
1088170530Ssam		m->m_len = hdrsize + payload;
1089170530Ssam		m->m_pkthdr.len = hdrsize + payload;
1090170530Ssam		m->m_flags |= M_FRAG;
1091170530Ssam
1092170530Ssam		/* chain up the fragment */
1093170530Ssam		prev->m_nextpkt = m;
1094170530Ssam		prev = m;
1095170530Ssam
1096170530Ssam		/* deduct fragment just formed */
1097170530Ssam		remainder -= payload;
1098170530Ssam		off += payload;
1099170530Ssam	} while (remainder != 0);
1100170530Ssam	whf->i_fc[1] &= ~IEEE80211_FC1_MORE_FRAG;
1101170530Ssam
1102170530Ssam	/* strip first mbuf now that everything has been copied */
1103170530Ssam	m_adj(m0, -(m0->m_pkthdr.len - (mtu - ciphdrsize)));
1104170530Ssam	m0->m_flags |= M_FIRSTFRAG | M_FRAG;
1105170530Ssam
1106170530Ssam	ic->ic_stats.is_tx_fragframes++;
1107170530Ssam	ic->ic_stats.is_tx_frags += fragno-1;
1108170530Ssam
1109170530Ssam	return 1;
1110170530Ssambad:
1111170530Ssam	/* reclaim fragments but leave original frame for caller to free */
1112170530Ssam	for (m = m0->m_nextpkt; m != NULL; m = next) {
1113170530Ssam		next = m->m_nextpkt;
1114170530Ssam		m->m_nextpkt = NULL;		/* XXX paranoid */
1115170530Ssam		m_freem(m);
1116170530Ssam	}
1117170530Ssam	m0->m_nextpkt = NULL;
1118170530Ssam	return 0;
1119170530Ssam}
1120170530Ssam
1121170530Ssam/*
1122116742Ssam * Add a supported rates element id to a frame.
1123116742Ssam */
1124170530Ssamstatic uint8_t *
1125170530Ssamieee80211_add_rates(uint8_t *frm, const struct ieee80211_rateset *rs)
1126116742Ssam{
1127116742Ssam	int nrates;
1128116742Ssam
1129116742Ssam	*frm++ = IEEE80211_ELEMID_RATES;
1130116742Ssam	nrates = rs->rs_nrates;
1131116742Ssam	if (nrates > IEEE80211_RATE_SIZE)
1132116742Ssam		nrates = IEEE80211_RATE_SIZE;
1133116742Ssam	*frm++ = nrates;
1134116742Ssam	memcpy(frm, rs->rs_rates, nrates);
1135116742Ssam	return frm + nrates;
1136116742Ssam}
1137116742Ssam
1138116742Ssam/*
1139116742Ssam * Add an extended supported rates element id to a frame.
1140116742Ssam */
1141170530Ssamstatic uint8_t *
1142170530Ssamieee80211_add_xrates(uint8_t *frm, const struct ieee80211_rateset *rs)
1143116742Ssam{
1144116742Ssam	/*
1145116742Ssam	 * Add an extended supported rates element if operating in 11g mode.
1146116742Ssam	 */
1147116742Ssam	if (rs->rs_nrates > IEEE80211_RATE_SIZE) {
1148116742Ssam		int nrates = rs->rs_nrates - IEEE80211_RATE_SIZE;
1149116742Ssam		*frm++ = IEEE80211_ELEMID_XRATES;
1150116742Ssam		*frm++ = nrates;
1151116742Ssam		memcpy(frm, rs->rs_rates + IEEE80211_RATE_SIZE, nrates);
1152116742Ssam		frm += nrates;
1153116742Ssam	}
1154116742Ssam	return frm;
1155116742Ssam}
1156116742Ssam
1157116742Ssam/*
1158116742Ssam * Add an ssid elemet to a frame.
1159116742Ssam */
1160170530Ssamstatic uint8_t *
1161170530Ssamieee80211_add_ssid(uint8_t *frm, const uint8_t *ssid, u_int len)
1162116742Ssam{
1163116742Ssam	*frm++ = IEEE80211_ELEMID_SSID;
1164116742Ssam	*frm++ = len;
1165116742Ssam	memcpy(frm, ssid, len);
1166116742Ssam	return frm + len;
1167116742Ssam}
1168116742Ssam
1169138568Ssam/*
1170138568Ssam * Add an erp element to a frame.
1171138568Ssam */
1172170530Ssamstatic uint8_t *
1173170530Ssamieee80211_add_erp(uint8_t *frm, struct ieee80211com *ic)
1174116742Ssam{
1175170530Ssam	uint8_t erp;
1176116742Ssam
1177138568Ssam	*frm++ = IEEE80211_ELEMID_ERP;
1178138568Ssam	*frm++ = 1;
1179138568Ssam	erp = 0;
1180138568Ssam	if (ic->ic_nonerpsta != 0)
1181138568Ssam		erp |= IEEE80211_ERP_NON_ERP_PRESENT;
1182138568Ssam	if (ic->ic_flags & IEEE80211_F_USEPROT)
1183138568Ssam		erp |= IEEE80211_ERP_USE_PROTECTION;
1184138568Ssam	if (ic->ic_flags & IEEE80211_F_USEBARKER)
1185138568Ssam		erp |= IEEE80211_ERP_LONG_PREAMBLE;
1186138568Ssam	*frm++ = erp;
1187138568Ssam	return frm;
1188138568Ssam}
1189138568Ssam
1190170530Ssamstatic uint8_t *
1191170530Ssamieee80211_setup_wpa_ie(struct ieee80211com *ic, uint8_t *ie)
1192138568Ssam{
1193138568Ssam#define	WPA_OUI_BYTES		0x00, 0x50, 0xf2
1194138568Ssam#define	ADDSHORT(frm, v) do {			\
1195138568Ssam	frm[0] = (v) & 0xff;			\
1196138568Ssam	frm[1] = (v) >> 8;			\
1197138568Ssam	frm += 2;				\
1198138568Ssam} while (0)
1199138568Ssam#define	ADDSELECTOR(frm, sel) do {		\
1200138568Ssam	memcpy(frm, sel, 4);			\
1201138568Ssam	frm += 4;				\
1202138568Ssam} while (0)
1203170530Ssam	static const uint8_t oui[4] = { WPA_OUI_BYTES, WPA_OUI_TYPE };
1204170530Ssam	static const uint8_t cipher_suite[][4] = {
1205138568Ssam		{ WPA_OUI_BYTES, WPA_CSE_WEP40 },	/* NB: 40-bit */
1206138568Ssam		{ WPA_OUI_BYTES, WPA_CSE_TKIP },
1207138568Ssam		{ 0x00, 0x00, 0x00, 0x00 },		/* XXX WRAP */
1208138568Ssam		{ WPA_OUI_BYTES, WPA_CSE_CCMP },
1209138568Ssam		{ 0x00, 0x00, 0x00, 0x00 },		/* XXX CKIP */
1210138568Ssam		{ WPA_OUI_BYTES, WPA_CSE_NULL },
1211138568Ssam	};
1212170530Ssam	static const uint8_t wep104_suite[4] =
1213138568Ssam		{ WPA_OUI_BYTES, WPA_CSE_WEP104 };
1214170530Ssam	static const uint8_t key_mgt_unspec[4] =
1215138568Ssam		{ WPA_OUI_BYTES, WPA_ASE_8021X_UNSPEC };
1216170530Ssam	static const uint8_t key_mgt_psk[4] =
1217138568Ssam		{ WPA_OUI_BYTES, WPA_ASE_8021X_PSK };
1218138568Ssam	const struct ieee80211_rsnparms *rsn = &ic->ic_bss->ni_rsn;
1219170530Ssam	uint8_t *frm = ie;
1220170530Ssam	uint8_t *selcnt;
1221138568Ssam
1222138568Ssam	*frm++ = IEEE80211_ELEMID_VENDOR;
1223138568Ssam	*frm++ = 0;				/* length filled in below */
1224138568Ssam	memcpy(frm, oui, sizeof(oui));		/* WPA OUI */
1225138568Ssam	frm += sizeof(oui);
1226138568Ssam	ADDSHORT(frm, WPA_VERSION);
1227138568Ssam
1228138568Ssam	/* XXX filter out CKIP */
1229138568Ssam
1230138568Ssam	/* multicast cipher */
1231138568Ssam	if (rsn->rsn_mcastcipher == IEEE80211_CIPHER_WEP &&
1232138568Ssam	    rsn->rsn_mcastkeylen >= 13)
1233138568Ssam		ADDSELECTOR(frm, wep104_suite);
1234116742Ssam	else
1235138568Ssam		ADDSELECTOR(frm, cipher_suite[rsn->rsn_mcastcipher]);
1236138568Ssam
1237138568Ssam	/* unicast cipher list */
1238138568Ssam	selcnt = frm;
1239138568Ssam	ADDSHORT(frm, 0);			/* selector count */
1240138568Ssam	if (rsn->rsn_ucastcipherset & (1<<IEEE80211_CIPHER_AES_CCM)) {
1241138568Ssam		selcnt[0]++;
1242138568Ssam		ADDSELECTOR(frm, cipher_suite[IEEE80211_CIPHER_AES_CCM]);
1243138568Ssam	}
1244138568Ssam	if (rsn->rsn_ucastcipherset & (1<<IEEE80211_CIPHER_TKIP)) {
1245138568Ssam		selcnt[0]++;
1246138568Ssam		ADDSELECTOR(frm, cipher_suite[IEEE80211_CIPHER_TKIP]);
1247138568Ssam	}
1248138568Ssam
1249138568Ssam	/* authenticator selector list */
1250138568Ssam	selcnt = frm;
1251138568Ssam	ADDSHORT(frm, 0);			/* selector count */
1252138568Ssam	if (rsn->rsn_keymgmtset & WPA_ASE_8021X_UNSPEC) {
1253138568Ssam		selcnt[0]++;
1254138568Ssam		ADDSELECTOR(frm, key_mgt_unspec);
1255138568Ssam	}
1256138568Ssam	if (rsn->rsn_keymgmtset & WPA_ASE_8021X_PSK) {
1257138568Ssam		selcnt[0]++;
1258138568Ssam		ADDSELECTOR(frm, key_mgt_psk);
1259138568Ssam	}
1260138568Ssam
1261138568Ssam	/* optional capabilities */
1262147066Ssam	if (rsn->rsn_caps != 0 && rsn->rsn_caps != RSN_CAP_PREAUTH)
1263138568Ssam		ADDSHORT(frm, rsn->rsn_caps);
1264138568Ssam
1265138568Ssam	/* calculate element length */
1266138568Ssam	ie[1] = frm - ie - 2;
1267138568Ssam	KASSERT(ie[1]+2 <= sizeof(struct ieee80211_ie_wpa),
1268138609Ssam		("WPA IE too big, %u > %zu",
1269138568Ssam		ie[1]+2, sizeof(struct ieee80211_ie_wpa)));
1270138568Ssam	return frm;
1271138568Ssam#undef ADDSHORT
1272138568Ssam#undef ADDSELECTOR
1273138568Ssam#undef WPA_OUI_BYTES
1274116742Ssam}
1275116742Ssam
1276170530Ssamstatic uint8_t *
1277170530Ssamieee80211_setup_rsn_ie(struct ieee80211com *ic, uint8_t *ie)
1278138568Ssam{
1279138568Ssam#define	RSN_OUI_BYTES		0x00, 0x0f, 0xac
1280138568Ssam#define	ADDSHORT(frm, v) do {			\
1281138568Ssam	frm[0] = (v) & 0xff;			\
1282138568Ssam	frm[1] = (v) >> 8;			\
1283138568Ssam	frm += 2;				\
1284138568Ssam} while (0)
1285138568Ssam#define	ADDSELECTOR(frm, sel) do {		\
1286138568Ssam	memcpy(frm, sel, 4);			\
1287138568Ssam	frm += 4;				\
1288138568Ssam} while (0)
1289170530Ssam	static const uint8_t cipher_suite[][4] = {
1290138568Ssam		{ RSN_OUI_BYTES, RSN_CSE_WEP40 },	/* NB: 40-bit */
1291138568Ssam		{ RSN_OUI_BYTES, RSN_CSE_TKIP },
1292138568Ssam		{ RSN_OUI_BYTES, RSN_CSE_WRAP },
1293138568Ssam		{ RSN_OUI_BYTES, RSN_CSE_CCMP },
1294138568Ssam		{ 0x00, 0x00, 0x00, 0x00 },		/* XXX CKIP */
1295138568Ssam		{ RSN_OUI_BYTES, RSN_CSE_NULL },
1296138568Ssam	};
1297170530Ssam	static const uint8_t wep104_suite[4] =
1298138568Ssam		{ RSN_OUI_BYTES, RSN_CSE_WEP104 };
1299170530Ssam	static const uint8_t key_mgt_unspec[4] =
1300138568Ssam		{ RSN_OUI_BYTES, RSN_ASE_8021X_UNSPEC };
1301170530Ssam	static const uint8_t key_mgt_psk[4] =
1302138568Ssam		{ RSN_OUI_BYTES, RSN_ASE_8021X_PSK };
1303138568Ssam	const struct ieee80211_rsnparms *rsn = &ic->ic_bss->ni_rsn;
1304170530Ssam	uint8_t *frm = ie;
1305170530Ssam	uint8_t *selcnt;
1306138568Ssam
1307138568Ssam	*frm++ = IEEE80211_ELEMID_RSN;
1308138568Ssam	*frm++ = 0;				/* length filled in below */
1309138568Ssam	ADDSHORT(frm, RSN_VERSION);
1310138568Ssam
1311138568Ssam	/* XXX filter out CKIP */
1312138568Ssam
1313138568Ssam	/* multicast cipher */
1314138568Ssam	if (rsn->rsn_mcastcipher == IEEE80211_CIPHER_WEP &&
1315138568Ssam	    rsn->rsn_mcastkeylen >= 13)
1316138568Ssam		ADDSELECTOR(frm, wep104_suite);
1317138568Ssam	else
1318138568Ssam		ADDSELECTOR(frm, cipher_suite[rsn->rsn_mcastcipher]);
1319138568Ssam
1320138568Ssam	/* unicast cipher list */
1321138568Ssam	selcnt = frm;
1322138568Ssam	ADDSHORT(frm, 0);			/* selector count */
1323138568Ssam	if (rsn->rsn_ucastcipherset & (1<<IEEE80211_CIPHER_AES_CCM)) {
1324138568Ssam		selcnt[0]++;
1325138568Ssam		ADDSELECTOR(frm, cipher_suite[IEEE80211_CIPHER_AES_CCM]);
1326138568Ssam	}
1327138568Ssam	if (rsn->rsn_ucastcipherset & (1<<IEEE80211_CIPHER_TKIP)) {
1328138568Ssam		selcnt[0]++;
1329138568Ssam		ADDSELECTOR(frm, cipher_suite[IEEE80211_CIPHER_TKIP]);
1330138568Ssam	}
1331138568Ssam
1332138568Ssam	/* authenticator selector list */
1333138568Ssam	selcnt = frm;
1334138568Ssam	ADDSHORT(frm, 0);			/* selector count */
1335138568Ssam	if (rsn->rsn_keymgmtset & WPA_ASE_8021X_UNSPEC) {
1336138568Ssam		selcnt[0]++;
1337138568Ssam		ADDSELECTOR(frm, key_mgt_unspec);
1338138568Ssam	}
1339138568Ssam	if (rsn->rsn_keymgmtset & WPA_ASE_8021X_PSK) {
1340138568Ssam		selcnt[0]++;
1341138568Ssam		ADDSELECTOR(frm, key_mgt_psk);
1342138568Ssam	}
1343138568Ssam
1344138568Ssam	/* optional capabilities */
1345147066Ssam	ADDSHORT(frm, rsn->rsn_caps);
1346138568Ssam	/* XXX PMKID */
1347138568Ssam
1348138568Ssam	/* calculate element length */
1349138568Ssam	ie[1] = frm - ie - 2;
1350138568Ssam	KASSERT(ie[1]+2 <= sizeof(struct ieee80211_ie_wpa),
1351138609Ssam		("RSN IE too big, %u > %zu",
1352138568Ssam		ie[1]+2, sizeof(struct ieee80211_ie_wpa)));
1353138568Ssam	return frm;
1354138568Ssam#undef ADDSELECTOR
1355138568Ssam#undef ADDSHORT
1356138568Ssam#undef RSN_OUI_BYTES
1357138568Ssam}
1358138568Ssam
1359119150Ssam/*
1360138568Ssam * Add a WPA/RSN element to a frame.
1361138568Ssam */
1362170530Ssamstatic uint8_t *
1363170530Ssamieee80211_add_wpa(uint8_t *frm, struct ieee80211com *ic)
1364138568Ssam{
1365138568Ssam
1366138568Ssam	KASSERT(ic->ic_flags & IEEE80211_F_WPA, ("no WPA/RSN!"));
1367138568Ssam	if (ic->ic_flags & IEEE80211_F_WPA2)
1368138568Ssam		frm = ieee80211_setup_rsn_ie(ic, frm);
1369138568Ssam	if (ic->ic_flags & IEEE80211_F_WPA1)
1370138568Ssam		frm = ieee80211_setup_wpa_ie(ic, frm);
1371138568Ssam	return frm;
1372138568Ssam}
1373138568Ssam
1374138568Ssam#define	WME_OUI_BYTES		0x00, 0x50, 0xf2
1375138568Ssam/*
1376138568Ssam * Add a WME information element to a frame.
1377138568Ssam */
1378170530Ssamstatic uint8_t *
1379170530Ssamieee80211_add_wme_info(uint8_t *frm, struct ieee80211_wme_state *wme)
1380138568Ssam{
1381138568Ssam	static const struct ieee80211_wme_info info = {
1382138568Ssam		.wme_id		= IEEE80211_ELEMID_VENDOR,
1383138568Ssam		.wme_len	= sizeof(struct ieee80211_wme_info) - 2,
1384138568Ssam		.wme_oui	= { WME_OUI_BYTES },
1385138568Ssam		.wme_type	= WME_OUI_TYPE,
1386138568Ssam		.wme_subtype	= WME_INFO_OUI_SUBTYPE,
1387138568Ssam		.wme_version	= WME_VERSION,
1388138568Ssam		.wme_info	= 0,
1389138568Ssam	};
1390138568Ssam	memcpy(frm, &info, sizeof(info));
1391138568Ssam	return frm + sizeof(info);
1392138568Ssam}
1393138568Ssam
1394138568Ssam/*
1395138568Ssam * Add a WME parameters element to a frame.
1396138568Ssam */
1397170530Ssamstatic uint8_t *
1398170530Ssamieee80211_add_wme_param(uint8_t *frm, struct ieee80211_wme_state *wme)
1399138568Ssam{
1400138568Ssam#define	SM(_v, _f)	(((_v) << _f##_S) & _f)
1401138568Ssam#define	ADDSHORT(frm, v) do {			\
1402138568Ssam	frm[0] = (v) & 0xff;			\
1403138568Ssam	frm[1] = (v) >> 8;			\
1404138568Ssam	frm += 2;				\
1405138568Ssam} while (0)
1406138568Ssam	/* NB: this works 'cuz a param has an info at the front */
1407138568Ssam	static const struct ieee80211_wme_info param = {
1408138568Ssam		.wme_id		= IEEE80211_ELEMID_VENDOR,
1409138568Ssam		.wme_len	= sizeof(struct ieee80211_wme_param) - 2,
1410138568Ssam		.wme_oui	= { WME_OUI_BYTES },
1411138568Ssam		.wme_type	= WME_OUI_TYPE,
1412138568Ssam		.wme_subtype	= WME_PARAM_OUI_SUBTYPE,
1413138568Ssam		.wme_version	= WME_VERSION,
1414138568Ssam	};
1415138568Ssam	int i;
1416138568Ssam
1417138568Ssam	memcpy(frm, &param, sizeof(param));
1418138568Ssam	frm += __offsetof(struct ieee80211_wme_info, wme_info);
1419138568Ssam	*frm++ = wme->wme_bssChanParams.cap_info;	/* AC info */
1420138568Ssam	*frm++ = 0;					/* reserved field */
1421138568Ssam	for (i = 0; i < WME_NUM_AC; i++) {
1422138568Ssam		const struct wmeParams *ac =
1423138568Ssam		       &wme->wme_bssChanParams.cap_wmeParams[i];
1424138568Ssam		*frm++ = SM(i, WME_PARAM_ACI)
1425138568Ssam		       | SM(ac->wmep_acm, WME_PARAM_ACM)
1426138568Ssam		       | SM(ac->wmep_aifsn, WME_PARAM_AIFSN)
1427138568Ssam		       ;
1428138568Ssam		*frm++ = SM(ac->wmep_logcwmax, WME_PARAM_LOGCWMAX)
1429138568Ssam		       | SM(ac->wmep_logcwmin, WME_PARAM_LOGCWMIN)
1430138568Ssam		       ;
1431138568Ssam		ADDSHORT(frm, ac->wmep_txopLimit);
1432138568Ssam	}
1433138568Ssam	return frm;
1434138568Ssam#undef SM
1435138568Ssam#undef ADDSHORT
1436138568Ssam}
1437138568Ssam#undef WME_OUI_BYTES
1438138568Ssam
1439170530Ssam#define	ATH_OUI_BYTES		0x00, 0x03, 0x7f
1440138568Ssam/*
1441170530Ssam * Add a WME information element to a frame.
1442170530Ssam */
1443170530Ssamstatic uint8_t *
1444170530Ssamieee80211_add_ath(uint8_t *frm, uint8_t caps, uint16_t defkeyix)
1445170530Ssam{
1446170530Ssam	static const struct ieee80211_ath_ie info = {
1447170530Ssam		.ath_id		= IEEE80211_ELEMID_VENDOR,
1448170530Ssam		.ath_len	= sizeof(struct ieee80211_ath_ie) - 2,
1449170530Ssam		.ath_oui	= { ATH_OUI_BYTES },
1450170530Ssam		.ath_oui_type	= ATH_OUI_TYPE,
1451170530Ssam		.ath_oui_subtype= ATH_OUI_SUBTYPE,
1452170530Ssam		.ath_version	= ATH_OUI_VERSION,
1453170530Ssam	};
1454170530Ssam	struct ieee80211_ath_ie *ath = (struct ieee80211_ath_ie *) frm;
1455170530Ssam
1456170530Ssam	memcpy(frm, &info, sizeof(info));
1457170530Ssam	ath->ath_capability = caps;
1458170530Ssam	ath->ath_defkeyix[0] = (defkeyix & 0xff);
1459170530Ssam	ath->ath_defkeyix[1] = ((defkeyix >> 8) & 0xff);
1460170530Ssam	return frm + sizeof(info);
1461170530Ssam}
1462170530Ssam#undef ATH_OUI_BYTES
1463170530Ssam
1464170530Ssam/*
1465148315Ssam * Send a probe request frame with the specified ssid
1466148315Ssam * and any optional information element data.
1467148315Ssam */
1468148315Ssamint
1469148315Ssamieee80211_send_probereq(struct ieee80211_node *ni,
1470170530Ssam	const uint8_t sa[IEEE80211_ADDR_LEN],
1471170530Ssam	const uint8_t da[IEEE80211_ADDR_LEN],
1472170530Ssam	const uint8_t bssid[IEEE80211_ADDR_LEN],
1473170530Ssam	const uint8_t *ssid, size_t ssidlen,
1474148315Ssam	const void *optie, size_t optielen)
1475148315Ssam{
1476148315Ssam	struct ieee80211com *ic = ni->ni_ic;
1477148315Ssam	struct ieee80211_frame *wh;
1478165569Ssam	const struct ieee80211_rateset *rs;
1479148315Ssam	struct mbuf *m;
1480170530Ssam	uint8_t *frm;
1481148315Ssam
1482148315Ssam	/*
1483148315Ssam	 * Hold a reference on the node so it doesn't go away until after
1484148315Ssam	 * the xmit is complete all the way in the driver.  On error we
1485148315Ssam	 * will remove our reference.
1486148315Ssam	 */
1487148315Ssam	IEEE80211_DPRINTF(ic, IEEE80211_MSG_NODE,
1488148315Ssam		"ieee80211_ref_node (%s:%u) %p<%s> refcnt %d\n",
1489148315Ssam		__func__, __LINE__,
1490148315Ssam		ni, ether_sprintf(ni->ni_macaddr),
1491148315Ssam		ieee80211_node_refcnt(ni)+1);
1492148315Ssam	ieee80211_ref_node(ni);
1493148315Ssam
1494148315Ssam	/*
1495148315Ssam	 * prreq frame format
1496148315Ssam	 *	[tlv] ssid
1497148315Ssam	 *	[tlv] supported rates
1498148315Ssam	 *	[tlv] extended supported rates
1499148315Ssam	 *	[tlv] user-specified ie's
1500148315Ssam	 */
1501148315Ssam	m = ieee80211_getmgtframe(&frm,
1502170530Ssam		 ic->ic_headroom + sizeof(struct ieee80211_frame),
1503148315Ssam		 2 + IEEE80211_NWID_LEN
1504148315Ssam	       + 2 + IEEE80211_RATE_SIZE
1505148315Ssam	       + 2 + (IEEE80211_RATE_MAXSIZE - IEEE80211_RATE_SIZE)
1506148315Ssam	       + (optie != NULL ? optielen : 0)
1507148315Ssam	);
1508148315Ssam	if (m == NULL) {
1509148315Ssam		ic->ic_stats.is_tx_nobuf++;
1510148315Ssam		ieee80211_free_node(ni);
1511148315Ssam		return ENOMEM;
1512148315Ssam	}
1513148315Ssam
1514148315Ssam	frm = ieee80211_add_ssid(frm, ssid, ssidlen);
1515165569Ssam	rs = ieee80211_get_suprates(ic, ic->ic_curchan);
1516165569Ssam	frm = ieee80211_add_rates(frm, rs);
1517165569Ssam	frm = ieee80211_add_xrates(frm, rs);
1518148315Ssam
1519148315Ssam	if (optie != NULL) {
1520148315Ssam		memcpy(frm, optie, optielen);
1521148315Ssam		frm += optielen;
1522148315Ssam	}
1523170530Ssam	m->m_pkthdr.len = m->m_len = frm - mtod(m, uint8_t *);
1524148315Ssam
1525148315Ssam	M_PREPEND(m, sizeof(struct ieee80211_frame), M_DONTWAIT);
1526148315Ssam	if (m == NULL)
1527148315Ssam		return ENOMEM;
1528148315Ssam	KASSERT(m->m_pkthdr.rcvif == NULL, ("rcvif not null"));
1529148315Ssam	m->m_pkthdr.rcvif = (void *)ni;
1530148315Ssam
1531148315Ssam	wh = mtod(m, struct ieee80211_frame *);
1532148315Ssam	ieee80211_send_setup(ic, ni, wh,
1533148315Ssam		IEEE80211_FC0_TYPE_MGT | IEEE80211_FC0_SUBTYPE_PROBE_REQ,
1534148315Ssam		sa, da, bssid);
1535148315Ssam	/* XXX power management? */
1536148315Ssam
1537148315Ssam	IEEE80211_NODE_STAT(ni, tx_probereq);
1538148315Ssam	IEEE80211_NODE_STAT(ni, tx_mgmt);
1539148315Ssam
1540148315Ssam	IEEE80211_DPRINTF(ic, IEEE80211_MSG_DEBUG | IEEE80211_MSG_DUMPPKTS,
1541148315Ssam	    "[%s] send probe req on channel %u\n",
1542148315Ssam	    ether_sprintf(wh->i_addr1),
1543148936Ssam	    ieee80211_chan2ieee(ic, ic->ic_curchan));
1544148315Ssam
1545148315Ssam	IF_ENQUEUE(&ic->ic_mgtq, m);
1546148315Ssam	if_start(ic->ic_ifp);
1547148315Ssam	return 0;
1548148315Ssam}
1549148315Ssam
1550148315Ssam/*
1551155999Ssam * Calculate capability information for mgt frames.
1552155999Ssam */
1553170530Ssamstatic uint16_t
1554155999Ssamgetcapinfo(struct ieee80211com *ic, struct ieee80211_channel *chan)
1555155999Ssam{
1556170530Ssam	uint16_t capinfo;
1557155999Ssam
1558155999Ssam	KASSERT(ic->ic_opmode != IEEE80211_M_STA, ("station mode"));
1559155999Ssam
1560155999Ssam	if (ic->ic_opmode == IEEE80211_M_HOSTAP)
1561155999Ssam		capinfo = IEEE80211_CAPINFO_ESS;
1562155999Ssam	else if (ic->ic_opmode == IEEE80211_M_IBSS)
1563155999Ssam		capinfo = IEEE80211_CAPINFO_IBSS;
1564155999Ssam	else
1565155999Ssam		capinfo = 0;
1566155999Ssam	if (ic->ic_flags & IEEE80211_F_PRIVACY)
1567155999Ssam		capinfo |= IEEE80211_CAPINFO_PRIVACY;
1568155999Ssam	if ((ic->ic_flags & IEEE80211_F_SHPREAMBLE) &&
1569155999Ssam	    IEEE80211_IS_CHAN_2GHZ(chan))
1570155999Ssam		capinfo |= IEEE80211_CAPINFO_SHORT_PREAMBLE;
1571155999Ssam	if (ic->ic_flags & IEEE80211_F_SHSLOT)
1572155999Ssam		capinfo |= IEEE80211_CAPINFO_SHORT_SLOTTIME;
1573155999Ssam	return capinfo;
1574155999Ssam}
1575155999Ssam
1576155999Ssam/*
1577119150Ssam * Send a management frame.  The node is for the destination (or ic_bss
1578119150Ssam * when in station mode).  Nodes other than ic_bss have their reference
1579119150Ssam * count bumped to reflect our use for an indeterminant time.
1580119150Ssam */
1581116742Ssamint
1582116742Ssamieee80211_send_mgmt(struct ieee80211com *ic, struct ieee80211_node *ni,
1583116742Ssam	int type, int arg)
1584116742Ssam{
1585121180Ssam#define	senderr(_x, _v)	do { ic->ic_stats._v++; ret = _x; goto bad; } while (0)
1586116742Ssam	struct mbuf *m;
1587170530Ssam	uint8_t *frm;
1588170530Ssam	uint16_t capinfo;
1589170530Ssam	int has_challenge, is_shared_key, ret, status;
1590116742Ssam
1591119150Ssam	KASSERT(ni != NULL, ("null node"));
1592119150Ssam
1593119150Ssam	/*
1594119150Ssam	 * Hold a reference on the node so it doesn't go away until after
1595119150Ssam	 * the xmit is complete all the way in the driver.  On error we
1596119150Ssam	 * will remove our reference.
1597119150Ssam	 */
1598138568Ssam	IEEE80211_DPRINTF(ic, IEEE80211_MSG_NODE,
1599140766Ssam		"ieee80211_ref_node (%s:%u) %p<%s> refcnt %d\n",
1600138568Ssam		__func__, __LINE__,
1601140766Ssam		ni, ether_sprintf(ni->ni_macaddr),
1602140766Ssam		ieee80211_node_refcnt(ni)+1);
1603138568Ssam	ieee80211_ref_node(ni);
1604138568Ssam
1605116742Ssam	switch (type) {
1606116742Ssam	case IEEE80211_FC0_SUBTYPE_PROBE_RESP:
1607116742Ssam		/*
1608116742Ssam		 * probe response frame format
1609116742Ssam		 *	[8] time stamp
1610116742Ssam		 *	[2] beacon interval
1611116742Ssam		 *	[2] cabability information
1612116742Ssam		 *	[tlv] ssid
1613116742Ssam		 *	[tlv] supported rates
1614121178Ssam		 *	[tlv] parameter set (FH/DS)
1615116742Ssam		 *	[tlv] parameter set (IBSS)
1616138568Ssam		 *	[tlv] extended rate phy (ERP)
1617116742Ssam		 *	[tlv] extended supported rates
1618138568Ssam		 *	[tlv] WPA
1619144136Ssam		 *	[tlv] WME (optional)
1620170530Ssam		 *	[tlv] HT capabilities
1621170530Ssam		 *	[tlv] HT information
1622170530Ssam		 *	[tlv] Vendor OUI HT capabilities (optional)
1623170530Ssam		 *	[tlv] Vendor OUI HT information (optional)
1624170530Ssam		 *	[tlv] Atheros capabilities
1625116742Ssam		 */
1626138568Ssam		m = ieee80211_getmgtframe(&frm,
1627170530Ssam			 ic->ic_headroom + sizeof(struct ieee80211_frame),
1628138568Ssam			 8
1629170530Ssam		       + sizeof(uint16_t)
1630170530Ssam		       + sizeof(uint16_t)
1631138568Ssam		       + 2 + IEEE80211_NWID_LEN
1632116742Ssam		       + 2 + IEEE80211_RATE_SIZE
1633138568Ssam		       + 7	/* max(7,3) */
1634116742Ssam		       + 6
1635138568Ssam		       + 3
1636138568Ssam		       + 2 + (IEEE80211_RATE_MAXSIZE - IEEE80211_RATE_SIZE)
1637138568Ssam		       /* XXX !WPA1+WPA2 fits w/o a cluster */
1638138568Ssam		       + (ic->ic_flags & IEEE80211_F_WPA ?
1639138568Ssam				2*sizeof(struct ieee80211_ie_wpa) : 0)
1640144136Ssam		       + sizeof(struct ieee80211_wme_param)
1641170530Ssam		       /* XXX check for cluster requirement */
1642170530Ssam		       + 2*sizeof(struct ieee80211_ie_htcap) + 4
1643170530Ssam		       + 2*sizeof(struct ieee80211_ie_htinfo) + 4
1644170530Ssam		       + sizeof(struct ieee80211_ath_ie)
1645138568Ssam		);
1646116742Ssam		if (m == NULL)
1647138568Ssam			senderr(ENOMEM, is_tx_nobuf);
1648116742Ssam
1649116742Ssam		memset(frm, 0, 8);	/* timestamp should be filled later */
1650116742Ssam		frm += 8;
1651170530Ssam		*(uint16_t *)frm = htole16(ic->ic_bss->ni_intval);
1652116742Ssam		frm += 2;
1653155999Ssam		capinfo = getcapinfo(ic, ic->ic_curchan);
1654170530Ssam		*(uint16_t *)frm = htole16(capinfo);
1655116742Ssam		frm += 2;
1656116742Ssam
1657116742Ssam		frm = ieee80211_add_ssid(frm, ic->ic_bss->ni_essid,
1658116742Ssam				ic->ic_bss->ni_esslen);
1659138568Ssam		frm = ieee80211_add_rates(frm, &ni->ni_rates);
1660116742Ssam
1661170530Ssam		if (IEEE80211_IS_CHAN_FHSS(ic->ic_curchan)) {
1662121178Ssam                        *frm++ = IEEE80211_ELEMID_FHPARMS;
1663121178Ssam                        *frm++ = 5;
1664121178Ssam                        *frm++ = ni->ni_fhdwell & 0x00ff;
1665121178Ssam                        *frm++ = (ni->ni_fhdwell >> 8) & 0x00ff;
1666121178Ssam                        *frm++ = IEEE80211_FH_CHANSET(
1667148936Ssam			    ieee80211_chan2ieee(ic, ic->ic_curchan));
1668121178Ssam                        *frm++ = IEEE80211_FH_CHANPAT(
1669148936Ssam			    ieee80211_chan2ieee(ic, ic->ic_curchan));
1670121178Ssam                        *frm++ = ni->ni_fhindex;
1671121178Ssam		} else {
1672121178Ssam			*frm++ = IEEE80211_ELEMID_DSPARMS;
1673121178Ssam			*frm++ = 1;
1674148936Ssam			*frm++ = ieee80211_chan2ieee(ic, ic->ic_curchan);
1675121178Ssam		}
1676121178Ssam
1677116742Ssam		if (ic->ic_opmode == IEEE80211_M_IBSS) {
1678116742Ssam			*frm++ = IEEE80211_ELEMID_IBSSPARMS;
1679116742Ssam			*frm++ = 2;
1680116742Ssam			*frm++ = 0; *frm++ = 0;		/* TODO: ATIM window */
1681116742Ssam		}
1682138568Ssam		if (ic->ic_flags & IEEE80211_F_WPA)
1683138568Ssam			frm = ieee80211_add_wpa(frm, ic);
1684170530Ssam		if (IEEE80211_IS_CHAN_ANYG(ic->ic_curchan))
1685138568Ssam			frm = ieee80211_add_erp(frm, ic);
1686138568Ssam		frm = ieee80211_add_xrates(frm, &ni->ni_rates);
1687144136Ssam		if (ic->ic_flags & IEEE80211_F_WME)
1688144136Ssam			frm = ieee80211_add_wme_param(frm, &ic->ic_wme);
1689170530Ssam		if (IEEE80211_IS_CHAN_HT(ic->ic_curchan)) {
1690170530Ssam			frm = ieee80211_add_htcap(frm, ni);
1691170530Ssam			frm = ieee80211_add_htinfo(frm, ni);
1692170530Ssam			if (ic->ic_flags_ext & IEEE80211_FEXT_HTCOMPAT) {
1693170530Ssam				frm = ieee80211_add_htcap_vendor(frm, ni);
1694170530Ssam				frm = ieee80211_add_htinfo_vendor(frm, ni);
1695170530Ssam			}
1696170530Ssam		}
1697170530Ssam		if (ni->ni_ath_ie != NULL)
1698170530Ssam			frm = ieee80211_add_ath(frm, ni->ni_ath_flags,
1699170530Ssam				ni->ni_ath_defkeyix);
1700170530Ssam		m->m_pkthdr.len = m->m_len = frm - mtod(m, uint8_t *);
1701116742Ssam		break;
1702116742Ssam
1703116742Ssam	case IEEE80211_FC0_SUBTYPE_AUTH:
1704138568Ssam		status = arg >> 16;
1705138568Ssam		arg &= 0xffff;
1706138568Ssam		has_challenge = ((arg == IEEE80211_AUTH_SHARED_CHALLENGE ||
1707138568Ssam		    arg == IEEE80211_AUTH_SHARED_RESPONSE) &&
1708138568Ssam		    ni->ni_challenge != NULL);
1709138568Ssam
1710138568Ssam		/*
1711138568Ssam		 * Deduce whether we're doing open authentication or
1712138568Ssam		 * shared key authentication.  We do the latter if
1713138568Ssam		 * we're in the middle of a shared key authentication
1714138568Ssam		 * handshake or if we're initiating an authentication
1715138568Ssam		 * request and configured to use shared key.
1716138568Ssam		 */
1717138568Ssam		is_shared_key = has_challenge ||
1718138568Ssam		     arg >= IEEE80211_AUTH_SHARED_RESPONSE ||
1719138568Ssam		     (arg == IEEE80211_AUTH_SHARED_REQUEST &&
1720138568Ssam		      ic->ic_bss->ni_authmode == IEEE80211_AUTH_SHARED);
1721138568Ssam
1722138568Ssam		m = ieee80211_getmgtframe(&frm,
1723170530Ssam			  ic->ic_headroom + sizeof(struct ieee80211_frame),
1724170530Ssam			  3 * sizeof(uint16_t)
1725138568Ssam			+ (has_challenge && status == IEEE80211_STATUS_SUCCESS ?
1726170530Ssam				sizeof(uint16_t)+IEEE80211_CHALLENGE_LEN : 0)
1727138568Ssam		);
1728116742Ssam		if (m == NULL)
1729138568Ssam			senderr(ENOMEM, is_tx_nobuf);
1730138568Ssam
1731170530Ssam		((uint16_t *)frm)[0] =
1732138568Ssam		    (is_shared_key) ? htole16(IEEE80211_AUTH_ALG_SHARED)
1733138568Ssam		                    : htole16(IEEE80211_AUTH_ALG_OPEN);
1734170530Ssam		((uint16_t *)frm)[1] = htole16(arg);	/* sequence number */
1735170530Ssam		((uint16_t *)frm)[2] = htole16(status);/* status */
1736138568Ssam
1737138568Ssam		if (has_challenge && status == IEEE80211_STATUS_SUCCESS) {
1738170530Ssam			((uint16_t *)frm)[3] =
1739138568Ssam			    htole16((IEEE80211_CHALLENGE_LEN << 8) |
1740138568Ssam			    IEEE80211_ELEMID_CHALLENGE);
1741170530Ssam			memcpy(&((uint16_t *)frm)[4], ni->ni_challenge,
1742138568Ssam			    IEEE80211_CHALLENGE_LEN);
1743138568Ssam			m->m_pkthdr.len = m->m_len =
1744170530Ssam				4 * sizeof(uint16_t) + IEEE80211_CHALLENGE_LEN;
1745138568Ssam			if (arg == IEEE80211_AUTH_SHARED_RESPONSE) {
1746138568Ssam				IEEE80211_DPRINTF(ic, IEEE80211_MSG_AUTH,
1747138568Ssam				    "[%s] request encrypt frame (%s)\n",
1748138568Ssam				    ether_sprintf(ni->ni_macaddr), __func__);
1749138568Ssam				m->m_flags |= M_LINK0; /* WEP-encrypt, please */
1750138568Ssam			}
1751138568Ssam		} else
1752170530Ssam			m->m_pkthdr.len = m->m_len = 3 * sizeof(uint16_t);
1753138568Ssam
1754138568Ssam		/* XXX not right for shared key */
1755138568Ssam		if (status == IEEE80211_STATUS_SUCCESS)
1756138568Ssam			IEEE80211_NODE_STAT(ni, tx_auth);
1757138568Ssam		else
1758138568Ssam			IEEE80211_NODE_STAT(ni, tx_auth_fail);
1759138568Ssam
1760116742Ssam		if (ic->ic_opmode == IEEE80211_M_STA)
1761170530Ssam			ieee80211_add_callback(m, ieee80211_tx_mgt_cb,
1762170530Ssam				(void *) ic->ic_state);
1763116742Ssam		break;
1764116742Ssam
1765116742Ssam	case IEEE80211_FC0_SUBTYPE_DEAUTH:
1766138568Ssam		IEEE80211_DPRINTF(ic, IEEE80211_MSG_AUTH,
1767138568Ssam			"[%s] send station deauthenticate (reason %d)\n",
1768138568Ssam			ether_sprintf(ni->ni_macaddr), arg);
1769170530Ssam		m = ieee80211_getmgtframe(&frm,
1770170530Ssam			ic->ic_headroom + sizeof(struct ieee80211_frame),
1771170530Ssam			sizeof(uint16_t));
1772116742Ssam		if (m == NULL)
1773138568Ssam			senderr(ENOMEM, is_tx_nobuf);
1774170530Ssam		*(uint16_t *)frm = htole16(arg);	/* reason */
1775170530Ssam		m->m_pkthdr.len = m->m_len = sizeof(uint16_t);
1776138568Ssam
1777138568Ssam		IEEE80211_NODE_STAT(ni, tx_deauth);
1778138568Ssam		IEEE80211_NODE_STAT_SET(ni, tx_deauth_code, arg);
1779138568Ssam
1780148302Ssam		ieee80211_node_unauthorize(ni);		/* port closed */
1781116742Ssam		break;
1782116742Ssam
1783116742Ssam	case IEEE80211_FC0_SUBTYPE_ASSOC_REQ:
1784116742Ssam	case IEEE80211_FC0_SUBTYPE_REASSOC_REQ:
1785116742Ssam		/*
1786116742Ssam		 * asreq frame format
1787116742Ssam		 *	[2] capability information
1788116742Ssam		 *	[2] listen interval
1789116742Ssam		 *	[6*] current AP address (reassoc only)
1790116742Ssam		 *	[tlv] ssid
1791116742Ssam		 *	[tlv] supported rates
1792116742Ssam		 *	[tlv] extended supported rates
1793138568Ssam		 *	[tlv] WME
1794170530Ssam		 *	[tlv] HT capabilities
1795170530Ssam		 *	[tlv] Vendor OUI HT capabilities (optional)
1796170530Ssam		 *	[tlv] Atheros capabilities (if negotiated)
1797138568Ssam		 *	[tlv] user-specified ie's
1798116742Ssam		 */
1799138568Ssam		m = ieee80211_getmgtframe(&frm,
1800170530Ssam			 ic->ic_headroom + sizeof(struct ieee80211_frame),
1801170530Ssam			 sizeof(uint16_t)
1802170530Ssam		       + sizeof(uint16_t)
1803116742Ssam		       + IEEE80211_ADDR_LEN
1804138568Ssam		       + 2 + IEEE80211_NWID_LEN
1805116742Ssam		       + 2 + IEEE80211_RATE_SIZE
1806138568Ssam		       + 2 + (IEEE80211_RATE_MAXSIZE - IEEE80211_RATE_SIZE)
1807138568Ssam		       + sizeof(struct ieee80211_wme_info)
1808170530Ssam		       + 2*sizeof(struct ieee80211_ie_htcap) + 4
1809170530Ssam		       + sizeof(struct ieee80211_ath_ie)
1810138568Ssam		       + (ic->ic_opt_ie != NULL ? ic->ic_opt_ie_len : 0)
1811138568Ssam		);
1812116742Ssam		if (m == NULL)
1813138568Ssam			senderr(ENOMEM, is_tx_nobuf);
1814116742Ssam
1815155999Ssam		KASSERT(ic->ic_opmode == IEEE80211_M_STA,
1816155999Ssam		    ("wrong mode %u", ic->ic_opmode));
1817155999Ssam		capinfo = IEEE80211_CAPINFO_ESS;
1818138568Ssam		if (ic->ic_flags & IEEE80211_F_PRIVACY)
1819116742Ssam			capinfo |= IEEE80211_CAPINFO_PRIVACY;
1820120070Ssam		/*
1821120070Ssam		 * NB: Some 11a AP's reject the request when
1822120070Ssam		 *     short premable is set.
1823120070Ssam		 */
1824120070Ssam		if ((ic->ic_flags & IEEE80211_F_SHPREAMBLE) &&
1825148936Ssam		    IEEE80211_IS_CHAN_2GHZ(ic->ic_curchan))
1826116742Ssam			capinfo |= IEEE80211_CAPINFO_SHORT_PREAMBLE;
1827170530Ssam		if (IEEE80211_IS_CHAN_ANYG(ic->ic_curchan) &&
1828138568Ssam		    (ic->ic_caps & IEEE80211_C_SHSLOT))
1829116742Ssam			capinfo |= IEEE80211_CAPINFO_SHORT_SLOTTIME;
1830170530Ssam		*(uint16_t *)frm = htole16(capinfo);
1831116742Ssam		frm += 2;
1832116742Ssam
1833170530Ssam		KASSERT(ic->ic_bss->ni_intval != 0,
1834170530Ssam			("beacon interval is zero!"));
1835170530Ssam		*(uint16_t *)frm = htole16(howmany(ic->ic_lintval,
1836170530Ssam						   ic->ic_bss->ni_intval));
1837116742Ssam		frm += 2;
1838116742Ssam
1839116742Ssam		if (type == IEEE80211_FC0_SUBTYPE_REASSOC_REQ) {
1840116742Ssam			IEEE80211_ADDR_COPY(frm, ic->ic_bss->ni_bssid);
1841116742Ssam			frm += IEEE80211_ADDR_LEN;
1842116742Ssam		}
1843116742Ssam
1844116742Ssam		frm = ieee80211_add_ssid(frm, ni->ni_essid, ni->ni_esslen);
1845116742Ssam		frm = ieee80211_add_rates(frm, &ni->ni_rates);
1846116742Ssam		frm = ieee80211_add_xrates(frm, &ni->ni_rates);
1847138568Ssam		if ((ic->ic_flags & IEEE80211_F_WME) && ni->ni_wme_ie != NULL)
1848138568Ssam			frm = ieee80211_add_wme_info(frm, &ic->ic_wme);
1849170530Ssam		if (IEEE80211_IS_CHAN_HT(ic->ic_curchan)) {
1850170530Ssam			frm = ieee80211_add_htcap(frm, ni);
1851170530Ssam			if (ic->ic_flags_ext & IEEE80211_FEXT_HTCOMPAT)
1852170530Ssam				frm = ieee80211_add_htcap_vendor(frm, ni);
1853170530Ssam		}
1854170530Ssam		if (IEEE80211_ATH_CAP(ic, ni, IEEE80211_F_ATHEROS))
1855170530Ssam			frm = ieee80211_add_ath(frm,
1856170530Ssam				IEEE80211_ATH_CAP(ic, ni, IEEE80211_F_ATHEROS),
1857170530Ssam				(ic->ic_flags & IEEE80211_F_WPA) == 0 &&
1858170530Ssam				ni->ni_authmode != IEEE80211_AUTH_8021X &&
1859170530Ssam				ic->ic_def_txkey != IEEE80211_KEYIX_NONE ?
1860170530Ssam				ic->ic_def_txkey : 0x7fff);
1861138568Ssam		if (ic->ic_opt_ie != NULL) {
1862138568Ssam			memcpy(frm, ic->ic_opt_ie, ic->ic_opt_ie_len);
1863138568Ssam			frm += ic->ic_opt_ie_len;
1864138568Ssam		}
1865170530Ssam		m->m_pkthdr.len = m->m_len = frm - mtod(m, uint8_t *);
1866116742Ssam
1867170530Ssam		ieee80211_add_callback(m, ieee80211_tx_mgt_cb,
1868170530Ssam			(void *) ic->ic_state);
1869116742Ssam		break;
1870116742Ssam
1871116742Ssam	case IEEE80211_FC0_SUBTYPE_ASSOC_RESP:
1872116742Ssam	case IEEE80211_FC0_SUBTYPE_REASSOC_RESP:
1873116742Ssam		/*
1874170530Ssam		 * asresp frame format
1875116742Ssam		 *	[2] capability information
1876116742Ssam		 *	[2] status
1877116742Ssam		 *	[2] association ID
1878116742Ssam		 *	[tlv] supported rates
1879116742Ssam		 *	[tlv] extended supported rates
1880138568Ssam		 *	[tlv] WME (if enabled and STA enabled)
1881170530Ssam		 *	[tlv] HT capabilities (standard or vendor OUI)
1882170530Ssam		 *	[tlv] HT information (standard or vendor OUI)
1883170530Ssam		 *	[tlv] Atheros capabilities (if enabled and STA enabled)
1884116742Ssam		 */
1885138568Ssam		m = ieee80211_getmgtframe(&frm,
1886170530Ssam			 ic->ic_headroom + sizeof(struct ieee80211_frame),
1887170530Ssam			 sizeof(uint16_t)
1888170530Ssam		       + sizeof(uint16_t)
1889170530Ssam		       + sizeof(uint16_t)
1890116742Ssam		       + 2 + IEEE80211_RATE_SIZE
1891138568Ssam		       + 2 + (IEEE80211_RATE_MAXSIZE - IEEE80211_RATE_SIZE)
1892138568Ssam		       + sizeof(struct ieee80211_wme_param)
1893170530Ssam		       + sizeof(struct ieee80211_ie_htcap) + 4
1894170530Ssam		       + sizeof(struct ieee80211_ie_htinfo) + 4
1895170530Ssam		       + sizeof(struct ieee80211_ath_ie)
1896138568Ssam		);
1897116742Ssam		if (m == NULL)
1898138568Ssam			senderr(ENOMEM, is_tx_nobuf);
1899116742Ssam
1900155999Ssam		capinfo = getcapinfo(ic, ic->ic_curchan);
1901170530Ssam		*(uint16_t *)frm = htole16(capinfo);
1902116742Ssam		frm += 2;
1903116742Ssam
1904170530Ssam		*(uint16_t *)frm = htole16(arg);	/* status */
1905116742Ssam		frm += 2;
1906116742Ssam
1907138568Ssam		if (arg == IEEE80211_STATUS_SUCCESS) {
1908170530Ssam			*(uint16_t *)frm = htole16(ni->ni_associd);
1909138568Ssam			IEEE80211_NODE_STAT(ni, tx_assoc);
1910138568Ssam		} else
1911138568Ssam			IEEE80211_NODE_STAT(ni, tx_assoc_fail);
1912116742Ssam		frm += 2;
1913116742Ssam
1914119150Ssam		frm = ieee80211_add_rates(frm, &ni->ni_rates);
1915119150Ssam		frm = ieee80211_add_xrates(frm, &ni->ni_rates);
1916138568Ssam		if ((ic->ic_flags & IEEE80211_F_WME) && ni->ni_wme_ie != NULL)
1917138568Ssam			frm = ieee80211_add_wme_param(frm, &ic->ic_wme);
1918170530Ssam		if (IEEE80211_IS_CHAN_HT(ic->ic_curchan)) {
1919170530Ssam			/* NB: respond according to what we received */
1920170530Ssam			if (ni->ni_flags & IEEE80211_NODE_HTCOMPAT) {
1921170530Ssam				frm = ieee80211_add_htcap_vendor(frm, ni);
1922170530Ssam				frm = ieee80211_add_htinfo_vendor(frm, ni);
1923170530Ssam			} else {
1924170530Ssam				frm = ieee80211_add_htcap(frm, ni);
1925170530Ssam				frm = ieee80211_add_htinfo(frm, ni);
1926170530Ssam			}
1927170530Ssam		}
1928170530Ssam		if (IEEE80211_ATH_CAP(ic, ni, IEEE80211_F_ATHEROS))
1929170530Ssam			frm = ieee80211_add_ath(frm,
1930170530Ssam				IEEE80211_ATH_CAP(ic, ni, IEEE80211_F_ATHEROS),
1931170530Ssam				ni->ni_ath_defkeyix);
1932170530Ssam		m->m_pkthdr.len = m->m_len = frm - mtod(m, uint8_t *);
1933116742Ssam		break;
1934116742Ssam
1935116742Ssam	case IEEE80211_FC0_SUBTYPE_DISASSOC:
1936138568Ssam		IEEE80211_DPRINTF(ic, IEEE80211_MSG_ASSOC,
1937138568Ssam			"[%s] send station disassociate (reason %d)\n",
1938138568Ssam			ether_sprintf(ni->ni_macaddr), arg);
1939170530Ssam		m = ieee80211_getmgtframe(&frm,
1940170530Ssam			ic->ic_headroom + sizeof(struct ieee80211_frame),
1941170530Ssam			sizeof(uint16_t));
1942116742Ssam		if (m == NULL)
1943138568Ssam			senderr(ENOMEM, is_tx_nobuf);
1944170530Ssam		*(uint16_t *)frm = htole16(arg);	/* reason */
1945170530Ssam		m->m_pkthdr.len = m->m_len = sizeof(uint16_t);
1946138568Ssam
1947138568Ssam		IEEE80211_NODE_STAT(ni, tx_disassoc);
1948138568Ssam		IEEE80211_NODE_STAT_SET(ni, tx_disassoc_code, arg);
1949116742Ssam		break;
1950116742Ssam
1951116742Ssam	default:
1952138568Ssam		IEEE80211_DPRINTF(ic, IEEE80211_MSG_ANY,
1953138568Ssam			"[%s] invalid mgmt frame type %u\n",
1954138568Ssam			ether_sprintf(ni->ni_macaddr), type);
1955121180Ssam		senderr(EINVAL, is_tx_unknownmgt);
1956119150Ssam		/* NOTREACHED */
1957116742Ssam	}
1958170530Ssam
1959170530Ssam	ret = ieee80211_mgmt_output(ic, ni, m, type);
1960170530Ssam	if (ret != 0)
1961170530Ssam		goto bad;
1962170530Ssam	return 0;
1963119150Ssambad:
1964170530Ssam	ieee80211_free_node(ni);
1965116742Ssam	return ret;
1966119150Ssam#undef senderr
1967116742Ssam}
1968138568Ssam
1969170530Ssamstatic void
1970170530Ssamieee80211_tx_mgt_timeout(void *arg)
1971170530Ssam{
1972170530Ssam	struct ieee80211_node *ni = arg;
1973170530Ssam	struct ieee80211com *ic	= ni->ni_ic;
1974170530Ssam
1975170530Ssam	if (ic->ic_state != IEEE80211_S_INIT &&
1976170530Ssam	    (ic->ic_flags & IEEE80211_F_SCAN) == 0) {
1977170530Ssam		/*
1978170530Ssam		 * NB: it's safe to specify a timeout as the reason here;
1979170530Ssam		 *     it'll only be used in the right state.
1980170530Ssam		 */
1981170530Ssam		ieee80211_new_state(ic, IEEE80211_S_SCAN,
1982170530Ssam			IEEE80211_SCAN_FAIL_TIMEOUT);
1983170530Ssam	}
1984170530Ssam}
1985170530Ssam
1986170530Ssamstatic void
1987170530Ssamieee80211_tx_mgt_cb(struct ieee80211_node *ni, void *arg, int status)
1988170530Ssam{
1989170530Ssam	struct ieee80211com *ic = ni->ni_ic;
1990170530Ssam	enum ieee80211_state ostate = (enum ieee80211_state) arg;
1991170530Ssam
1992170530Ssam	/*
1993170530Ssam	 * Frame transmit completed; arrange timer callback.  If
1994170530Ssam	 * transmit was successfuly we wait for response.  Otherwise
1995170530Ssam	 * we arrange an immediate callback instead of doing the
1996170530Ssam	 * callback directly since we don't know what state the driver
1997170530Ssam	 * is in (e.g. what locks it is holding).  This work should
1998170530Ssam	 * not be too time-critical and not happen too often so the
1999170530Ssam	 * added overhead is acceptable.
2000170530Ssam	 *
2001170530Ssam	 * XXX what happens if !acked but response shows up before callback?
2002170530Ssam	 */
2003170530Ssam	if (ic->ic_state == ostate)
2004170530Ssam		callout_reset(&ic->ic_mgtsend,
2005170530Ssam			status == 0 ? IEEE80211_TRANS_WAIT*hz : 0,
2006170530Ssam			ieee80211_tx_mgt_timeout, ni);
2007170530Ssam}
2008170530Ssam
2009138568Ssam/*
2010138568Ssam * Allocate a beacon frame and fillin the appropriate bits.
2011138568Ssam */
2012138568Ssamstruct mbuf *
2013172211Ssamieee80211_beacon_alloc(struct ieee80211_node *ni,
2014138568Ssam	struct ieee80211_beacon_offsets *bo)
2015138568Ssam{
2016172211Ssam	struct ieee80211com *ic = ni->ni_ic;
2017138568Ssam	struct ifnet *ifp = ic->ic_ifp;
2018138568Ssam	struct ieee80211_frame *wh;
2019138568Ssam	struct mbuf *m;
2020138568Ssam	int pktlen;
2021170530Ssam	uint8_t *frm;
2022170530Ssam	uint16_t capinfo;
2023138568Ssam	struct ieee80211_rateset *rs;
2024138568Ssam
2025138568Ssam	/*
2026138568Ssam	 * beacon frame format
2027138568Ssam	 *	[8] time stamp
2028138568Ssam	 *	[2] beacon interval
2029138568Ssam	 *	[2] cabability information
2030138568Ssam	 *	[tlv] ssid
2031138568Ssam	 *	[tlv] supported rates
2032138568Ssam	 *	[3] parameter set (DS)
2033138568Ssam	 *	[tlv] parameter set (IBSS/TIM)
2034170530Ssam	 *	[tlv] country code
2035138568Ssam	 *	[tlv] extended rate phy (ERP)
2036138568Ssam	 *	[tlv] extended supported rates
2037138568Ssam	 *	[tlv] WME parameters
2038138568Ssam	 *	[tlv] WPA/RSN parameters
2039170530Ssam	 *	[tlv] HT capabilities
2040170530Ssam	 *	[tlv] HT information
2041170530Ssam	 *	[tlv] Vendor OUI HT capabilities (optional)
2042170530Ssam	 *	[tlv] Vendor OUI HT information (optional)
2043138568Ssam	 * XXX Vendor-specific OIDs (e.g. Atheros)
2044138568Ssam	 * NB: we allocate the max space required for the TIM bitmap.
2045138568Ssam	 */
2046138568Ssam	rs = &ni->ni_rates;
2047138568Ssam	pktlen =   8					/* time stamp */
2048170530Ssam		 + sizeof(uint16_t)			/* beacon interval */
2049170530Ssam		 + sizeof(uint16_t)			/* capabilities */
2050138568Ssam		 + 2 + ni->ni_esslen			/* ssid */
2051138568Ssam	         + 2 + IEEE80211_RATE_SIZE		/* supported rates */
2052138568Ssam	         + 2 + 1				/* DS parameters */
2053138568Ssam		 + 2 + 4 + ic->ic_tim_len		/* DTIM/IBSSPARMS */
2054170530Ssam		 + sizeof(struct ieee80211_country_ie)	/* country code */
2055138568Ssam		 + 2 + 1				/* ERP */
2056138568Ssam	         + 2 + (IEEE80211_RATE_MAXSIZE - IEEE80211_RATE_SIZE)
2057138568Ssam		 + (ic->ic_caps & IEEE80211_C_WME ?	/* WME */
2058138568Ssam			sizeof(struct ieee80211_wme_param) : 0)
2059138568Ssam		 + (ic->ic_caps & IEEE80211_C_WPA ?	/* WPA 1+2 */
2060138568Ssam			2*sizeof(struct ieee80211_ie_wpa) : 0)
2061170530Ssam		 /* XXX conditional? */
2062170530Ssam		 + 4+2*sizeof(struct ieee80211_ie_htcap)/* HT caps */
2063170530Ssam		 + 4+2*sizeof(struct ieee80211_ie_htinfo)/* HT info */
2064138568Ssam		 ;
2065170530Ssam	m = ieee80211_getmgtframe(&frm,
2066170530Ssam		ic->ic_headroom + sizeof(struct ieee80211_frame), pktlen);
2067138568Ssam	if (m == NULL) {
2068138568Ssam		IEEE80211_DPRINTF(ic, IEEE80211_MSG_ANY,
2069138568Ssam			"%s: cannot get buf; size %u\n", __func__, pktlen);
2070138568Ssam		ic->ic_stats.is_tx_nobuf++;
2071138568Ssam		return NULL;
2072138568Ssam	}
2073138568Ssam
2074138568Ssam	memset(frm, 0, 8);	/* XXX timestamp is set by hardware/driver */
2075138568Ssam	frm += 8;
2076170530Ssam	*(uint16_t *)frm = htole16(ni->ni_intval);
2077138568Ssam	frm += 2;
2078155999Ssam	capinfo = getcapinfo(ic, ni->ni_chan);
2079170530Ssam	bo->bo_caps = (uint16_t *)frm;
2080170530Ssam	*(uint16_t *)frm = htole16(capinfo);
2081138568Ssam	frm += 2;
2082138568Ssam	*frm++ = IEEE80211_ELEMID_SSID;
2083138568Ssam	if ((ic->ic_flags & IEEE80211_F_HIDESSID) == 0) {
2084138568Ssam		*frm++ = ni->ni_esslen;
2085138568Ssam		memcpy(frm, ni->ni_essid, ni->ni_esslen);
2086138568Ssam		frm += ni->ni_esslen;
2087138568Ssam	} else
2088138568Ssam		*frm++ = 0;
2089138568Ssam	frm = ieee80211_add_rates(frm, rs);
2090170530Ssam	if (!IEEE80211_IS_CHAN_FHSS(ic->ic_bsschan)) {
2091138568Ssam		*frm++ = IEEE80211_ELEMID_DSPARMS;
2092138568Ssam		*frm++ = 1;
2093170530Ssam		*frm++ = ieee80211_chan2ieee(ic, ic->ic_bsschan);
2094138568Ssam	}
2095138568Ssam	bo->bo_tim = frm;
2096138568Ssam	if (ic->ic_opmode == IEEE80211_M_IBSS) {
2097138568Ssam		*frm++ = IEEE80211_ELEMID_IBSSPARMS;
2098138568Ssam		*frm++ = 2;
2099138568Ssam		*frm++ = 0; *frm++ = 0;		/* TODO: ATIM window */
2100138568Ssam		bo->bo_tim_len = 0;
2101155999Ssam	} else if (ic->ic_opmode == IEEE80211_M_HOSTAP) {
2102138568Ssam		struct ieee80211_tim_ie *tie = (struct ieee80211_tim_ie *) frm;
2103138568Ssam
2104138568Ssam		tie->tim_ie = IEEE80211_ELEMID_TIM;
2105138568Ssam		tie->tim_len = 4;	/* length */
2106138568Ssam		tie->tim_count = 0;	/* DTIM count */
2107138568Ssam		tie->tim_period = ic->ic_dtim_period;	/* DTIM period */
2108138568Ssam		tie->tim_bitctl = 0;	/* bitmap control */
2109138568Ssam		tie->tim_bitmap[0] = 0;	/* Partial Virtual Bitmap */
2110138568Ssam		frm += sizeof(struct ieee80211_tim_ie);
2111138568Ssam		bo->bo_tim_len = 1;
2112138568Ssam	}
2113172211Ssam	bo->bo_tim_trailer = frm;
2114170530Ssam	if (ic->ic_flags & IEEE80211_F_DOTH)
2115170530Ssam		frm = ieee80211_add_countryie(frm, ic,
2116170530Ssam			ic->ic_countrycode, ic->ic_location);
2117138568Ssam	if (ic->ic_flags & IEEE80211_F_WME) {
2118138568Ssam		bo->bo_wme = frm;
2119138568Ssam		frm = ieee80211_add_wme_param(frm, &ic->ic_wme);
2120170530Ssam	} else
2121170530Ssam		bo->bo_wme = NULL;
2122138568Ssam	if (ic->ic_flags & IEEE80211_F_WPA)
2123138568Ssam		frm = ieee80211_add_wpa(frm, ic);
2124170530Ssam	if (IEEE80211_IS_CHAN_ANYG(ic->ic_bsschan)) {
2125153973Ssam		bo->bo_erp = frm;
2126138568Ssam		frm = ieee80211_add_erp(frm, ic);
2127170530Ssam	} else
2128170530Ssam		bo->bo_erp = NULL;
2129170530Ssam	frm = ieee80211_add_xrates(frm, rs);
2130170530Ssam	if (IEEE80211_IS_CHAN_HT(ic->ic_bsschan)) {
2131170530Ssam		frm = ieee80211_add_htcap(frm, ni);
2132170530Ssam		bo->bo_htinfo = frm;
2133170530Ssam		frm = ieee80211_add_htinfo(frm, ni);
2134170530Ssam		if (ic->ic_flags_ext & IEEE80211_FEXT_HTCOMPAT) {
2135170530Ssam			frm = ieee80211_add_htcap_vendor(frm, ni);
2136170530Ssam			frm = ieee80211_add_htinfo_vendor(frm, ni);
2137170530Ssam		}
2138170530Ssam	} else
2139170530Ssam		bo->bo_htinfo = NULL;
2140172211Ssam	bo->bo_tim_trailer_len = frm - bo->bo_tim_trailer;
2141170530Ssam	m->m_pkthdr.len = m->m_len = frm - mtod(m, uint8_t *);
2142138568Ssam
2143138568Ssam	M_PREPEND(m, sizeof(struct ieee80211_frame), M_DONTWAIT);
2144138568Ssam	KASSERT(m != NULL, ("no space for 802.11 header?"));
2145138568Ssam	wh = mtod(m, struct ieee80211_frame *);
2146138568Ssam	wh->i_fc[0] = IEEE80211_FC0_VERSION_0 | IEEE80211_FC0_TYPE_MGT |
2147138568Ssam	    IEEE80211_FC0_SUBTYPE_BEACON;
2148138568Ssam	wh->i_fc[1] = IEEE80211_FC1_DIR_NODS;
2149170530Ssam	*(uint16_t *)wh->i_dur = 0;
2150138568Ssam	IEEE80211_ADDR_COPY(wh->i_addr1, ifp->if_broadcastaddr);
2151138568Ssam	IEEE80211_ADDR_COPY(wh->i_addr2, ic->ic_myaddr);
2152138568Ssam	IEEE80211_ADDR_COPY(wh->i_addr3, ni->ni_bssid);
2153170530Ssam	*(uint16_t *)wh->i_seq = 0;
2154138568Ssam
2155138568Ssam	return m;
2156138568Ssam}
2157138568Ssam
2158138568Ssam/*
2159138568Ssam * Update the dynamic parts of a beacon frame based on the current state.
2160138568Ssam */
2161138568Ssamint
2162172211Ssamieee80211_beacon_update(struct ieee80211_node *ni,
2163138568Ssam	struct ieee80211_beacon_offsets *bo, struct mbuf *m, int mcast)
2164138568Ssam{
2165172211Ssam	struct ieee80211com *ic = ni->ni_ic;
2166138568Ssam	int len_changed = 0;
2167170530Ssam	uint16_t capinfo;
2168138568Ssam
2169138568Ssam	IEEE80211_BEACON_LOCK(ic);
2170138568Ssam	/* XXX faster to recalculate entirely or just changes? */
2171155999Ssam	capinfo = getcapinfo(ic, ni->ni_chan);
2172138568Ssam	*bo->bo_caps = htole16(capinfo);
2173138568Ssam
2174138568Ssam	if (ic->ic_flags & IEEE80211_F_WME) {
2175138568Ssam		struct ieee80211_wme_state *wme = &ic->ic_wme;
2176138568Ssam
2177138568Ssam		/*
2178138568Ssam		 * Check for agressive mode change.  When there is
2179138568Ssam		 * significant high priority traffic in the BSS
2180138568Ssam		 * throttle back BE traffic by using conservative
2181138568Ssam		 * parameters.  Otherwise BE uses agressive params
2182138568Ssam		 * to optimize performance of legacy/non-QoS traffic.
2183138568Ssam		 */
2184138568Ssam		if (wme->wme_flags & WME_F_AGGRMODE) {
2185138568Ssam			if (wme->wme_hipri_traffic >
2186138568Ssam			    wme->wme_hipri_switch_thresh) {
2187138568Ssam				IEEE80211_DPRINTF(ic, IEEE80211_MSG_WME,
2188138568Ssam				    "%s: traffic %u, disable aggressive mode\n",
2189138568Ssam				    __func__, wme->wme_hipri_traffic);
2190138568Ssam				wme->wme_flags &= ~WME_F_AGGRMODE;
2191138568Ssam				ieee80211_wme_updateparams_locked(ic);
2192138568Ssam				wme->wme_hipri_traffic =
2193138568Ssam					wme->wme_hipri_switch_hysteresis;
2194138568Ssam			} else
2195138568Ssam				wme->wme_hipri_traffic = 0;
2196138568Ssam		} else {
2197138568Ssam			if (wme->wme_hipri_traffic <=
2198138568Ssam			    wme->wme_hipri_switch_thresh) {
2199138568Ssam				IEEE80211_DPRINTF(ic, IEEE80211_MSG_WME,
2200138568Ssam				    "%s: traffic %u, enable aggressive mode\n",
2201138568Ssam				    __func__, wme->wme_hipri_traffic);
2202138568Ssam				wme->wme_flags |= WME_F_AGGRMODE;
2203138568Ssam				ieee80211_wme_updateparams_locked(ic);
2204138568Ssam				wme->wme_hipri_traffic = 0;
2205138568Ssam			} else
2206138568Ssam				wme->wme_hipri_traffic =
2207138568Ssam					wme->wme_hipri_switch_hysteresis;
2208138568Ssam		}
2209172211Ssam		if (isset(bo->bo_flags, IEEE80211_BEACON_WME)) {
2210138568Ssam			(void) ieee80211_add_wme_param(bo->bo_wme, wme);
2211172211Ssam			clrbit(bo->bo_flags, IEEE80211_BEACON_WME);
2212138568Ssam		}
2213138568Ssam	}
2214138568Ssam
2215172211Ssam	if (isset(bo->bo_flags, IEEE80211_BEACON_HTINFO)) {
2216172211Ssam		ieee80211_ht_update_beacon(ic, bo);
2217172211Ssam		clrbit(bo->bo_flags, IEEE80211_BEACON_HTINFO);
2218170530Ssam	}
2219170530Ssam
2220138568Ssam	if (ic->ic_opmode == IEEE80211_M_HOSTAP) {	/* NB: no IBSS support*/
2221138568Ssam		struct ieee80211_tim_ie *tie =
2222138568Ssam			(struct ieee80211_tim_ie *) bo->bo_tim;
2223172211Ssam		if (isset(bo->bo_flags, IEEE80211_BEACON_TIM)) {
2224138568Ssam			u_int timlen, timoff, i;
2225138568Ssam			/*
2226138568Ssam			 * ATIM/DTIM needs updating.  If it fits in the
2227138568Ssam			 * current space allocated then just copy in the
2228138568Ssam			 * new bits.  Otherwise we need to move any trailing
2229138568Ssam			 * data to make room.  Note that we know there is
2230138568Ssam			 * contiguous space because ieee80211_beacon_allocate
2231138568Ssam			 * insures there is space in the mbuf to write a
2232138568Ssam			 * maximal-size virtual bitmap (based on ic_max_aid).
2233138568Ssam			 */
2234138568Ssam			/*
2235138568Ssam			 * Calculate the bitmap size and offset, copy any
2236138568Ssam			 * trailer out of the way, and then copy in the
2237138568Ssam			 * new bitmap and update the information element.
2238138568Ssam			 * Note that the tim bitmap must contain at least
2239138568Ssam			 * one byte and any offset must be even.
2240138568Ssam			 */
2241138568Ssam			if (ic->ic_ps_pending != 0) {
2242138568Ssam				timoff = 128;		/* impossibly large */
2243138568Ssam				for (i = 0; i < ic->ic_tim_len; i++)
2244138568Ssam					if (ic->ic_tim_bitmap[i]) {
2245138568Ssam						timoff = i &~ 1;
2246138568Ssam						break;
2247138568Ssam					}
2248138568Ssam				KASSERT(timoff != 128, ("tim bitmap empty!"));
2249138568Ssam				for (i = ic->ic_tim_len-1; i >= timoff; i--)
2250138568Ssam					if (ic->ic_tim_bitmap[i])
2251138568Ssam						break;
2252138568Ssam				timlen = 1 + (i - timoff);
2253138568Ssam			} else {
2254138568Ssam				timoff = 0;
2255138568Ssam				timlen = 1;
2256138568Ssam			}
2257138568Ssam			if (timlen != bo->bo_tim_len) {
2258138568Ssam				/* copy up/down trailer */
2259153973Ssam				int adjust = tie->tim_bitmap+timlen
2260172211Ssam					   - bo->bo_tim_trailer;
2261172211Ssam				ovbcopy(bo->bo_tim_trailer,
2262172211Ssam				    bo->bo_tim_trailer+adjust,
2263172211Ssam				    bo->bo_tim_trailer_len);
2264172211Ssam				bo->bo_tim_trailer += adjust;
2265153973Ssam				bo->bo_wme += adjust;
2266153973Ssam				bo->bo_erp += adjust;
2267170530Ssam				bo->bo_htinfo += adjust;
2268138568Ssam				bo->bo_tim_len = timlen;
2269138568Ssam
2270138568Ssam				/* update information element */
2271138568Ssam				tie->tim_len = 3 + timlen;
2272138568Ssam				tie->tim_bitctl = timoff;
2273138568Ssam				len_changed = 1;
2274138568Ssam			}
2275138568Ssam			memcpy(tie->tim_bitmap, ic->ic_tim_bitmap + timoff,
2276138568Ssam				bo->bo_tim_len);
2277138568Ssam
2278172211Ssam			clrbit(bo->bo_flags, IEEE80211_BEACON_TIM);
2279138568Ssam
2280138568Ssam			IEEE80211_DPRINTF(ic, IEEE80211_MSG_POWER,
2281138568Ssam				"%s: TIM updated, pending %u, off %u, len %u\n",
2282138568Ssam				__func__, ic->ic_ps_pending, timoff, timlen);
2283138568Ssam		}
2284138568Ssam		/* count down DTIM period */
2285138568Ssam		if (tie->tim_count == 0)
2286138568Ssam			tie->tim_count = tie->tim_period - 1;
2287138568Ssam		else
2288138568Ssam			tie->tim_count--;
2289138568Ssam		/* update state for buffered multicast frames on DTIM */
2290153139Ssam		if (mcast && tie->tim_count == 0)
2291138568Ssam			tie->tim_bitctl |= 1;
2292138568Ssam		else
2293138568Ssam			tie->tim_bitctl &= ~1;
2294172211Ssam		if (isset(bo->bo_flags, IEEE80211_BEACON_ERP)) {
2295153973Ssam			/*
2296153973Ssam			 * ERP element needs updating.
2297153973Ssam			 */
2298153973Ssam			(void) ieee80211_add_erp(bo->bo_erp, ic);
2299172211Ssam			clrbit(bo->bo_flags, IEEE80211_BEACON_ERP);
2300153973Ssam		}
2301138568Ssam	}
2302138568Ssam	IEEE80211_BEACON_UNLOCK(ic);
2303138568Ssam
2304138568Ssam	return len_changed;
2305138568Ssam}
2306