ieee80211_output.c revision 184286
1116742Ssam/*-
2116904Ssam * Copyright (c) 2001 Atsushi Onoe
3178354Ssam * Copyright (c) 2002-2008 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 184286 2008-10-26 00:55:38Z sam $");
29116742Ssam
30116742Ssam#include "opt_inet.h"
31178354Ssam#include "opt_wlan.h"
32116742Ssam
33116742Ssam#include <sys/param.h>
34116742Ssam#include <sys/systm.h>
35116742Ssam#include <sys/mbuf.h>
36116742Ssam#include <sys/kernel.h>
37116742Ssam#include <sys/endian.h>
38116742Ssam
39138568Ssam#include <sys/socket.h>
40116742Ssam
41138568Ssam#include <net/bpf.h>
42138568Ssam#include <net/ethernet.h>
43116742Ssam#include <net/if.h>
44138568Ssam#include <net/if_llc.h>
45116742Ssam#include <net/if_media.h>
46138568Ssam#include <net/if_vlan_var.h>
47116742Ssam
48116742Ssam#include <net80211/ieee80211_var.h>
49170530Ssam#include <net80211/ieee80211_regdomain.h>
50178354Ssam#include <net80211/ieee80211_wds.h>
51116742Ssam
52116742Ssam#ifdef INET
53116742Ssam#include <netinet/in.h>
54116742Ssam#include <netinet/if_ether.h>
55138568Ssam#include <netinet/in_systm.h>
56138568Ssam#include <netinet/ip.h>
57116742Ssam#endif
58116742Ssam
59170530Ssam#define	ETHER_HEADER_COPY(dst, src) \
60170530Ssam	memcpy(dst, src, sizeof(struct ether_header))
61170530Ssam
62178354Ssamstatic struct mbuf *ieee80211_encap_fastframe(struct ieee80211vap *,
63170530Ssam	struct mbuf *m1, const struct ether_header *eh1,
64170530Ssam	struct mbuf *m2, const struct ether_header *eh2);
65178354Ssamstatic int ieee80211_fragment(struct ieee80211vap *, struct mbuf *,
66170530Ssam	u_int hdrsize, u_int ciphdrsize, u_int mtu);
67170530Ssamstatic	void ieee80211_tx_mgt_cb(struct ieee80211_node *, void *, int);
68170530Ssam
69138568Ssam#ifdef IEEE80211_DEBUG
70119150Ssam/*
71138568Ssam * Decide if an outbound management frame should be
72138568Ssam * printed when debugging is enabled.  This filters some
73138568Ssam * of the less interesting frames that come frequently
74138568Ssam * (e.g. beacons).
75138568Ssam */
76138568Ssamstatic __inline int
77178354Ssamdoprint(struct ieee80211vap *vap, int subtype)
78138568Ssam{
79138568Ssam	switch (subtype) {
80138568Ssam	case IEEE80211_FC0_SUBTYPE_PROBE_RESP:
81178354Ssam		return (vap->iv_opmode == IEEE80211_M_IBSS);
82138568Ssam	}
83138568Ssam	return 1;
84138568Ssam}
85138568Ssam#endif
86138568Ssam
87138568Ssam/*
88178354Ssam * Start method for vap's.  All packets from the stack come
89178354Ssam * through here.  We handle common processing of the packets
90178354Ssam * before dispatching them to the underlying device.
91178354Ssam */
92178354Ssamvoid
93178354Ssamieee80211_start(struct ifnet *ifp)
94178354Ssam{
95178354Ssam#define	IS_DWDS(vap) \
96178354Ssam	(vap->iv_opmode == IEEE80211_M_WDS && \
97178354Ssam	 (vap->iv_flags_ext & IEEE80211_FEXT_WDSLEGACY) == 0)
98178354Ssam	struct ieee80211vap *vap = ifp->if_softc;
99178354Ssam	struct ieee80211com *ic = vap->iv_ic;
100178354Ssam	struct ifnet *parent = ic->ic_ifp;
101178354Ssam	struct ieee80211_node *ni;
102178354Ssam	struct mbuf *m;
103178354Ssam	struct ether_header *eh;
104178354Ssam	int error;
105178354Ssam
106178354Ssam	/* NB: parent must be up and running */
107178354Ssam	if (!IFNET_IS_UP_RUNNING(parent)) {
108178354Ssam		IEEE80211_DPRINTF(vap, IEEE80211_MSG_OUTPUT,
109178354Ssam		    "%s: ignore queue, parent %s not up+running\n",
110178354Ssam		    __func__, parent->if_xname);
111178354Ssam		/* XXX stat */
112178354Ssam		return;
113178354Ssam	}
114178354Ssam	if (vap->iv_state == IEEE80211_S_SLEEP) {
115178354Ssam		/*
116178354Ssam		 * In power save, wakeup device for transmit.
117178354Ssam		 */
118178354Ssam		ieee80211_new_state(vap, IEEE80211_S_RUN, 0);
119178354Ssam		return;
120178354Ssam	}
121178354Ssam	/*
122178354Ssam	 * No data frames go out unless we're running.
123178354Ssam	 * Note in particular this covers CAC and CSA
124178354Ssam	 * states (though maybe we should check muting
125178354Ssam	 * for CSA).
126178354Ssam	 */
127178354Ssam	if (vap->iv_state != IEEE80211_S_RUN) {
128178354Ssam		IEEE80211_LOCK(ic);
129178354Ssam		/* re-check under the com lock to avoid races */
130178354Ssam		if (vap->iv_state != IEEE80211_S_RUN) {
131178354Ssam			IEEE80211_DPRINTF(vap, IEEE80211_MSG_OUTPUT,
132178354Ssam			    "%s: ignore queue, in %s state\n",
133178354Ssam			    __func__, ieee80211_state_name[vap->iv_state]);
134178354Ssam			vap->iv_stats.is_tx_badstate++;
135178354Ssam			ifp->if_drv_flags |= IFF_DRV_OACTIVE;
136178354Ssam			IEEE80211_UNLOCK(ic);
137178354Ssam			return;
138178354Ssam		}
139178354Ssam		IEEE80211_UNLOCK(ic);
140178354Ssam	}
141178354Ssam	for (;;) {
142178354Ssam		IFQ_DEQUEUE(&ifp->if_snd, m);
143178354Ssam		if (m == NULL)
144178354Ssam			break;
145178354Ssam		/*
146178354Ssam		 * Sanitize mbuf flags for net80211 use.  We cannot
147178354Ssam		 * clear M_PWR_SAV because this may be set for frames
148178354Ssam		 * that are re-submitted from the power save queue.
149178354Ssam		 *
150178354Ssam		 * NB: This must be done before ieee80211_classify as
151178354Ssam		 *     it marks EAPOL in frames with M_EAPOL.
152178354Ssam		 */
153178354Ssam		m->m_flags &= ~(M_80211_TX - M_PWR_SAV);
154178354Ssam		/*
155178354Ssam		 * Cancel any background scan.
156178354Ssam		 */
157178354Ssam		if (ic->ic_flags & IEEE80211_F_SCAN)
158178354Ssam			ieee80211_cancel_anyscan(vap);
159178354Ssam		/*
160178354Ssam		 * Find the node for the destination so we can do
161178354Ssam		 * things like power save and fast frames aggregation.
162178354Ssam		 *
163178354Ssam		 * NB: past this point various code assumes the first
164178354Ssam		 *     mbuf has the 802.3 header present (and contiguous).
165178354Ssam		 */
166178354Ssam		ni = NULL;
167178354Ssam		if (m->m_len < sizeof(struct ether_header) &&
168178354Ssam		   (m = m_pullup(m, sizeof(struct ether_header))) == NULL) {
169178354Ssam			IEEE80211_DPRINTF(vap, IEEE80211_MSG_OUTPUT,
170178354Ssam			    "discard frame, %s\n", "m_pullup failed");
171178354Ssam			vap->iv_stats.is_tx_nobuf++;	/* XXX */
172178354Ssam			ifp->if_oerrors++;
173178354Ssam			continue;
174178354Ssam		}
175178354Ssam		eh = mtod(m, struct ether_header *);
176178354Ssam		if (ETHER_IS_MULTICAST(eh->ether_dhost)) {
177178354Ssam			if (IS_DWDS(vap)) {
178178354Ssam				/*
179178354Ssam				 * Only unicast frames from the above go out
180178354Ssam				 * DWDS vaps; multicast frames are handled by
181178354Ssam				 * dispatching the frame as it comes through
182178354Ssam				 * the AP vap (see below).
183178354Ssam				 */
184178354Ssam				IEEE80211_DISCARD_MAC(vap, IEEE80211_MSG_WDS,
185178354Ssam				    eh->ether_dhost, "mcast", "%s", "on DWDS");
186178354Ssam				vap->iv_stats.is_dwds_mcast++;
187178354Ssam				m_freem(m);
188178354Ssam				continue;
189178354Ssam			}
190178354Ssam			if (vap->iv_opmode == IEEE80211_M_HOSTAP) {
191178354Ssam				/*
192178354Ssam				 * Spam DWDS vap's w/ multicast traffic.
193178354Ssam				 */
194178354Ssam				/* XXX only if dwds in use? */
195178354Ssam				ieee80211_dwds_mcast(vap, m);
196178354Ssam			}
197178354Ssam		}
198178354Ssam		ni = ieee80211_find_txnode(vap, eh->ether_dhost);
199178354Ssam		if (ni == NULL) {
200178354Ssam			/* NB: ieee80211_find_txnode does stat+msg */
201178354Ssam			ifp->if_oerrors++;
202178354Ssam			m_freem(m);
203178354Ssam			continue;
204178354Ssam		}
205178354Ssam		/* XXX AUTH'd */
206184271Ssam		/* XXX mark vap to identify if associd is required */
207184271Ssam		if (ni->ni_associd == 0 &&
208184271Ssam		    (vap->iv_opmode == IEEE80211_M_STA ||
209184271Ssam		     vap->iv_opmode == IEEE80211_M_HOSTAP || IS_DWDS(vap))) {
210184271Ssam			IEEE80211_DISCARD_MAC(vap, IEEE80211_MSG_OUTPUT,
211184271Ssam			    eh->ether_dhost, NULL,
212184271Ssam			    "sta not associated (type 0x%04x)",
213184271Ssam			    htons(eh->ether_type));
214184271Ssam			vap->iv_stats.is_tx_notassoc++;
215184271Ssam			ifp->if_oerrors++;
216184271Ssam			m_freem(m);
217184271Ssam			ieee80211_free_node(ni);
218184271Ssam			continue;
219178354Ssam		}
220178354Ssam		if ((ni->ni_flags & IEEE80211_NODE_PWR_MGT) &&
221178354Ssam		    (m->m_flags & M_PWR_SAV) == 0) {
222178354Ssam			/*
223178354Ssam			 * Station in power save mode; pass the frame
224178354Ssam			 * to the 802.11 layer and continue.  We'll get
225178354Ssam			 * the frame back when the time is right.
226178354Ssam			 * XXX lose WDS vap linkage?
227178354Ssam			 */
228178354Ssam			ieee80211_pwrsave(ni, m);
229178354Ssam			ieee80211_free_node(ni);
230178354Ssam			continue;
231178354Ssam		}
232178354Ssam		/* calculate priority so drivers can find the tx queue */
233178354Ssam		if (ieee80211_classify(ni, m)) {
234178354Ssam			IEEE80211_DISCARD_MAC(vap, IEEE80211_MSG_OUTPUT,
235178354Ssam			    eh->ether_dhost, NULL,
236178354Ssam			    "%s", "classification failure");
237178354Ssam			vap->iv_stats.is_tx_classify++;
238178354Ssam			ifp->if_oerrors++;
239178354Ssam			m_freem(m);
240178354Ssam			ieee80211_free_node(ni);
241178354Ssam			continue;
242178354Ssam		}
243178354Ssam
244178354Ssam		BPF_MTAP(ifp, m);		/* 802.11 tx path */
245178354Ssam
246178354Ssam		/*
247178354Ssam		 * XXX When ni is associated with a WDS link then
248178354Ssam		 * the vap will be the WDS vap but ni_vap will point
249178354Ssam		 * to the ap vap the station associated to.  Once
250178354Ssam		 * we handoff the packet to the driver the callback
251178354Ssam		 * to ieee80211_encap won't be able to tell if the
252178354Ssam		 * packet should be encapsulated for WDS or not (e.g.
253178354Ssam		 * multicast frames will not be handled correctly).
254178354Ssam		 * We hack this by marking the mbuf so ieee80211_encap
255178354Ssam		 * can do the right thing.
256178354Ssam		 */
257178354Ssam		if (vap->iv_opmode == IEEE80211_M_WDS)
258178354Ssam			m->m_flags |= M_WDS;
259178354Ssam		else
260178354Ssam			m->m_flags &= ~M_WDS;
261178354Ssam
262178354Ssam		/*
263178354Ssam		 * Stash the node pointer and hand the frame off to
264178354Ssam		 * the underlying device.  Note that we do this after
265178354Ssam		 * any call to ieee80211_dwds_mcast because that code
266178354Ssam		 * uses any existing value for rcvif.
267178354Ssam		 */
268178354Ssam		m->m_pkthdr.rcvif = (void *)ni;
269178354Ssam
270178354Ssam		/* XXX defer if_start calls? */
271178354Ssam		IFQ_HANDOFF(parent, m, error);
272178354Ssam		if (error != 0) {
273178354Ssam			/* NB: IFQ_HANDOFF reclaims mbuf */
274178354Ssam			ieee80211_free_node(ni);
275178354Ssam		} else {
276178354Ssam			ifp->if_opackets++;
277178354Ssam		}
278178354Ssam		ic->ic_lastdata = ticks;
279178354Ssam	}
280178354Ssam#undef IS_DWDS
281178354Ssam}
282178354Ssam
283178354Ssam/*
284178354Ssam * 802.11 output routine. This is (currently) used only to
285178354Ssam * connect bpf write calls to the 802.11 layer for injecting
286178354Ssam * raw 802.11 frames.  Note we locate the ieee80211com from
287178354Ssam * the ifnet using a spare field setup at attach time.  This
288178354Ssam * will go away when the virtual ap support comes in.
289178354Ssam */
290178354Ssamint
291178354Ssamieee80211_output(struct ifnet *ifp, struct mbuf *m,
292178354Ssam	struct sockaddr *dst, struct rtentry *rt0)
293178354Ssam{
294178354Ssam#define senderr(e) do { error = (e); goto bad;} while (0)
295178354Ssam	struct ieee80211_node *ni = NULL;
296178354Ssam	struct ieee80211vap *vap;
297178354Ssam	struct ieee80211_frame *wh;
298178354Ssam	int error;
299178354Ssam
300178354Ssam	if (ifp->if_drv_flags & IFF_DRV_OACTIVE) {
301178354Ssam		/*
302178354Ssam		 * Short-circuit requests if the vap is marked OACTIVE
303178354Ssam		 * as this is used when tearing down state to indicate
304178354Ssam		 * the vap may be gone.  This can also happen because a
305178354Ssam		 * packet came down through ieee80211_start before the
306178354Ssam		 * vap entered RUN state in which case it's also ok to
307178354Ssam		 * just drop the frame.  This should not be necessary
308178354Ssam		 * but callers of if_output don't check OACTIVE.
309178354Ssam		 */
310178354Ssam		senderr(ENETDOWN);
311178354Ssam	}
312178354Ssam	vap = ifp->if_softc;
313178354Ssam	/*
314178354Ssam	 * Hand to the 802.3 code if not tagged as
315178354Ssam	 * a raw 802.11 frame.
316178354Ssam	 */
317178354Ssam	if (dst->sa_family != AF_IEEE80211)
318178354Ssam		return vap->iv_output(ifp, m, dst, rt0);
319178354Ssam#ifdef MAC
320178354Ssam	error = mac_check_ifnet_transmit(ifp, m);
321178354Ssam	if (error)
322178354Ssam		senderr(error);
323178354Ssam#endif
324178354Ssam	if (ifp->if_flags & IFF_MONITOR)
325178354Ssam		senderr(ENETDOWN);
326178354Ssam	if (!IFNET_IS_UP_RUNNING(ifp))
327178354Ssam		senderr(ENETDOWN);
328178354Ssam	if (vap->iv_state == IEEE80211_S_CAC) {
329178354Ssam		IEEE80211_DPRINTF(vap,
330178354Ssam		    IEEE80211_MSG_OUTPUT | IEEE80211_MSG_DOTH,
331178354Ssam		    "block %s frame in CAC state\n", "raw data");
332178354Ssam		vap->iv_stats.is_tx_badstate++;
333178354Ssam		senderr(EIO);		/* XXX */
334178354Ssam	}
335178354Ssam	/* XXX bypass bridge, pfil, carp, etc. */
336178354Ssam
337178354Ssam	if (m->m_pkthdr.len < sizeof(struct ieee80211_frame_ack))
338178354Ssam		senderr(EIO);	/* XXX */
339178354Ssam	wh = mtod(m, struct ieee80211_frame *);
340178354Ssam	if ((wh->i_fc[0] & IEEE80211_FC0_VERSION_MASK) !=
341178354Ssam	    IEEE80211_FC0_VERSION_0)
342178354Ssam		senderr(EIO);	/* XXX */
343178354Ssam
344178354Ssam	/* locate destination node */
345178354Ssam	switch (wh->i_fc[1] & IEEE80211_FC1_DIR_MASK) {
346178354Ssam	case IEEE80211_FC1_DIR_NODS:
347178354Ssam	case IEEE80211_FC1_DIR_FROMDS:
348178354Ssam		ni = ieee80211_find_txnode(vap, wh->i_addr1);
349178354Ssam		break;
350178354Ssam	case IEEE80211_FC1_DIR_TODS:
351178354Ssam	case IEEE80211_FC1_DIR_DSTODS:
352178354Ssam		if (m->m_pkthdr.len < sizeof(struct ieee80211_frame))
353178354Ssam			senderr(EIO);	/* XXX */
354178354Ssam		ni = ieee80211_find_txnode(vap, wh->i_addr3);
355178354Ssam		break;
356178354Ssam	default:
357178354Ssam		senderr(EIO);	/* XXX */
358178354Ssam	}
359178354Ssam	if (ni == NULL) {
360178354Ssam		/*
361178354Ssam		 * Permit packets w/ bpf params through regardless
362178354Ssam		 * (see below about sa_len).
363178354Ssam		 */
364178354Ssam		if (dst->sa_len == 0)
365178354Ssam			senderr(EHOSTUNREACH);
366178354Ssam		ni = ieee80211_ref_node(vap->iv_bss);
367178354Ssam	}
368178354Ssam
369178354Ssam	/*
370178354Ssam	 * Sanitize mbuf for net80211 flags leaked from above.
371178354Ssam	 *
372178354Ssam	 * NB: This must be done before ieee80211_classify as
373178354Ssam	 *     it marks EAPOL in frames with M_EAPOL.
374178354Ssam	 */
375178354Ssam	m->m_flags &= ~M_80211_TX;
376178354Ssam
377178354Ssam	/* calculate priority so drivers can find the tx queue */
378178354Ssam	/* XXX assumes an 802.3 frame */
379178354Ssam	if (ieee80211_classify(ni, m))
380178354Ssam		senderr(EIO);		/* XXX */
381178354Ssam
382178354Ssam	BPF_MTAP(ifp, m);
383178354Ssam
384178354Ssam	/*
385178354Ssam	 * NB: DLT_IEEE802_11_RADIO identifies the parameters are
386178354Ssam	 * present by setting the sa_len field of the sockaddr (yes,
387178354Ssam	 * this is a hack).
388178354Ssam	 * NB: we assume sa_data is suitably aligned to cast.
389178354Ssam	 */
390178354Ssam	return vap->iv_ic->ic_raw_xmit(ni, m,
391178354Ssam	    (const struct ieee80211_bpf_params *)(dst->sa_len ?
392178354Ssam		dst->sa_data : NULL));
393178354Ssambad:
394178354Ssam	if (m != NULL)
395178354Ssam		m_freem(m);
396178354Ssam	if (ni != NULL)
397178354Ssam		ieee80211_free_node(ni);
398178354Ssam	return error;
399178354Ssam#undef senderr
400178354Ssam}
401178354Ssam
402178354Ssam/*
403148314Ssam * Set the direction field and address fields of an outgoing
404184285Ssam * frame.  Note this should be called early on in constructing
405184285Ssam * a frame as it sets i_fc[1]; other bits can then be or'd in.
406148314Ssam */
407148314Ssamstatic void
408178354Ssamieee80211_send_setup(
409148314Ssam	struct ieee80211_node *ni,
410148314Ssam	struct ieee80211_frame *wh,
411184282Ssam	int type, int tid,
412170530Ssam	const uint8_t sa[IEEE80211_ADDR_LEN],
413170530Ssam	const uint8_t da[IEEE80211_ADDR_LEN],
414170530Ssam	const uint8_t bssid[IEEE80211_ADDR_LEN])
415148314Ssam{
416148314Ssam#define	WH4(wh)	((struct ieee80211_frame_addr4 *)wh)
417148314Ssam
418148314Ssam	wh->i_fc[0] = IEEE80211_FC0_VERSION_0 | type;
419148314Ssam	if ((type & IEEE80211_FC0_TYPE_MASK) == IEEE80211_FC0_TYPE_DATA) {
420178354Ssam		struct ieee80211vap *vap = ni->ni_vap;
421178354Ssam
422178354Ssam		switch (vap->iv_opmode) {
423148314Ssam		case IEEE80211_M_STA:
424148314Ssam			wh->i_fc[1] = IEEE80211_FC1_DIR_TODS;
425148314Ssam			IEEE80211_ADDR_COPY(wh->i_addr1, bssid);
426148314Ssam			IEEE80211_ADDR_COPY(wh->i_addr2, sa);
427148314Ssam			IEEE80211_ADDR_COPY(wh->i_addr3, da);
428148314Ssam			break;
429148314Ssam		case IEEE80211_M_IBSS:
430148314Ssam		case IEEE80211_M_AHDEMO:
431148314Ssam			wh->i_fc[1] = IEEE80211_FC1_DIR_NODS;
432148314Ssam			IEEE80211_ADDR_COPY(wh->i_addr1, da);
433148314Ssam			IEEE80211_ADDR_COPY(wh->i_addr2, sa);
434148314Ssam			IEEE80211_ADDR_COPY(wh->i_addr3, bssid);
435148314Ssam			break;
436148314Ssam		case IEEE80211_M_HOSTAP:
437148314Ssam			wh->i_fc[1] = IEEE80211_FC1_DIR_FROMDS;
438148314Ssam			IEEE80211_ADDR_COPY(wh->i_addr1, da);
439148314Ssam			IEEE80211_ADDR_COPY(wh->i_addr2, bssid);
440148314Ssam			IEEE80211_ADDR_COPY(wh->i_addr3, sa);
441148314Ssam			break;
442170530Ssam		case IEEE80211_M_WDS:
443170530Ssam			wh->i_fc[1] = IEEE80211_FC1_DIR_DSTODS;
444178354Ssam			IEEE80211_ADDR_COPY(wh->i_addr1, da);
445178354Ssam			IEEE80211_ADDR_COPY(wh->i_addr2, vap->iv_myaddr);
446170530Ssam			IEEE80211_ADDR_COPY(wh->i_addr3, da);
447170530Ssam			IEEE80211_ADDR_COPY(WH4(wh)->i_addr4, sa);
448170530Ssam			break;
449148314Ssam		case IEEE80211_M_MONITOR:	/* NB: to quiet compiler */
450148314Ssam			break;
451148314Ssam		}
452148314Ssam	} else {
453148314Ssam		wh->i_fc[1] = IEEE80211_FC1_DIR_NODS;
454148314Ssam		IEEE80211_ADDR_COPY(wh->i_addr1, da);
455148314Ssam		IEEE80211_ADDR_COPY(wh->i_addr2, sa);
456148314Ssam		IEEE80211_ADDR_COPY(wh->i_addr3, bssid);
457148314Ssam	}
458170530Ssam	*(uint16_t *)&wh->i_dur[0] = 0;
459170530Ssam	*(uint16_t *)&wh->i_seq[0] =
460184282Ssam	    htole16(ni->ni_txseqs[tid] << IEEE80211_SEQ_SEQ_SHIFT);
461184282Ssam	ni->ni_txseqs[tid]++;
462148314Ssam#undef WH4
463148314Ssam}
464148314Ssam
465148314Ssam/*
466119150Ssam * Send a management frame to the specified node.  The node pointer
467119150Ssam * must have a reference as the pointer will be passed to the driver
468119150Ssam * and potentially held for a long time.  If the frame is successfully
469119150Ssam * dispatched to the driver, then it is responsible for freeing the
470178354Ssam * reference (and potentially free'ing up any associated storage);
471178354Ssam * otherwise deal with reclaiming any reference (on error).
472119150Ssam */
473170530Ssamint
474184282Ssamieee80211_mgmt_output(struct ieee80211_node *ni, struct mbuf *m, int type,
475184282Ssam	struct ieee80211_bpf_params *params)
476116742Ssam{
477178354Ssam	struct ieee80211vap *vap = ni->ni_vap;
478178354Ssam	struct ieee80211com *ic = ni->ni_ic;
479116742Ssam	struct ieee80211_frame *wh;
480116742Ssam
481119150Ssam	KASSERT(ni != NULL, ("null node"));
482116742Ssam
483178354Ssam	if (vap->iv_state == IEEE80211_S_CAC) {
484178354Ssam		IEEE80211_NOTE(vap, IEEE80211_MSG_OUTPUT | IEEE80211_MSG_DOTH,
485178354Ssam		    ni, "block %s frame in CAC state",
486178354Ssam			ieee80211_mgt_subtype_name[
487178354Ssam			    (type & IEEE80211_FC0_SUBTYPE_MASK) >>
488178354Ssam				IEEE80211_FC0_SUBTYPE_SHIFT]);
489178354Ssam		vap->iv_stats.is_tx_badstate++;
490178354Ssam		ieee80211_free_node(ni);
491178354Ssam		m_freem(m);
492178354Ssam		return EIO;		/* XXX */
493178354Ssam	}
494178354Ssam
495116742Ssam	M_PREPEND(m, sizeof(struct ieee80211_frame), M_DONTWAIT);
496178354Ssam	if (m == NULL) {
497178354Ssam		ieee80211_free_node(ni);
498116742Ssam		return ENOMEM;
499178354Ssam	}
500119150Ssam
501116742Ssam	wh = mtod(m, struct ieee80211_frame *);
502184282Ssam	ieee80211_send_setup(ni, wh,
503184282Ssam	     IEEE80211_FC0_TYPE_MGT | type, IEEE80211_NONQOS_TID,
504184282Ssam	     vap->iv_myaddr, ni->ni_macaddr, ni->ni_bssid);
505184282Ssam	if (params->ibp_flags & IEEE80211_BPF_CRYPTO) {
506178354Ssam		IEEE80211_NOTE_MAC(vap, IEEE80211_MSG_AUTH, wh->i_addr1,
507178354Ssam		    "encrypting frame (%s)", __func__);
508138568Ssam		wh->i_fc[1] |= IEEE80211_FC1_WEP;
509138568Ssam	}
510184286Ssam	m->m_flags |= M_ENCAP;		/* mark encapsulated */
511184282Ssam
512184282Ssam	KASSERT(type != IEEE80211_FC0_SUBTYPE_PROBE_RESP, ("probe response?"));
513184282Ssam	M_WME_SETAC(m, params->ibp_pri);
514184282Ssam
515116742Ssam#ifdef IEEE80211_DEBUG
516138568Ssam	/* avoid printing too many frames */
517178354Ssam	if ((ieee80211_msg_debug(vap) && doprint(vap, type)) ||
518178354Ssam	    ieee80211_msg_dumppkts(vap)) {
519138568Ssam		printf("[%s] send %s on channel %u\n",
520138568Ssam		    ether_sprintf(wh->i_addr1),
521138568Ssam		    ieee80211_mgt_subtype_name[
522138568Ssam			(type & IEEE80211_FC0_SUBTYPE_MASK) >>
523138568Ssam				IEEE80211_FC0_SUBTYPE_SHIFT],
524148936Ssam		    ieee80211_chan2ieee(ic, ic->ic_curchan));
525138568Ssam	}
526116742Ssam#endif
527138568Ssam	IEEE80211_NODE_STAT(ni, tx_mgmt);
528170530Ssam
529184282Ssam	return ic->ic_raw_xmit(ni, m, params);
530116742Ssam}
531116742Ssam
532119150Ssam/*
533184283Ssam * Send a null data frame to the specified node.  If the station
534184283Ssam * is setup for QoS then a QoS Null Data frame is constructed.
535184283Ssam * If this is a WDS station then a 4-address frame is constructed.
536148582Ssam *
537148582Ssam * NB: the caller is assumed to have setup a node reference
538148582Ssam *     for use; this is necessary to deal with a race condition
539178354Ssam *     when probing for inactive stations.  Like ieee80211_mgmt_output
540178354Ssam *     we must cleanup any node reference on error;  however we
541178354Ssam *     can safely just unref it as we know it will never be the
542178354Ssam *     last reference to the node.
543119150Ssam */
544138568Ssamint
545148301Ssamieee80211_send_nulldata(struct ieee80211_node *ni)
546138568Ssam{
547178354Ssam	struct ieee80211vap *vap = ni->ni_vap;
548148301Ssam	struct ieee80211com *ic = ni->ni_ic;
549138568Ssam	struct mbuf *m;
550138568Ssam	struct ieee80211_frame *wh;
551184283Ssam	int hdrlen;
552184283Ssam	uint8_t *frm;
553138568Ssam
554178354Ssam	if (vap->iv_state == IEEE80211_S_CAC) {
555178354Ssam		IEEE80211_NOTE(vap, IEEE80211_MSG_OUTPUT | IEEE80211_MSG_DOTH,
556178354Ssam		    ni, "block %s frame in CAC state", "null data");
557178354Ssam		ieee80211_unref_node(&ni);
558178354Ssam		vap->iv_stats.is_tx_badstate++;
559178354Ssam		return EIO;		/* XXX */
560178354Ssam	}
561178354Ssam
562184283Ssam	if (ni->ni_flags & (IEEE80211_NODE_QOS|IEEE80211_NODE_HT))
563184283Ssam		hdrlen = sizeof(struct ieee80211_qosframe);
564184283Ssam	else
565184283Ssam		hdrlen = sizeof(struct ieee80211_frame);
566184283Ssam	/* NB: only WDS vap's get 4-address frames */
567184283Ssam	if (vap->iv_opmode == IEEE80211_M_WDS)
568184283Ssam		hdrlen += IEEE80211_ADDR_LEN;
569184283Ssam	if (ic->ic_flags & IEEE80211_F_DATAPAD)
570184283Ssam		hdrlen = roundup(hdrlen, sizeof(uint32_t));
571184283Ssam
572184283Ssam	m = ieee80211_getmgtframe(&frm, ic->ic_headroom + hdrlen, 0);
573138568Ssam	if (m == NULL) {
574138568Ssam		/* XXX debug msg */
575170530Ssam		ieee80211_unref_node(&ni);
576178354Ssam		vap->iv_stats.is_tx_nobuf++;
577138568Ssam		return ENOMEM;
578138568Ssam	}
579184283Ssam	KASSERT(M_LEADINGSPACE(m) >= hdrlen,
580184283Ssam	    ("leading space %zd", M_LEADINGSPACE(m)));
581184283Ssam	M_PREPEND(m, hdrlen, M_DONTWAIT);
582184283Ssam	if (m == NULL) {
583184283Ssam		/* NB: cannot happen */
584184283Ssam		ieee80211_free_node(ni);
585184283Ssam		return ENOMEM;
586184283Ssam	}
587138568Ssam
588184283Ssam	wh = mtod(m, struct ieee80211_frame *);		/* NB: a little lie */
589184283Ssam	if (ni->ni_flags & IEEE80211_NODE_QOS) {
590184283Ssam		const int tid = WME_AC_TO_TID(WME_AC_BE);
591184283Ssam		uint8_t *qos;
592184283Ssam
593184283Ssam		ieee80211_send_setup(ni, wh,
594184283Ssam		    IEEE80211_FC0_TYPE_DATA | IEEE80211_FC0_SUBTYPE_QOS_NULL,
595184283Ssam		    tid, vap->iv_myaddr, ni->ni_macaddr, ni->ni_bssid);
596184283Ssam
597184283Ssam		if (vap->iv_opmode == IEEE80211_M_WDS)
598184283Ssam			qos = ((struct ieee80211_qosframe_addr4 *) wh)->i_qos;
599184283Ssam		else
600184283Ssam			qos = ((struct ieee80211_qosframe *) wh)->i_qos;
601184283Ssam		qos[0] = tid & IEEE80211_QOS_TID;
602184283Ssam		if (ic->ic_wme.wme_wmeChanParams.cap_wmeParams[WME_AC_BE].wmep_noackPolicy)
603184283Ssam			qos[0] |= IEEE80211_QOS_ACKPOLICY_NOACK;
604184283Ssam		qos[1] = 0;
605184283Ssam	} else {
606184283Ssam		ieee80211_send_setup(ni, wh,
607184283Ssam		    IEEE80211_FC0_TYPE_DATA | IEEE80211_FC0_SUBTYPE_NODATA,
608184283Ssam		    IEEE80211_NONQOS_TID,
609184283Ssam		    vap->iv_myaddr, ni->ni_macaddr, ni->ni_bssid);
610184283Ssam	}
611178354Ssam	if (vap->iv_opmode != IEEE80211_M_WDS) {
612178354Ssam		/* NB: power management bit is never sent by an AP */
613178354Ssam		if ((ni->ni_flags & IEEE80211_NODE_PWR_MGT) &&
614178354Ssam		    vap->iv_opmode != IEEE80211_M_HOSTAP)
615178354Ssam			wh->i_fc[1] |= IEEE80211_FC1_PWR_MGT;
616178354Ssam	}
617184283Ssam	m->m_len = m->m_pkthdr.len = hdrlen;
618184286Ssam	m->m_flags |= M_ENCAP;		/* mark encapsulated */
619184283Ssam
620172231Ssam	M_WME_SETAC(m, WME_AC_BE);
621138568Ssam
622138568Ssam	IEEE80211_NODE_STAT(ni, tx_data);
623138568Ssam
624178354Ssam	IEEE80211_NOTE(vap, IEEE80211_MSG_DEBUG | IEEE80211_MSG_DUMPPKTS, ni,
625184283Ssam	    "send %snull data frame on channel %u, pwr mgt %s",
626184283Ssam	    ni->ni_flags & IEEE80211_NODE_QOS ? "QoS " : "",
627148936Ssam	    ieee80211_chan2ieee(ic, ic->ic_curchan),
628148314Ssam	    wh->i_fc[1] & IEEE80211_FC1_PWR_MGT ? "ena" : "dis");
629148314Ssam
630178354Ssam	return ic->ic_raw_xmit(ni, m, NULL);
631138568Ssam}
632138568Ssam
633138568Ssam/*
634138568Ssam * Assign priority to a frame based on any vlan tag assigned
635138568Ssam * to the station and/or any Diffserv setting in an IP header.
636138568Ssam * Finally, if an ACM policy is setup (in station mode) it's
637138568Ssam * applied.
638138568Ssam */
639138568Ssamint
640178354Ssamieee80211_classify(struct ieee80211_node *ni, struct mbuf *m)
641138568Ssam{
642178354Ssam	const struct ether_header *eh = mtod(m, struct ether_header *);
643138568Ssam	int v_wme_ac, d_wme_ac, ac;
644138568Ssam
645178354Ssam	/*
646178354Ssam	 * Always promote PAE/EAPOL frames to high priority.
647178354Ssam	 */
648178354Ssam	if (eh->ether_type == htons(ETHERTYPE_PAE)) {
649178354Ssam		/* NB: mark so others don't need to check header */
650178354Ssam		m->m_flags |= M_EAPOL;
651178354Ssam		ac = WME_AC_VO;
652178354Ssam		goto done;
653178354Ssam	}
654178354Ssam	/*
655178354Ssam	 * Non-qos traffic goes to BE.
656178354Ssam	 */
657138568Ssam	if ((ni->ni_flags & IEEE80211_NODE_QOS) == 0) {
658138568Ssam		ac = WME_AC_BE;
659138568Ssam		goto done;
660138568Ssam	}
661138568Ssam
662138568Ssam	/*
663138568Ssam	 * If node has a vlan tag then all traffic
664138568Ssam	 * to it must have a matching tag.
665138568Ssam	 */
666138568Ssam	v_wme_ac = 0;
667138568Ssam	if (ni->ni_vlan != 0) {
668162375Sandre		 if ((m->m_flags & M_VLANTAG) == 0) {
669138568Ssam			IEEE80211_NODE_STAT(ni, tx_novlantag);
670138568Ssam			return 1;
671138568Ssam		}
672162375Sandre		if (EVL_VLANOFTAG(m->m_pkthdr.ether_vtag) !=
673138568Ssam		    EVL_VLANOFTAG(ni->ni_vlan)) {
674138568Ssam			IEEE80211_NODE_STAT(ni, tx_vlanmismatch);
675138568Ssam			return 1;
676138568Ssam		}
677138568Ssam		/* map vlan priority to AC */
678173867Ssam		v_wme_ac = TID_TO_WME_AC(EVL_PRIOFTAG(ni->ni_vlan));
679138568Ssam	}
680138568Ssam
681138568Ssam#ifdef INET
682138568Ssam	if (eh->ether_type == htons(ETHERTYPE_IP)) {
683173867Ssam		uint8_t tos;
684138568Ssam		/*
685173867Ssam		 * IP frame, map the DSCP bits from the TOS field.
686138568Ssam		 */
687173867Ssam		/* XXX m_copydata may be too slow for fast path */
688173867Ssam		/* NB: ip header may not be in first mbuf */
689173867Ssam		m_copydata(m, sizeof(struct ether_header) +
690173867Ssam		    offsetof(struct ip, ip_tos), sizeof(tos), &tos);
691173867Ssam		tos >>= 5;		/* NB: ECN + low 3 bits of DSCP */
692173867Ssam		d_wme_ac = TID_TO_WME_AC(tos);
693138568Ssam	} else {
694138568Ssam#endif /* INET */
695138568Ssam		d_wme_ac = WME_AC_BE;
696138568Ssam#ifdef INET
697138568Ssam	}
698138568Ssam#endif
699138568Ssam	/*
700138568Ssam	 * Use highest priority AC.
701138568Ssam	 */
702138568Ssam	if (v_wme_ac > d_wme_ac)
703138568Ssam		ac = v_wme_ac;
704138568Ssam	else
705138568Ssam		ac = d_wme_ac;
706138568Ssam
707138568Ssam	/*
708138568Ssam	 * Apply ACM policy.
709138568Ssam	 */
710178354Ssam	if (ni->ni_vap->iv_opmode == IEEE80211_M_STA) {
711138568Ssam		static const int acmap[4] = {
712138568Ssam			WME_AC_BK,	/* WME_AC_BE */
713138568Ssam			WME_AC_BK,	/* WME_AC_BK */
714138568Ssam			WME_AC_BE,	/* WME_AC_VI */
715138568Ssam			WME_AC_VI,	/* WME_AC_VO */
716138568Ssam		};
717178354Ssam		struct ieee80211com *ic = ni->ni_ic;
718178354Ssam
719138568Ssam		while (ac != WME_AC_BK &&
720138568Ssam		    ic->ic_wme.wme_wmeBssChanParams.cap_wmeParams[ac].wmep_acm)
721138568Ssam			ac = acmap[ac];
722138568Ssam	}
723138568Ssamdone:
724138568Ssam	M_WME_SETAC(m, ac);
725138568Ssam	return 0;
726138568Ssam}
727138568Ssam
728138568Ssam/*
729139527Ssam * Insure there is sufficient contiguous space to encapsulate the
730139527Ssam * 802.11 data frame.  If room isn't already there, arrange for it.
731139527Ssam * Drivers and cipher modules assume we have done the necessary work
732139527Ssam * and fail rudely if they don't find the space they need.
733139527Ssam */
734139527Ssamstatic struct mbuf *
735178354Ssamieee80211_mbuf_adjust(struct ieee80211vap *vap, int hdrsize,
736139527Ssam	struct ieee80211_key *key, struct mbuf *m)
737139527Ssam{
738164805Ssam#define	TO_BE_RECLAIMED	(sizeof(struct ether_header) - sizeof(struct llc))
739178354Ssam	int needed_space = vap->iv_ic->ic_headroom + hdrsize;
740139527Ssam
741139527Ssam	if (key != NULL) {
742139527Ssam		/* XXX belongs in crypto code? */
743139527Ssam		needed_space += key->wk_cipher->ic_header;
744139527Ssam		/* XXX frags */
745156758Ssam		/*
746156758Ssam		 * When crypto is being done in the host we must insure
747156758Ssam		 * the data are writable for the cipher routines; clone
748156758Ssam		 * a writable mbuf chain.
749156758Ssam		 * XXX handle SWMIC specially
750156758Ssam		 */
751179394Ssam		if (key->wk_flags & (IEEE80211_KEY_SWENCRYPT|IEEE80211_KEY_SWENMIC)) {
752156758Ssam			m = m_unshare(m, M_NOWAIT);
753156758Ssam			if (m == NULL) {
754178354Ssam				IEEE80211_DPRINTF(vap, IEEE80211_MSG_OUTPUT,
755156758Ssam				    "%s: cannot get writable mbuf\n", __func__);
756178354Ssam				vap->iv_stats.is_tx_nobuf++; /* XXX new stat */
757156758Ssam				return NULL;
758156758Ssam			}
759156758Ssam		}
760139527Ssam	}
761139527Ssam	/*
762139527Ssam	 * We know we are called just before stripping an Ethernet
763139527Ssam	 * header and prepending an LLC header.  This means we know
764139527Ssam	 * there will be
765164805Ssam	 *	sizeof(struct ether_header) - sizeof(struct llc)
766139527Ssam	 * bytes recovered to which we need additional space for the
767139527Ssam	 * 802.11 header and any crypto header.
768139527Ssam	 */
769139527Ssam	/* XXX check trailing space and copy instead? */
770139527Ssam	if (M_LEADINGSPACE(m) < needed_space - TO_BE_RECLAIMED) {
771139527Ssam		struct mbuf *n = m_gethdr(M_NOWAIT, m->m_type);
772139527Ssam		if (n == NULL) {
773178354Ssam			IEEE80211_DPRINTF(vap, IEEE80211_MSG_OUTPUT,
774139527Ssam			    "%s: cannot expand storage\n", __func__);
775178354Ssam			vap->iv_stats.is_tx_nobuf++;
776139527Ssam			m_freem(m);
777139527Ssam			return NULL;
778139527Ssam		}
779139527Ssam		KASSERT(needed_space <= MHLEN,
780139527Ssam		    ("not enough room, need %u got %zu\n", needed_space, MHLEN));
781139527Ssam		/*
782139527Ssam		 * Setup new mbuf to have leading space to prepend the
783139527Ssam		 * 802.11 header and any crypto header bits that are
784139527Ssam		 * required (the latter are added when the driver calls
785139527Ssam		 * back to ieee80211_crypto_encap to do crypto encapsulation).
786139527Ssam		 */
787139527Ssam		/* NB: must be first 'cuz it clobbers m_data */
788139527Ssam		m_move_pkthdr(n, m);
789139527Ssam		n->m_len = 0;			/* NB: m_gethdr does not set */
790139527Ssam		n->m_data += needed_space;
791139527Ssam		/*
792139527Ssam		 * Pull up Ethernet header to create the expected layout.
793139527Ssam		 * We could use m_pullup but that's overkill (i.e. we don't
794139527Ssam		 * need the actual data) and it cannot fail so do it inline
795139527Ssam		 * for speed.
796139527Ssam		 */
797139527Ssam		/* NB: struct ether_header is known to be contiguous */
798139527Ssam		n->m_len += sizeof(struct ether_header);
799139527Ssam		m->m_len -= sizeof(struct ether_header);
800139527Ssam		m->m_data += sizeof(struct ether_header);
801139527Ssam		/*
802139527Ssam		 * Replace the head of the chain.
803139527Ssam		 */
804139527Ssam		n->m_next = m;
805139527Ssam		m = n;
806139527Ssam	}
807139527Ssam	return m;
808139527Ssam#undef TO_BE_RECLAIMED
809139527Ssam}
810139527Ssam
811139527Ssam/*
812139527Ssam * Return the transmit key to use in sending a unicast frame.
813139527Ssam * If a unicast key is set we use that.  When no unicast key is set
814139527Ssam * we fall back to the default transmit key.
815138568Ssam */
816138568Ssamstatic __inline struct ieee80211_key *
817178354Ssamieee80211_crypto_getucastkey(struct ieee80211vap *vap,
818178354Ssam	struct ieee80211_node *ni)
819138568Ssam{
820167432Ssam	if (IEEE80211_KEY_UNDEFINED(&ni->ni_ucastkey)) {
821178354Ssam		if (vap->iv_def_txkey == IEEE80211_KEYIX_NONE ||
822178354Ssam		    IEEE80211_KEY_UNDEFINED(&vap->iv_nw_keys[vap->iv_def_txkey]))
823138568Ssam			return NULL;
824178354Ssam		return &vap->iv_nw_keys[vap->iv_def_txkey];
825138568Ssam	} else {
826138568Ssam		return &ni->ni_ucastkey;
827138568Ssam	}
828138568Ssam}
829138568Ssam
830138568Ssam/*
831139527Ssam * Return the transmit key to use in sending a multicast frame.
832139527Ssam * Multicast traffic always uses the group key which is installed as
833139527Ssam * the default tx key.
834139527Ssam */
835139527Ssamstatic __inline struct ieee80211_key *
836178354Ssamieee80211_crypto_getmcastkey(struct ieee80211vap *vap,
837178354Ssam	struct ieee80211_node *ni)
838139527Ssam{
839178354Ssam	if (vap->iv_def_txkey == IEEE80211_KEYIX_NONE ||
840178354Ssam	    IEEE80211_KEY_UNDEFINED(&vap->iv_nw_keys[vap->iv_def_txkey]))
841139527Ssam		return NULL;
842178354Ssam	return &vap->iv_nw_keys[vap->iv_def_txkey];
843139527Ssam}
844139527Ssam
845139527Ssam/*
846138568Ssam * Encapsulate an outbound data frame.  The mbuf chain is updated.
847138568Ssam * If an error is encountered NULL is returned.  The caller is required
848138568Ssam * to provide a node reference and pullup the ethernet header in the
849138568Ssam * first mbuf.
850178354Ssam *
851178354Ssam * NB: Packet is assumed to be processed by ieee80211_classify which
852178354Ssam *     marked EAPOL frames w/ M_EAPOL.
853138568Ssam */
854116742Ssamstruct mbuf *
855178354Ssamieee80211_encap(struct ieee80211_node *ni, struct mbuf *m)
856116742Ssam{
857178354Ssam#define	WH4(wh)	((struct ieee80211_frame_addr4 *)(wh))
858178354Ssam	struct ieee80211vap *vap = ni->ni_vap;
859178354Ssam	struct ieee80211com *ic = ni->ni_ic;
860116742Ssam	struct ether_header eh;
861116742Ssam	struct ieee80211_frame *wh;
862138568Ssam	struct ieee80211_key *key;
863116742Ssam	struct llc *llc;
864178354Ssam	int hdrsize, hdrspace, datalen, addqos, txfrag, isff, is4addr;
865116742Ssam
866170530Ssam	/*
867170530Ssam	 * Copy existing Ethernet header to a safe place.  The
868170530Ssam	 * rest of the code assumes it's ok to strip it when
869170530Ssam	 * reorganizing state for the final encapsulation.
870170530Ssam	 */
871138568Ssam	KASSERT(m->m_len >= sizeof(eh), ("no ethernet header!"));
872178354Ssam	ETHER_HEADER_COPY(&eh, mtod(m, caddr_t));
873116742Ssam
874138568Ssam	/*
875138568Ssam	 * Insure space for additional headers.  First identify
876138568Ssam	 * transmit key to use in calculating any buffer adjustments
877138568Ssam	 * required.  This is also used below to do privacy
878138568Ssam	 * encapsulation work.  Then calculate the 802.11 header
879138568Ssam	 * size and any padding required by the driver.
880138568Ssam	 *
881138568Ssam	 * Note key may be NULL if we fall back to the default
882138568Ssam	 * transmit key and that is not set.  In that case the
883138568Ssam	 * buffer may not be expanded as needed by the cipher
884138568Ssam	 * routines, but they will/should discard it.
885138568Ssam	 */
886178354Ssam	if (vap->iv_flags & IEEE80211_F_PRIVACY) {
887178354Ssam		if (vap->iv_opmode == IEEE80211_M_STA ||
888178354Ssam		    !IEEE80211_IS_MULTICAST(eh.ether_dhost) ||
889178354Ssam		    (vap->iv_opmode == IEEE80211_M_WDS &&
890178354Ssam		     (vap->iv_flags_ext & IEEE80211_FEXT_WDSLEGACY)))
891178354Ssam			key = ieee80211_crypto_getucastkey(vap, ni);
892139527Ssam		else
893178354Ssam			key = ieee80211_crypto_getmcastkey(vap, ni);
894178354Ssam		if (key == NULL && (m->m_flags & M_EAPOL) == 0) {
895178354Ssam			IEEE80211_NOTE_MAC(vap, IEEE80211_MSG_CRYPTO,
896178354Ssam			    eh.ether_dhost,
897178354Ssam			    "no default transmit key (%s) deftxkey %u",
898178354Ssam			    __func__, vap->iv_def_txkey);
899178354Ssam			vap->iv_stats.is_tx_nodefkey++;
900171950Ssam			goto bad;
901138568Ssam		}
902138568Ssam	} else
903138568Ssam		key = NULL;
904139527Ssam	/*
905139527Ssam	 * XXX Some ap's don't handle QoS-encapsulated EAPOL
906139527Ssam	 * frames so suppress use.  This may be an issue if other
907139527Ssam	 * ap's require all data frames to be QoS-encapsulated
908139527Ssam	 * once negotiated in which case we'll need to make this
909139527Ssam	 * configurable.
910139527Ssam	 */
911170530Ssam	addqos = (ni->ni_flags & (IEEE80211_NODE_QOS|IEEE80211_NODE_HT)) &&
912178354Ssam		 (m->m_flags & M_EAPOL) == 0;
913139527Ssam	if (addqos)
914138568Ssam		hdrsize = sizeof(struct ieee80211_qosframe);
915138568Ssam	else
916138568Ssam		hdrsize = sizeof(struct ieee80211_frame);
917178354Ssam	/*
918178354Ssam	 * 4-address frames need to be generated for:
919178354Ssam	 * o packets sent through a WDS vap (M_WDS || IEEE80211_M_WDS)
920178354Ssam	 * o packets relayed by a station operating with dynamic WDS
921178354Ssam	 *   (IEEE80211_M_STA+IEEE80211_F_DWDS and src address)
922178354Ssam	 */
923178354Ssam	is4addr = (m->m_flags & M_WDS) ||
924178354Ssam	    vap->iv_opmode == IEEE80211_M_WDS ||	/* XXX redundant? */
925178354Ssam	    (vap->iv_opmode == IEEE80211_M_STA &&
926178354Ssam	     (vap->iv_flags & IEEE80211_F_DWDS) &&
927178354Ssam	     !IEEE80211_ADDR_EQ(eh.ether_shost, vap->iv_myaddr));
928178354Ssam	if (is4addr)
929178354Ssam		hdrsize += IEEE80211_ADDR_LEN;
930178354Ssam	/*
931178354Ssam	 * Honor driver DATAPAD requirement.
932178354Ssam	 */
933138568Ssam	if (ic->ic_flags & IEEE80211_F_DATAPAD)
934178354Ssam		hdrspace = roundup(hdrsize, sizeof(uint32_t));
935178354Ssam	else
936178354Ssam		hdrspace = hdrsize;
937170530Ssam
938170530Ssam	if ((isff = m->m_flags & M_FF) != 0) {
939170530Ssam		struct mbuf *m2;
940170530Ssam		struct ether_header eh2;
941170530Ssam
942170530Ssam		/*
943170530Ssam		 * Fast frame encapsulation.  There must be two packets
944170530Ssam		 * chained with m_nextpkt.  We do header adjustment for
945170530Ssam		 * each, add the tunnel encapsulation, and then concatenate
946170530Ssam		 * the mbuf chains to form a single frame for transmission.
947170530Ssam		 */
948170530Ssam		m2 = m->m_nextpkt;
949170530Ssam		if (m2 == NULL) {
950178354Ssam			IEEE80211_DPRINTF(vap, IEEE80211_MSG_SUPERG,
951170530Ssam				"%s: only one frame\n", __func__);
952170530Ssam			goto bad;
953170530Ssam		}
954170530Ssam		m->m_nextpkt = NULL;
955170530Ssam		/*
956170530Ssam		 * Include fast frame headers in adjusting header
957170530Ssam		 * layout; this allocates space according to what
958170530Ssam		 * ieee80211_encap_fastframe will do.
959170530Ssam		 */
960178354Ssam		m = ieee80211_mbuf_adjust(vap,
961178354Ssam			hdrspace + sizeof(struct llc) + sizeof(uint32_t) + 2 +
962170530Ssam			    sizeof(struct ether_header),
963170530Ssam			key, m);
964170530Ssam		if (m == NULL) {
965170530Ssam			/* NB: ieee80211_mbuf_adjust handles msgs+statistics */
966170530Ssam			m_freem(m2);
967170530Ssam			goto bad;
968170530Ssam		}
969170530Ssam		/*
970170530Ssam		 * Copy second frame's Ethernet header out of line
971170530Ssam		 * and adjust for encapsulation headers.  Note that
972170530Ssam		 * we make room for padding in case there isn't room
973170530Ssam		 * at the end of first frame.
974170530Ssam		 */
975170530Ssam		KASSERT(m2->m_len >= sizeof(eh2), ("no ethernet header!"));
976178354Ssam		ETHER_HEADER_COPY(&eh2, mtod(m2, caddr_t));
977178354Ssam		m2 = ieee80211_mbuf_adjust(vap,
978170530Ssam			ATH_FF_MAX_HDR_PAD + sizeof(struct ether_header),
979170530Ssam			NULL, m2);
980170530Ssam		if (m2 == NULL) {
981170530Ssam			/* NB: ieee80211_mbuf_adjust handles msgs+statistics */
982170530Ssam			goto bad;
983170530Ssam		}
984178354Ssam		m = ieee80211_encap_fastframe(vap, m, &eh, m2, &eh2);
985170530Ssam		if (m == NULL)
986170530Ssam			goto bad;
987170530Ssam	} else {
988170530Ssam		/*
989170530Ssam		 * Normal frame.
990170530Ssam		 */
991178354Ssam		m = ieee80211_mbuf_adjust(vap, hdrspace, key, m);
992170530Ssam		if (m == NULL) {
993170530Ssam			/* NB: ieee80211_mbuf_adjust handles msgs+statistics */
994170530Ssam			goto bad;
995170530Ssam		}
996170530Ssam		/* NB: this could be optimized 'cuz of ieee80211_mbuf_adjust */
997170530Ssam		m_adj(m, sizeof(struct ether_header) - sizeof(struct llc));
998170530Ssam		llc = mtod(m, struct llc *);
999170530Ssam		llc->llc_dsap = llc->llc_ssap = LLC_SNAP_LSAP;
1000170530Ssam		llc->llc_control = LLC_UI;
1001170530Ssam		llc->llc_snap.org_code[0] = 0;
1002170530Ssam		llc->llc_snap.org_code[1] = 0;
1003170530Ssam		llc->llc_snap.org_code[2] = 0;
1004170530Ssam		llc->llc_snap.ether_type = eh.ether_type;
1005127772Ssam	}
1006138568Ssam	datalen = m->m_pkthdr.len;		/* NB: w/o 802.11 header */
1007138568Ssam
1008178354Ssam	M_PREPEND(m, hdrspace, M_DONTWAIT);
1009121180Ssam	if (m == NULL) {
1010178354Ssam		vap->iv_stats.is_tx_nobuf++;
1011119150Ssam		goto bad;
1012121180Ssam	}
1013116742Ssam	wh = mtod(m, struct ieee80211_frame *);
1014116742Ssam	wh->i_fc[0] = IEEE80211_FC0_VERSION_0 | IEEE80211_FC0_TYPE_DATA;
1015170530Ssam	*(uint16_t *)wh->i_dur = 0;
1016178354Ssam	if (is4addr) {
1017178354Ssam		wh->i_fc[1] = IEEE80211_FC1_DIR_DSTODS;
1018178354Ssam		IEEE80211_ADDR_COPY(wh->i_addr1, ni->ni_macaddr);
1019178354Ssam		IEEE80211_ADDR_COPY(wh->i_addr2, vap->iv_myaddr);
1020178354Ssam		IEEE80211_ADDR_COPY(wh->i_addr3, eh.ether_dhost);
1021178354Ssam		IEEE80211_ADDR_COPY(WH4(wh)->i_addr4, eh.ether_shost);
1022178354Ssam	} else switch (vap->iv_opmode) {
1023116742Ssam	case IEEE80211_M_STA:
1024116742Ssam		wh->i_fc[1] = IEEE80211_FC1_DIR_TODS;
1025116742Ssam		IEEE80211_ADDR_COPY(wh->i_addr1, ni->ni_bssid);
1026116742Ssam		IEEE80211_ADDR_COPY(wh->i_addr2, eh.ether_shost);
1027116742Ssam		IEEE80211_ADDR_COPY(wh->i_addr3, eh.ether_dhost);
1028116742Ssam		break;
1029116742Ssam	case IEEE80211_M_IBSS:
1030116742Ssam	case IEEE80211_M_AHDEMO:
1031116742Ssam		wh->i_fc[1] = IEEE80211_FC1_DIR_NODS;
1032116742Ssam		IEEE80211_ADDR_COPY(wh->i_addr1, eh.ether_dhost);
1033116742Ssam		IEEE80211_ADDR_COPY(wh->i_addr2, eh.ether_shost);
1034140636Ssam		/*
1035178354Ssam		 * NB: always use the bssid from iv_bss as the
1036140636Ssam		 *     neighbor's may be stale after an ibss merge
1037140636Ssam		 */
1038178354Ssam		IEEE80211_ADDR_COPY(wh->i_addr3, vap->iv_bss->ni_bssid);
1039116742Ssam		break;
1040116742Ssam	case IEEE80211_M_HOSTAP:
1041116742Ssam		wh->i_fc[1] = IEEE80211_FC1_DIR_FROMDS;
1042116742Ssam		IEEE80211_ADDR_COPY(wh->i_addr1, eh.ether_dhost);
1043116742Ssam		IEEE80211_ADDR_COPY(wh->i_addr2, ni->ni_bssid);
1044116742Ssam		IEEE80211_ADDR_COPY(wh->i_addr3, eh.ether_shost);
1045116742Ssam		break;
1046117817Ssam	case IEEE80211_M_MONITOR:
1047178354Ssam	case IEEE80211_M_WDS:		/* NB: is4addr should always be true */
1048119150Ssam		goto bad;
1049116742Ssam	}
1050147789Ssam	if (m->m_flags & M_MORE_DATA)
1051147789Ssam		wh->i_fc[1] |= IEEE80211_FC1_MORE_DATA;
1052139527Ssam	if (addqos) {
1053178354Ssam		uint8_t *qos;
1054138568Ssam		int ac, tid;
1055138568Ssam
1056178354Ssam		if (is4addr) {
1057178354Ssam			qos = ((struct ieee80211_qosframe_addr4 *) wh)->i_qos;
1058178354Ssam		} else
1059178354Ssam			qos = ((struct ieee80211_qosframe *) wh)->i_qos;
1060138568Ssam		ac = M_WME_GETAC(m);
1061138568Ssam		/* map from access class/queue to 11e header priorty value */
1062138568Ssam		tid = WME_AC_TO_TID(ac);
1063178354Ssam		qos[0] = tid & IEEE80211_QOS_TID;
1064170530Ssam		/*
1065170530Ssam		 * Check if A-MPDU tx aggregation is setup or if we
1066170530Ssam		 * should try to enable it.  The sta must be associated
1067178354Ssam		 * with HT and A-MPDU enabled for use.  When the policy
1068178354Ssam		 * routine decides we should enable A-MPDU we issue an
1069178354Ssam		 * ADDBA request and wait for a reply.  The frame being
1070178354Ssam		 * encapsulated will go out w/o using A-MPDU, or possibly
1071178354Ssam		 * it might be collected by the driver and held/retransmit.
1072178354Ssam		 * The default ic_ampdu_enable routine handles staggering
1073178354Ssam		 * ADDBA requests in case the receiver NAK's us or we are
1074178354Ssam		 * otherwise unable to establish a BA stream.
1075170530Ssam		 */
1076173273Ssam		if ((ni->ni_flags & IEEE80211_NODE_AMPDU_TX) &&
1077178354Ssam		    (vap->iv_flags_ext & IEEE80211_FEXT_AMPDU_TX)) {
1078170530Ssam			struct ieee80211_tx_ampdu *tap = &ni->ni_tx_ampdu[ac];
1079170530Ssam
1080178354Ssam			ieee80211_txampdu_count_packet(tap);
1081170530Ssam			if (IEEE80211_AMPDU_RUNNING(tap)) {
1082170530Ssam				/*
1083170530Ssam				 * Operational, mark frame for aggregation.
1084183247Ssam				 *
1085183247Ssam				 * NB: We support only immediate BA's for
1086183247Ssam				 * AMPDU which means we set the QoS control
1087183247Ssam				 * field to "normal ack" (0) to get "implicit
1088183247Ssam				 * block ack" behaviour.
1089170530Ssam				 */
1090183247Ssam				m->m_flags |= M_AMPDU_MPDU;
1091178354Ssam			} else if (!IEEE80211_AMPDU_REQUESTED(tap) &&
1092178354Ssam			    ic->ic_ampdu_enable(ni, tap)) {
1093170530Ssam				/*
1094170530Ssam				 * Not negotiated yet, request service.
1095170530Ssam				 */
1096170530Ssam				ieee80211_ampdu_request(ni, tap);
1097170530Ssam			}
1098170530Ssam		}
1099170530Ssam		/* XXX works even when BA marked above */
1100138568Ssam		if (ic->ic_wme.wme_wmeChanParams.cap_wmeParams[ac].wmep_noackPolicy)
1101178354Ssam			qos[0] |= IEEE80211_QOS_ACKPOLICY_NOACK;
1102178354Ssam		qos[1] = 0;
1103178354Ssam		wh->i_fc[0] |= IEEE80211_FC0_SUBTYPE_QOS;
1104138568Ssam
1105183247Ssam		if ((m->m_flags & M_AMPDU_MPDU) == 0) {
1106183247Ssam			/*
1107183247Ssam			 * NB: don't assign a sequence # to potential
1108183247Ssam			 * aggregates; we expect this happens at the
1109183247Ssam			 * point the frame comes off any aggregation q
1110183247Ssam			 * as otherwise we may introduce holes in the
1111183247Ssam			 * BA sequence space and/or make window accouting
1112183247Ssam			 * more difficult.
1113183247Ssam			 *
1114183247Ssam			 * XXX may want to control this with a driver
1115183247Ssam			 * capability; this may also change when we pull
1116183247Ssam			 * aggregation up into net80211
1117183247Ssam			 */
1118183247Ssam			*(uint16_t *)wh->i_seq =
1119183247Ssam			    htole16(ni->ni_txseqs[tid] << IEEE80211_SEQ_SEQ_SHIFT);
1120183247Ssam			ni->ni_txseqs[tid]++;
1121183247Ssam		}
1122138568Ssam	} else {
1123170530Ssam		*(uint16_t *)wh->i_seq =
1124167439Ssam		    htole16(ni->ni_txseqs[IEEE80211_NONQOS_TID] << IEEE80211_SEQ_SEQ_SHIFT);
1125167439Ssam		ni->ni_txseqs[IEEE80211_NONQOS_TID]++;
1126138568Ssam	}
1127170530Ssam	/* check if xmit fragmentation is required */
1128178354Ssam	txfrag = (m->m_pkthdr.len > vap->iv_fragthreshold &&
1129170530Ssam	    !IEEE80211_IS_MULTICAST(wh->i_addr1) &&
1130178354Ssam	    (vap->iv_caps & IEEE80211_C_TXFRAG) &&
1131170530Ssam	    !isff);		/* NB: don't fragment ff's */
1132139527Ssam	if (key != NULL) {
1133139527Ssam		/*
1134139527Ssam		 * IEEE 802.1X: send EAPOL frames always in the clear.
1135139527Ssam		 * WPA/WPA2: encrypt EAPOL keys when pairwise keys are set.
1136139527Ssam		 */
1137178354Ssam		if ((m->m_flags & M_EAPOL) == 0 ||
1138178354Ssam		    ((vap->iv_flags & IEEE80211_F_WPA) &&
1139178354Ssam		     (vap->iv_opmode == IEEE80211_M_STA ?
1140167432Ssam		      !IEEE80211_KEY_UNDEFINED(key) :
1141167432Ssam		      !IEEE80211_KEY_UNDEFINED(&ni->ni_ucastkey)))) {
1142139527Ssam			wh->i_fc[1] |= IEEE80211_FC1_WEP;
1143178354Ssam			if (!ieee80211_crypto_enmic(vap, key, m, txfrag)) {
1144178354Ssam				IEEE80211_NOTE_MAC(vap, IEEE80211_MSG_OUTPUT,
1145178354Ssam				    eh.ether_dhost,
1146178354Ssam				    "%s", "enmic failed, discard frame");
1147178354Ssam				vap->iv_stats.is_crypto_enmicfail++;
1148139527Ssam				goto bad;
1149139527Ssam			}
1150139527Ssam		}
1151139527Ssam	}
1152178354Ssam	if (txfrag && !ieee80211_fragment(vap, m, hdrsize,
1153178354Ssam	    key != NULL ? key->wk_cipher->ic_header : 0, vap->iv_fragthreshold))
1154170530Ssam		goto bad;
1155138568Ssam
1156184286Ssam	m->m_flags |= M_ENCAP;		/* mark encapsulated */
1157184286Ssam
1158138568Ssam	IEEE80211_NODE_STAT(ni, tx_data);
1159161144Ssam	if (IEEE80211_IS_MULTICAST(wh->i_addr1))
1160161144Ssam		IEEE80211_NODE_STAT(ni, tx_mcast);
1161161144Ssam	else
1162161144Ssam		IEEE80211_NODE_STAT(ni, tx_ucast);
1163138568Ssam	IEEE80211_NODE_STAT_ADD(ni, tx_bytes, datalen);
1164138568Ssam
1165178354Ssam	/* XXX fragmented frames not handled */
1166178354Ssam	if (bpf_peers_present(vap->iv_rawbpf))
1167178354Ssam		bpf_mtap(vap->iv_rawbpf, m);
1168178354Ssam
1169116742Ssam	return m;
1170119150Ssambad:
1171119150Ssam	if (m != NULL)
1172119150Ssam		m_freem(m);
1173119150Ssam	return NULL;
1174178354Ssam#undef WH4
1175116742Ssam}
1176116742Ssam
1177116742Ssam/*
1178170530Ssam * Do Ethernet-LLC encapsulation for each payload in a fast frame
1179170530Ssam * tunnel encapsulation.  The frame is assumed to have an Ethernet
1180170530Ssam * header at the front that must be stripped before prepending the
1181170530Ssam * LLC followed by the Ethernet header passed in (with an Ethernet
1182170530Ssam * type that specifies the payload size).
1183170530Ssam */
1184170530Ssamstatic struct mbuf *
1185178354Ssamieee80211_encap1(struct ieee80211vap *vap, struct mbuf *m,
1186170530Ssam	const struct ether_header *eh)
1187170530Ssam{
1188170530Ssam	struct llc *llc;
1189170530Ssam	uint16_t payload;
1190170530Ssam
1191170530Ssam	/* XXX optimize by combining m_adj+M_PREPEND */
1192170530Ssam	m_adj(m, sizeof(struct ether_header) - sizeof(struct llc));
1193170530Ssam	llc = mtod(m, struct llc *);
1194170530Ssam	llc->llc_dsap = llc->llc_ssap = LLC_SNAP_LSAP;
1195170530Ssam	llc->llc_control = LLC_UI;
1196170530Ssam	llc->llc_snap.org_code[0] = 0;
1197170530Ssam	llc->llc_snap.org_code[1] = 0;
1198170530Ssam	llc->llc_snap.org_code[2] = 0;
1199170530Ssam	llc->llc_snap.ether_type = eh->ether_type;
1200170530Ssam	payload = m->m_pkthdr.len;		/* NB: w/o Ethernet header */
1201170530Ssam
1202170530Ssam	M_PREPEND(m, sizeof(struct ether_header), M_DONTWAIT);
1203170530Ssam	if (m == NULL) {		/* XXX cannot happen */
1204178354Ssam		IEEE80211_DPRINTF(vap, IEEE80211_MSG_SUPERG,
1205170530Ssam			"%s: no space for ether_header\n", __func__);
1206178354Ssam		vap->iv_stats.is_tx_nobuf++;
1207170530Ssam		return NULL;
1208170530Ssam	}
1209170530Ssam	ETHER_HEADER_COPY(mtod(m, void *), eh);
1210170530Ssam	mtod(m, struct ether_header *)->ether_type = htons(payload);
1211170530Ssam	return m;
1212170530Ssam}
1213170530Ssam
1214170530Ssam/*
1215170530Ssam * Do fast frame tunnel encapsulation.  The two frames and
1216170530Ssam * Ethernet headers are supplied.  The caller is assumed to
1217170530Ssam * have arrange for space in the mbuf chains for encapsulating
1218170530Ssam * headers (to avoid major mbuf fragmentation).
1219170530Ssam *
1220170530Ssam * The encapsulated frame is returned or NULL if there is a
1221170530Ssam * problem (should not happen).
1222170530Ssam */
1223170530Ssamstatic struct mbuf *
1224178354Ssamieee80211_encap_fastframe(struct ieee80211vap *vap,
1225170530Ssam	struct mbuf *m1, const struct ether_header *eh1,
1226170530Ssam	struct mbuf *m2, const struct ether_header *eh2)
1227170530Ssam{
1228170530Ssam	struct llc *llc;
1229170530Ssam	struct mbuf *m;
1230170530Ssam	int pad;
1231170530Ssam
1232170530Ssam	/*
1233170530Ssam	 * First, each frame gets a standard encapsulation.
1234170530Ssam	 */
1235178354Ssam	m1 = ieee80211_encap1(vap, m1, eh1);
1236170530Ssam	if (m1 == NULL) {
1237170530Ssam		m_freem(m2);
1238170530Ssam		return NULL;
1239170530Ssam	}
1240178354Ssam	m2 = ieee80211_encap1(vap, m2, eh2);
1241170530Ssam	if (m2 == NULL) {
1242170530Ssam		m_freem(m1);
1243170530Ssam		return NULL;
1244170530Ssam	}
1245170530Ssam
1246170530Ssam	/*
1247170530Ssam	 * Pad leading frame to a 4-byte boundary.  If there
1248170530Ssam	 * is space at the end of the first frame, put it
1249170530Ssam	 * there; otherwise prepend to the front of the second
1250170530Ssam	 * frame.  We know doing the second will always work
1251170530Ssam	 * because we reserve space above.  We prefer appending
1252170530Ssam	 * as this typically has better DMA alignment properties.
1253170530Ssam	 */
1254170530Ssam	for (m = m1; m->m_next != NULL; m = m->m_next)
1255170530Ssam		;
1256170530Ssam	pad = roundup2(m1->m_pkthdr.len, 4) - m1->m_pkthdr.len;
1257170530Ssam	if (pad) {
1258170530Ssam		if (M_TRAILINGSPACE(m) < pad) {		/* prepend to second */
1259170530Ssam			m2->m_data -= pad;
1260170530Ssam			m2->m_len += pad;
1261170530Ssam			m2->m_pkthdr.len += pad;
1262170530Ssam		} else {				/* append to first */
1263170530Ssam			m->m_len += pad;
1264170530Ssam			m1->m_pkthdr.len += pad;
1265170530Ssam		}
1266170530Ssam	}
1267170530Ssam
1268170530Ssam	/*
1269170530Ssam	 * Now, stick 'em together and prepend the tunnel headers;
1270170530Ssam	 * first the Atheros tunnel header (all zero for now) and
1271170530Ssam	 * then a special fast frame LLC.
1272170530Ssam	 *
1273170530Ssam	 * XXX optimize by prepending together
1274170530Ssam	 */
1275170530Ssam	m->m_next = m2;			/* NB: last mbuf from above */
1276170530Ssam	m1->m_pkthdr.len += m2->m_pkthdr.len;
1277170530Ssam	M_PREPEND(m1, sizeof(uint32_t)+2, M_DONTWAIT);
1278170530Ssam	if (m1 == NULL) {		/* XXX cannot happen */
1279178354Ssam		IEEE80211_DPRINTF(vap, IEEE80211_MSG_SUPERG,
1280170530Ssam			"%s: no space for tunnel header\n", __func__);
1281178354Ssam		vap->iv_stats.is_tx_nobuf++;
1282170530Ssam		return NULL;
1283170530Ssam	}
1284170530Ssam	memset(mtod(m1, void *), 0, sizeof(uint32_t)+2);
1285170530Ssam
1286170530Ssam	M_PREPEND(m1, sizeof(struct llc), M_DONTWAIT);
1287170530Ssam	if (m1 == NULL) {		/* XXX cannot happen */
1288178354Ssam		IEEE80211_DPRINTF(vap, IEEE80211_MSG_SUPERG,
1289170530Ssam			"%s: no space for llc header\n", __func__);
1290178354Ssam		vap->iv_stats.is_tx_nobuf++;
1291170530Ssam		return NULL;
1292170530Ssam	}
1293170530Ssam	llc = mtod(m1, struct llc *);
1294170530Ssam	llc->llc_dsap = llc->llc_ssap = LLC_SNAP_LSAP;
1295170530Ssam	llc->llc_control = LLC_UI;
1296170530Ssam	llc->llc_snap.org_code[0] = ATH_FF_SNAP_ORGCODE_0;
1297170530Ssam	llc->llc_snap.org_code[1] = ATH_FF_SNAP_ORGCODE_1;
1298170530Ssam	llc->llc_snap.org_code[2] = ATH_FF_SNAP_ORGCODE_2;
1299170530Ssam	llc->llc_snap.ether_type = htons(ATH_FF_ETH_TYPE);
1300170530Ssam
1301178354Ssam	vap->iv_stats.is_ff_encap++;
1302170530Ssam
1303170530Ssam	return m1;
1304170530Ssam}
1305170530Ssam
1306170530Ssam/*
1307170530Ssam * Fragment the frame according to the specified mtu.
1308170530Ssam * The size of the 802.11 header (w/o padding) is provided
1309170530Ssam * so we don't need to recalculate it.  We create a new
1310170530Ssam * mbuf for each fragment and chain it through m_nextpkt;
1311170530Ssam * we might be able to optimize this by reusing the original
1312170530Ssam * packet's mbufs but that is significantly more complicated.
1313170530Ssam */
1314170530Ssamstatic int
1315178354Ssamieee80211_fragment(struct ieee80211vap *vap, struct mbuf *m0,
1316170530Ssam	u_int hdrsize, u_int ciphdrsize, u_int mtu)
1317170530Ssam{
1318170530Ssam	struct ieee80211_frame *wh, *whf;
1319170530Ssam	struct mbuf *m, *prev, *next;
1320170530Ssam	u_int totalhdrsize, fragno, fragsize, off, remainder, payload;
1321170530Ssam
1322170530Ssam	KASSERT(m0->m_nextpkt == NULL, ("mbuf already chained?"));
1323170530Ssam	KASSERT(m0->m_pkthdr.len > mtu,
1324170530Ssam		("pktlen %u mtu %u", m0->m_pkthdr.len, mtu));
1325170530Ssam
1326170530Ssam	wh = mtod(m0, struct ieee80211_frame *);
1327170530Ssam	/* NB: mark the first frag; it will be propagated below */
1328170530Ssam	wh->i_fc[1] |= IEEE80211_FC1_MORE_FRAG;
1329170530Ssam	totalhdrsize = hdrsize + ciphdrsize;
1330170530Ssam	fragno = 1;
1331170530Ssam	off = mtu - ciphdrsize;
1332170530Ssam	remainder = m0->m_pkthdr.len - off;
1333170530Ssam	prev = m0;
1334170530Ssam	do {
1335170530Ssam		fragsize = totalhdrsize + remainder;
1336170530Ssam		if (fragsize > mtu)
1337170530Ssam			fragsize = mtu;
1338178354Ssam		/* XXX fragsize can be >2048! */
1339170530Ssam		KASSERT(fragsize < MCLBYTES,
1340170530Ssam			("fragment size %u too big!", fragsize));
1341170530Ssam		if (fragsize > MHLEN)
1342170530Ssam			m = m_getcl(M_DONTWAIT, MT_DATA, M_PKTHDR);
1343170530Ssam		else
1344170530Ssam			m = m_gethdr(M_DONTWAIT, MT_DATA);
1345170530Ssam		if (m == NULL)
1346170530Ssam			goto bad;
1347170530Ssam		/* leave room to prepend any cipher header */
1348170530Ssam		m_align(m, fragsize - ciphdrsize);
1349170530Ssam
1350170530Ssam		/*
1351170530Ssam		 * Form the header in the fragment.  Note that since
1352170530Ssam		 * we mark the first fragment with the MORE_FRAG bit
1353170530Ssam		 * it automatically is propagated to each fragment; we
1354170530Ssam		 * need only clear it on the last fragment (done below).
1355170530Ssam		 */
1356170530Ssam		whf = mtod(m, struct ieee80211_frame *);
1357170530Ssam		memcpy(whf, wh, hdrsize);
1358170530Ssam		*(uint16_t *)&whf->i_seq[0] |= htole16(
1359170530Ssam			(fragno & IEEE80211_SEQ_FRAG_MASK) <<
1360170530Ssam				IEEE80211_SEQ_FRAG_SHIFT);
1361170530Ssam		fragno++;
1362170530Ssam
1363170530Ssam		payload = fragsize - totalhdrsize;
1364170530Ssam		/* NB: destination is known to be contiguous */
1365170530Ssam		m_copydata(m0, off, payload, mtod(m, uint8_t *) + hdrsize);
1366170530Ssam		m->m_len = hdrsize + payload;
1367170530Ssam		m->m_pkthdr.len = hdrsize + payload;
1368170530Ssam		m->m_flags |= M_FRAG;
1369170530Ssam
1370170530Ssam		/* chain up the fragment */
1371170530Ssam		prev->m_nextpkt = m;
1372170530Ssam		prev = m;
1373170530Ssam
1374170530Ssam		/* deduct fragment just formed */
1375170530Ssam		remainder -= payload;
1376170530Ssam		off += payload;
1377170530Ssam	} while (remainder != 0);
1378170530Ssam	whf->i_fc[1] &= ~IEEE80211_FC1_MORE_FRAG;
1379170530Ssam
1380170530Ssam	/* strip first mbuf now that everything has been copied */
1381170530Ssam	m_adj(m0, -(m0->m_pkthdr.len - (mtu - ciphdrsize)));
1382170530Ssam	m0->m_flags |= M_FIRSTFRAG | M_FRAG;
1383170530Ssam
1384178354Ssam	vap->iv_stats.is_tx_fragframes++;
1385178354Ssam	vap->iv_stats.is_tx_frags += fragno-1;
1386170530Ssam
1387170530Ssam	return 1;
1388170530Ssambad:
1389170530Ssam	/* reclaim fragments but leave original frame for caller to free */
1390170530Ssam	for (m = m0->m_nextpkt; m != NULL; m = next) {
1391170530Ssam		next = m->m_nextpkt;
1392170530Ssam		m->m_nextpkt = NULL;		/* XXX paranoid */
1393170530Ssam		m_freem(m);
1394170530Ssam	}
1395170530Ssam	m0->m_nextpkt = NULL;
1396170530Ssam	return 0;
1397170530Ssam}
1398170530Ssam
1399170530Ssam/*
1400116742Ssam * Add a supported rates element id to a frame.
1401116742Ssam */
1402170530Ssamstatic uint8_t *
1403170530Ssamieee80211_add_rates(uint8_t *frm, const struct ieee80211_rateset *rs)
1404116742Ssam{
1405116742Ssam	int nrates;
1406116742Ssam
1407116742Ssam	*frm++ = IEEE80211_ELEMID_RATES;
1408116742Ssam	nrates = rs->rs_nrates;
1409116742Ssam	if (nrates > IEEE80211_RATE_SIZE)
1410116742Ssam		nrates = IEEE80211_RATE_SIZE;
1411116742Ssam	*frm++ = nrates;
1412116742Ssam	memcpy(frm, rs->rs_rates, nrates);
1413116742Ssam	return frm + nrates;
1414116742Ssam}
1415116742Ssam
1416116742Ssam/*
1417116742Ssam * Add an extended supported rates element id to a frame.
1418116742Ssam */
1419170530Ssamstatic uint8_t *
1420170530Ssamieee80211_add_xrates(uint8_t *frm, const struct ieee80211_rateset *rs)
1421116742Ssam{
1422116742Ssam	/*
1423116742Ssam	 * Add an extended supported rates element if operating in 11g mode.
1424116742Ssam	 */
1425116742Ssam	if (rs->rs_nrates > IEEE80211_RATE_SIZE) {
1426116742Ssam		int nrates = rs->rs_nrates - IEEE80211_RATE_SIZE;
1427116742Ssam		*frm++ = IEEE80211_ELEMID_XRATES;
1428116742Ssam		*frm++ = nrates;
1429116742Ssam		memcpy(frm, rs->rs_rates + IEEE80211_RATE_SIZE, nrates);
1430116742Ssam		frm += nrates;
1431116742Ssam	}
1432116742Ssam	return frm;
1433116742Ssam}
1434116742Ssam
1435116742Ssam/*
1436178354Ssam * Add an ssid element to a frame.
1437116742Ssam */
1438170530Ssamstatic uint8_t *
1439170530Ssamieee80211_add_ssid(uint8_t *frm, const uint8_t *ssid, u_int len)
1440116742Ssam{
1441116742Ssam	*frm++ = IEEE80211_ELEMID_SSID;
1442116742Ssam	*frm++ = len;
1443116742Ssam	memcpy(frm, ssid, len);
1444116742Ssam	return frm + len;
1445116742Ssam}
1446116742Ssam
1447138568Ssam/*
1448138568Ssam * Add an erp element to a frame.
1449138568Ssam */
1450170530Ssamstatic uint8_t *
1451170530Ssamieee80211_add_erp(uint8_t *frm, struct ieee80211com *ic)
1452116742Ssam{
1453170530Ssam	uint8_t erp;
1454116742Ssam
1455138568Ssam	*frm++ = IEEE80211_ELEMID_ERP;
1456138568Ssam	*frm++ = 1;
1457138568Ssam	erp = 0;
1458138568Ssam	if (ic->ic_nonerpsta != 0)
1459138568Ssam		erp |= IEEE80211_ERP_NON_ERP_PRESENT;
1460138568Ssam	if (ic->ic_flags & IEEE80211_F_USEPROT)
1461138568Ssam		erp |= IEEE80211_ERP_USE_PROTECTION;
1462138568Ssam	if (ic->ic_flags & IEEE80211_F_USEBARKER)
1463138568Ssam		erp |= IEEE80211_ERP_LONG_PREAMBLE;
1464138568Ssam	*frm++ = erp;
1465138568Ssam	return frm;
1466138568Ssam}
1467138568Ssam
1468178354Ssam/*
1469178354Ssam * Add a CFParams element to a frame.
1470178354Ssam */
1471170530Ssamstatic uint8_t *
1472178354Ssamieee80211_add_cfparms(uint8_t *frm, struct ieee80211com *ic)
1473138568Ssam{
1474138568Ssam#define	ADDSHORT(frm, v) do {			\
1475138568Ssam	frm[0] = (v) & 0xff;			\
1476138568Ssam	frm[1] = (v) >> 8;			\
1477138568Ssam	frm += 2;				\
1478138568Ssam} while (0)
1479178354Ssam	*frm++ = IEEE80211_ELEMID_CFPARMS;
1480178354Ssam	*frm++ = 6;
1481178354Ssam	*frm++ = 0;		/* CFP count */
1482178354Ssam	*frm++ = 2;		/* CFP period */
1483178354Ssam	ADDSHORT(frm, 0);	/* CFP MaxDuration (TU) */
1484178354Ssam	ADDSHORT(frm, 0);	/* CFP CurRemaining (TU) */
1485138568Ssam	return frm;
1486138568Ssam#undef ADDSHORT
1487116742Ssam}
1488116742Ssam
1489178354Ssamstatic __inline uint8_t *
1490178354Ssamadd_appie(uint8_t *frm, const struct ieee80211_appie *ie)
1491138568Ssam{
1492178354Ssam	memcpy(frm, ie->ie_data, ie->ie_len);
1493178354Ssam	return frm + ie->ie_len;
1494138568Ssam}
1495138568Ssam
1496178354Ssamstatic __inline uint8_t *
1497178354Ssamadd_ie(uint8_t *frm, const uint8_t *ie)
1498138568Ssam{
1499178354Ssam	memcpy(frm, ie, 2 + ie[1]);
1500178354Ssam	return frm + 2 + ie[1];
1501138568Ssam}
1502138568Ssam
1503138568Ssam#define	WME_OUI_BYTES		0x00, 0x50, 0xf2
1504138568Ssam/*
1505138568Ssam * Add a WME information element to a frame.
1506138568Ssam */
1507170530Ssamstatic uint8_t *
1508170530Ssamieee80211_add_wme_info(uint8_t *frm, struct ieee80211_wme_state *wme)
1509138568Ssam{
1510138568Ssam	static const struct ieee80211_wme_info info = {
1511138568Ssam		.wme_id		= IEEE80211_ELEMID_VENDOR,
1512138568Ssam		.wme_len	= sizeof(struct ieee80211_wme_info) - 2,
1513138568Ssam		.wme_oui	= { WME_OUI_BYTES },
1514138568Ssam		.wme_type	= WME_OUI_TYPE,
1515138568Ssam		.wme_subtype	= WME_INFO_OUI_SUBTYPE,
1516138568Ssam		.wme_version	= WME_VERSION,
1517138568Ssam		.wme_info	= 0,
1518138568Ssam	};
1519138568Ssam	memcpy(frm, &info, sizeof(info));
1520138568Ssam	return frm + sizeof(info);
1521138568Ssam}
1522138568Ssam
1523138568Ssam/*
1524138568Ssam * Add a WME parameters element to a frame.
1525138568Ssam */
1526170530Ssamstatic uint8_t *
1527170530Ssamieee80211_add_wme_param(uint8_t *frm, struct ieee80211_wme_state *wme)
1528138568Ssam{
1529138568Ssam#define	SM(_v, _f)	(((_v) << _f##_S) & _f)
1530138568Ssam#define	ADDSHORT(frm, v) do {			\
1531138568Ssam	frm[0] = (v) & 0xff;			\
1532138568Ssam	frm[1] = (v) >> 8;			\
1533138568Ssam	frm += 2;				\
1534138568Ssam} while (0)
1535138568Ssam	/* NB: this works 'cuz a param has an info at the front */
1536138568Ssam	static const struct ieee80211_wme_info param = {
1537138568Ssam		.wme_id		= IEEE80211_ELEMID_VENDOR,
1538138568Ssam		.wme_len	= sizeof(struct ieee80211_wme_param) - 2,
1539138568Ssam		.wme_oui	= { WME_OUI_BYTES },
1540138568Ssam		.wme_type	= WME_OUI_TYPE,
1541138568Ssam		.wme_subtype	= WME_PARAM_OUI_SUBTYPE,
1542138568Ssam		.wme_version	= WME_VERSION,
1543138568Ssam	};
1544138568Ssam	int i;
1545138568Ssam
1546138568Ssam	memcpy(frm, &param, sizeof(param));
1547138568Ssam	frm += __offsetof(struct ieee80211_wme_info, wme_info);
1548138568Ssam	*frm++ = wme->wme_bssChanParams.cap_info;	/* AC info */
1549138568Ssam	*frm++ = 0;					/* reserved field */
1550138568Ssam	for (i = 0; i < WME_NUM_AC; i++) {
1551138568Ssam		const struct wmeParams *ac =
1552138568Ssam		       &wme->wme_bssChanParams.cap_wmeParams[i];
1553138568Ssam		*frm++ = SM(i, WME_PARAM_ACI)
1554138568Ssam		       | SM(ac->wmep_acm, WME_PARAM_ACM)
1555138568Ssam		       | SM(ac->wmep_aifsn, WME_PARAM_AIFSN)
1556138568Ssam		       ;
1557138568Ssam		*frm++ = SM(ac->wmep_logcwmax, WME_PARAM_LOGCWMAX)
1558138568Ssam		       | SM(ac->wmep_logcwmin, WME_PARAM_LOGCWMIN)
1559138568Ssam		       ;
1560138568Ssam		ADDSHORT(frm, ac->wmep_txopLimit);
1561138568Ssam	}
1562138568Ssam	return frm;
1563138568Ssam#undef SM
1564138568Ssam#undef ADDSHORT
1565138568Ssam}
1566138568Ssam#undef WME_OUI_BYTES
1567138568Ssam
1568170530Ssam#define	ATH_OUI_BYTES		0x00, 0x03, 0x7f
1569138568Ssam/*
1570170530Ssam * Add a WME information element to a frame.
1571170530Ssam */
1572170530Ssamstatic uint8_t *
1573170530Ssamieee80211_add_ath(uint8_t *frm, uint8_t caps, uint16_t defkeyix)
1574170530Ssam{
1575170530Ssam	static const struct ieee80211_ath_ie info = {
1576170530Ssam		.ath_id		= IEEE80211_ELEMID_VENDOR,
1577170530Ssam		.ath_len	= sizeof(struct ieee80211_ath_ie) - 2,
1578170530Ssam		.ath_oui	= { ATH_OUI_BYTES },
1579170530Ssam		.ath_oui_type	= ATH_OUI_TYPE,
1580170530Ssam		.ath_oui_subtype= ATH_OUI_SUBTYPE,
1581170530Ssam		.ath_version	= ATH_OUI_VERSION,
1582170530Ssam	};
1583170530Ssam	struct ieee80211_ath_ie *ath = (struct ieee80211_ath_ie *) frm;
1584170530Ssam
1585170530Ssam	memcpy(frm, &info, sizeof(info));
1586170530Ssam	ath->ath_capability = caps;
1587170530Ssam	ath->ath_defkeyix[0] = (defkeyix & 0xff);
1588170530Ssam	ath->ath_defkeyix[1] = ((defkeyix >> 8) & 0xff);
1589170530Ssam	return frm + sizeof(info);
1590170530Ssam}
1591170530Ssam#undef ATH_OUI_BYTES
1592170530Ssam
1593170530Ssam/*
1594178354Ssam * Add an 11h Power Constraint element to a frame.
1595178354Ssam */
1596178354Ssamstatic uint8_t *
1597178354Ssamieee80211_add_powerconstraint(uint8_t *frm, struct ieee80211vap *vap)
1598178354Ssam{
1599178354Ssam	const struct ieee80211_channel *c = vap->iv_bss->ni_chan;
1600178354Ssam	/* XXX per-vap tx power limit? */
1601178354Ssam	int8_t limit = vap->iv_ic->ic_txpowlimit / 2;
1602178354Ssam
1603178354Ssam	frm[0] = IEEE80211_ELEMID_PWRCNSTR;
1604178354Ssam	frm[1] = 1;
1605178354Ssam	frm[2] = c->ic_maxregpower > limit ?  c->ic_maxregpower - limit : 0;
1606178354Ssam	return frm + 3;
1607178354Ssam}
1608178354Ssam
1609178354Ssam/*
1610178354Ssam * Add an 11h Power Capability element to a frame.
1611178354Ssam */
1612178354Ssamstatic uint8_t *
1613178354Ssamieee80211_add_powercapability(uint8_t *frm, const struct ieee80211_channel *c)
1614178354Ssam{
1615178354Ssam	frm[0] = IEEE80211_ELEMID_PWRCAP;
1616178354Ssam	frm[1] = 2;
1617178354Ssam	frm[2] = c->ic_minpower;
1618178354Ssam	frm[3] = c->ic_maxpower;
1619178354Ssam	return frm + 4;
1620178354Ssam}
1621178354Ssam
1622178354Ssam/*
1623178354Ssam * Add an 11h Supported Channels element to a frame.
1624178354Ssam */
1625178354Ssamstatic uint8_t *
1626178354Ssamieee80211_add_supportedchannels(uint8_t *frm, struct ieee80211com *ic)
1627178354Ssam{
1628178354Ssam	static const int ielen = 26;
1629178354Ssam
1630178354Ssam	frm[0] = IEEE80211_ELEMID_SUPPCHAN;
1631178354Ssam	frm[1] = ielen;
1632178354Ssam	/* XXX not correct */
1633178354Ssam	memcpy(frm+2, ic->ic_chan_avail, ielen);
1634178354Ssam	return frm + 2 + ielen;
1635178354Ssam}
1636178354Ssam
1637178354Ssam/*
1638178354Ssam * Add an 11h Channel Switch Announcement element to a frame.
1639178354Ssam * Note that we use the per-vap CSA count to adjust the global
1640178354Ssam * counter so we can use this routine to form probe response
1641178354Ssam * frames and get the current count.
1642178354Ssam */
1643178354Ssamstatic uint8_t *
1644178354Ssamieee80211_add_csa(uint8_t *frm, struct ieee80211vap *vap)
1645178354Ssam{
1646178354Ssam	struct ieee80211com *ic = vap->iv_ic;
1647178354Ssam	struct ieee80211_csa_ie *csa = (struct ieee80211_csa_ie *) frm;
1648178354Ssam
1649178354Ssam	csa->csa_ie = IEEE80211_ELEMID_CHANSWITCHANN;
1650178354Ssam	csa->csa_len = 3;
1651178354Ssam	csa->csa_mode = 1;		/* XXX force quiet on channel */
1652178354Ssam	csa->csa_newchan = ieee80211_chan2ieee(ic, ic->ic_csa_newchan);
1653178354Ssam	csa->csa_count = ic->ic_csa_count - vap->iv_csa_count;
1654178354Ssam	return frm + sizeof(*csa);
1655178354Ssam}
1656178354Ssam
1657178354Ssam/*
1658178354Ssam * Add an 11h country information element to a frame.
1659178354Ssam */
1660178354Ssamstatic uint8_t *
1661178354Ssamieee80211_add_countryie(uint8_t *frm, struct ieee80211com *ic)
1662178354Ssam{
1663178354Ssam
1664178354Ssam	if (ic->ic_countryie == NULL ||
1665178354Ssam	    ic->ic_countryie_chan != ic->ic_bsschan) {
1666178354Ssam		/*
1667178354Ssam		 * Handle lazy construction of ie.  This is done on
1668178354Ssam		 * first use and after a channel change that requires
1669178354Ssam		 * re-calculation.
1670178354Ssam		 */
1671178354Ssam		if (ic->ic_countryie != NULL)
1672178354Ssam			free(ic->ic_countryie, M_80211_NODE_IE);
1673178354Ssam		ic->ic_countryie = ieee80211_alloc_countryie(ic);
1674178354Ssam		if (ic->ic_countryie == NULL)
1675178354Ssam			return frm;
1676178354Ssam		ic->ic_countryie_chan = ic->ic_bsschan;
1677178354Ssam	}
1678178354Ssam	return add_appie(frm, ic->ic_countryie);
1679178354Ssam}
1680178354Ssam
1681178354Ssam/*
1682148315Ssam * Send a probe request frame with the specified ssid
1683148315Ssam * and any optional information element data.
1684148315Ssam */
1685148315Ssamint
1686148315Ssamieee80211_send_probereq(struct ieee80211_node *ni,
1687170530Ssam	const uint8_t sa[IEEE80211_ADDR_LEN],
1688170530Ssam	const uint8_t da[IEEE80211_ADDR_LEN],
1689170530Ssam	const uint8_t bssid[IEEE80211_ADDR_LEN],
1690178354Ssam	const uint8_t *ssid, size_t ssidlen)
1691148315Ssam{
1692178354Ssam	struct ieee80211vap *vap = ni->ni_vap;
1693148315Ssam	struct ieee80211com *ic = ni->ni_ic;
1694184284Ssam	const struct ieee80211_txparam *tp;
1695184284Ssam	struct ieee80211_bpf_params params;
1696148315Ssam	struct ieee80211_frame *wh;
1697165569Ssam	const struct ieee80211_rateset *rs;
1698148315Ssam	struct mbuf *m;
1699170530Ssam	uint8_t *frm;
1700148315Ssam
1701178354Ssam	if (vap->iv_state == IEEE80211_S_CAC) {
1702178354Ssam		IEEE80211_NOTE(vap, IEEE80211_MSG_OUTPUT, ni,
1703178354Ssam		    "block %s frame in CAC state", "probe request");
1704178354Ssam		vap->iv_stats.is_tx_badstate++;
1705178354Ssam		return EIO;		/* XXX */
1706178354Ssam	}
1707178354Ssam
1708148315Ssam	/*
1709148315Ssam	 * Hold a reference on the node so it doesn't go away until after
1710148315Ssam	 * the xmit is complete all the way in the driver.  On error we
1711148315Ssam	 * will remove our reference.
1712148315Ssam	 */
1713178354Ssam	IEEE80211_DPRINTF(vap, IEEE80211_MSG_NODE,
1714148315Ssam		"ieee80211_ref_node (%s:%u) %p<%s> refcnt %d\n",
1715148315Ssam		__func__, __LINE__,
1716148315Ssam		ni, ether_sprintf(ni->ni_macaddr),
1717148315Ssam		ieee80211_node_refcnt(ni)+1);
1718148315Ssam	ieee80211_ref_node(ni);
1719148315Ssam
1720148315Ssam	/*
1721148315Ssam	 * prreq frame format
1722148315Ssam	 *	[tlv] ssid
1723148315Ssam	 *	[tlv] supported rates
1724178354Ssam	 *	[tlv] RSN (optional)
1725148315Ssam	 *	[tlv] extended supported rates
1726178354Ssam	 *	[tlv] WPA (optional)
1727148315Ssam	 *	[tlv] user-specified ie's
1728148315Ssam	 */
1729148315Ssam	m = ieee80211_getmgtframe(&frm,
1730170530Ssam		 ic->ic_headroom + sizeof(struct ieee80211_frame),
1731178354Ssam	       	 2 + IEEE80211_NWID_LEN
1732148315Ssam	       + 2 + IEEE80211_RATE_SIZE
1733178354Ssam	       + sizeof(struct ieee80211_ie_wpa)
1734148315Ssam	       + 2 + (IEEE80211_RATE_MAXSIZE - IEEE80211_RATE_SIZE)
1735178354Ssam	       + sizeof(struct ieee80211_ie_wpa)
1736178354Ssam	       + (vap->iv_appie_probereq != NULL ?
1737178354Ssam		   vap->iv_appie_probereq->ie_len : 0)
1738148315Ssam	);
1739148315Ssam	if (m == NULL) {
1740178354Ssam		vap->iv_stats.is_tx_nobuf++;
1741148315Ssam		ieee80211_free_node(ni);
1742148315Ssam		return ENOMEM;
1743148315Ssam	}
1744148315Ssam
1745148315Ssam	frm = ieee80211_add_ssid(frm, ssid, ssidlen);
1746165569Ssam	rs = ieee80211_get_suprates(ic, ic->ic_curchan);
1747165569Ssam	frm = ieee80211_add_rates(frm, rs);
1748178354Ssam	if (vap->iv_flags & IEEE80211_F_WPA2) {
1749178354Ssam		if (vap->iv_rsn_ie != NULL)
1750178354Ssam			frm = add_ie(frm, vap->iv_rsn_ie);
1751178354Ssam		/* XXX else complain? */
1752178354Ssam	}
1753165569Ssam	frm = ieee80211_add_xrates(frm, rs);
1754178354Ssam	if (vap->iv_flags & IEEE80211_F_WPA1) {
1755178354Ssam		if (vap->iv_wpa_ie != NULL)
1756178354Ssam			frm = add_ie(frm, vap->iv_wpa_ie);
1757178354Ssam		/* XXX else complain? */
1758148315Ssam	}
1759178354Ssam	if (vap->iv_appie_probereq != NULL)
1760178354Ssam		frm = add_appie(frm, vap->iv_appie_probereq);
1761170530Ssam	m->m_pkthdr.len = m->m_len = frm - mtod(m, uint8_t *);
1762148315Ssam
1763184284Ssam	KASSERT(M_LEADINGSPACE(m) >= sizeof(struct ieee80211_frame),
1764184284Ssam	    ("leading space %zd", M_LEADINGSPACE(m)));
1765148315Ssam	M_PREPEND(m, sizeof(struct ieee80211_frame), M_DONTWAIT);
1766184284Ssam	if (m == NULL) {
1767184284Ssam		/* NB: cannot happen */
1768184284Ssam		ieee80211_free_node(ni);
1769148315Ssam		return ENOMEM;
1770184284Ssam	}
1771148315Ssam
1772148315Ssam	wh = mtod(m, struct ieee80211_frame *);
1773178354Ssam	ieee80211_send_setup(ni, wh,
1774184282Ssam	     IEEE80211_FC0_TYPE_MGT | IEEE80211_FC0_SUBTYPE_PROBE_REQ,
1775184282Ssam	     IEEE80211_NONQOS_TID, sa, da, bssid);
1776148315Ssam	/* XXX power management? */
1777184286Ssam	m->m_flags |= M_ENCAP;		/* mark encapsulated */
1778148315Ssam
1779178354Ssam	M_WME_SETAC(m, WME_AC_BE);
1780178354Ssam
1781148315Ssam	IEEE80211_NODE_STAT(ni, tx_probereq);
1782148315Ssam	IEEE80211_NODE_STAT(ni, tx_mgmt);
1783148315Ssam
1784178354Ssam	IEEE80211_DPRINTF(vap, IEEE80211_MSG_DEBUG | IEEE80211_MSG_DUMPPKTS,
1785178354Ssam	    "send probe req on channel %u bssid %s ssid \"%.*s\"\n",
1786178354Ssam	    ieee80211_chan2ieee(ic, ic->ic_curchan), ether_sprintf(bssid),
1787178354Ssam	    ssidlen, ssid);
1788148315Ssam
1789184284Ssam	memset(&params, 0, sizeof(params));
1790184284Ssam	params.ibp_pri = M_WME_GETAC(m);
1791184284Ssam	tp = &vap->iv_txparms[ieee80211_chan2mode(ic->ic_curchan)];
1792184284Ssam	params.ibp_rate0 = tp->mgmtrate;
1793184284Ssam	if (IEEE80211_IS_MULTICAST(da)) {
1794184284Ssam		params.ibp_flags |= IEEE80211_BPF_NOACK;
1795184284Ssam		params.ibp_try0 = 1;
1796184284Ssam	} else
1797184284Ssam		params.ibp_try0 = tp->maxretry;
1798184284Ssam	params.ibp_power = ni->ni_txpower;
1799184284Ssam	return ic->ic_raw_xmit(ni, m, &params);
1800148315Ssam}
1801148315Ssam
1802148315Ssam/*
1803155999Ssam * Calculate capability information for mgt frames.
1804155999Ssam */
1805170530Ssamstatic uint16_t
1806178354Ssamgetcapinfo(struct ieee80211vap *vap, struct ieee80211_channel *chan)
1807155999Ssam{
1808178354Ssam	struct ieee80211com *ic = vap->iv_ic;
1809170530Ssam	uint16_t capinfo;
1810155999Ssam
1811178354Ssam	KASSERT(vap->iv_opmode != IEEE80211_M_STA, ("station mode"));
1812155999Ssam
1813178354Ssam	if (vap->iv_opmode == IEEE80211_M_HOSTAP)
1814155999Ssam		capinfo = IEEE80211_CAPINFO_ESS;
1815178354Ssam	else if (vap->iv_opmode == IEEE80211_M_IBSS)
1816155999Ssam		capinfo = IEEE80211_CAPINFO_IBSS;
1817155999Ssam	else
1818155999Ssam		capinfo = 0;
1819178354Ssam	if (vap->iv_flags & IEEE80211_F_PRIVACY)
1820155999Ssam		capinfo |= IEEE80211_CAPINFO_PRIVACY;
1821155999Ssam	if ((ic->ic_flags & IEEE80211_F_SHPREAMBLE) &&
1822155999Ssam	    IEEE80211_IS_CHAN_2GHZ(chan))
1823155999Ssam		capinfo |= IEEE80211_CAPINFO_SHORT_PREAMBLE;
1824155999Ssam	if (ic->ic_flags & IEEE80211_F_SHSLOT)
1825155999Ssam		capinfo |= IEEE80211_CAPINFO_SHORT_SLOTTIME;
1826178354Ssam	if (IEEE80211_IS_CHAN_5GHZ(chan) && (vap->iv_flags & IEEE80211_F_DOTH))
1827178354Ssam		capinfo |= IEEE80211_CAPINFO_SPECTRUM_MGMT;
1828155999Ssam	return capinfo;
1829155999Ssam}
1830155999Ssam
1831155999Ssam/*
1832119150Ssam * Send a management frame.  The node is for the destination (or ic_bss
1833119150Ssam * when in station mode).  Nodes other than ic_bss have their reference
1834119150Ssam * count bumped to reflect our use for an indeterminant time.
1835119150Ssam */
1836116742Ssamint
1837178354Ssamieee80211_send_mgmt(struct ieee80211_node *ni, int type, int arg)
1838116742Ssam{
1839173273Ssam#define	HTFLAGS (IEEE80211_NODE_HT | IEEE80211_NODE_HTCOMPAT)
1840178354Ssam#define	senderr(_x, _v)	do { vap->iv_stats._v++; ret = _x; goto bad; } while (0)
1841178354Ssam	struct ieee80211vap *vap = ni->ni_vap;
1842178354Ssam	struct ieee80211com *ic = ni->ni_ic;
1843178354Ssam	struct ieee80211_node *bss = vap->iv_bss;
1844184282Ssam	struct ieee80211_bpf_params params;
1845116742Ssam	struct mbuf *m;
1846170530Ssam	uint8_t *frm;
1847170530Ssam	uint16_t capinfo;
1848170530Ssam	int has_challenge, is_shared_key, ret, status;
1849116742Ssam
1850119150Ssam	KASSERT(ni != NULL, ("null node"));
1851119150Ssam
1852119150Ssam	/*
1853119150Ssam	 * Hold a reference on the node so it doesn't go away until after
1854119150Ssam	 * the xmit is complete all the way in the driver.  On error we
1855119150Ssam	 * will remove our reference.
1856119150Ssam	 */
1857178354Ssam	IEEE80211_DPRINTF(vap, IEEE80211_MSG_NODE,
1858140766Ssam		"ieee80211_ref_node (%s:%u) %p<%s> refcnt %d\n",
1859138568Ssam		__func__, __LINE__,
1860140766Ssam		ni, ether_sprintf(ni->ni_macaddr),
1861140766Ssam		ieee80211_node_refcnt(ni)+1);
1862138568Ssam	ieee80211_ref_node(ni);
1863138568Ssam
1864184282Ssam	memset(&params, 0, sizeof(params));
1865116742Ssam	switch (type) {
1866116742Ssam
1867116742Ssam	case IEEE80211_FC0_SUBTYPE_AUTH:
1868138568Ssam		status = arg >> 16;
1869138568Ssam		arg &= 0xffff;
1870138568Ssam		has_challenge = ((arg == IEEE80211_AUTH_SHARED_CHALLENGE ||
1871138568Ssam		    arg == IEEE80211_AUTH_SHARED_RESPONSE) &&
1872138568Ssam		    ni->ni_challenge != NULL);
1873138568Ssam
1874138568Ssam		/*
1875138568Ssam		 * Deduce whether we're doing open authentication or
1876138568Ssam		 * shared key authentication.  We do the latter if
1877138568Ssam		 * we're in the middle of a shared key authentication
1878138568Ssam		 * handshake or if we're initiating an authentication
1879138568Ssam		 * request and configured to use shared key.
1880138568Ssam		 */
1881138568Ssam		is_shared_key = has_challenge ||
1882138568Ssam		     arg >= IEEE80211_AUTH_SHARED_RESPONSE ||
1883138568Ssam		     (arg == IEEE80211_AUTH_SHARED_REQUEST &&
1884178354Ssam		      bss->ni_authmode == IEEE80211_AUTH_SHARED);
1885138568Ssam
1886138568Ssam		m = ieee80211_getmgtframe(&frm,
1887184282Ssam			  ic->ic_headroom + sizeof(struct ieee80211_frame),
1888170530Ssam			  3 * sizeof(uint16_t)
1889138568Ssam			+ (has_challenge && status == IEEE80211_STATUS_SUCCESS ?
1890170530Ssam				sizeof(uint16_t)+IEEE80211_CHALLENGE_LEN : 0)
1891138568Ssam		);
1892116742Ssam		if (m == NULL)
1893138568Ssam			senderr(ENOMEM, is_tx_nobuf);
1894138568Ssam
1895170530Ssam		((uint16_t *)frm)[0] =
1896138568Ssam		    (is_shared_key) ? htole16(IEEE80211_AUTH_ALG_SHARED)
1897138568Ssam		                    : htole16(IEEE80211_AUTH_ALG_OPEN);
1898170530Ssam		((uint16_t *)frm)[1] = htole16(arg);	/* sequence number */
1899170530Ssam		((uint16_t *)frm)[2] = htole16(status);/* status */
1900138568Ssam
1901138568Ssam		if (has_challenge && status == IEEE80211_STATUS_SUCCESS) {
1902170530Ssam			((uint16_t *)frm)[3] =
1903138568Ssam			    htole16((IEEE80211_CHALLENGE_LEN << 8) |
1904138568Ssam			    IEEE80211_ELEMID_CHALLENGE);
1905170530Ssam			memcpy(&((uint16_t *)frm)[4], ni->ni_challenge,
1906138568Ssam			    IEEE80211_CHALLENGE_LEN);
1907138568Ssam			m->m_pkthdr.len = m->m_len =
1908170530Ssam				4 * sizeof(uint16_t) + IEEE80211_CHALLENGE_LEN;
1909138568Ssam			if (arg == IEEE80211_AUTH_SHARED_RESPONSE) {
1910178354Ssam				IEEE80211_NOTE(vap, IEEE80211_MSG_AUTH, ni,
1911178354Ssam				    "request encrypt frame (%s)", __func__);
1912184282Ssam				/* mark frame for encryption */
1913184282Ssam				params.ibp_flags |= IEEE80211_BPF_CRYPTO;
1914138568Ssam			}
1915138568Ssam		} else
1916170530Ssam			m->m_pkthdr.len = m->m_len = 3 * sizeof(uint16_t);
1917138568Ssam
1918138568Ssam		/* XXX not right for shared key */
1919138568Ssam		if (status == IEEE80211_STATUS_SUCCESS)
1920138568Ssam			IEEE80211_NODE_STAT(ni, tx_auth);
1921138568Ssam		else
1922138568Ssam			IEEE80211_NODE_STAT(ni, tx_auth_fail);
1923138568Ssam
1924178354Ssam		if (vap->iv_opmode == IEEE80211_M_STA)
1925170530Ssam			ieee80211_add_callback(m, ieee80211_tx_mgt_cb,
1926178354Ssam				(void *) vap->iv_state);
1927116742Ssam		break;
1928116742Ssam
1929116742Ssam	case IEEE80211_FC0_SUBTYPE_DEAUTH:
1930178354Ssam		IEEE80211_NOTE(vap, IEEE80211_MSG_AUTH, ni,
1931178354Ssam		    "send station deauthenticate (reason %d)", arg);
1932170530Ssam		m = ieee80211_getmgtframe(&frm,
1933170530Ssam			ic->ic_headroom + sizeof(struct ieee80211_frame),
1934170530Ssam			sizeof(uint16_t));
1935116742Ssam		if (m == NULL)
1936138568Ssam			senderr(ENOMEM, is_tx_nobuf);
1937170530Ssam		*(uint16_t *)frm = htole16(arg);	/* reason */
1938170530Ssam		m->m_pkthdr.len = m->m_len = sizeof(uint16_t);
1939138568Ssam
1940138568Ssam		IEEE80211_NODE_STAT(ni, tx_deauth);
1941138568Ssam		IEEE80211_NODE_STAT_SET(ni, tx_deauth_code, arg);
1942138568Ssam
1943148302Ssam		ieee80211_node_unauthorize(ni);		/* port closed */
1944116742Ssam		break;
1945116742Ssam
1946116742Ssam	case IEEE80211_FC0_SUBTYPE_ASSOC_REQ:
1947116742Ssam	case IEEE80211_FC0_SUBTYPE_REASSOC_REQ:
1948116742Ssam		/*
1949116742Ssam		 * asreq frame format
1950116742Ssam		 *	[2] capability information
1951116742Ssam		 *	[2] listen interval
1952116742Ssam		 *	[6*] current AP address (reassoc only)
1953116742Ssam		 *	[tlv] ssid
1954116742Ssam		 *	[tlv] supported rates
1955116742Ssam		 *	[tlv] extended supported rates
1956178354Ssam		 *	[4] power capability (optional)
1957178354Ssam		 *	[28] supported channels (optional)
1958170530Ssam		 *	[tlv] HT capabilities
1959178354Ssam		 *	[tlv] WME (optional)
1960170530Ssam		 *	[tlv] Vendor OUI HT capabilities (optional)
1961170530Ssam		 *	[tlv] Atheros capabilities (if negotiated)
1962178354Ssam		 *	[tlv] AppIE's (optional)
1963116742Ssam		 */
1964138568Ssam		m = ieee80211_getmgtframe(&frm,
1965170530Ssam			 ic->ic_headroom + sizeof(struct ieee80211_frame),
1966170530Ssam			 sizeof(uint16_t)
1967170530Ssam		       + sizeof(uint16_t)
1968116742Ssam		       + IEEE80211_ADDR_LEN
1969138568Ssam		       + 2 + IEEE80211_NWID_LEN
1970116742Ssam		       + 2 + IEEE80211_RATE_SIZE
1971138568Ssam		       + 2 + (IEEE80211_RATE_MAXSIZE - IEEE80211_RATE_SIZE)
1972178354Ssam		       + 4
1973178354Ssam		       + 2 + 26
1974138568Ssam		       + sizeof(struct ieee80211_wme_info)
1975178354Ssam		       + sizeof(struct ieee80211_ie_htcap)
1976178354Ssam		       + 4 + sizeof(struct ieee80211_ie_htcap)
1977170530Ssam		       + sizeof(struct ieee80211_ath_ie)
1978178354Ssam		       + (vap->iv_appie_wpa != NULL ?
1979178354Ssam				vap->iv_appie_wpa->ie_len : 0)
1980178354Ssam		       + (vap->iv_appie_assocreq != NULL ?
1981178354Ssam				vap->iv_appie_assocreq->ie_len : 0)
1982138568Ssam		);
1983116742Ssam		if (m == NULL)
1984138568Ssam			senderr(ENOMEM, is_tx_nobuf);
1985116742Ssam
1986178354Ssam		KASSERT(vap->iv_opmode == IEEE80211_M_STA,
1987178354Ssam		    ("wrong mode %u", vap->iv_opmode));
1988155999Ssam		capinfo = IEEE80211_CAPINFO_ESS;
1989178354Ssam		if (vap->iv_flags & IEEE80211_F_PRIVACY)
1990116742Ssam			capinfo |= IEEE80211_CAPINFO_PRIVACY;
1991120070Ssam		/*
1992120070Ssam		 * NB: Some 11a AP's reject the request when
1993120070Ssam		 *     short premable is set.
1994120070Ssam		 */
1995120070Ssam		if ((ic->ic_flags & IEEE80211_F_SHPREAMBLE) &&
1996148936Ssam		    IEEE80211_IS_CHAN_2GHZ(ic->ic_curchan))
1997116742Ssam			capinfo |= IEEE80211_CAPINFO_SHORT_PREAMBLE;
1998170530Ssam		if (IEEE80211_IS_CHAN_ANYG(ic->ic_curchan) &&
1999138568Ssam		    (ic->ic_caps & IEEE80211_C_SHSLOT))
2000116742Ssam			capinfo |= IEEE80211_CAPINFO_SHORT_SLOTTIME;
2001173273Ssam		if ((ni->ni_capinfo & IEEE80211_CAPINFO_SPECTRUM_MGMT) &&
2002178354Ssam		    (vap->iv_flags & IEEE80211_F_DOTH))
2003173273Ssam			capinfo |= IEEE80211_CAPINFO_SPECTRUM_MGMT;
2004170530Ssam		*(uint16_t *)frm = htole16(capinfo);
2005116742Ssam		frm += 2;
2006116742Ssam
2007178354Ssam		KASSERT(bss->ni_intval != 0, ("beacon interval is zero!"));
2008170530Ssam		*(uint16_t *)frm = htole16(howmany(ic->ic_lintval,
2009178354Ssam						    bss->ni_intval));
2010116742Ssam		frm += 2;
2011116742Ssam
2012116742Ssam		if (type == IEEE80211_FC0_SUBTYPE_REASSOC_REQ) {
2013178354Ssam			IEEE80211_ADDR_COPY(frm, bss->ni_bssid);
2014116742Ssam			frm += IEEE80211_ADDR_LEN;
2015116742Ssam		}
2016116742Ssam
2017116742Ssam		frm = ieee80211_add_ssid(frm, ni->ni_essid, ni->ni_esslen);
2018116742Ssam		frm = ieee80211_add_rates(frm, &ni->ni_rates);
2019178354Ssam		if (vap->iv_flags & IEEE80211_F_WPA2) {
2020178354Ssam			if (vap->iv_rsn_ie != NULL)
2021178354Ssam				frm = add_ie(frm, vap->iv_rsn_ie);
2022178354Ssam			/* XXX else complain? */
2023178354Ssam		}
2024116742Ssam		frm = ieee80211_add_xrates(frm, &ni->ni_rates);
2025178354Ssam		if (capinfo & IEEE80211_CAPINFO_SPECTRUM_MGMT) {
2026178354Ssam			frm = ieee80211_add_powercapability(frm,
2027178354Ssam			    ic->ic_curchan);
2028178354Ssam			frm = ieee80211_add_supportedchannels(frm, ic);
2029178354Ssam		}
2030178354Ssam		if ((vap->iv_flags_ext & IEEE80211_FEXT_HT) &&
2031178354Ssam		    ni->ni_ies.htcap_ie != NULL &&
2032178354Ssam		    ni->ni_ies.htcap_ie[0] == IEEE80211_ELEMID_HTCAP)
2033173273Ssam			frm = ieee80211_add_htcap(frm, ni);
2034178354Ssam		if (vap->iv_flags & IEEE80211_F_WPA1) {
2035178354Ssam			if (vap->iv_wpa_ie != NULL)
2036178354Ssam				frm = add_ie(frm, vap->iv_wpa_ie);
2037178354Ssam			/* XXX else complain */
2038178354Ssam		}
2039178354Ssam		if ((ic->ic_flags & IEEE80211_F_WME) &&
2040178354Ssam		    ni->ni_ies.wme_ie != NULL)
2041138568Ssam			frm = ieee80211_add_wme_info(frm, &ic->ic_wme);
2042178354Ssam		if ((vap->iv_flags_ext & IEEE80211_FEXT_HT) &&
2043178354Ssam		    ni->ni_ies.htcap_ie != NULL &&
2044178354Ssam		    ni->ni_ies.htcap_ie[0] == IEEE80211_ELEMID_VENDOR)
2045173273Ssam			frm = ieee80211_add_htcap_vendor(frm, ni);
2046178354Ssam		if (IEEE80211_ATH_CAP(vap, ni, IEEE80211_F_ATHEROS))
2047170530Ssam			frm = ieee80211_add_ath(frm,
2048178354Ssam				IEEE80211_ATH_CAP(vap, ni, IEEE80211_F_ATHEROS),
2049178354Ssam				(vap->iv_flags & IEEE80211_F_WPA) == 0 &&
2050170530Ssam				ni->ni_authmode != IEEE80211_AUTH_8021X &&
2051178354Ssam				vap->iv_def_txkey != IEEE80211_KEYIX_NONE ?
2052178354Ssam				vap->iv_def_txkey : 0x7fff);
2053178354Ssam		if (vap->iv_appie_assocreq != NULL)
2054178354Ssam			frm = add_appie(frm, vap->iv_appie_assocreq);
2055170530Ssam		m->m_pkthdr.len = m->m_len = frm - mtod(m, uint8_t *);
2056116742Ssam
2057170530Ssam		ieee80211_add_callback(m, ieee80211_tx_mgt_cb,
2058178354Ssam			(void *) vap->iv_state);
2059116742Ssam		break;
2060116742Ssam
2061116742Ssam	case IEEE80211_FC0_SUBTYPE_ASSOC_RESP:
2062116742Ssam	case IEEE80211_FC0_SUBTYPE_REASSOC_RESP:
2063116742Ssam		/*
2064170530Ssam		 * asresp frame format
2065116742Ssam		 *	[2] capability information
2066116742Ssam		 *	[2] status
2067116742Ssam		 *	[2] association ID
2068116742Ssam		 *	[tlv] supported rates
2069116742Ssam		 *	[tlv] extended supported rates
2070178354Ssam		 *	[tlv] HT capabilities (standard, if STA enabled)
2071178354Ssam		 *	[tlv] HT information (standard, if STA enabled)
2072178354Ssam		 *	[tlv] WME (if configured and STA enabled)
2073178354Ssam		 *	[tlv] HT capabilities (vendor OUI, if STA enabled)
2074178354Ssam		 *	[tlv] HT information (vendor OUI, if STA enabled)
2075178354Ssam		 *	[tlv] Atheros capabilities (if STA enabled)
2076178354Ssam		 *	[tlv] AppIE's (optional)
2077116742Ssam		 */
2078138568Ssam		m = ieee80211_getmgtframe(&frm,
2079170530Ssam			 ic->ic_headroom + sizeof(struct ieee80211_frame),
2080170530Ssam			 sizeof(uint16_t)
2081170530Ssam		       + sizeof(uint16_t)
2082170530Ssam		       + sizeof(uint16_t)
2083116742Ssam		       + 2 + IEEE80211_RATE_SIZE
2084138568Ssam		       + 2 + (IEEE80211_RATE_MAXSIZE - IEEE80211_RATE_SIZE)
2085170530Ssam		       + sizeof(struct ieee80211_ie_htcap) + 4
2086170530Ssam		       + sizeof(struct ieee80211_ie_htinfo) + 4
2087178354Ssam		       + sizeof(struct ieee80211_wme_param)
2088170530Ssam		       + sizeof(struct ieee80211_ath_ie)
2089178354Ssam		       + (vap->iv_appie_assocresp != NULL ?
2090178354Ssam				vap->iv_appie_assocresp->ie_len : 0)
2091138568Ssam		);
2092116742Ssam		if (m == NULL)
2093138568Ssam			senderr(ENOMEM, is_tx_nobuf);
2094116742Ssam
2095178354Ssam		capinfo = getcapinfo(vap, bss->ni_chan);
2096170530Ssam		*(uint16_t *)frm = htole16(capinfo);
2097116742Ssam		frm += 2;
2098116742Ssam
2099170530Ssam		*(uint16_t *)frm = htole16(arg);	/* status */
2100116742Ssam		frm += 2;
2101116742Ssam
2102138568Ssam		if (arg == IEEE80211_STATUS_SUCCESS) {
2103170530Ssam			*(uint16_t *)frm = htole16(ni->ni_associd);
2104138568Ssam			IEEE80211_NODE_STAT(ni, tx_assoc);
2105138568Ssam		} else
2106138568Ssam			IEEE80211_NODE_STAT(ni, tx_assoc_fail);
2107116742Ssam		frm += 2;
2108116742Ssam
2109119150Ssam		frm = ieee80211_add_rates(frm, &ni->ni_rates);
2110119150Ssam		frm = ieee80211_add_xrates(frm, &ni->ni_rates);
2111173273Ssam		/* NB: respond according to what we received */
2112173273Ssam		if ((ni->ni_flags & HTFLAGS) == IEEE80211_NODE_HT) {
2113173273Ssam			frm = ieee80211_add_htcap(frm, ni);
2114173273Ssam			frm = ieee80211_add_htinfo(frm, ni);
2115173273Ssam		}
2116178354Ssam		if ((vap->iv_flags & IEEE80211_F_WME) &&
2117178354Ssam		    ni->ni_ies.wme_ie != NULL)
2118138568Ssam			frm = ieee80211_add_wme_param(frm, &ic->ic_wme);
2119173273Ssam		if ((ni->ni_flags & HTFLAGS) == HTFLAGS) {
2120173273Ssam			frm = ieee80211_add_htcap_vendor(frm, ni);
2121173273Ssam			frm = ieee80211_add_htinfo_vendor(frm, ni);
2122170530Ssam		}
2123178354Ssam		if (IEEE80211_ATH_CAP(vap, ni, IEEE80211_F_ATHEROS))
2124170530Ssam			frm = ieee80211_add_ath(frm,
2125178354Ssam				IEEE80211_ATH_CAP(vap, ni, IEEE80211_F_ATHEROS),
2126170530Ssam				ni->ni_ath_defkeyix);
2127178354Ssam		if (vap->iv_appie_assocresp != NULL)
2128178354Ssam			frm = add_appie(frm, vap->iv_appie_assocresp);
2129170530Ssam		m->m_pkthdr.len = m->m_len = frm - mtod(m, uint8_t *);
2130116742Ssam		break;
2131116742Ssam
2132116742Ssam	case IEEE80211_FC0_SUBTYPE_DISASSOC:
2133178354Ssam		IEEE80211_NOTE(vap, IEEE80211_MSG_ASSOC, ni,
2134178354Ssam		    "send station disassociate (reason %d)", arg);
2135170530Ssam		m = ieee80211_getmgtframe(&frm,
2136170530Ssam			ic->ic_headroom + sizeof(struct ieee80211_frame),
2137170530Ssam			sizeof(uint16_t));
2138116742Ssam		if (m == NULL)
2139138568Ssam			senderr(ENOMEM, is_tx_nobuf);
2140170530Ssam		*(uint16_t *)frm = htole16(arg);	/* reason */
2141170530Ssam		m->m_pkthdr.len = m->m_len = sizeof(uint16_t);
2142138568Ssam
2143138568Ssam		IEEE80211_NODE_STAT(ni, tx_disassoc);
2144138568Ssam		IEEE80211_NODE_STAT_SET(ni, tx_disassoc_code, arg);
2145116742Ssam		break;
2146116742Ssam
2147116742Ssam	default:
2148178354Ssam		IEEE80211_NOTE(vap, IEEE80211_MSG_ANY, ni,
2149178354Ssam		    "invalid mgmt frame type %u", type);
2150121180Ssam		senderr(EINVAL, is_tx_unknownmgt);
2151119150Ssam		/* NOTREACHED */
2152116742Ssam	}
2153170530Ssam
2154184282Ssam	/* NB: force non-ProbeResp frames to the highest queue */
2155184282Ssam	params.ibp_pri = WME_AC_VO;
2156184282Ssam	params.ibp_rate0 = bss->ni_txparms->mgmtrate;
2157184282Ssam	/* NB: we know all frames are unicast */
2158184282Ssam	params.ibp_try0 = bss->ni_txparms->maxretry;
2159184282Ssam	params.ibp_power = bss->ni_txpower;
2160184282Ssam	return ieee80211_mgmt_output(ni, m, type, &params);
2161119150Ssambad:
2162170530Ssam	ieee80211_free_node(ni);
2163116742Ssam	return ret;
2164119150Ssam#undef senderr
2165173273Ssam#undef HTFLAGS
2166116742Ssam}
2167138568Ssam
2168178354Ssam/*
2169178354Ssam * Return an mbuf with a probe response frame in it.
2170178354Ssam * Space is left to prepend and 802.11 header at the
2171178354Ssam * front but it's left to the caller to fill in.
2172178354Ssam */
2173178354Ssamstruct mbuf *
2174178354Ssamieee80211_alloc_proberesp(struct ieee80211_node *bss, int legacy)
2175178354Ssam{
2176178354Ssam	struct ieee80211vap *vap = bss->ni_vap;
2177178354Ssam	struct ieee80211com *ic = bss->ni_ic;
2178178354Ssam	const struct ieee80211_rateset *rs;
2179178354Ssam	struct mbuf *m;
2180178354Ssam	uint16_t capinfo;
2181178354Ssam	uint8_t *frm;
2182178354Ssam
2183178354Ssam	/*
2184178354Ssam	 * probe response frame format
2185178354Ssam	 *	[8] time stamp
2186178354Ssam	 *	[2] beacon interval
2187178354Ssam	 *	[2] cabability information
2188178354Ssam	 *	[tlv] ssid
2189178354Ssam	 *	[tlv] supported rates
2190178354Ssam	 *	[tlv] parameter set (FH/DS)
2191178354Ssam	 *	[tlv] parameter set (IBSS)
2192178354Ssam	 *	[tlv] country (optional)
2193178354Ssam	 *	[3] power control (optional)
2194178354Ssam	 *	[5] channel switch announcement (CSA) (optional)
2195178354Ssam	 *	[tlv] extended rate phy (ERP)
2196178354Ssam	 *	[tlv] extended supported rates
2197180351Ssam	 *	[tlv] RSN (optional)
2198178354Ssam	 *	[tlv] HT capabilities
2199178354Ssam	 *	[tlv] HT information
2200178354Ssam	 *	[tlv] WPA (optional)
2201178354Ssam	 *	[tlv] WME (optional)
2202178354Ssam	 *	[tlv] Vendor OUI HT capabilities (optional)
2203178354Ssam	 *	[tlv] Vendor OUI HT information (optional)
2204178354Ssam	 *	[tlv] Atheros capabilities
2205178354Ssam	 *	[tlv] AppIE's (optional)
2206178354Ssam	 */
2207178354Ssam	m = ieee80211_getmgtframe(&frm,
2208178354Ssam		 ic->ic_headroom + sizeof(struct ieee80211_frame),
2209178354Ssam		 8
2210178354Ssam	       + sizeof(uint16_t)
2211178354Ssam	       + sizeof(uint16_t)
2212178354Ssam	       + 2 + IEEE80211_NWID_LEN
2213178354Ssam	       + 2 + IEEE80211_RATE_SIZE
2214178354Ssam	       + 7	/* max(7,3) */
2215178354Ssam	       + IEEE80211_COUNTRY_MAX_SIZE
2216178354Ssam	       + 3
2217178354Ssam	       + sizeof(struct ieee80211_csa_ie)
2218178354Ssam	       + 3
2219178354Ssam	       + 2 + (IEEE80211_RATE_MAXSIZE - IEEE80211_RATE_SIZE)
2220180351Ssam	       + sizeof(struct ieee80211_ie_wpa)
2221178354Ssam	       + sizeof(struct ieee80211_ie_htcap)
2222178354Ssam	       + sizeof(struct ieee80211_ie_htinfo)
2223178354Ssam	       + sizeof(struct ieee80211_ie_wpa)
2224178354Ssam	       + sizeof(struct ieee80211_wme_param)
2225178354Ssam	       + 4 + sizeof(struct ieee80211_ie_htcap)
2226178354Ssam	       + 4 + sizeof(struct ieee80211_ie_htinfo)
2227178354Ssam	       + sizeof(struct ieee80211_ath_ie)
2228178354Ssam	       + (vap->iv_appie_proberesp != NULL ?
2229178354Ssam			vap->iv_appie_proberesp->ie_len : 0)
2230178354Ssam	);
2231178354Ssam	if (m == NULL) {
2232178354Ssam		vap->iv_stats.is_tx_nobuf++;
2233178354Ssam		return NULL;
2234178354Ssam	}
2235178354Ssam
2236178354Ssam	memset(frm, 0, 8);	/* timestamp should be filled later */
2237178354Ssam	frm += 8;
2238178354Ssam	*(uint16_t *)frm = htole16(bss->ni_intval);
2239178354Ssam	frm += 2;
2240178354Ssam	capinfo = getcapinfo(vap, bss->ni_chan);
2241178354Ssam	*(uint16_t *)frm = htole16(capinfo);
2242178354Ssam	frm += 2;
2243178354Ssam
2244178354Ssam	frm = ieee80211_add_ssid(frm, bss->ni_essid, bss->ni_esslen);
2245178354Ssam	rs = ieee80211_get_suprates(ic, bss->ni_chan);
2246178354Ssam	frm = ieee80211_add_rates(frm, rs);
2247178354Ssam
2248178354Ssam	if (IEEE80211_IS_CHAN_FHSS(bss->ni_chan)) {
2249178354Ssam		*frm++ = IEEE80211_ELEMID_FHPARMS;
2250178354Ssam		*frm++ = 5;
2251178354Ssam		*frm++ = bss->ni_fhdwell & 0x00ff;
2252178354Ssam		*frm++ = (bss->ni_fhdwell >> 8) & 0x00ff;
2253178354Ssam		*frm++ = IEEE80211_FH_CHANSET(
2254178354Ssam		    ieee80211_chan2ieee(ic, bss->ni_chan));
2255178354Ssam		*frm++ = IEEE80211_FH_CHANPAT(
2256178354Ssam		    ieee80211_chan2ieee(ic, bss->ni_chan));
2257178354Ssam		*frm++ = bss->ni_fhindex;
2258178354Ssam	} else {
2259178354Ssam		*frm++ = IEEE80211_ELEMID_DSPARMS;
2260178354Ssam		*frm++ = 1;
2261178354Ssam		*frm++ = ieee80211_chan2ieee(ic, bss->ni_chan);
2262178354Ssam	}
2263178354Ssam
2264178354Ssam	if (vap->iv_opmode == IEEE80211_M_IBSS) {
2265178354Ssam		*frm++ = IEEE80211_ELEMID_IBSSPARMS;
2266178354Ssam		*frm++ = 2;
2267178354Ssam		*frm++ = 0; *frm++ = 0;		/* TODO: ATIM window */
2268178354Ssam	}
2269178354Ssam	if ((vap->iv_flags & IEEE80211_F_DOTH) ||
2270178354Ssam	    (vap->iv_flags_ext & IEEE80211_FEXT_DOTD))
2271178354Ssam		frm = ieee80211_add_countryie(frm, ic);
2272178354Ssam	if (vap->iv_flags & IEEE80211_F_DOTH) {
2273178354Ssam		if (IEEE80211_IS_CHAN_5GHZ(bss->ni_chan))
2274178354Ssam			frm = ieee80211_add_powerconstraint(frm, vap);
2275178354Ssam		if (ic->ic_flags & IEEE80211_F_CSAPENDING)
2276178354Ssam			frm = ieee80211_add_csa(frm, vap);
2277178354Ssam	}
2278178354Ssam	if (IEEE80211_IS_CHAN_ANYG(bss->ni_chan))
2279178354Ssam		frm = ieee80211_add_erp(frm, ic);
2280178354Ssam	frm = ieee80211_add_xrates(frm, rs);
2281180351Ssam	if (vap->iv_flags & IEEE80211_F_WPA2) {
2282180351Ssam		if (vap->iv_rsn_ie != NULL)
2283180351Ssam			frm = add_ie(frm, vap->iv_rsn_ie);
2284180351Ssam		/* XXX else complain? */
2285180351Ssam	}
2286178354Ssam	/*
2287178354Ssam	 * NB: legacy 11b clients do not get certain ie's.
2288178354Ssam	 *     The caller identifies such clients by passing
2289178354Ssam	 *     a token in legacy to us.  Could expand this to be
2290178354Ssam	 *     any legacy client for stuff like HT ie's.
2291178354Ssam	 */
2292178354Ssam	if (IEEE80211_IS_CHAN_HT(bss->ni_chan) &&
2293178354Ssam	    legacy != IEEE80211_SEND_LEGACY_11B) {
2294178354Ssam		frm = ieee80211_add_htcap(frm, bss);
2295178354Ssam		frm = ieee80211_add_htinfo(frm, bss);
2296178354Ssam	}
2297178354Ssam	if (vap->iv_flags & IEEE80211_F_WPA1) {
2298178354Ssam		if (vap->iv_wpa_ie != NULL)
2299178354Ssam			frm = add_ie(frm, vap->iv_wpa_ie);
2300178354Ssam		/* XXX else complain? */
2301178354Ssam	}
2302178354Ssam	if (vap->iv_flags & IEEE80211_F_WME)
2303178354Ssam		frm = ieee80211_add_wme_param(frm, &ic->ic_wme);
2304178354Ssam	if (IEEE80211_IS_CHAN_HT(bss->ni_chan) &&
2305178354Ssam	    (vap->iv_flags_ext & IEEE80211_FEXT_HTCOMPAT) &&
2306178354Ssam	    legacy != IEEE80211_SEND_LEGACY_11B) {
2307178354Ssam		frm = ieee80211_add_htcap_vendor(frm, bss);
2308178354Ssam		frm = ieee80211_add_htinfo_vendor(frm, bss);
2309178354Ssam	}
2310178354Ssam	if (bss->ni_ies.ath_ie != NULL && legacy != IEEE80211_SEND_LEGACY_11B)
2311178354Ssam		frm = ieee80211_add_ath(frm, bss->ni_ath_flags,
2312178354Ssam			bss->ni_ath_defkeyix);
2313178354Ssam	if (vap->iv_appie_proberesp != NULL)
2314178354Ssam		frm = add_appie(frm, vap->iv_appie_proberesp);
2315178354Ssam	m->m_pkthdr.len = m->m_len = frm - mtod(m, uint8_t *);
2316178354Ssam
2317178354Ssam	return m;
2318178354Ssam}
2319178354Ssam
2320178354Ssam/*
2321178354Ssam * Send a probe response frame to the specified mac address.
2322178354Ssam * This does not go through the normal mgt frame api so we
2323178354Ssam * can specify the destination address and re-use the bss node
2324178354Ssam * for the sta reference.
2325178354Ssam */
2326178354Ssamint
2327178354Ssamieee80211_send_proberesp(struct ieee80211vap *vap,
2328178354Ssam	const uint8_t da[IEEE80211_ADDR_LEN], int legacy)
2329178354Ssam{
2330178354Ssam	struct ieee80211_node *bss = vap->iv_bss;
2331178354Ssam	struct ieee80211com *ic = vap->iv_ic;
2332178354Ssam	struct ieee80211_frame *wh;
2333178354Ssam	struct mbuf *m;
2334178354Ssam
2335178354Ssam	if (vap->iv_state == IEEE80211_S_CAC) {
2336178354Ssam		IEEE80211_NOTE(vap, IEEE80211_MSG_OUTPUT, bss,
2337178354Ssam		    "block %s frame in CAC state", "probe response");
2338178354Ssam		vap->iv_stats.is_tx_badstate++;
2339178354Ssam		return EIO;		/* XXX */
2340178354Ssam	}
2341178354Ssam
2342178354Ssam	/*
2343178354Ssam	 * Hold a reference on the node so it doesn't go away until after
2344178354Ssam	 * the xmit is complete all the way in the driver.  On error we
2345178354Ssam	 * will remove our reference.
2346178354Ssam	 */
2347178354Ssam	IEEE80211_DPRINTF(vap, IEEE80211_MSG_NODE,
2348178354Ssam	    "ieee80211_ref_node (%s:%u) %p<%s> refcnt %d\n",
2349178354Ssam	    __func__, __LINE__, bss, ether_sprintf(bss->ni_macaddr),
2350178354Ssam	    ieee80211_node_refcnt(bss)+1);
2351178354Ssam	ieee80211_ref_node(bss);
2352178354Ssam
2353178354Ssam	m = ieee80211_alloc_proberesp(bss, legacy);
2354178354Ssam	if (m == NULL) {
2355178354Ssam		ieee80211_free_node(bss);
2356178354Ssam		return ENOMEM;
2357178354Ssam	}
2358178354Ssam
2359178354Ssam	M_PREPEND(m, sizeof(struct ieee80211_frame), M_DONTWAIT);
2360178354Ssam	KASSERT(m != NULL, ("no room for header"));
2361178354Ssam
2362178354Ssam	wh = mtod(m, struct ieee80211_frame *);
2363178354Ssam	ieee80211_send_setup(bss, wh,
2364184282Ssam	     IEEE80211_FC0_TYPE_MGT | IEEE80211_FC0_SUBTYPE_PROBE_RESP,
2365184282Ssam	     IEEE80211_NONQOS_TID, vap->iv_myaddr, da, bss->ni_bssid);
2366178354Ssam	/* XXX power management? */
2367184286Ssam	m->m_flags |= M_ENCAP;		/* mark encapsulated */
2368178354Ssam
2369178354Ssam	M_WME_SETAC(m, WME_AC_BE);
2370178354Ssam
2371178354Ssam	IEEE80211_DPRINTF(vap, IEEE80211_MSG_DEBUG | IEEE80211_MSG_DUMPPKTS,
2372178354Ssam	    "send probe resp on channel %u to %s%s\n",
2373178354Ssam	    ieee80211_chan2ieee(ic, ic->ic_curchan), ether_sprintf(da),
2374178354Ssam	    legacy ? " <legacy>" : "");
2375178354Ssam	IEEE80211_NODE_STAT(bss, tx_mgmt);
2376178354Ssam
2377178354Ssam	return ic->ic_raw_xmit(bss, m, NULL);
2378178354Ssam}
2379178354Ssam
2380178354Ssam/*
2381178354Ssam * Allocate and build a RTS (Request To Send) control frame.
2382178354Ssam */
2383178354Ssamstruct mbuf *
2384178354Ssamieee80211_alloc_rts(struct ieee80211com *ic,
2385178354Ssam	const uint8_t ra[IEEE80211_ADDR_LEN],
2386178354Ssam	const uint8_t ta[IEEE80211_ADDR_LEN],
2387178354Ssam	uint16_t dur)
2388178354Ssam{
2389178354Ssam	struct ieee80211_frame_rts *rts;
2390178354Ssam	struct mbuf *m;
2391178354Ssam
2392178354Ssam	/* XXX honor ic_headroom */
2393178354Ssam	m = m_gethdr(M_DONTWAIT, MT_DATA);
2394178354Ssam	if (m != NULL) {
2395178354Ssam		rts = mtod(m, struct ieee80211_frame_rts *);
2396178354Ssam		rts->i_fc[0] = IEEE80211_FC0_VERSION_0 |
2397178354Ssam			IEEE80211_FC0_TYPE_CTL | IEEE80211_FC0_SUBTYPE_RTS;
2398178354Ssam		rts->i_fc[1] = IEEE80211_FC1_DIR_NODS;
2399178354Ssam		*(u_int16_t *)rts->i_dur = htole16(dur);
2400178354Ssam		IEEE80211_ADDR_COPY(rts->i_ra, ra);
2401178354Ssam		IEEE80211_ADDR_COPY(rts->i_ta, ta);
2402178354Ssam
2403178354Ssam		m->m_pkthdr.len = m->m_len = sizeof(struct ieee80211_frame_rts);
2404178354Ssam	}
2405178354Ssam	return m;
2406178354Ssam}
2407178354Ssam
2408178354Ssam/*
2409178354Ssam * Allocate and build a CTS (Clear To Send) control frame.
2410178354Ssam */
2411178354Ssamstruct mbuf *
2412178354Ssamieee80211_alloc_cts(struct ieee80211com *ic,
2413178354Ssam	const uint8_t ra[IEEE80211_ADDR_LEN], uint16_t dur)
2414178354Ssam{
2415178354Ssam	struct ieee80211_frame_cts *cts;
2416178354Ssam	struct mbuf *m;
2417178354Ssam
2418178354Ssam	/* XXX honor ic_headroom */
2419178354Ssam	m = m_gethdr(M_DONTWAIT, MT_DATA);
2420178354Ssam	if (m != NULL) {
2421178354Ssam		cts = mtod(m, struct ieee80211_frame_cts *);
2422178354Ssam		cts->i_fc[0] = IEEE80211_FC0_VERSION_0 |
2423178354Ssam			IEEE80211_FC0_TYPE_CTL | IEEE80211_FC0_SUBTYPE_CTS;
2424178354Ssam		cts->i_fc[1] = IEEE80211_FC1_DIR_NODS;
2425178354Ssam		*(u_int16_t *)cts->i_dur = htole16(dur);
2426178354Ssam		IEEE80211_ADDR_COPY(cts->i_ra, ra);
2427178354Ssam
2428178354Ssam		m->m_pkthdr.len = m->m_len = sizeof(struct ieee80211_frame_cts);
2429178354Ssam	}
2430178354Ssam	return m;
2431178354Ssam}
2432178354Ssam
2433170530Ssamstatic void
2434170530Ssamieee80211_tx_mgt_timeout(void *arg)
2435170530Ssam{
2436170530Ssam	struct ieee80211_node *ni = arg;
2437178354Ssam	struct ieee80211vap *vap = ni->ni_vap;
2438170530Ssam
2439178354Ssam	if (vap->iv_state != IEEE80211_S_INIT &&
2440178354Ssam	    (vap->iv_ic->ic_flags & IEEE80211_F_SCAN) == 0) {
2441170530Ssam		/*
2442170530Ssam		 * NB: it's safe to specify a timeout as the reason here;
2443170530Ssam		 *     it'll only be used in the right state.
2444170530Ssam		 */
2445178354Ssam		ieee80211_new_state(vap, IEEE80211_S_SCAN,
2446170530Ssam			IEEE80211_SCAN_FAIL_TIMEOUT);
2447170530Ssam	}
2448170530Ssam}
2449170530Ssam
2450170530Ssamstatic void
2451170530Ssamieee80211_tx_mgt_cb(struct ieee80211_node *ni, void *arg, int status)
2452170530Ssam{
2453178354Ssam	struct ieee80211vap *vap = ni->ni_vap;
2454170530Ssam	enum ieee80211_state ostate = (enum ieee80211_state) arg;
2455170530Ssam
2456170530Ssam	/*
2457170530Ssam	 * Frame transmit completed; arrange timer callback.  If
2458170530Ssam	 * transmit was successfuly we wait for response.  Otherwise
2459170530Ssam	 * we arrange an immediate callback instead of doing the
2460170530Ssam	 * callback directly since we don't know what state the driver
2461170530Ssam	 * is in (e.g. what locks it is holding).  This work should
2462170530Ssam	 * not be too time-critical and not happen too often so the
2463170530Ssam	 * added overhead is acceptable.
2464170530Ssam	 *
2465170530Ssam	 * XXX what happens if !acked but response shows up before callback?
2466170530Ssam	 */
2467178354Ssam	if (vap->iv_state == ostate)
2468178354Ssam		callout_reset(&vap->iv_mgtsend,
2469170530Ssam			status == 0 ? IEEE80211_TRANS_WAIT*hz : 0,
2470170530Ssam			ieee80211_tx_mgt_timeout, ni);
2471170530Ssam}
2472170530Ssam
2473178354Ssamstatic void
2474178354Ssamieee80211_beacon_construct(struct mbuf *m, uint8_t *frm,
2475178354Ssam	struct ieee80211_beacon_offsets *bo, struct ieee80211_node *ni)
2476138568Ssam{
2477178354Ssam	struct ieee80211vap *vap = ni->ni_vap;
2478172211Ssam	struct ieee80211com *ic = ni->ni_ic;
2479178354Ssam	struct ieee80211_rateset *rs = &ni->ni_rates;
2480170530Ssam	uint16_t capinfo;
2481138568Ssam
2482138568Ssam	/*
2483138568Ssam	 * beacon frame format
2484138568Ssam	 *	[8] time stamp
2485138568Ssam	 *	[2] beacon interval
2486138568Ssam	 *	[2] cabability information
2487138568Ssam	 *	[tlv] ssid
2488138568Ssam	 *	[tlv] supported rates
2489138568Ssam	 *	[3] parameter set (DS)
2490178354Ssam	 *	[8] CF parameter set (optional)
2491138568Ssam	 *	[tlv] parameter set (IBSS/TIM)
2492178354Ssam	 *	[tlv] country (optional)
2493178354Ssam	 *	[3] power control (optional)
2494178354Ssam	 *	[5] channel switch announcement (CSA) (optional)
2495138568Ssam	 *	[tlv] extended rate phy (ERP)
2496138568Ssam	 *	[tlv] extended supported rates
2497180351Ssam	 *	[tlv] RSN parameters
2498170530Ssam	 *	[tlv] HT capabilities
2499170530Ssam	 *	[tlv] HT information
2500178354Ssam	 * XXX Vendor-specific OIDs (e.g. Atheros)
2501178354Ssam	 *	[tlv] WPA parameters
2502178354Ssam	 *	[tlv] WME parameters
2503170530Ssam	 *	[tlv] Vendor OUI HT capabilities (optional)
2504170530Ssam	 *	[tlv] Vendor OUI HT information (optional)
2505178354Ssam	 *	[tlv] application data (optional)
2506138568Ssam	 */
2507138568Ssam
2508173273Ssam	memset(bo, 0, sizeof(*bo));
2509173273Ssam
2510138568Ssam	memset(frm, 0, 8);	/* XXX timestamp is set by hardware/driver */
2511138568Ssam	frm += 8;
2512170530Ssam	*(uint16_t *)frm = htole16(ni->ni_intval);
2513138568Ssam	frm += 2;
2514178354Ssam	capinfo = getcapinfo(vap, ni->ni_chan);
2515170530Ssam	bo->bo_caps = (uint16_t *)frm;
2516170530Ssam	*(uint16_t *)frm = htole16(capinfo);
2517138568Ssam	frm += 2;
2518138568Ssam	*frm++ = IEEE80211_ELEMID_SSID;
2519178354Ssam	if ((vap->iv_flags & IEEE80211_F_HIDESSID) == 0) {
2520138568Ssam		*frm++ = ni->ni_esslen;
2521138568Ssam		memcpy(frm, ni->ni_essid, ni->ni_esslen);
2522138568Ssam		frm += ni->ni_esslen;
2523138568Ssam	} else
2524138568Ssam		*frm++ = 0;
2525138568Ssam	frm = ieee80211_add_rates(frm, rs);
2526178354Ssam	if (!IEEE80211_IS_CHAN_FHSS(ni->ni_chan)) {
2527138568Ssam		*frm++ = IEEE80211_ELEMID_DSPARMS;
2528138568Ssam		*frm++ = 1;
2529178354Ssam		*frm++ = ieee80211_chan2ieee(ic, ni->ni_chan);
2530138568Ssam	}
2531178354Ssam	if (ic->ic_flags & IEEE80211_F_PCF) {
2532178354Ssam		bo->bo_cfp = frm;
2533178354Ssam		frm = ieee80211_add_cfparms(frm, ic);
2534178354Ssam	}
2535138568Ssam	bo->bo_tim = frm;
2536178354Ssam	if (vap->iv_opmode == IEEE80211_M_IBSS) {
2537138568Ssam		*frm++ = IEEE80211_ELEMID_IBSSPARMS;
2538138568Ssam		*frm++ = 2;
2539138568Ssam		*frm++ = 0; *frm++ = 0;		/* TODO: ATIM window */
2540138568Ssam		bo->bo_tim_len = 0;
2541178354Ssam	} else if (vap->iv_opmode == IEEE80211_M_HOSTAP) {
2542138568Ssam		struct ieee80211_tim_ie *tie = (struct ieee80211_tim_ie *) frm;
2543138568Ssam
2544138568Ssam		tie->tim_ie = IEEE80211_ELEMID_TIM;
2545138568Ssam		tie->tim_len = 4;	/* length */
2546138568Ssam		tie->tim_count = 0;	/* DTIM count */
2547178354Ssam		tie->tim_period = vap->iv_dtim_period;	/* DTIM period */
2548138568Ssam		tie->tim_bitctl = 0;	/* bitmap control */
2549138568Ssam		tie->tim_bitmap[0] = 0;	/* Partial Virtual Bitmap */
2550138568Ssam		frm += sizeof(struct ieee80211_tim_ie);
2551138568Ssam		bo->bo_tim_len = 1;
2552138568Ssam	}
2553172211Ssam	bo->bo_tim_trailer = frm;
2554178354Ssam	if ((vap->iv_flags & IEEE80211_F_DOTH) ||
2555178354Ssam	    (vap->iv_flags_ext & IEEE80211_FEXT_DOTD))
2556178354Ssam		frm = ieee80211_add_countryie(frm, ic);
2557178354Ssam	if (vap->iv_flags & IEEE80211_F_DOTH) {
2558178354Ssam		if (IEEE80211_IS_CHAN_5GHZ(ni->ni_chan))
2559178354Ssam			frm = ieee80211_add_powerconstraint(frm, vap);
2560178354Ssam		bo->bo_csa = frm;
2561178354Ssam		if (ic->ic_flags & IEEE80211_F_CSAPENDING)
2562178354Ssam			frm = ieee80211_add_csa(frm, vap);
2563178354Ssam	} else
2564178354Ssam		bo->bo_csa = frm;
2565178354Ssam	if (IEEE80211_IS_CHAN_ANYG(ni->ni_chan)) {
2566153973Ssam		bo->bo_erp = frm;
2567138568Ssam		frm = ieee80211_add_erp(frm, ic);
2568173273Ssam	}
2569170530Ssam	frm = ieee80211_add_xrates(frm, rs);
2570180351Ssam	if (vap->iv_flags & IEEE80211_F_WPA2) {
2571180351Ssam		if (vap->iv_rsn_ie != NULL)
2572180351Ssam			frm = add_ie(frm, vap->iv_rsn_ie);
2573180351Ssam		/* XXX else complain */
2574180351Ssam	}
2575178354Ssam	if (IEEE80211_IS_CHAN_HT(ni->ni_chan)) {
2576170530Ssam		frm = ieee80211_add_htcap(frm, ni);
2577170530Ssam		bo->bo_htinfo = frm;
2578170530Ssam		frm = ieee80211_add_htinfo(frm, ni);
2579173273Ssam	}
2580178354Ssam	if (vap->iv_flags & IEEE80211_F_WPA1) {
2581178354Ssam		if (vap->iv_wpa_ie != NULL)
2582178354Ssam			frm = add_ie(frm, vap->iv_wpa_ie);
2583178354Ssam		/* XXX else complain */
2584178354Ssam	}
2585178354Ssam	if (vap->iv_flags & IEEE80211_F_WME) {
2586173273Ssam		bo->bo_wme = frm;
2587173273Ssam		frm = ieee80211_add_wme_param(frm, &ic->ic_wme);
2588173273Ssam	}
2589178354Ssam	if (IEEE80211_IS_CHAN_HT(ni->ni_chan) &&
2590178354Ssam	    (vap->iv_flags_ext & IEEE80211_FEXT_HTCOMPAT)) {
2591173273Ssam		frm = ieee80211_add_htcap_vendor(frm, ni);
2592173273Ssam		frm = ieee80211_add_htinfo_vendor(frm, ni);
2593173273Ssam	}
2594178354Ssam	if (vap->iv_appie_beacon != NULL) {
2595178354Ssam		bo->bo_appie = frm;
2596178354Ssam		bo->bo_appie_len = vap->iv_appie_beacon->ie_len;
2597178354Ssam		frm = add_appie(frm, vap->iv_appie_beacon);
2598178354Ssam	}
2599172211Ssam	bo->bo_tim_trailer_len = frm - bo->bo_tim_trailer;
2600178354Ssam	bo->bo_csa_trailer_len = frm - bo->bo_csa;
2601170530Ssam	m->m_pkthdr.len = m->m_len = frm - mtod(m, uint8_t *);
2602178354Ssam}
2603138568Ssam
2604178354Ssam/*
2605178354Ssam * Allocate a beacon frame and fillin the appropriate bits.
2606178354Ssam */
2607178354Ssamstruct mbuf *
2608178354Ssamieee80211_beacon_alloc(struct ieee80211_node *ni,
2609178354Ssam	struct ieee80211_beacon_offsets *bo)
2610178354Ssam{
2611178354Ssam	struct ieee80211vap *vap = ni->ni_vap;
2612178354Ssam	struct ieee80211com *ic = ni->ni_ic;
2613178354Ssam	struct ifnet *ifp = vap->iv_ifp;
2614178354Ssam	struct ieee80211_frame *wh;
2615178354Ssam	struct mbuf *m;
2616178354Ssam	int pktlen;
2617178354Ssam	uint8_t *frm;
2618178354Ssam
2619178354Ssam	/*
2620178354Ssam	 * beacon frame format
2621178354Ssam	 *	[8] time stamp
2622178354Ssam	 *	[2] beacon interval
2623178354Ssam	 *	[2] cabability information
2624178354Ssam	 *	[tlv] ssid
2625178354Ssam	 *	[tlv] supported rates
2626178354Ssam	 *	[3] parameter set (DS)
2627178354Ssam	 *	[8] CF parameter set (optional)
2628178354Ssam	 *	[tlv] parameter set (IBSS/TIM)
2629178354Ssam	 *	[tlv] country (optional)
2630178354Ssam	 *	[3] power control (optional)
2631178354Ssam	 *	[5] channel switch announcement (CSA) (optional)
2632178354Ssam	 *	[tlv] extended rate phy (ERP)
2633178354Ssam	 *	[tlv] extended supported rates
2634178354Ssam	 *	[tlv] RSN parameters
2635178354Ssam	 *	[tlv] HT capabilities
2636178354Ssam	 *	[tlv] HT information
2637178354Ssam	 *	[tlv] Vendor OUI HT capabilities (optional)
2638178354Ssam	 *	[tlv] Vendor OUI HT information (optional)
2639178354Ssam	 * XXX Vendor-specific OIDs (e.g. Atheros)
2640178354Ssam	 *	[tlv] WPA parameters
2641178354Ssam	 *	[tlv] WME parameters
2642178354Ssam	 *	[tlv] application data (optional)
2643178354Ssam	 * NB: we allocate the max space required for the TIM bitmap.
2644178354Ssam	 * XXX how big is this?
2645178354Ssam	 */
2646178354Ssam	pktlen =   8					/* time stamp */
2647178354Ssam		 + sizeof(uint16_t)			/* beacon interval */
2648178354Ssam		 + sizeof(uint16_t)			/* capabilities */
2649178354Ssam		 + 2 + ni->ni_esslen			/* ssid */
2650178354Ssam	         + 2 + IEEE80211_RATE_SIZE		/* supported rates */
2651178354Ssam	         + 2 + 1				/* DS parameters */
2652178354Ssam		 + 2 + 6				/* CF parameters */
2653178354Ssam		 + 2 + 4 + vap->iv_tim_len		/* DTIM/IBSSPARMS */
2654178354Ssam		 + IEEE80211_COUNTRY_MAX_SIZE		/* country */
2655178354Ssam		 + 2 + 1				/* power control */
2656178354Ssam	         + sizeof(struct ieee80211_csa_ie)	/* CSA */
2657178354Ssam		 + 2 + 1				/* ERP */
2658178354Ssam	         + 2 + (IEEE80211_RATE_MAXSIZE - IEEE80211_RATE_SIZE)
2659178354Ssam		 + (vap->iv_caps & IEEE80211_C_WPA ?	/* WPA 1+2 */
2660178354Ssam			2*sizeof(struct ieee80211_ie_wpa) : 0)
2661178354Ssam		 /* XXX conditional? */
2662178354Ssam		 + 4+2*sizeof(struct ieee80211_ie_htcap)/* HT caps */
2663178354Ssam		 + 4+2*sizeof(struct ieee80211_ie_htinfo)/* HT info */
2664178354Ssam		 + (vap->iv_caps & IEEE80211_C_WME ?	/* WME */
2665178354Ssam			sizeof(struct ieee80211_wme_param) : 0)
2666178354Ssam		 + IEEE80211_MAX_APPIE
2667178354Ssam		 ;
2668178354Ssam	m = ieee80211_getmgtframe(&frm,
2669178354Ssam		ic->ic_headroom + sizeof(struct ieee80211_frame), pktlen);
2670178354Ssam	if (m == NULL) {
2671178354Ssam		IEEE80211_DPRINTF(vap, IEEE80211_MSG_ANY,
2672178354Ssam			"%s: cannot get buf; size %u\n", __func__, pktlen);
2673178354Ssam		vap->iv_stats.is_tx_nobuf++;
2674178354Ssam		return NULL;
2675178354Ssam	}
2676178354Ssam	ieee80211_beacon_construct(m, frm, bo, ni);
2677178354Ssam
2678138568Ssam	M_PREPEND(m, sizeof(struct ieee80211_frame), M_DONTWAIT);
2679138568Ssam	KASSERT(m != NULL, ("no space for 802.11 header?"));
2680138568Ssam	wh = mtod(m, struct ieee80211_frame *);
2681138568Ssam	wh->i_fc[0] = IEEE80211_FC0_VERSION_0 | IEEE80211_FC0_TYPE_MGT |
2682138568Ssam	    IEEE80211_FC0_SUBTYPE_BEACON;
2683138568Ssam	wh->i_fc[1] = IEEE80211_FC1_DIR_NODS;
2684170530Ssam	*(uint16_t *)wh->i_dur = 0;
2685138568Ssam	IEEE80211_ADDR_COPY(wh->i_addr1, ifp->if_broadcastaddr);
2686178354Ssam	IEEE80211_ADDR_COPY(wh->i_addr2, vap->iv_myaddr);
2687138568Ssam	IEEE80211_ADDR_COPY(wh->i_addr3, ni->ni_bssid);
2688170530Ssam	*(uint16_t *)wh->i_seq = 0;
2689138568Ssam
2690138568Ssam	return m;
2691138568Ssam}
2692138568Ssam
2693138568Ssam/*
2694138568Ssam * Update the dynamic parts of a beacon frame based on the current state.
2695138568Ssam */
2696138568Ssamint
2697172211Ssamieee80211_beacon_update(struct ieee80211_node *ni,
2698138568Ssam	struct ieee80211_beacon_offsets *bo, struct mbuf *m, int mcast)
2699138568Ssam{
2700178354Ssam	struct ieee80211vap *vap = ni->ni_vap;
2701172211Ssam	struct ieee80211com *ic = ni->ni_ic;
2702138568Ssam	int len_changed = 0;
2703170530Ssam	uint16_t capinfo;
2704138568Ssam
2705178354Ssam	IEEE80211_LOCK(ic);
2706178354Ssam	/*
2707178354Ssam	 * Handle 11h channel change when we've reached the count.
2708178354Ssam	 * We must recalculate the beacon frame contents to account
2709178354Ssam	 * for the new channel.  Note we do this only for the first
2710178354Ssam	 * vap that reaches this point; subsequent vaps just update
2711178354Ssam	 * their beacon state to reflect the recalculated channel.
2712178354Ssam	 */
2713178354Ssam	if (isset(bo->bo_flags, IEEE80211_BEACON_CSA) &&
2714178354Ssam	    vap->iv_csa_count == ic->ic_csa_count) {
2715178354Ssam		vap->iv_csa_count = 0;
2716178354Ssam		/*
2717178354Ssam		 * Effect channel change before reconstructing the beacon
2718178354Ssam		 * frame contents as many places reference ni_chan.
2719178354Ssam		 */
2720178354Ssam		if (ic->ic_csa_newchan != NULL)
2721178354Ssam			ieee80211_csa_completeswitch(ic);
2722178354Ssam		/*
2723178354Ssam		 * NB: ieee80211_beacon_construct clears all pending
2724178354Ssam		 * updates in bo_flags so we don't need to explicitly
2725178354Ssam		 * clear IEEE80211_BEACON_CSA.
2726178354Ssam		 */
2727178354Ssam		ieee80211_beacon_construct(m,
2728178354Ssam		    mtod(m, uint8_t*) + sizeof(struct ieee80211_frame), bo, ni);
2729178354Ssam
2730178354Ssam		/* XXX do WME aggressive mode processing? */
2731178354Ssam		IEEE80211_UNLOCK(ic);
2732178354Ssam		return 1;		/* just assume length changed */
2733178354Ssam	}
2734178354Ssam
2735138568Ssam	/* XXX faster to recalculate entirely or just changes? */
2736178354Ssam	capinfo = getcapinfo(vap, ni->ni_chan);
2737138568Ssam	*bo->bo_caps = htole16(capinfo);
2738138568Ssam
2739178354Ssam	if (vap->iv_flags & IEEE80211_F_WME) {
2740138568Ssam		struct ieee80211_wme_state *wme = &ic->ic_wme;
2741138568Ssam
2742138568Ssam		/*
2743138568Ssam		 * Check for agressive mode change.  When there is
2744138568Ssam		 * significant high priority traffic in the BSS
2745138568Ssam		 * throttle back BE traffic by using conservative
2746138568Ssam		 * parameters.  Otherwise BE uses agressive params
2747138568Ssam		 * to optimize performance of legacy/non-QoS traffic.
2748138568Ssam		 */
2749138568Ssam		if (wme->wme_flags & WME_F_AGGRMODE) {
2750138568Ssam			if (wme->wme_hipri_traffic >
2751138568Ssam			    wme->wme_hipri_switch_thresh) {
2752178354Ssam				IEEE80211_DPRINTF(vap, IEEE80211_MSG_WME,
2753138568Ssam				    "%s: traffic %u, disable aggressive mode\n",
2754138568Ssam				    __func__, wme->wme_hipri_traffic);
2755138568Ssam				wme->wme_flags &= ~WME_F_AGGRMODE;
2756178354Ssam				ieee80211_wme_updateparams_locked(vap);
2757138568Ssam				wme->wme_hipri_traffic =
2758138568Ssam					wme->wme_hipri_switch_hysteresis;
2759138568Ssam			} else
2760138568Ssam				wme->wme_hipri_traffic = 0;
2761138568Ssam		} else {
2762138568Ssam			if (wme->wme_hipri_traffic <=
2763138568Ssam			    wme->wme_hipri_switch_thresh) {
2764178354Ssam				IEEE80211_DPRINTF(vap, IEEE80211_MSG_WME,
2765138568Ssam				    "%s: traffic %u, enable aggressive mode\n",
2766138568Ssam				    __func__, wme->wme_hipri_traffic);
2767138568Ssam				wme->wme_flags |= WME_F_AGGRMODE;
2768178354Ssam				ieee80211_wme_updateparams_locked(vap);
2769138568Ssam				wme->wme_hipri_traffic = 0;
2770138568Ssam			} else
2771138568Ssam				wme->wme_hipri_traffic =
2772138568Ssam					wme->wme_hipri_switch_hysteresis;
2773138568Ssam		}
2774172211Ssam		if (isset(bo->bo_flags, IEEE80211_BEACON_WME)) {
2775138568Ssam			(void) ieee80211_add_wme_param(bo->bo_wme, wme);
2776172211Ssam			clrbit(bo->bo_flags, IEEE80211_BEACON_WME);
2777138568Ssam		}
2778138568Ssam	}
2779138568Ssam
2780178354Ssam	if (isset(bo->bo_flags,  IEEE80211_BEACON_HTINFO)) {
2781178354Ssam		ieee80211_ht_update_beacon(vap, bo);
2782172211Ssam		clrbit(bo->bo_flags, IEEE80211_BEACON_HTINFO);
2783170530Ssam	}
2784170530Ssam
2785178354Ssam	if (vap->iv_opmode == IEEE80211_M_HOSTAP) {	/* NB: no IBSS support*/
2786138568Ssam		struct ieee80211_tim_ie *tie =
2787138568Ssam			(struct ieee80211_tim_ie *) bo->bo_tim;
2788172211Ssam		if (isset(bo->bo_flags, IEEE80211_BEACON_TIM)) {
2789138568Ssam			u_int timlen, timoff, i;
2790138568Ssam			/*
2791138568Ssam			 * ATIM/DTIM needs updating.  If it fits in the
2792138568Ssam			 * current space allocated then just copy in the
2793138568Ssam			 * new bits.  Otherwise we need to move any trailing
2794138568Ssam			 * data to make room.  Note that we know there is
2795138568Ssam			 * contiguous space because ieee80211_beacon_allocate
2796138568Ssam			 * insures there is space in the mbuf to write a
2797178354Ssam			 * maximal-size virtual bitmap (based on iv_max_aid).
2798138568Ssam			 */
2799138568Ssam			/*
2800138568Ssam			 * Calculate the bitmap size and offset, copy any
2801138568Ssam			 * trailer out of the way, and then copy in the
2802138568Ssam			 * new bitmap and update the information element.
2803138568Ssam			 * Note that the tim bitmap must contain at least
2804138568Ssam			 * one byte and any offset must be even.
2805138568Ssam			 */
2806178354Ssam			if (vap->iv_ps_pending != 0) {
2807138568Ssam				timoff = 128;		/* impossibly large */
2808178354Ssam				for (i = 0; i < vap->iv_tim_len; i++)
2809178354Ssam					if (vap->iv_tim_bitmap[i]) {
2810138568Ssam						timoff = i &~ 1;
2811138568Ssam						break;
2812138568Ssam					}
2813138568Ssam				KASSERT(timoff != 128, ("tim bitmap empty!"));
2814178354Ssam				for (i = vap->iv_tim_len-1; i >= timoff; i--)
2815178354Ssam					if (vap->iv_tim_bitmap[i])
2816138568Ssam						break;
2817138568Ssam				timlen = 1 + (i - timoff);
2818138568Ssam			} else {
2819138568Ssam				timoff = 0;
2820138568Ssam				timlen = 1;
2821138568Ssam			}
2822138568Ssam			if (timlen != bo->bo_tim_len) {
2823138568Ssam				/* copy up/down trailer */
2824153973Ssam				int adjust = tie->tim_bitmap+timlen
2825172211Ssam					   - bo->bo_tim_trailer;
2826172211Ssam				ovbcopy(bo->bo_tim_trailer,
2827172211Ssam				    bo->bo_tim_trailer+adjust,
2828172211Ssam				    bo->bo_tim_trailer_len);
2829172211Ssam				bo->bo_tim_trailer += adjust;
2830153973Ssam				bo->bo_erp += adjust;
2831170530Ssam				bo->bo_htinfo += adjust;
2832178354Ssam				bo->bo_appie += adjust;
2833178354Ssam				bo->bo_wme += adjust;
2834178354Ssam				bo->bo_csa += adjust;
2835138568Ssam				bo->bo_tim_len = timlen;
2836138568Ssam
2837138568Ssam				/* update information element */
2838138568Ssam				tie->tim_len = 3 + timlen;
2839138568Ssam				tie->tim_bitctl = timoff;
2840138568Ssam				len_changed = 1;
2841138568Ssam			}
2842178354Ssam			memcpy(tie->tim_bitmap, vap->iv_tim_bitmap + timoff,
2843138568Ssam				bo->bo_tim_len);
2844138568Ssam
2845172211Ssam			clrbit(bo->bo_flags, IEEE80211_BEACON_TIM);
2846138568Ssam
2847178354Ssam			IEEE80211_DPRINTF(vap, IEEE80211_MSG_POWER,
2848138568Ssam				"%s: TIM updated, pending %u, off %u, len %u\n",
2849178354Ssam				__func__, vap->iv_ps_pending, timoff, timlen);
2850138568Ssam		}
2851138568Ssam		/* count down DTIM period */
2852138568Ssam		if (tie->tim_count == 0)
2853138568Ssam			tie->tim_count = tie->tim_period - 1;
2854138568Ssam		else
2855138568Ssam			tie->tim_count--;
2856138568Ssam		/* update state for buffered multicast frames on DTIM */
2857153139Ssam		if (mcast && tie->tim_count == 0)
2858138568Ssam			tie->tim_bitctl |= 1;
2859138568Ssam		else
2860138568Ssam			tie->tim_bitctl &= ~1;
2861178354Ssam		if (isset(bo->bo_flags, IEEE80211_BEACON_CSA)) {
2862178354Ssam			struct ieee80211_csa_ie *csa =
2863178354Ssam			    (struct ieee80211_csa_ie *) bo->bo_csa;
2864178354Ssam
2865178354Ssam			/*
2866178354Ssam			 * Insert or update CSA ie.  If we're just starting
2867178354Ssam			 * to count down to the channel switch then we need
2868178354Ssam			 * to insert the CSA ie.  Otherwise we just need to
2869178354Ssam			 * drop the count.  The actual change happens above
2870178354Ssam			 * when the vap's count reaches the target count.
2871178354Ssam			 */
2872178354Ssam			if (vap->iv_csa_count == 0) {
2873178354Ssam				memmove(&csa[1], csa, bo->bo_csa_trailer_len);
2874178354Ssam				bo->bo_erp += sizeof(*csa);
2875178354Ssam				bo->bo_wme += sizeof(*csa);
2876178354Ssam				bo->bo_appie += sizeof(*csa);
2877178354Ssam				bo->bo_csa_trailer_len += sizeof(*csa);
2878178354Ssam				bo->bo_tim_trailer_len += sizeof(*csa);
2879178354Ssam				m->m_len += sizeof(*csa);
2880178354Ssam				m->m_pkthdr.len += sizeof(*csa);
2881178354Ssam
2882178354Ssam				ieee80211_add_csa(bo->bo_csa, vap);
2883178354Ssam			} else
2884178354Ssam				csa->csa_count--;
2885178354Ssam			vap->iv_csa_count++;
2886178354Ssam			/* NB: don't clear IEEE80211_BEACON_CSA */
2887178354Ssam		}
2888172211Ssam		if (isset(bo->bo_flags, IEEE80211_BEACON_ERP)) {
2889153973Ssam			/*
2890153973Ssam			 * ERP element needs updating.
2891153973Ssam			 */
2892153973Ssam			(void) ieee80211_add_erp(bo->bo_erp, ic);
2893172211Ssam			clrbit(bo->bo_flags, IEEE80211_BEACON_ERP);
2894153973Ssam		}
2895138568Ssam	}
2896178354Ssam	if (isset(bo->bo_flags, IEEE80211_BEACON_APPIE)) {
2897178354Ssam		const struct ieee80211_appie *aie = vap->iv_appie_beacon;
2898178354Ssam		int aielen;
2899178354Ssam		uint8_t *frm;
2900138568Ssam
2901178354Ssam		aielen = 0;
2902178354Ssam		if (aie != NULL)
2903178354Ssam			aielen += aie->ie_len;
2904178354Ssam		if (aielen != bo->bo_appie_len) {
2905178354Ssam			/* copy up/down trailer */
2906178354Ssam			int adjust = aielen - bo->bo_appie_len;
2907178354Ssam			ovbcopy(bo->bo_tim_trailer, bo->bo_tim_trailer+adjust,
2908178354Ssam				bo->bo_tim_trailer_len);
2909178354Ssam			bo->bo_tim_trailer += adjust;
2910178354Ssam			bo->bo_appie += adjust;
2911178354Ssam			bo->bo_appie_len = aielen;
2912178354Ssam
2913178354Ssam			len_changed = 1;
2914178354Ssam		}
2915178354Ssam		frm = bo->bo_appie;
2916178354Ssam		if (aie != NULL)
2917178354Ssam			frm  = add_appie(frm, aie);
2918178354Ssam		clrbit(bo->bo_flags, IEEE80211_BEACON_APPIE);
2919178354Ssam	}
2920178354Ssam	IEEE80211_UNLOCK(ic);
2921178354Ssam
2922138568Ssam	return len_changed;
2923138568Ssam}
2924