ieee80211.c revision 178703
1238104Sdes/*-
2238104Sdes * Copyright (c) 2001 Atsushi Onoe
3238104Sdes * Copyright (c) 2002-2008 Sam Leffler, Errno Consulting
4238104Sdes * All rights reserved.
5238104Sdes *
6238104Sdes * Redistribution and use in source and binary forms, with or without
7238104Sdes * modification, are permitted provided that the following conditions
8238104Sdes * are met:
9238104Sdes * 1. Redistributions of source code must retain the above copyright
10238104Sdes *    notice, this list of conditions and the following disclaimer.
11238104Sdes * 2. Redistributions in binary form must reproduce the above copyright
12238104Sdes *    notice, this list of conditions and the following disclaimer in the
13238104Sdes *    documentation and/or other materials provided with the distribution.
14238104Sdes *
15238104Sdes * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
16238104Sdes * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
17238104Sdes * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
18238104Sdes * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
19238104Sdes * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
20238104Sdes * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
21238104Sdes * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
22238104Sdes * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
23238104Sdes * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
24238104Sdes * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
25238104Sdes */
26238104Sdes
27238104Sdes#include <sys/cdefs.h>
28238104Sdes__FBSDID("$FreeBSD: head/sys/net80211/ieee80211.c 178703 2008-05-01 03:49:59Z sam $");
29238104Sdes
30238104Sdes/*
31238104Sdes * IEEE 802.11 generic handler
32238104Sdes */
33238104Sdes#include "opt_wlan.h"
34238104Sdes
35238104Sdes#include <sys/param.h>
36269257Sdes#include <sys/systm.h>
37238104Sdes#include <sys/kernel.h>
38238104Sdes
39238104Sdes#include <sys/socket.h>
40238104Sdes
41238104Sdes#include <net/if.h>
42238104Sdes#include <net/if_dl.h>
43238104Sdes#include <net/if_media.h>
44238104Sdes#include <net/if_types.h>
45238104Sdes#include <net/ethernet.h>
46238104Sdes
47238104Sdes#include <net80211/ieee80211_var.h>
48238104Sdes#include <net80211/ieee80211_regdomain.h>
49238104Sdes
50238104Sdes#include <net/bpf.h>
51246854Sdes
52246854Sdesconst char *ieee80211_phymode_name[] = {
53246854Sdes	"auto",		/* IEEE80211_MODE_AUTO */
54246854Sdes	"11a",		/* IEEE80211_MODE_11A */
55246854Sdes	"11b",		/* IEEE80211_MODE_11B */
56246854Sdes	"11g",		/* IEEE80211_MODE_11G */
57246854Sdes	"FH",		/* IEEE80211_MODE_FH */
58246854Sdes	"turboA",	/* IEEE80211_MODE_TURBO_A */
59246854Sdes	"turboG",	/* IEEE80211_MODE_TURBO_G */
60246854Sdes	"sturboA",	/* IEEE80211_MODE_STURBO_A */
61238104Sdes	"11na",		/* IEEE80211_MODE_11NA */
62238104Sdes	"11ng",		/* IEEE80211_MODE_11NG */
63238104Sdes};
64238104Sdesstatic const uint8_t ieee80211broadcastaddr[IEEE80211_ADDR_LEN] =
65238104Sdes	{ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff };
66238104Sdes
67246854Sdesstatic	void ieee80211_syncflag_locked(struct ieee80211com *ic, int flag);
68238104Sdesstatic	void ieee80211_syncflag_ext_locked(struct ieee80211com *ic, int flag);
69246854Sdesstatic	int ieee80211_media_setup(struct ieee80211com *ic,
70238104Sdes		struct ifmedia *media, int caps, int addsta,
71238104Sdes		ifm_change_cb_t media_change, ifm_stat_cb_t media_stat);
72238104Sdesstatic	void ieee80211com_media_status(struct ifnet *, struct ifmediareq *);
73238104Sdesstatic	int ieee80211com_media_change(struct ifnet *);
74238104Sdesstatic	int media_status(enum ieee80211_opmode,
75238104Sdes		const struct ieee80211_channel *);
76238104Sdes
77238104SdesMALLOC_DEFINE(M_80211_VAP, "80211vap", "802.11 vap state");
78238104Sdes
79238104Sdes/*
80238104Sdes * Default supported rates for 802.11 operation (in IEEE .5Mb units).
81238104Sdes */
82238104Sdes#define	B(r)	((r) | IEEE80211_RATE_BASIC)
83238104Sdesstatic const struct ieee80211_rateset ieee80211_rateset_11a =
84238104Sdes	{ 8, { B(12), 18, B(24), 36, B(48), 72, 96, 108 } };
85238104Sdesstatic const struct ieee80211_rateset ieee80211_rateset_half =
86238104Sdes	{ 8, { B(6), 9, B(12), 18, B(24), 36, 48, 54 } };
87238104Sdesstatic const struct ieee80211_rateset ieee80211_rateset_quarter =
88238104Sdes	{ 8, { B(3), 4, B(6), 9, B(12), 18, 24, 27 } };
89238104Sdesstatic const struct ieee80211_rateset ieee80211_rateset_11b =
90238104Sdes	{ 4, { B(2), B(4), B(11), B(22) } };
91238104Sdes/* NB: OFDM rates are handled specially based on mode */
92238104Sdesstatic const struct ieee80211_rateset ieee80211_rateset_11g =
93238104Sdes	{ 12, { B(2), B(4), B(11), B(22), 12, 18, 24, 36, 48, 72, 96, 108 } };
94238104Sdes#undef B
95238104Sdes
96238104Sdes/*
97238104Sdes * Fill in 802.11 available channel set, mark
98238104Sdes * all available channels as active, and pick
99238104Sdes * a default channel if not already specified.
100238104Sdes */
101238104Sdesstatic void
102238104Sdesieee80211_chan_init(struct ieee80211com *ic)
103238104Sdes{
104238104Sdes#define	DEFAULTRATES(m, def) do { \
105238104Sdes	if (isset(ic->ic_modecaps, m) && ic->ic_sup_rates[m].rs_nrates == 0) \
106238104Sdes		ic->ic_sup_rates[m] = def; \
107269257Sdes} while (0)
108238104Sdes	struct ieee80211_channel *c;
109238104Sdes	int i;
110238104Sdes
111238104Sdes	KASSERT(0 < ic->ic_nchans && ic->ic_nchans < IEEE80211_CHAN_MAX,
112238104Sdes		("invalid number of channels specified: %u", ic->ic_nchans));
113238104Sdes	memset(ic->ic_chan_avail, 0, sizeof(ic->ic_chan_avail));
114238104Sdes	memset(ic->ic_modecaps, 0, sizeof(ic->ic_modecaps));
115269257Sdes	setbit(ic->ic_modecaps, IEEE80211_MODE_AUTO);
116238104Sdes	for (i = 0; i < ic->ic_nchans; i++) {
117238104Sdes		c = &ic->ic_channels[i];
118238104Sdes		KASSERT(c->ic_flags != 0, ("channel with no flags"));
119238104Sdes		KASSERT(c->ic_ieee < IEEE80211_CHAN_MAX,
120238104Sdes			("channel with bogus ieee number %u", c->ic_ieee));
121238104Sdes		setbit(ic->ic_chan_avail, c->ic_ieee);
122238104Sdes		/*
123238104Sdes		 * Identify mode capabilities.
124238104Sdes		 */
125238104Sdes		if (IEEE80211_IS_CHAN_A(c))
126238104Sdes			setbit(ic->ic_modecaps, IEEE80211_MODE_11A);
127238104Sdes		if (IEEE80211_IS_CHAN_B(c))
128238104Sdes			setbit(ic->ic_modecaps, IEEE80211_MODE_11B);
129238104Sdes		if (IEEE80211_IS_CHAN_ANYG(c))
130238104Sdes			setbit(ic->ic_modecaps, IEEE80211_MODE_11G);
131238104Sdes		if (IEEE80211_IS_CHAN_FHSS(c))
132238104Sdes			setbit(ic->ic_modecaps, IEEE80211_MODE_FH);
133238104Sdes		if (IEEE80211_IS_CHAN_108A(c))
134238104Sdes			setbit(ic->ic_modecaps, IEEE80211_MODE_TURBO_A);
135238104Sdes		if (IEEE80211_IS_CHAN_108G(c))
136238104Sdes			setbit(ic->ic_modecaps, IEEE80211_MODE_TURBO_G);
137238104Sdes		if (IEEE80211_IS_CHAN_ST(c))
138238104Sdes			setbit(ic->ic_modecaps, IEEE80211_MODE_STURBO_A);
139238104Sdes		if (IEEE80211_IS_CHAN_HTA(c))
140238104Sdes			setbit(ic->ic_modecaps, IEEE80211_MODE_11NA);
141238104Sdes		if (IEEE80211_IS_CHAN_HTG(c))
142238104Sdes			setbit(ic->ic_modecaps, IEEE80211_MODE_11NG);
143238104Sdes	}
144238104Sdes	/* initialize candidate channels to all available */
145238104Sdes	memcpy(ic->ic_chan_active, ic->ic_chan_avail,
146238104Sdes		sizeof(ic->ic_chan_avail));
147238104Sdes
148238104Sdes	/* sort channel table to allow lookup optimizations */
149238104Sdes	ieee80211_sort_channels(ic->ic_channels, ic->ic_nchans);
150238104Sdes
151238104Sdes	/* invalidate any previous state */
152238104Sdes	ic->ic_bsschan = IEEE80211_CHAN_ANYC;
153238104Sdes	ic->ic_prevchan = NULL;
154238104Sdes	ic->ic_csa_newchan = NULL;
155238104Sdes	/* arbitrarily pick the first channel */
156238104Sdes	ic->ic_curchan = &ic->ic_channels[0];
157238104Sdes
158238104Sdes	/* fillin well-known rate sets if driver has not specified */
159238104Sdes	DEFAULTRATES(IEEE80211_MODE_11B,	 ieee80211_rateset_11b);
160238104Sdes	DEFAULTRATES(IEEE80211_MODE_11G,	 ieee80211_rateset_11g);
161238104Sdes	DEFAULTRATES(IEEE80211_MODE_11A,	 ieee80211_rateset_11a);
162238104Sdes	DEFAULTRATES(IEEE80211_MODE_TURBO_A,	 ieee80211_rateset_11a);
163269257Sdes	DEFAULTRATES(IEEE80211_MODE_TURBO_G,	 ieee80211_rateset_11g);
164238104Sdes
165238104Sdes	/*
166238104Sdes	 * Set auto mode to reset active channel state and any desired channel.
167238104Sdes	 */
168238104Sdes	(void) ieee80211_setmode(ic, IEEE80211_MODE_AUTO);
169238104Sdes#undef DEFAULTRATES
170238104Sdes}
171238104Sdes
172238104Sdesstatic void
173238104Sdesnull_update_mcast(struct ifnet *ifp)
174238104Sdes{
175238104Sdes	if_printf(ifp, "need multicast update callback\n");
176238104Sdes}
177238104Sdes
178238104Sdesstatic void
179238104Sdesnull_update_promisc(struct ifnet *ifp)
180238104Sdes{
181238104Sdes	if_printf(ifp, "need promiscuous mode update callback\n");
182238104Sdes}
183238104Sdes
184238104Sdesstatic int
185238104Sdesnull_output(struct ifnet *ifp, struct mbuf *m,
186238104Sdes	struct sockaddr *dst, struct rtentry *rt0)
187238104Sdes{
188238104Sdes	if_printf(ifp, "discard raw packet\n");
189238104Sdes	m_freem(m);
190238104Sdes	return EIO;
191238104Sdes}
192238104Sdes
193238104Sdesstatic void
194238104Sdesnull_input(struct ifnet *ifp, struct mbuf *m)
195238104Sdes{
196238104Sdes	if_printf(ifp, "if_input should not be called\n");
197238104Sdes	m_freem(m);
198238104Sdes}
199238104Sdes
200238104Sdes/*
201269257Sdes * Attach/setup the common net80211 state.  Called by
202238104Sdes * the driver on attach to prior to creating any vap's.
203238104Sdes */
204238104Sdesvoid
205238104Sdesieee80211_ifattach(struct ieee80211com *ic)
206238104Sdes{
207238104Sdes	struct ifnet *ifp = ic->ic_ifp;
208238104Sdes	struct sockaddr_dl *sdl;
209238104Sdes	struct ifaddr *ifa;
210238104Sdes
211238104Sdes	KASSERT(ifp->if_type == IFT_IEEE80211, ("if_type %d", ifp->if_type));
212238104Sdes
213238104Sdes	IEEE80211_LOCK_INIT(ic, "ieee80211com");
214269257Sdes	TAILQ_INIT(&ic->ic_vaps);
215238104Sdes	/*
216238104Sdes	 * Fill in 802.11 available channel set, mark all
217238104Sdes	 * available channels as active, and pick a default
218238104Sdes	 * channel if not already specified.
219238104Sdes	 */
220238104Sdes	ieee80211_media_init(ic);
221238104Sdes
222238104Sdes	ic->ic_update_mcast = null_update_mcast;
223238104Sdes	ic->ic_update_promisc = null_update_promisc;
224238104Sdes
225238104Sdes	ic->ic_bintval = IEEE80211_BINTVAL_DEFAULT;
226238104Sdes	ic->ic_lintval = ic->ic_bintval;
227238104Sdes	ic->ic_txpowlimit = IEEE80211_TXPOWER_MAX;
228238104Sdes
229238104Sdes	ieee80211_crypto_attach(ic);
230238104Sdes	ieee80211_node_attach(ic);
231238104Sdes	ieee80211_power_attach(ic);
232238104Sdes	ieee80211_proto_attach(ic);
233238104Sdes	ieee80211_ht_attach(ic);
234238104Sdes	ieee80211_scan_attach(ic);
235238104Sdes	ieee80211_regdomain_attach(ic);
236238104Sdes
237238104Sdes	ieee80211_sysctl_attach(ic);
238238104Sdes
239238104Sdes	ifp->if_addrlen = IEEE80211_ADDR_LEN;
240238104Sdes	ifp->if_hdrlen = 0;
241238104Sdes	if_attach(ifp);
242238104Sdes	ifp->if_mtu = IEEE80211_MTU_MAX;
243238104Sdes	ifp->if_broadcastaddr = ieee80211broadcastaddr;
244238104Sdes	ifp->if_output = null_output;
245238104Sdes	ifp->if_input = null_input;	/* just in case */
246238104Sdes	ifp->if_resolvemulti = NULL;	/* NB: callers check */
247238104Sdes
248238104Sdes	ifa = ifaddr_byindex(ifp->if_index);
249238104Sdes	KASSERT(ifa != NULL, ("%s: no lladdr!\n", __func__));
250238104Sdes	sdl = (struct sockaddr_dl *)ifa->ifa_addr;
251238104Sdes	sdl->sdl_type = IFT_ETHER;		/* XXX IFT_IEEE80211? */
252238104Sdes	sdl->sdl_alen = IEEE80211_ADDR_LEN;
253238104Sdes	IEEE80211_ADDR_COPY(LLADDR(sdl), ic->ic_myaddr);
254238104Sdes}
255238104Sdes
256238104Sdes/*
257238104Sdes * Detach net80211 state on device detach.  Tear down
258238104Sdes * all vap's and reclaim all common state prior to the
259238104Sdes * device state going away.  Note we may call back into
260238104Sdes * driver; it must be prepared for this.
261238104Sdes */
262238104Sdesvoid
263238104Sdesieee80211_ifdetach(struct ieee80211com *ic)
264238104Sdes{
265238104Sdes	struct ifnet *ifp = ic->ic_ifp;
266238104Sdes	struct ieee80211vap *vap;
267238104Sdes
268238104Sdes	/* XXX ieee80211_stop_all? */
269238104Sdes	while ((vap = TAILQ_FIRST(&ic->ic_vaps)) != NULL)
270238104Sdes		ieee80211_vap_destroy(vap);
271238104Sdes
272238104Sdes	ieee80211_sysctl_detach(ic);
273238104Sdes	ieee80211_regdomain_detach(ic);
274238104Sdes	ieee80211_scan_detach(ic);
275238104Sdes	ieee80211_ht_detach(ic);
276238104Sdes	/* NB: must be called before ieee80211_node_detach */
277238104Sdes	ieee80211_proto_detach(ic);
278238104Sdes	ieee80211_crypto_detach(ic);
279238104Sdes	ieee80211_power_detach(ic);
280238104Sdes	ieee80211_node_detach(ic);
281238104Sdes	ifmedia_removeall(&ic->ic_media);
282238104Sdes
283238104Sdes	IEEE80211_LOCK_DESTROY(ic);
284246854Sdes	if_detach(ifp);
285246854Sdes}
286238104Sdes
287238104Sdes/*
288238104Sdes * Default reset method for use with the ioctl support.  This
289238104Sdes * method is invoked after any state change in the 802.11
290238104Sdes * layer that should be propagated to the hardware but not
291238104Sdes * require re-initialization of the 802.11 state machine (e.g
292238104Sdes * rescanning for an ap).  We always return ENETRESET which
293238104Sdes * should cause the driver to re-initialize the device. Drivers
294238104Sdes * can override this method to implement more optimized support.
295238104Sdes */
296238104Sdesstatic int
297238104Sdesdefault_reset(struct ieee80211vap *vap, u_long cmd)
298238104Sdes{
299238104Sdes	return ENETRESET;
300238104Sdes}
301238104Sdes
302238104Sdes/*
303238104Sdes * Prepare a vap for use.  Drivers use this call to
304238104Sdes * setup net80211 state in new vap's prior attaching
305238104Sdes * them with ieee80211_vap_attach (below).
306238104Sdes */
307238104Sdesint
308238104Sdesieee80211_vap_setup(struct ieee80211com *ic, struct ieee80211vap *vap,
309238104Sdes	const char name[IFNAMSIZ], int unit, int opmode, int flags,
310238104Sdes	const uint8_t bssid[IEEE80211_ADDR_LEN],
311238104Sdes	const uint8_t macaddr[IEEE80211_ADDR_LEN])
312238104Sdes{
313238104Sdes#define	IEEE80211_C_OPMODE \
314238104Sdes	(IEEE80211_C_IBSS | IEEE80211_C_HOSTAP | IEEE80211_C_AHDEMO | \
315238104Sdes	 IEEE80211_C_MONITOR | IEEE80211_C_WDS)
316238104Sdes	struct ifnet *ifp;
317238104Sdes
318238104Sdes	ifp = if_alloc(IFT_ETHER);
319238104Sdes	if (ifp == NULL) {
320238104Sdes		if_printf(ic->ic_ifp, "%s: unable to allocate ifnet\n",
321238104Sdes		    __func__);
322238104Sdes		return ENOMEM;
323238104Sdes	}
324238104Sdes	if_initname(ifp, name, unit);
325238104Sdes	ifp->if_softc = vap;			/* back pointer */
326238104Sdes	ifp->if_flags = IFF_SIMPLEX | IFF_BROADCAST | IFF_MULTICAST;
327238104Sdes	ifp->if_start = ieee80211_start;
328238104Sdes	ifp->if_ioctl = ieee80211_ioctl;
329238104Sdes	ifp->if_watchdog = NULL;		/* NB: no watchdog routine */
330238104Sdes	ifp->if_init = ieee80211_init;
331238104Sdes	/* NB: input+output filled in by ether_ifattach */
332238104Sdes	IFQ_SET_MAXLEN(&ifp->if_snd, IFQ_MAXLEN);
333238104Sdes	ifp->if_snd.ifq_drv_maxlen = IFQ_MAXLEN;
334238104Sdes	IFQ_SET_READY(&ifp->if_snd);
335238104Sdes
336238104Sdes	vap->iv_ifp = ifp;
337238104Sdes	vap->iv_ic = ic;
338238104Sdes	vap->iv_flags = ic->ic_flags;		/* propagate common flags */
339238104Sdes	vap->iv_flags_ext = ic->ic_flags_ext;
340238104Sdes	vap->iv_flags_ven = ic->ic_flags_ven;
341238104Sdes	vap->iv_caps = ic->ic_caps &~ IEEE80211_C_OPMODE;
342238104Sdes	vap->iv_htcaps = ic->ic_htcaps;
343238104Sdes	vap->iv_opmode = opmode;
344238104Sdes	switch (opmode) {
345238104Sdes	case IEEE80211_M_STA:
346238104Sdes		/* auto-enable s/w beacon miss support */
347238104Sdes		if (flags & IEEE80211_CLONE_NOBEACONS)
348238104Sdes			vap->iv_flags_ext |= IEEE80211_FEXT_SWBMISS;
349238104Sdes		break;
350238104Sdes	case IEEE80211_M_IBSS:
351238104Sdes		vap->iv_caps |= IEEE80211_C_IBSS;
352238104Sdes		break;
353238104Sdes	case IEEE80211_M_AHDEMO:
354238104Sdes		vap->iv_caps |= IEEE80211_C_AHDEMO;
355238104Sdes		break;
356238104Sdes	case IEEE80211_M_HOSTAP:
357238104Sdes		vap->iv_caps |= IEEE80211_C_HOSTAP;
358238104Sdes		break;
359238104Sdes	case IEEE80211_M_MONITOR:
360238104Sdes		vap->iv_caps |= IEEE80211_C_MONITOR;
361238104Sdes		break;
362238104Sdes	case IEEE80211_M_WDS:
363238104Sdes		vap->iv_caps |= IEEE80211_C_WDS;
364238104Sdes		/*
365238104Sdes		 * WDS links must specify the bssid of the far end.
366238104Sdes		 * For legacy operation this is a static relationship.
367238104Sdes		 * For non-legacy operation the station must associate
368238104Sdes		 * and be authorized to pass traffic.  Plumbing the
369238104Sdes		 * vap to the proper node happens when the vap
370238104Sdes		 * transitions to RUN state.
371238104Sdes		 */
372238104Sdes		IEEE80211_ADDR_COPY(vap->iv_des_bssid, bssid);
373238104Sdes		vap->iv_flags |= IEEE80211_F_DESBSSID;
374238104Sdes		if (flags & IEEE80211_CLONE_WDSLEGACY)
375238104Sdes			vap->iv_flags_ext |= IEEE80211_FEXT_WDSLEGACY;
376238104Sdes		break;
377238104Sdes	}
378238104Sdes	/*
379238104Sdes	 * Enable various functionality by default if we're
380238104Sdes	 * capable; the driver can override us if it knows better.
381238104Sdes	 */
382238104Sdes	if (vap->iv_caps & IEEE80211_C_WME)
383238104Sdes		vap->iv_flags |= IEEE80211_F_WME;
384238104Sdes	if (vap->iv_caps & IEEE80211_C_BURST)
385238104Sdes		vap->iv_flags |= IEEE80211_F_BURST;
386238104Sdes	if (vap->iv_caps & IEEE80211_C_FF)
387238104Sdes		vap->iv_flags |= IEEE80211_F_FF;
388238104Sdes	if (vap->iv_caps & IEEE80211_C_TURBOP)
389238104Sdes		vap->iv_flags |= IEEE80211_F_TURBOP;
390238104Sdes	/* NB: bg scanning only makes sense for station mode right now */
391238104Sdes	if (vap->iv_opmode == IEEE80211_M_STA &&
392238104Sdes	    (vap->iv_caps & IEEE80211_C_BGSCAN))
393238104Sdes		vap->iv_flags |= IEEE80211_F_BGSCAN;
394238104Sdes	vap->iv_flags |= IEEE80211_F_DOTH;	/* XXX out of caps, just ena */
395238104Sdes	/* XXX out of caps, just ena */
396238104Sdes	if (vap->iv_opmode == IEEE80211_M_HOSTAP)
397238104Sdes		vap->iv_flags_ext |= IEEE80211_FEXT_DFS;
398238104Sdes
399238104Sdes	vap->iv_des_chan = IEEE80211_CHAN_ANYC;		/* any channel is ok */
400238104Sdes	vap->iv_bmissthreshold = IEEE80211_HWBMISS_DEFAULT;
401238104Sdes	vap->iv_dtim_period = IEEE80211_DTIM_DEFAULT;
402238104Sdes	/*
403238104Sdes	 * Install a default reset method for the ioctl support;
404238104Sdes	 * the driver can override this.
405238104Sdes	 */
406238104Sdes	vap->iv_reset = default_reset;
407238104Sdes
408238104Sdes	IEEE80211_ADDR_COPY(vap->iv_myaddr, macaddr);
409238104Sdes
410246854Sdes	ieee80211_sysctl_vattach(vap);
411246854Sdes	ieee80211_crypto_vattach(vap);
412246854Sdes	ieee80211_node_vattach(vap);
413246854Sdes	ieee80211_power_vattach(vap);
414246854Sdes	ieee80211_proto_vattach(vap);
415246854Sdes	ieee80211_ht_vattach(vap);
416246854Sdes	ieee80211_scan_vattach(vap);
417246854Sdes	ieee80211_regdomain_vattach(vap);
418246854Sdes
419238104Sdes	return 0;
420238104Sdes#undef IEEE80211_C_OPMODE
421238104Sdes}
422238104Sdes
423238104Sdes/*
424238104Sdes * Activate a vap.  State should have been prepared with a
425238104Sdes * call to ieee80211_vap_setup and by the driver.  On return
426238104Sdes * from this call the vap is ready for use.
427238104Sdes */
428238104Sdesint
429238104Sdesieee80211_vap_attach(struct ieee80211vap *vap,
430238104Sdes	ifm_change_cb_t media_change, ifm_stat_cb_t media_stat)
431238104Sdes{
432238104Sdes	struct ifnet *ifp = vap->iv_ifp;
433238104Sdes	struct ieee80211com *ic = vap->iv_ic;
434238104Sdes	struct ifmediareq imr;
435238104Sdes	int maxrate;
436238104Sdes
437238104Sdes	IEEE80211_DPRINTF(vap, IEEE80211_MSG_STATE,
438238104Sdes	    "%s: %s parent %s flags 0x%x flags_ext 0x%x\n",
439238104Sdes	    __func__, ieee80211_opmode_name[vap->iv_opmode],
440238104Sdes	    ic->ic_ifp->if_xname, vap->iv_flags, vap->iv_flags_ext);
441238104Sdes
442238104Sdes	/*
443238104Sdes	 * Do late attach work that cannot happen until after
444238104Sdes	 * the driver has had a chance to override defaults.
445238104Sdes	 */
446238104Sdes	ieee80211_node_latevattach(vap);
447238104Sdes	ieee80211_power_latevattach(vap);
448238104Sdes
449238104Sdes	maxrate = ieee80211_media_setup(ic, &vap->iv_media, vap->iv_caps,
450238104Sdes	    vap->iv_opmode == IEEE80211_M_STA, media_change, media_stat);
451238104Sdes	ieee80211_media_status(ifp, &imr);
452238104Sdes	/* NB: strip explicit mode; we're actually in autoselect */
453238104Sdes	ifmedia_set(&vap->iv_media, imr.ifm_active &~ IFM_MMASK);
454238104Sdes	if (maxrate)
455238104Sdes		ifp->if_baudrate = IF_Mbps(maxrate);
456238104Sdes
457238104Sdes	ether_ifattach(ifp, vap->iv_myaddr);
458238104Sdes	/* hook output method setup by ether_ifattach */
459238104Sdes	vap->iv_output = ifp->if_output;
460238104Sdes	ifp->if_output = ieee80211_output;
461238104Sdes	/* NB: if_mtu set by ether_ifattach to ETHERMTU */
462238104Sdes	bpfattach2(ifp, DLT_IEEE802_11, ifp->if_hdrlen, &vap->iv_rawbpf);
463238104Sdes
464238104Sdes	IEEE80211_LOCK(ic);
465238104Sdes	TAILQ_INSERT_TAIL(&ic->ic_vaps, vap, iv_next);
466238104Sdes	ieee80211_syncflag_locked(ic, IEEE80211_F_WME);
467238104Sdes	ieee80211_syncflag_locked(ic, IEEE80211_F_TURBOP);
468238104Sdes	ieee80211_syncflag_locked(ic, IEEE80211_F_PCF);
469238104Sdes	ieee80211_syncflag_locked(ic, IEEE80211_F_BURST);
470238104Sdes	ieee80211_syncflag_ext_locked(ic, IEEE80211_FEXT_HT);
471238104Sdes	ieee80211_syncflag_ext_locked(ic, IEEE80211_FEXT_USEHT40);
472238104Sdes	ieee80211_syncifflag_locked(ic, IFF_PROMISC);
473238104Sdes	ieee80211_syncifflag_locked(ic, IFF_ALLMULTI);
474238104Sdes	IEEE80211_UNLOCK(ic);
475238104Sdes
476238104Sdes	return 1;
477238104Sdes}
478238104Sdes
479238104Sdes/*
480238104Sdes * Tear down vap state and reclaim the ifnet.
481238104Sdes * The driver is assumed to have prepared for
482238104Sdes * this; e.g. by turning off interrupts for the
483238104Sdes * underlying device.
484238104Sdes */
485238104Sdesvoid
486238104Sdesieee80211_vap_detach(struct ieee80211vap *vap)
487238104Sdes{
488269257Sdes	struct ieee80211com *ic = vap->iv_ic;
489269257Sdes	struct ifnet *ifp = vap->iv_ifp;
490269257Sdes
491269257Sdes	IEEE80211_DPRINTF(vap, IEEE80211_MSG_STATE, "%s: %s parent %s\n",
492269257Sdes	    __func__, ieee80211_opmode_name[vap->iv_opmode],
493269257Sdes	    ic->ic_ifp->if_xname);
494269257Sdes
495269257Sdes	IEEE80211_LOCK(ic);
496238104Sdes	/* block traffic from above */
497238104Sdes	ifp->if_drv_flags |= IFF_DRV_OACTIVE;
498238104Sdes	/*
499238104Sdes	 * Evil hack.  Clear the backpointer from the ifnet to the
500238104Sdes	 * vap so any requests from above will return an error or
501238104Sdes	 * be ignored.  In particular this short-circuits requests
502238104Sdes	 * by the bridge to turn off promiscuous mode as a result
503238104Sdes	 * of calling ether_ifdetach.
504238104Sdes	 */
505238104Sdes	ifp->if_softc = NULL;
506238104Sdes	/*
507238104Sdes	 * Stop the vap before detaching the ifnet.  Ideally we'd
508238104Sdes	 * do this in the other order so the ifnet is inaccessible
509238104Sdes	 * while we cleanup internal state but that is hard.
510238104Sdes	 */
511238104Sdes	ieee80211_stop_locked(vap);
512238104Sdes
513238104Sdes	/* XXX accumulate iv_stats in ic_stats? */
514238104Sdes	TAILQ_REMOVE(&ic->ic_vaps, vap, iv_next);
515238104Sdes	ieee80211_syncflag_locked(ic, IEEE80211_F_WME);
516238104Sdes	ieee80211_syncflag_locked(ic, IEEE80211_F_TURBOP);
517238104Sdes	ieee80211_syncflag_locked(ic, IEEE80211_F_PCF);
518238104Sdes	ieee80211_syncflag_locked(ic, IEEE80211_F_BURST);
519238104Sdes	ieee80211_syncflag_ext_locked(ic, IEEE80211_FEXT_HT);
520238104Sdes	ieee80211_syncflag_ext_locked(ic, IEEE80211_FEXT_USEHT40);
521238104Sdes	ieee80211_syncifflag_locked(ic, IFF_PROMISC);
522238104Sdes	ieee80211_syncifflag_locked(ic, IFF_ALLMULTI);
523238104Sdes	IEEE80211_UNLOCK(ic);
524238104Sdes
525238104Sdes	/* XXX can't hold com lock */
526238104Sdes	/* NB: bpfattach is called by ether_ifdetach and claims all taps */
527269257Sdes	ether_ifdetach(ifp);
528238104Sdes
529238104Sdes	ifmedia_removeall(&vap->iv_media);
530238104Sdes
531238104Sdes	ieee80211_regdomain_vdetach(vap);
532238104Sdes	ieee80211_scan_vdetach(vap);
533238104Sdes	ieee80211_ht_vdetach(vap);
534238104Sdes	/* NB: must be before ieee80211_node_vdetach */
535238104Sdes	ieee80211_proto_vdetach(vap);
536238104Sdes	ieee80211_crypto_vdetach(vap);
537238104Sdes	ieee80211_power_vdetach(vap);
538238104Sdes	ieee80211_node_vdetach(vap);
539238104Sdes	ieee80211_sysctl_vdetach(vap);
540238104Sdes}
541238104Sdes
542238104Sdes/*
543238104Sdes * Synchronize flag bit state in the parent ifnet structure
544238104Sdes * according to the state of all vap ifnet's.  This is used,
545238104Sdes * for example, to handle IFF_PROMISC and IFF_ALLMULTI.
546238104Sdes */
547238104Sdesvoid
548238104Sdesieee80211_syncifflag_locked(struct ieee80211com *ic, int flag)
549238104Sdes{
550238104Sdes	struct ifnet *ifp = ic->ic_ifp;
551238104Sdes	struct ieee80211vap *vap;
552238104Sdes	int bit, oflags;
553238104Sdes
554238104Sdes	IEEE80211_LOCK_ASSERT(ic);
555238104Sdes
556238104Sdes	bit = 0;
557238104Sdes	TAILQ_FOREACH(vap, &ic->ic_vaps, iv_next)
558269257Sdes		if (vap->iv_ifp->if_flags & flag) {
559238104Sdes			/*
560238104Sdes			 * XXX the bridge sets PROMISC but we don't want to
561238104Sdes			 * enable it on the device, discard here so all the
562238104Sdes			 * drivers don't need to special-case it
563238104Sdes			 */
564238104Sdes			if (flag == IFF_PROMISC &&
565238104Sdes			    vap->iv_opmode == IEEE80211_M_HOSTAP)
566238104Sdes				continue;
567238104Sdes			bit = 1;
568238104Sdes			break;
569238104Sdes		}
570238104Sdes	oflags = ifp->if_flags;
571238104Sdes	if (bit)
572238104Sdes		ifp->if_flags |= flag;
573238104Sdes	else
574238104Sdes		ifp->if_flags &= ~flag;
575238104Sdes	if ((ifp->if_flags ^ oflags) & flag) {
576238104Sdes		/* XXX should we return 1/0 and let caller do this? */
577238104Sdes		if (ifp->if_drv_flags & IFF_DRV_RUNNING) {
578238104Sdes			if (flag == IFF_PROMISC)
579238104Sdes				ic->ic_update_promisc(ifp);
580238104Sdes			else if (flag == IFF_ALLMULTI)
581238104Sdes				ic->ic_update_mcast(ifp);
582238104Sdes		}
583238104Sdes	}
584238104Sdes}
585238104Sdes
586238104Sdes/*
587238104Sdes * Synchronize flag bit state in the com structure
588238104Sdes * according to the state of all vap's.  This is used,
589238104Sdes * for example, to handle state changes via ioctls.
590238104Sdes */
591238104Sdesstatic void
592238104Sdesieee80211_syncflag_locked(struct ieee80211com *ic, int flag)
593238104Sdes{
594238104Sdes	struct ieee80211vap *vap;
595238104Sdes	int bit;
596238104Sdes
597238104Sdes	IEEE80211_LOCK_ASSERT(ic);
598238104Sdes
599238104Sdes	bit = 0;
600238104Sdes	TAILQ_FOREACH(vap, &ic->ic_vaps, iv_next)
601238104Sdes		if (vap->iv_flags & flag) {
602238104Sdes			bit = 1;
603238104Sdes			break;
604238104Sdes		}
605238104Sdes	if (bit)
606238104Sdes		ic->ic_flags |= flag;
607238104Sdes	else
608238104Sdes		ic->ic_flags &= ~flag;
609238104Sdes}
610238104Sdes
611238104Sdesvoid
612238104Sdesieee80211_syncflag(struct ieee80211vap *vap, int flag)
613238104Sdes{
614238104Sdes	struct ieee80211com *ic = vap->iv_ic;
615238104Sdes
616238104Sdes	IEEE80211_LOCK(ic);
617238104Sdes	if (flag < 0) {
618238104Sdes		flag = -flag;
619238104Sdes		vap->iv_flags &= ~flag;
620238104Sdes	} else
621238104Sdes		vap->iv_flags |= flag;
622238104Sdes	ieee80211_syncflag_locked(ic, flag);
623238104Sdes	IEEE80211_UNLOCK(ic);
624238104Sdes}
625238104Sdes
626238104Sdes/*
627238104Sdes * Synchronize flag bit state in the com structure
628238104Sdes * according to the state of all vap's.  This is used,
629269257Sdes * for example, to handle state changes via ioctls.
630269257Sdes */
631269257Sdesstatic void
632269257Sdesieee80211_syncflag_ext_locked(struct ieee80211com *ic, int flag)
633269257Sdes{
634269257Sdes	struct ieee80211vap *vap;
635269257Sdes	int bit;
636238104Sdes
637269257Sdes	IEEE80211_LOCK_ASSERT(ic);
638269257Sdes
639269257Sdes	bit = 0;
640238104Sdes	TAILQ_FOREACH(vap, &ic->ic_vaps, iv_next)
641238104Sdes		if (vap->iv_flags_ext & flag) {
642238104Sdes			bit = 1;
643238104Sdes			break;
644238104Sdes		}
645238104Sdes	if (bit)
646238104Sdes		ic->ic_flags_ext |= flag;
647238104Sdes	else
648238104Sdes		ic->ic_flags_ext &= ~flag;
649238104Sdes}
650238104Sdes
651238104Sdesvoid
652238104Sdesieee80211_syncflag_ext(struct ieee80211vap *vap, int flag)
653238104Sdes{
654238104Sdes	struct ieee80211com *ic = vap->iv_ic;
655238104Sdes
656238104Sdes	IEEE80211_LOCK(ic);
657238104Sdes	if (flag < 0) {
658238104Sdes		flag = -flag;
659238104Sdes		vap->iv_flags_ext &= ~flag;
660238104Sdes	} else
661238104Sdes		vap->iv_flags_ext |= flag;
662238104Sdes	ieee80211_syncflag_ext_locked(ic, flag);
663238104Sdes	IEEE80211_UNLOCK(ic);
664238104Sdes}
665238104Sdes
666238104Sdesstatic __inline int
667238104Sdesmapgsm(u_int freq, u_int flags)
668238104Sdes{
669238104Sdes	freq *= 10;
670238104Sdes	if (flags & IEEE80211_CHAN_QUARTER)
671238104Sdes		freq += 5;
672238104Sdes	else if (flags & IEEE80211_CHAN_HALF)
673238104Sdes		freq += 10;
674238104Sdes	else
675238104Sdes		freq += 20;
676238104Sdes	/* NB: there is no 907/20 wide but leave room */
677238104Sdes	return (freq - 906*10) / 5;
678238104Sdes}
679238104Sdes
680238104Sdesstatic __inline int
681238104Sdesmappsb(u_int freq, u_int flags)
682238104Sdes{
683238104Sdes	return 37 + ((freq * 10) + ((freq % 5) == 2 ? 5 : 0) - 49400) / 5;
684238104Sdes}
685238104Sdes
686238104Sdes/*
687238104Sdes * Convert MHz frequency to IEEE channel number.
688238104Sdes */
689238104Sdesint
690238104Sdesieee80211_mhz2ieee(u_int freq, u_int flags)
691238104Sdes{
692238104Sdes#define	IS_FREQ_IN_PSB(_freq) ((_freq) > 4940 && (_freq) < 4990)
693238104Sdes	if (flags & IEEE80211_CHAN_GSM)
694238104Sdes		return mapgsm(freq, flags);
695238104Sdes	if (flags & IEEE80211_CHAN_2GHZ) {	/* 2GHz band */
696238104Sdes		if (freq == 2484)
697238104Sdes			return 14;
698238104Sdes		if (freq < 2484)
699238104Sdes			return ((int) freq - 2407) / 5;
700238104Sdes		else
701238104Sdes			return 15 + ((freq - 2512) / 20);
702238104Sdes	} else if (flags & IEEE80211_CHAN_5GHZ) {	/* 5Ghz band */
703238104Sdes		if (freq <= 5000) {
704238104Sdes			/* XXX check regdomain? */
705238104Sdes			if (IS_FREQ_IN_PSB(freq))
706238104Sdes				return mappsb(freq, flags);
707238104Sdes			return (freq - 4000) / 5;
708238104Sdes		} else
709238104Sdes			return (freq - 5000) / 5;
710238104Sdes	} else {				/* either, guess */
711238104Sdes		if (freq == 2484)
712238104Sdes			return 14;
713238104Sdes		if (freq < 2484) {
714238104Sdes			if (907 <= freq && freq <= 922)
715238104Sdes				return mapgsm(freq, flags);
716238104Sdes			return ((int) freq - 2407) / 5;
717238104Sdes		}
718238104Sdes		if (freq < 5000) {
719238104Sdes			if (IS_FREQ_IN_PSB(freq))
720238104Sdes				return mappsb(freq, flags);
721238104Sdes			else if (freq > 4900)
722238104Sdes				return (freq - 4000) / 5;
723238104Sdes			else
724238104Sdes				return 15 + ((freq - 2512) / 20);
725238104Sdes		}
726238104Sdes		return (freq - 5000) / 5;
727238104Sdes	}
728238104Sdes#undef IS_FREQ_IN_PSB
729238104Sdes}
730238104Sdes
731238104Sdes/*
732238104Sdes * Convert channel to IEEE channel number.
733238104Sdes */
734238104Sdesint
735238104Sdesieee80211_chan2ieee(struct ieee80211com *ic, const struct ieee80211_channel *c)
736238104Sdes{
737238104Sdes	if (c == NULL) {
738238104Sdes		if_printf(ic->ic_ifp, "invalid channel (NULL)\n");
739238104Sdes		return 0;		/* XXX */
740238104Sdes	}
741238104Sdes	return (c == IEEE80211_CHAN_ANYC ?  IEEE80211_CHAN_ANY : c->ic_ieee);
742238104Sdes}
743238104Sdes
744238104Sdes/*
745238104Sdes * Convert IEEE channel number to MHz frequency.
746238104Sdes */
747238104Sdesu_int
748238104Sdesieee80211_ieee2mhz(u_int chan, u_int flags)
749238104Sdes{
750238104Sdes	if (flags & IEEE80211_CHAN_GSM)
751238104Sdes		return 907 + 5 * (chan / 10);
752238104Sdes	if (flags & IEEE80211_CHAN_2GHZ) {	/* 2GHz band */
753238104Sdes		if (chan == 14)
754238104Sdes			return 2484;
755238104Sdes		if (chan < 14)
756238104Sdes			return 2407 + chan*5;
757238104Sdes		else
758238104Sdes			return 2512 + ((chan-15)*20);
759238104Sdes	} else if (flags & IEEE80211_CHAN_5GHZ) {/* 5Ghz band */
760238104Sdes		if (flags & (IEEE80211_CHAN_HALF|IEEE80211_CHAN_QUARTER)) {
761238104Sdes			chan -= 37;
762238104Sdes			return 4940 + chan*5 + (chan % 5 ? 2 : 0);
763238104Sdes		}
764238104Sdes		return 5000 + (chan*5);
765269257Sdes	} else {				/* either, guess */
766269257Sdes		/* XXX can't distinguish PSB+GSM channels */
767269257Sdes		if (chan == 14)
768269257Sdes			return 2484;
769269257Sdes		if (chan < 14)			/* 0-13 */
770269257Sdes			return 2407 + chan*5;
771269257Sdes		if (chan < 27)			/* 15-26 */
772238104Sdes			return 2512 + ((chan-15)*20);
773269257Sdes		return 5000 + (chan*5);
774269257Sdes	}
775269257Sdes}
776238104Sdes
777238104Sdes/*
778238104Sdes * Locate a channel given a frequency+flags.  We cache
779238104Sdes * the previous lookup to optimize switching between two
780238104Sdes * channels--as happens with dynamic turbo.
781238104Sdes */
782238104Sdesstruct ieee80211_channel *
783238104Sdesieee80211_find_channel(struct ieee80211com *ic, int freq, int flags)
784238104Sdes{
785238104Sdes	struct ieee80211_channel *c;
786238104Sdes	int i;
787238104Sdes
788238104Sdes	flags &= IEEE80211_CHAN_ALLTURBO;
789238104Sdes	c = ic->ic_prevchan;
790238104Sdes	if (c != NULL && c->ic_freq == freq &&
791238104Sdes	    (c->ic_flags & IEEE80211_CHAN_ALLTURBO) == flags)
792238104Sdes		return c;
793238104Sdes	/* brute force search */
794238104Sdes	for (i = 0; i < ic->ic_nchans; i++) {
795238104Sdes		c = &ic->ic_channels[i];
796238104Sdes		if (c->ic_freq == freq &&
797238104Sdes		    (c->ic_flags & IEEE80211_CHAN_ALLTURBO) == flags)
798238104Sdes			return c;
799238104Sdes	}
800238104Sdes	return NULL;
801238104Sdes}
802238104Sdes
803238104Sdes/*
804238104Sdes * Locate a channel given a channel number+flags.  We cache
805238104Sdes * the previous lookup to optimize switching between two
806238104Sdes * channels--as happens with dynamic turbo.
807238104Sdes */
808238104Sdesstruct ieee80211_channel *
809238104Sdesieee80211_find_channel_byieee(struct ieee80211com *ic, int ieee, int flags)
810238104Sdes{
811238104Sdes	struct ieee80211_channel *c;
812238104Sdes	int i;
813238104Sdes
814238104Sdes	flags &= IEEE80211_CHAN_ALLTURBO;
815238104Sdes	c = ic->ic_prevchan;
816238104Sdes	if (c != NULL && c->ic_ieee == ieee &&
817238104Sdes	    (c->ic_flags & IEEE80211_CHAN_ALLTURBO) == flags)
818238104Sdes		return c;
819238104Sdes	/* brute force search */
820238104Sdes	for (i = 0; i < ic->ic_nchans; i++) {
821238104Sdes		c = &ic->ic_channels[i];
822238104Sdes		if (c->ic_ieee == ieee &&
823238104Sdes		    (c->ic_flags & IEEE80211_CHAN_ALLTURBO) == flags)
824238104Sdes			return c;
825238104Sdes	}
826238104Sdes	return NULL;
827238104Sdes}
828238104Sdes
829238104Sdesstatic void
830238104Sdesaddmedia(struct ifmedia *media, int caps, int addsta, int mode, int mword)
831238104Sdes{
832238104Sdes#define	ADD(_ic, _s, _o) \
833238104Sdes	ifmedia_add(media, \
834238104Sdes		IFM_MAKEWORD(IFM_IEEE80211, (_s), (_o), 0), 0, NULL)
835238104Sdes	static const u_int mopts[IEEE80211_MODE_MAX] = {
836238104Sdes		IFM_AUTO,
837238104Sdes		IFM_IEEE80211_11A,
838238104Sdes		IFM_IEEE80211_11B,
839238104Sdes		IFM_IEEE80211_11G,
840238104Sdes		IFM_IEEE80211_FH,
841238104Sdes		IFM_IEEE80211_11A | IFM_IEEE80211_TURBO,
842238104Sdes		IFM_IEEE80211_11G | IFM_IEEE80211_TURBO,
843238104Sdes		IFM_IEEE80211_11A | IFM_IEEE80211_TURBO,
844238104Sdes		IFM_IEEE80211_11NA,
845238104Sdes		IFM_IEEE80211_11NG,
846269257Sdes	};
847269257Sdes	u_int mopt;
848269257Sdes
849269257Sdes	mopt = mopts[mode];
850269257Sdes	if (addsta)
851269257Sdes		ADD(ic, mword, mopt);	/* STA mode has no cap */
852269257Sdes	if (caps & IEEE80211_C_IBSS)
853269257Sdes		ADD(media, mword, mopt | IFM_IEEE80211_ADHOC);
854269257Sdes	if (caps & IEEE80211_C_HOSTAP)
855238104Sdes		ADD(media, mword, mopt | IFM_IEEE80211_HOSTAP);
856238104Sdes	if (caps & IEEE80211_C_AHDEMO)
857238104Sdes		ADD(media, mword, mopt | IFM_IEEE80211_ADHOC | IFM_FLAG0);
858238104Sdes	if (caps & IEEE80211_C_MONITOR)
859238104Sdes		ADD(media, mword, mopt | IFM_IEEE80211_MONITOR);
860238104Sdes	if (caps & IEEE80211_C_WDS)
861238104Sdes		ADD(media, mword, mopt | IFM_IEEE80211_WDS);
862238104Sdes#undef ADD
863238104Sdes}
864238104Sdes
865238104Sdes/*
866238104Sdes * Setup the media data structures according to the channel and
867238104Sdes * rate tables.
868238104Sdes */
869238104Sdesstatic int
870238104Sdesieee80211_media_setup(struct ieee80211com *ic,
871238104Sdes	struct ifmedia *media, int caps, int addsta,
872238104Sdes	ifm_change_cb_t media_change, ifm_stat_cb_t media_stat)
873238104Sdes{
874238104Sdes	int i, j, mode, rate, maxrate, mword, r;
875238104Sdes	const struct ieee80211_rateset *rs;
876238104Sdes	struct ieee80211_rateset allrates;
877238104Sdes
878238104Sdes	/*
879238104Sdes	 * Fill in media characteristics.
880238104Sdes	 */
881238104Sdes	ifmedia_init(media, 0, media_change, media_stat);
882238104Sdes	maxrate = 0;
883238104Sdes	/*
884238104Sdes	 * Add media for legacy operating modes.
885238104Sdes	 */
886238104Sdes	memset(&allrates, 0, sizeof(allrates));
887238104Sdes	for (mode = IEEE80211_MODE_AUTO; mode < IEEE80211_MODE_11NA; mode++) {
888238104Sdes		if (isclr(ic->ic_modecaps, mode))
889238104Sdes			continue;
890238104Sdes		addmedia(media, caps, addsta, mode, IFM_AUTO);
891238104Sdes		if (mode == IEEE80211_MODE_AUTO)
892238104Sdes			continue;
893238104Sdes		rs = &ic->ic_sup_rates[mode];
894238104Sdes		for (i = 0; i < rs->rs_nrates; i++) {
895238104Sdes			rate = rs->rs_rates[i];
896238104Sdes			mword = ieee80211_rate2media(ic, rate, mode);
897238104Sdes			if (mword == 0)
898238104Sdes				continue;
899238104Sdes			addmedia(media, caps, addsta, mode, mword);
900238104Sdes			/*
901238104Sdes			 * Add legacy rate to the collection of all rates.
902238104Sdes			 */
903238104Sdes			r = rate & IEEE80211_RATE_VAL;
904238104Sdes			for (j = 0; j < allrates.rs_nrates; j++)
905238104Sdes				if (allrates.rs_rates[j] == r)
906238104Sdes					break;
907238104Sdes			if (j == allrates.rs_nrates) {
908238104Sdes				/* unique, add to the set */
909238104Sdes				allrates.rs_rates[j] = r;
910238104Sdes				allrates.rs_nrates++;
911238104Sdes			}
912238104Sdes			rate = (rate & IEEE80211_RATE_VAL) / 2;
913238104Sdes			if (rate > maxrate)
914238104Sdes				maxrate = rate;
915238104Sdes		}
916238104Sdes	}
917238104Sdes	for (i = 0; i < allrates.rs_nrates; i++) {
918238104Sdes		mword = ieee80211_rate2media(ic, allrates.rs_rates[i],
919238104Sdes				IEEE80211_MODE_AUTO);
920238104Sdes		if (mword == 0)
921238104Sdes			continue;
922238104Sdes		/* NB: remove media options from mword */
923238104Sdes		addmedia(media, caps, addsta,
924238104Sdes		    IEEE80211_MODE_AUTO, IFM_SUBTYPE(mword));
925238104Sdes	}
926238104Sdes	/*
927238104Sdes	 * Add HT/11n media.  Note that we do not have enough
928238104Sdes	 * bits in the media subtype to express the MCS so we
929238104Sdes	 * use a "placeholder" media subtype and any fixed MCS
930238104Sdes	 * must be specified with a different mechanism.
931238104Sdes	 */
932238104Sdes	for (; mode < IEEE80211_MODE_MAX; mode++) {
933238104Sdes		if (isclr(ic->ic_modecaps, mode))
934238104Sdes			continue;
935238104Sdes		addmedia(media, caps, addsta, mode, IFM_AUTO);
936238104Sdes		addmedia(media, caps, addsta, mode, IFM_IEEE80211_MCS);
937238104Sdes	}
938238104Sdes	if (isset(ic->ic_modecaps, IEEE80211_MODE_11NA) ||
939238104Sdes	    isset(ic->ic_modecaps, IEEE80211_MODE_11NG)) {
940238104Sdes		addmedia(media, caps, addsta,
941238104Sdes		    IEEE80211_MODE_AUTO, IFM_IEEE80211_MCS);
942238104Sdes		/* XXX could walk htrates */
943238104Sdes		/* XXX known array size */
944238104Sdes		if (ieee80211_htrates[15].ht40_rate_400ns > maxrate)
945238104Sdes			maxrate = ieee80211_htrates[15].ht40_rate_400ns;
946238104Sdes	}
947238104Sdes	return maxrate;
948238104Sdes}
949238104Sdes
950238104Sdesvoid
951238104Sdesieee80211_media_init(struct ieee80211com *ic)
952238104Sdes{
953238104Sdes	struct ifnet *ifp = ic->ic_ifp;
954238104Sdes	int maxrate;
955238104Sdes
956238104Sdes	/* NB: this works because the structure is initialized to zero */
957238104Sdes	if (!LIST_EMPTY(&ic->ic_media.ifm_list)) {
958238104Sdes		/*
959238104Sdes		 * We are re-initializing the channel list; clear
960238104Sdes		 * the existing media state as the media routines
961238104Sdes		 * don't suppress duplicates.
962238104Sdes		 */
963238104Sdes		ifmedia_removeall(&ic->ic_media);
964238104Sdes	}
965269257Sdes	ieee80211_chan_init(ic);
966238104Sdes
967238104Sdes	/*
968238104Sdes	 * Recalculate media settings in case new channel list changes
969238104Sdes	 * the set of available modes.
970238104Sdes	 */
971238104Sdes	maxrate = ieee80211_media_setup(ic, &ic->ic_media, ic->ic_caps, 1,
972238104Sdes		ieee80211com_media_change, ieee80211com_media_status);
973238104Sdes	/* NB: strip explicit mode; we're actually in autoselect */
974238104Sdes	ifmedia_set(&ic->ic_media,
975238104Sdes		media_status(ic->ic_opmode, ic->ic_curchan) &~ IFM_MMASK);
976238104Sdes	if (maxrate)
977238104Sdes		ifp->if_baudrate = IF_Mbps(maxrate);
978238104Sdes
979238104Sdes	/* XXX need to propagate new media settings to vap's */
980238104Sdes}
981238104Sdes
982238104Sdesconst struct ieee80211_rateset *
983238104Sdesieee80211_get_suprates(struct ieee80211com *ic, const struct ieee80211_channel *c)
984238104Sdes{
985238104Sdes	if (IEEE80211_IS_CHAN_HALF(c))
986238104Sdes		return &ieee80211_rateset_half;
987238104Sdes	if (IEEE80211_IS_CHAN_QUARTER(c))
988		return &ieee80211_rateset_quarter;
989	if (IEEE80211_IS_CHAN_HTA(c))
990		return &ic->ic_sup_rates[IEEE80211_MODE_11A];
991	if (IEEE80211_IS_CHAN_HTG(c)) {
992		/* XXX does this work for basic rates? */
993		return &ic->ic_sup_rates[IEEE80211_MODE_11G];
994	}
995	return &ic->ic_sup_rates[ieee80211_chan2mode(c)];
996}
997
998void
999ieee80211_announce(struct ieee80211com *ic)
1000{
1001	struct ifnet *ifp = ic->ic_ifp;
1002	int i, mode, rate, mword;
1003	const struct ieee80211_rateset *rs;
1004
1005	/* NB: skip AUTO since it has no rates */
1006	for (mode = IEEE80211_MODE_AUTO+1; mode < IEEE80211_MODE_11NA; mode++) {
1007		if (isclr(ic->ic_modecaps, mode))
1008			continue;
1009		if_printf(ifp, "%s rates: ", ieee80211_phymode_name[mode]);
1010		rs = &ic->ic_sup_rates[mode];
1011		for (i = 0; i < rs->rs_nrates; i++) {
1012			mword = ieee80211_rate2media(ic, rs->rs_rates[i], mode);
1013			if (mword == 0)
1014				continue;
1015			rate = ieee80211_media2rate(mword);
1016			printf("%s%d%sMbps", (i != 0 ? " " : ""),
1017			    rate / 2, ((rate & 0x1) != 0 ? ".5" : ""));
1018		}
1019		printf("\n");
1020	}
1021	ieee80211_ht_announce(ic);
1022}
1023
1024void
1025ieee80211_announce_channels(struct ieee80211com *ic)
1026{
1027	const struct ieee80211_channel *c;
1028	char type;
1029	int i, cw;
1030
1031	printf("Chan  Freq  CW  RegPwr  MinPwr  MaxPwr\n");
1032	for (i = 0; i < ic->ic_nchans; i++) {
1033		c = &ic->ic_channels[i];
1034		if (IEEE80211_IS_CHAN_ST(c))
1035			type = 'S';
1036		else if (IEEE80211_IS_CHAN_108A(c))
1037			type = 'T';
1038		else if (IEEE80211_IS_CHAN_108G(c))
1039			type = 'G';
1040		else if (IEEE80211_IS_CHAN_HT(c))
1041			type = 'n';
1042		else if (IEEE80211_IS_CHAN_A(c))
1043			type = 'a';
1044		else if (IEEE80211_IS_CHAN_ANYG(c))
1045			type = 'g';
1046		else if (IEEE80211_IS_CHAN_B(c))
1047			type = 'b';
1048		else
1049			type = 'f';
1050		if (IEEE80211_IS_CHAN_HT40(c) || IEEE80211_IS_CHAN_TURBO(c))
1051			cw = 40;
1052		else if (IEEE80211_IS_CHAN_HALF(c))
1053			cw = 10;
1054		else if (IEEE80211_IS_CHAN_QUARTER(c))
1055			cw = 5;
1056		else
1057			cw = 20;
1058		printf("%4d  %4d%c %2d%c %6d  %4d.%d  %4d.%d\n"
1059			, c->ic_ieee, c->ic_freq, type
1060			, cw
1061			, IEEE80211_IS_CHAN_HT40U(c) ? '+' :
1062			  IEEE80211_IS_CHAN_HT40D(c) ? '-' : ' '
1063			, c->ic_maxregpower
1064			, c->ic_minpower / 2, c->ic_minpower & 1 ? 5 : 0
1065			, c->ic_maxpower / 2, c->ic_maxpower & 1 ? 5 : 0
1066		);
1067	}
1068}
1069
1070static int
1071media2mode(const struct ieee80211com *ic,
1072	const struct ifmedia_entry *ime, enum ieee80211_phymode *mode)
1073{
1074	switch (IFM_MODE(ime->ifm_media)) {
1075	case IFM_IEEE80211_11A:
1076		*mode = IEEE80211_MODE_11A;
1077		break;
1078	case IFM_IEEE80211_11B:
1079		*mode = IEEE80211_MODE_11B;
1080		break;
1081	case IFM_IEEE80211_11G:
1082		*mode = IEEE80211_MODE_11G;
1083		break;
1084	case IFM_IEEE80211_FH:
1085		*mode = IEEE80211_MODE_FH;
1086		break;
1087	case IFM_IEEE80211_11NA:
1088		*mode = IEEE80211_MODE_11NA;
1089		break;
1090	case IFM_IEEE80211_11NG:
1091		*mode = IEEE80211_MODE_11NG;
1092		break;
1093	case IFM_AUTO:
1094		*mode = IEEE80211_MODE_AUTO;
1095		break;
1096	default:
1097		return 0;
1098	}
1099	/*
1100	 * Turbo mode is an ``option''.
1101	 * XXX does not apply to AUTO
1102	 */
1103	if (ime->ifm_media & IFM_IEEE80211_TURBO) {
1104		if (*mode == IEEE80211_MODE_11A) {
1105			if (ic->ic_flags & IEEE80211_F_TURBOP)
1106				*mode = IEEE80211_MODE_TURBO_A;
1107			else
1108				*mode = IEEE80211_MODE_STURBO_A;
1109		} else if (*mode == IEEE80211_MODE_11G)
1110			*mode = IEEE80211_MODE_TURBO_G;
1111		else
1112			return 0;
1113	}
1114	/* XXX HT40 +/- */
1115	return 1;
1116}
1117
1118/*
1119 * Handle a media change request on the underlying
1120 * interface; we accept mode changes only.
1121 */
1122int
1123ieee80211com_media_change(struct ifnet *ifp)
1124{
1125	struct ieee80211com *ic = ifp->if_l2com;
1126	struct ifmedia_entry *ime = ic->ic_media.ifm_cur;
1127	enum ieee80211_phymode newphymode;
1128	int error = 0;
1129
1130	/*
1131	 * First, identify the phy mode.
1132	 */
1133	if (!media2mode(ic, ime, &newphymode))
1134		return EINVAL;
1135	/* NB: mode must be supported, no need to check */
1136
1137	/*
1138	 * Handle phy mode change.
1139	 */
1140	IEEE80211_LOCK(ic);
1141	if (ic->ic_curmode != newphymode) {		/* change phy mode */
1142		struct ieee80211vap *vap;
1143
1144		(void) ieee80211_setmode(ic, newphymode);
1145		/*
1146		 * Propagate new state to each vap.
1147		 */
1148		TAILQ_FOREACH(vap, &ic->ic_vaps, iv_next) {
1149		}
1150	}
1151	IEEE80211_UNLOCK(ic);
1152	return error;
1153}
1154
1155static int
1156findrate(const struct ieee80211com *ic, enum ieee80211_phymode m, int r)
1157{
1158	int i, nrates;
1159
1160	for (i = 0, nrates = ic->ic_sup_rates[m].rs_nrates; i < nrates; i++)
1161		if ((ic->ic_sup_rates[m].rs_rates[i] & IEEE80211_RATE_VAL) == r)
1162			return i;
1163	return -1;
1164}
1165
1166/*
1167 * Handle a media change request on the vap interface.
1168 */
1169int
1170ieee80211_media_change(struct ifnet *ifp)
1171{
1172	struct ieee80211vap *vap = ifp->if_softc;
1173	struct ifmedia_entry *ime = vap->iv_media.ifm_cur;
1174	struct ieee80211com *ic = vap->iv_ic;
1175	int newrate;
1176
1177	/* XXX this won't work unless ic_curmode is != IEEE80211_MODE_AUTO */
1178	if (ic->ic_curmode == IEEE80211_MODE_AUTO)
1179		return EINVAL;
1180	if (IFM_SUBTYPE(ime->ifm_media) != IFM_AUTO) {
1181		/*
1182		 * NB: this can only be used to specify a legacy rate.
1183		 */
1184		newrate = ieee80211_media2rate(ime->ifm_media);
1185		if (newrate == 0)
1186			return EINVAL;
1187		if (findrate(ic, ic->ic_curmode, newrate) == -1)
1188			return EINVAL;
1189	} else {
1190		newrate = IEEE80211_FIXED_RATE_NONE;
1191	}
1192	if (newrate != vap->iv_txparms[ic->ic_curmode].ucastrate) {
1193		vap->iv_txparms[ic->ic_curmode].ucastrate = newrate;
1194		return ENETRESET;
1195	}
1196	return 0;
1197}
1198
1199/*
1200 * Common code to calculate the media status word
1201 * from the operating mode and channel state.
1202 */
1203static int
1204media_status(enum ieee80211_opmode opmode, const struct ieee80211_channel *chan)
1205{
1206	int status;
1207
1208	status = IFM_IEEE80211;
1209	switch (opmode) {
1210	case IEEE80211_M_STA:
1211		break;
1212	case IEEE80211_M_IBSS:
1213		status |= IFM_IEEE80211_ADHOC;
1214		break;
1215	case IEEE80211_M_HOSTAP:
1216		status |= IFM_IEEE80211_HOSTAP;
1217		break;
1218	case IEEE80211_M_MONITOR:
1219		status |= IFM_IEEE80211_MONITOR;
1220		break;
1221	case IEEE80211_M_AHDEMO:
1222		status |= IFM_IEEE80211_ADHOC | IFM_FLAG0;
1223		break;
1224	case IEEE80211_M_WDS:
1225		status |= IFM_IEEE80211_WDS;
1226		break;
1227	}
1228	if (IEEE80211_IS_CHAN_HTA(chan)) {
1229		status |= IFM_IEEE80211_11NA;
1230	} else if (IEEE80211_IS_CHAN_HTG(chan)) {
1231		status |= IFM_IEEE80211_11NG;
1232	} else if (IEEE80211_IS_CHAN_A(chan)) {
1233		status |= IFM_IEEE80211_11A;
1234	} else if (IEEE80211_IS_CHAN_B(chan)) {
1235		status |= IFM_IEEE80211_11B;
1236	} else if (IEEE80211_IS_CHAN_ANYG(chan)) {
1237		status |= IFM_IEEE80211_11G;
1238	} else if (IEEE80211_IS_CHAN_FHSS(chan)) {
1239		status |= IFM_IEEE80211_FH;
1240	}
1241	/* XXX else complain? */
1242
1243	if (IEEE80211_IS_CHAN_TURBO(chan))
1244		status |= IFM_IEEE80211_TURBO;
1245#if 0
1246	if (IEEE80211_IS_CHAN_HT20(chan))
1247		status |= IFM_IEEE80211_HT20;
1248	if (IEEE80211_IS_CHAN_HT40(chan))
1249		status |= IFM_IEEE80211_HT40;
1250#endif
1251	return status;
1252}
1253
1254static void
1255ieee80211com_media_status(struct ifnet *ifp, struct ifmediareq *imr)
1256{
1257	struct ieee80211com *ic = ifp->if_l2com;
1258	struct ieee80211vap *vap;
1259
1260	imr->ifm_status = IFM_AVALID;
1261	TAILQ_FOREACH(vap, &ic->ic_vaps, iv_next)
1262		if (vap->iv_ifp->if_flags & IFF_UP) {
1263			imr->ifm_status |= IFM_ACTIVE;
1264			break;
1265		}
1266	imr->ifm_active = media_status(ic->ic_opmode, ic->ic_curchan);
1267	if (imr->ifm_status & IFM_ACTIVE)
1268		imr->ifm_current = imr->ifm_active;
1269}
1270
1271void
1272ieee80211_media_status(struct ifnet *ifp, struct ifmediareq *imr)
1273{
1274	struct ieee80211vap *vap = ifp->if_softc;
1275	struct ieee80211com *ic = vap->iv_ic;
1276	enum ieee80211_phymode mode;
1277
1278	imr->ifm_status = IFM_AVALID;
1279	/*
1280	 * NB: use the current channel's mode to lock down a xmit
1281	 * rate only when running; otherwise we may have a mismatch
1282	 * in which case the rate will not be convertible.
1283	 */
1284	if (vap->iv_state == IEEE80211_S_RUN) {
1285		imr->ifm_status |= IFM_ACTIVE;
1286		mode = ieee80211_chan2mode(ic->ic_curchan);
1287	} else
1288		mode = IEEE80211_MODE_AUTO;
1289	imr->ifm_active = media_status(vap->iv_opmode, ic->ic_curchan);
1290	/*
1291	 * Calculate a current rate if possible.
1292	 */
1293	if (vap->iv_txparms[mode].ucastrate != IEEE80211_FIXED_RATE_NONE) {
1294		/*
1295		 * A fixed rate is set, report that.
1296		 */
1297		imr->ifm_active |= ieee80211_rate2media(ic,
1298			vap->iv_txparms[mode].ucastrate, mode);
1299	} else if (vap->iv_opmode == IEEE80211_M_STA) {
1300		/*
1301		 * In station mode report the current transmit rate.
1302		 */
1303		imr->ifm_active |= ieee80211_rate2media(ic,
1304			vap->iv_bss->ni_txrate, mode);
1305	} else
1306		imr->ifm_active |= IFM_AUTO;
1307	if (imr->ifm_status & IFM_ACTIVE)
1308		imr->ifm_current = imr->ifm_active;
1309}
1310
1311/*
1312 * Set the current phy mode and recalculate the active channel
1313 * set based on the available channels for this mode.  Also
1314 * select a new default/current channel if the current one is
1315 * inappropriate for this mode.
1316 */
1317int
1318ieee80211_setmode(struct ieee80211com *ic, enum ieee80211_phymode mode)
1319{
1320	/*
1321	 * Adjust basic rates in 11b/11g supported rate set.
1322	 * Note that if operating on a hal/quarter rate channel
1323	 * this is a noop as those rates sets are different
1324	 * and used instead.
1325	 */
1326	if (mode == IEEE80211_MODE_11G || mode == IEEE80211_MODE_11B)
1327		ieee80211_setbasicrates(&ic->ic_sup_rates[mode], mode);
1328
1329	ic->ic_curmode = mode;
1330	ieee80211_reset_erp(ic);	/* reset ERP state */
1331
1332	return 0;
1333}
1334
1335/*
1336 * Return the phy mode for with the specified channel.
1337 */
1338enum ieee80211_phymode
1339ieee80211_chan2mode(const struct ieee80211_channel *chan)
1340{
1341
1342	if (IEEE80211_IS_CHAN_HTA(chan))
1343		return IEEE80211_MODE_11NA;
1344	else if (IEEE80211_IS_CHAN_HTG(chan))
1345		return IEEE80211_MODE_11NG;
1346	else if (IEEE80211_IS_CHAN_108G(chan))
1347		return IEEE80211_MODE_TURBO_G;
1348	else if (IEEE80211_IS_CHAN_ST(chan))
1349		return IEEE80211_MODE_STURBO_A;
1350	else if (IEEE80211_IS_CHAN_TURBO(chan))
1351		return IEEE80211_MODE_TURBO_A;
1352	else if (IEEE80211_IS_CHAN_A(chan))
1353		return IEEE80211_MODE_11A;
1354	else if (IEEE80211_IS_CHAN_ANYG(chan))
1355		return IEEE80211_MODE_11G;
1356	else if (IEEE80211_IS_CHAN_B(chan))
1357		return IEEE80211_MODE_11B;
1358	else if (IEEE80211_IS_CHAN_FHSS(chan))
1359		return IEEE80211_MODE_FH;
1360
1361	/* NB: should not get here */
1362	printf("%s: cannot map channel to mode; freq %u flags 0x%x\n",
1363		__func__, chan->ic_freq, chan->ic_flags);
1364	return IEEE80211_MODE_11B;
1365}
1366
1367struct ratemedia {
1368	u_int	match;	/* rate + mode */
1369	u_int	media;	/* if_media rate */
1370};
1371
1372static int
1373findmedia(const struct ratemedia rates[], int n, u_int match)
1374{
1375	int i;
1376
1377	for (i = 0; i < n; i++)
1378		if (rates[i].match == match)
1379			return rates[i].media;
1380	return IFM_AUTO;
1381}
1382
1383/*
1384 * Convert IEEE80211 rate value to ifmedia subtype.
1385 * Rate is either a legacy rate in units of 0.5Mbps
1386 * or an MCS index.
1387 */
1388int
1389ieee80211_rate2media(struct ieee80211com *ic, int rate, enum ieee80211_phymode mode)
1390{
1391#define	N(a)	(sizeof(a) / sizeof(a[0]))
1392	static const struct ratemedia rates[] = {
1393		{   2 | IFM_IEEE80211_FH, IFM_IEEE80211_FH1 },
1394		{   4 | IFM_IEEE80211_FH, IFM_IEEE80211_FH2 },
1395		{   2 | IFM_IEEE80211_11B, IFM_IEEE80211_DS1 },
1396		{   4 | IFM_IEEE80211_11B, IFM_IEEE80211_DS2 },
1397		{  11 | IFM_IEEE80211_11B, IFM_IEEE80211_DS5 },
1398		{  22 | IFM_IEEE80211_11B, IFM_IEEE80211_DS11 },
1399		{  44 | IFM_IEEE80211_11B, IFM_IEEE80211_DS22 },
1400		{  12 | IFM_IEEE80211_11A, IFM_IEEE80211_OFDM6 },
1401		{  18 | IFM_IEEE80211_11A, IFM_IEEE80211_OFDM9 },
1402		{  24 | IFM_IEEE80211_11A, IFM_IEEE80211_OFDM12 },
1403		{  36 | IFM_IEEE80211_11A, IFM_IEEE80211_OFDM18 },
1404		{  48 | IFM_IEEE80211_11A, IFM_IEEE80211_OFDM24 },
1405		{  72 | IFM_IEEE80211_11A, IFM_IEEE80211_OFDM36 },
1406		{  96 | IFM_IEEE80211_11A, IFM_IEEE80211_OFDM48 },
1407		{ 108 | IFM_IEEE80211_11A, IFM_IEEE80211_OFDM54 },
1408		{   2 | IFM_IEEE80211_11G, IFM_IEEE80211_DS1 },
1409		{   4 | IFM_IEEE80211_11G, IFM_IEEE80211_DS2 },
1410		{  11 | IFM_IEEE80211_11G, IFM_IEEE80211_DS5 },
1411		{  22 | IFM_IEEE80211_11G, IFM_IEEE80211_DS11 },
1412		{  12 | IFM_IEEE80211_11G, IFM_IEEE80211_OFDM6 },
1413		{  18 | IFM_IEEE80211_11G, IFM_IEEE80211_OFDM9 },
1414		{  24 | IFM_IEEE80211_11G, IFM_IEEE80211_OFDM12 },
1415		{  36 | IFM_IEEE80211_11G, IFM_IEEE80211_OFDM18 },
1416		{  48 | IFM_IEEE80211_11G, IFM_IEEE80211_OFDM24 },
1417		{  72 | IFM_IEEE80211_11G, IFM_IEEE80211_OFDM36 },
1418		{  96 | IFM_IEEE80211_11G, IFM_IEEE80211_OFDM48 },
1419		{ 108 | IFM_IEEE80211_11G, IFM_IEEE80211_OFDM54 },
1420		{   6 | IFM_IEEE80211_11A, IFM_IEEE80211_OFDM3 },
1421		{   9 | IFM_IEEE80211_11A, IFM_IEEE80211_OFDM4 },
1422		{  54 | IFM_IEEE80211_11A, IFM_IEEE80211_OFDM27 },
1423		/* NB: OFDM72 doesn't realy exist so we don't handle it */
1424	};
1425	static const struct ratemedia htrates[] = {
1426		{   0, IFM_IEEE80211_MCS },
1427		{   1, IFM_IEEE80211_MCS },
1428		{   2, IFM_IEEE80211_MCS },
1429		{   3, IFM_IEEE80211_MCS },
1430		{   4, IFM_IEEE80211_MCS },
1431		{   5, IFM_IEEE80211_MCS },
1432		{   6, IFM_IEEE80211_MCS },
1433		{   7, IFM_IEEE80211_MCS },
1434		{   8, IFM_IEEE80211_MCS },
1435		{   9, IFM_IEEE80211_MCS },
1436		{  10, IFM_IEEE80211_MCS },
1437		{  11, IFM_IEEE80211_MCS },
1438		{  12, IFM_IEEE80211_MCS },
1439		{  13, IFM_IEEE80211_MCS },
1440		{  14, IFM_IEEE80211_MCS },
1441		{  15, IFM_IEEE80211_MCS },
1442	};
1443	int m;
1444
1445	/*
1446	 * Check 11n rates first for match as an MCS.
1447	 */
1448	if (mode == IEEE80211_MODE_11NA) {
1449		if (rate & IEEE80211_RATE_MCS) {
1450			rate &= ~IEEE80211_RATE_MCS;
1451			m = findmedia(htrates, N(htrates), rate);
1452			if (m != IFM_AUTO)
1453				return m | IFM_IEEE80211_11NA;
1454		}
1455	} else if (mode == IEEE80211_MODE_11NG) {
1456		/* NB: 12 is ambiguous, it will be treated as an MCS */
1457		if (rate & IEEE80211_RATE_MCS) {
1458			rate &= ~IEEE80211_RATE_MCS;
1459			m = findmedia(htrates, N(htrates), rate);
1460			if (m != IFM_AUTO)
1461				return m | IFM_IEEE80211_11NG;
1462		}
1463	}
1464	rate &= IEEE80211_RATE_VAL;
1465	switch (mode) {
1466	case IEEE80211_MODE_11A:
1467	case IEEE80211_MODE_11NA:
1468	case IEEE80211_MODE_TURBO_A:
1469	case IEEE80211_MODE_STURBO_A:
1470		return findmedia(rates, N(rates), rate | IFM_IEEE80211_11A);
1471	case IEEE80211_MODE_11B:
1472		return findmedia(rates, N(rates), rate | IFM_IEEE80211_11B);
1473	case IEEE80211_MODE_FH:
1474		return findmedia(rates, N(rates), rate | IFM_IEEE80211_FH);
1475	case IEEE80211_MODE_AUTO:
1476		/* NB: ic may be NULL for some drivers */
1477		if (ic && ic->ic_phytype == IEEE80211_T_FH)
1478			return findmedia(rates, N(rates),
1479			    rate | IFM_IEEE80211_FH);
1480		/* NB: hack, 11g matches both 11b+11a rates */
1481		/* fall thru... */
1482	case IEEE80211_MODE_11G:
1483	case IEEE80211_MODE_11NG:
1484	case IEEE80211_MODE_TURBO_G:
1485		return findmedia(rates, N(rates), rate | IFM_IEEE80211_11G);
1486	}
1487	return IFM_AUTO;
1488#undef N
1489}
1490
1491int
1492ieee80211_media2rate(int mword)
1493{
1494#define	N(a)	(sizeof(a) / sizeof(a[0]))
1495	static const int ieeerates[] = {
1496		-1,		/* IFM_AUTO */
1497		0,		/* IFM_MANUAL */
1498		0,		/* IFM_NONE */
1499		2,		/* IFM_IEEE80211_FH1 */
1500		4,		/* IFM_IEEE80211_FH2 */
1501		2,		/* IFM_IEEE80211_DS1 */
1502		4,		/* IFM_IEEE80211_DS2 */
1503		11,		/* IFM_IEEE80211_DS5 */
1504		22,		/* IFM_IEEE80211_DS11 */
1505		44,		/* IFM_IEEE80211_DS22 */
1506		12,		/* IFM_IEEE80211_OFDM6 */
1507		18,		/* IFM_IEEE80211_OFDM9 */
1508		24,		/* IFM_IEEE80211_OFDM12 */
1509		36,		/* IFM_IEEE80211_OFDM18 */
1510		48,		/* IFM_IEEE80211_OFDM24 */
1511		72,		/* IFM_IEEE80211_OFDM36 */
1512		96,		/* IFM_IEEE80211_OFDM48 */
1513		108,		/* IFM_IEEE80211_OFDM54 */
1514		144,		/* IFM_IEEE80211_OFDM72 */
1515		0,		/* IFM_IEEE80211_DS354k */
1516		0,		/* IFM_IEEE80211_DS512k */
1517		6,		/* IFM_IEEE80211_OFDM3 */
1518		9,		/* IFM_IEEE80211_OFDM4 */
1519		54,		/* IFM_IEEE80211_OFDM27 */
1520		-1,		/* IFM_IEEE80211_MCS */
1521	};
1522	return IFM_SUBTYPE(mword) < N(ieeerates) ?
1523		ieeerates[IFM_SUBTYPE(mword)] : 0;
1524#undef N
1525}
1526