ieee80211.c revision 116742
1139804Simp/*-
21541Srgrimes * Copyright (c) 2002, 2003 Sam Leffler, Errno Consulting
31541Srgrimes * All rights reserved.
41541Srgrimes *
51541Srgrimes * Redistribution and use in source and binary forms, with or without
61541Srgrimes * modification, are permitted provided that the following conditions
71541Srgrimes * are met:
81541Srgrimes * 1. Redistributions of source code must retain the above copyright
91541Srgrimes *    notice, this list of conditions and the following disclaimer,
101541Srgrimes *    without modification.
111541Srgrimes * 2. Redistributions in binary form must reproduce at minimum a disclaimer
121541Srgrimes *    similar to the "NO WARRANTY" disclaimer below ("Disclaimer") and any
131541Srgrimes *    redistribution must be conditioned upon including a substantially
141541Srgrimes *    similar Disclaimer requirement for further binary redistribution.
151541Srgrimes * 3. Neither the names of the above-listed copyright holders nor the names
161541Srgrimes *    of any contributors may be used to endorse or promote products derived
171541Srgrimes *    from this software without specific prior written permission.
181541Srgrimes *
191541Srgrimes * Alternatively, this software may be distributed under the terms of the
201541Srgrimes * GNU General Public License ("GPL") version 2 as published by the Free
211541Srgrimes * Software Foundation.
221541Srgrimes *
231541Srgrimes * NO WARRANTY
241541Srgrimes * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
251541Srgrimes * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
261541Srgrimes * LIMITED TO, THE IMPLIED WARRANTIES OF NONINFRINGEMENT, MERCHANTIBILITY
271541Srgrimes * AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL
281541Srgrimes * THE COPYRIGHT HOLDERS OR CONTRIBUTORS BE LIABLE FOR SPECIAL, EXEMPLARY,
291541Srgrimes * OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
301541Srgrimes * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
311541Srgrimes * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER
32116182Sobrien * IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
33116182Sobrien * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
34116182Sobrien * THE POSSIBILITY OF SUCH DAMAGES.
3531778Seivind */
3631778Seivind
371541Srgrimes#include <sys/cdefs.h>
381541Srgrimes__FBSDID("$FreeBSD: head/sys/net80211/ieee80211.c 116742 2003-06-23 16:55:01Z sam $");
3912221Sbde
401541Srgrimes/*
41164033Srwatson * IEEE 802.11 generic handler
421541Srgrimes */
4382717Sdillon
4482717Sdillon#include "opt_inet.h"
45186570Sed
461541Srgrimes#include <sys/param.h>
471549Srgrimes#include <sys/systm.h>
481541Srgrimes#include <sys/mbuf.h>
49186570Sed#include <sys/malloc.h>
508876Srgrimes#include <sys/kernel.h>
51130344Sphk#include <sys/socket.h>
521541Srgrimes#include <sys/sockio.h>
5312221Sbde#include <sys/endian.h>
541541Srgrimes#include <sys/errno.h>
551541Srgrimes#include <sys/bus.h>
561541Srgrimes#include <sys/proc.h>
571541Srgrimes#include <sys/sysctl.h>
5812221Sbde
591541Srgrimes#include <machine/atomic.h>
601549Srgrimes
6183366Sjulian#include <net/if.h>
6283366Sjulian#include <net/if_dl.h>
631541Srgrimes#include <net/if_media.h>
641541Srgrimes#include <net/if_arp.h>
6512171Sphk#include <net/ethernet.h>
6638517Sdfr#include <net/if_llc.h>
671541Srgrimes
6812171Sphk#include <net80211/ieee80211_var.h>
6912171Sphk
70186564Sed#include <net/bpf.h>
71186564Sed
721541Srgrimes#ifdef INET
731541Srgrimes#include <netinet/in.h>
7412221Sbde#include <netinet/if_ether.h>
751541Srgrimes#endif
761541Srgrimes
771541Srgrimes#ifdef IEEE80211_DEBUG
781541Srgrimesint	ieee80211_debug = 0;
7912221SbdeSYSCTL_INT(_debug, OID_AUTO, ieee80211, CTLFLAG_RW, &ieee80211_debug,
801541Srgrimes	    0, "IEEE 802.11 media debugging printfs");
811549Srgrimes#endif
8283366Sjulian
8383366Sjulianstatic void ieee80211_set11gbasicrates(struct ieee80211_rateset *,
841541Srgrimes		enum ieee80211_phymode);
851541Srgrimes
8612171Sphkstatic const char *ieee80211_phymode_name[] = {
871541Srgrimes	"auto",		/* IEEE80211_MODE_AUTO */
8812171Sphk	"11a",		/* IEEE80211_MODE_11A */
8912171Sphk	"11b",		/* IEEE80211_MODE_11B */
90186564Sed	"11g",		/* IEEE80211_MODE_11G */
91186564Sed	"turbo",	/* IEEE80211_MODE_TURBO	*/
921541Srgrimes};
931541Srgrimes
9412221Sbdevoid
9512200Sbdeieee80211_ifattach(struct ifnet *ifp)
961541Srgrimes{
971541Srgrimes	struct ieee80211com *ic = (void *)ifp;
9812221Sbde	struct ieee80211_channel *c;
991541Srgrimes	int i;
1001549Srgrimes
10183366Sjulian	ether_ifattach(ifp, ic->ic_myaddr);
10283366Sjulian	bpfattach2(ifp, DLT_IEEE802_11,
10312200Sbde	    sizeof(struct ieee80211_frame_addr4), &ic->ic_rawbpf);
1041541Srgrimes	ieee80211_crypto_attach(ifp);
105193066Sjamie
106193066Sjamie	/*
1071541Srgrimes	 * Fill in 802.11 available channel set, mark
108193066Sjamie	 * all available channels as active, and pick
109193066Sjamie	 * a default channel if not already specified.
110193066Sjamie	 */
111193066Sjamie	memset(ic->ic_chan_avail, 0, sizeof(ic->ic_chan_avail));
1121541Srgrimes	ic->ic_modecaps |= 1<<IEEE80211_MODE_AUTO;
113130344Sphk	for (i = 0; i <= IEEE80211_CHAN_MAX; i++) {
1141541Srgrimes		c = &ic->ic_channels[i];
1151541Srgrimes		if (c->ic_flags) {
11612221Sbde			/*
11712200Sbde			 * Verify driver passed us valid data.
1181541Srgrimes			 */
1191541Srgrimes			if (i != ieee80211_chan2ieee(ic, c)) {
12012221Sbde				if_printf(ifp, "bad channel ignored; "
1211541Srgrimes					"freq %u flags %x number %u\n",
1221549Srgrimes					c->ic_freq, c->ic_flags, i);
12383366Sjulian				c->ic_flags = 0;	/* NB: remove */
12483366Sjulian				continue;
12512200Sbde			}
1261541Srgrimes			setbit(ic->ic_chan_avail, i);
127193066Sjamie			/*
1281541Srgrimes			 * Identify mode capabilities.
129193066Sjamie			 */
130193066Sjamie			if (IEEE80211_IS_CHAN_A(c))
131193066Sjamie				ic->ic_modecaps |= 1<<IEEE80211_MODE_11A;
132193066Sjamie			if (IEEE80211_IS_CHAN_B(c))
1331541Srgrimes				ic->ic_modecaps |= 1<<IEEE80211_MODE_11B;
1341541Srgrimes			if (IEEE80211_IS_CHAN_PUREG(c))
1351549Srgrimes				ic->ic_modecaps |= 1<<IEEE80211_MODE_11G;
13683366Sjulian			if (IEEE80211_IS_CHAN_T(c))
13783366Sjulian				ic->ic_modecaps |= 1<<IEEE80211_MODE_TURBO;
13812200Sbde		}
1391541Srgrimes	}
140167232Srwatson	/* validate ic->ic_curmode */
1411541Srgrimes	if ((ic->ic_modecaps & (1<<ic->ic_curmode)) == 0)
1421541Srgrimes		ic->ic_curmode = IEEE80211_MODE_AUTO;
143186570Sed
144186570Sed	(void) ieee80211_setmode(ic, ic->ic_curmode);
145186570Sed
146186570Sed	ic->ic_des_chan = IEEE80211_CHAN_ANYC;	/* any channel is ok */
147186570Sed	if (ic->ic_lintval == 0)
148186570Sed		ic->ic_lintval = 100;		/* default sleep */
149186570Sed	ic->ic_bmisstimeout = 7*ic->ic_lintval;	/* default 7 beacons */
150186570Sed
151186570Sed	ieee80211_node_attach(ifp);
152186570Sed	ieee80211_proto_attach(ifp);
153186570Sed}
154186570Sed
155186570Sedvoid
156186570Sedieee80211_ifdetach(struct ifnet *ifp)
157186570Sed{
158186570Sed	struct ieee80211com *ic = (void *)ifp;
159186570Sed
160186570Sed	ieee80211_proto_detach(ifp);
161186570Sed	ieee80211_crypto_detach(ifp);
162186570Sed	ieee80211_node_detach(ifp);
163186570Sed	ifmedia_removeall(&ic->ic_media);
164186570Sed	bpfdetach(ifp);
165186570Sed	ether_ifdetach(ifp);
166186570Sed}
167186570Sed
168186570Sed/*
169186570Sed * Convert MHz frequency to IEEE channel number.
170186570Sed */
171186570Sedu_int
172186570Sedieee80211_mhz2ieee(u_int freq, u_int flags)
173186570Sed{
174186570Sed	if (flags & IEEE80211_CHAN_2GHZ) {	/* 2GHz band */
175186570Sed		if (freq == 2484)
176186570Sed			return 14;
177186570Sed		if (freq < 2484)
178186570Sed			return (freq - 2407) / 5;
179186570Sed		else
180186570Sed			return 15 + ((freq - 2512) / 20);
181186570Sed	} else if (IEEE80211_CHAN_5GHZ) {	/* 5Ghz band */
182186570Sed		return (freq - 5000) / 5;
183186570Sed	} else {				/* either, guess */
184186570Sed		if (freq == 2484)
185186570Sed			return 14;
186186570Sed		if (freq < 2484)
187186570Sed			return (freq - 2407) / 5;
188186570Sed		if (freq < 5000)
189186570Sed			return 15 + ((freq - 2512) / 20);
190186570Sed		return (freq - 5000) / 5;
191186570Sed	}
192186570Sed}
193186570Sed
194186570Sed/*
195186570Sed * Convert channel to IEEE channel number.
196186570Sed */
197186570Sedu_int
198186570Sedieee80211_chan2ieee(struct ieee80211com *ic, struct ieee80211_channel *c)
199186570Sed{
200186570Sed	if (ic->ic_channels <= c && c <= &ic->ic_channels[IEEE80211_CHAN_MAX])
201186570Sed		return c - ic->ic_channels;
202186570Sed	else if (c == IEEE80211_CHAN_ANYC)
203186570Sed		return IEEE80211_CHAN_ANY;
204186570Sed	else {
205186570Sed		if_printf(&ic->ic_if, "invalid channel freq %u flags %x\n",
206186570Sed			c->ic_freq, c->ic_flags);
207186570Sed		return 0;		/* XXX */
208186570Sed	}
209186570Sed}
210186570Sed
211186570Sed/*
212186570Sed * Convert IEEE channel number to MHz frequency.
213186570Sed */
214186570Sedu_int
215186570Sedieee80211_ieee2mhz(u_int chan, u_int flags)
216186570Sed{
217186570Sed	if (flags & IEEE80211_CHAN_2GHZ) {	/* 2GHz band */
218186570Sed		if (chan == 14)
219186570Sed			return 2484;
220186570Sed		if (chan < 14)
221186570Sed			return 2407 + chan*5;
222186570Sed		else
223186570Sed			return 2512 + ((chan-15)*20);
224186570Sed	} else if (flags & IEEE80211_CHAN_5GHZ) {/* 5Ghz band */
225186570Sed		return 5000 + (chan*5);
226186570Sed	} else {				/* either, guess */
227186570Sed		if (chan == 14)
228186570Sed			return 2484;
229186570Sed		if (chan < 14)			/* 0-13 */
230186570Sed			return 2407 + chan*5;
231186570Sed		if (chan < 27)			/* 15-26 */
232186570Sed			return 2512 + ((chan-15)*20);
233186570Sed		return 5000 + (chan*5);
234186570Sed	}
235186570Sed}
236186570Sed
237186570Sed/*
238186570Sed * Setup the media data structures according to the channel and
239186570Sed * rate tables.  This must be called by the driver after
240186570Sed * ieee80211_attach and before most anything else.
241186570Sed */
242186570Sedvoid
243186570Sedieee80211_media_init(struct ifnet *ifp,
244186570Sed	ifm_change_cb_t media_change, ifm_stat_cb_t media_stat)
245186570Sed{
246186570Sed#define	ADD(_ic, _s, _o) \
247186570Sed	ifmedia_add(&(_ic)->ic_media, \
248186570Sed		IFM_MAKEWORD(IFM_IEEE80211, (_s), (_o), 0), 0, NULL)
249186570Sed	struct ieee80211com *ic = (void *)ifp;
250186570Sed	struct ifmediareq imr;
251186570Sed	int i, j, mode, rate, maxrate, mword, mopt, r;
252186570Sed	struct ieee80211_rateset *rs;
253186570Sed	struct ieee80211_rateset allrates;
254186570Sed
255186570Sed	/*
256186570Sed	 * Fill in media characteristics.
257186570Sed	 */
258186570Sed	ifmedia_init(&ic->ic_media, 0, media_change, media_stat);
259186570Sed	maxrate = 0;
260186570Sed	memset(&allrates, 0, sizeof(allrates));
261186570Sed	for (mode = IEEE80211_MODE_AUTO; mode < IEEE80211_MODE_MAX; mode++) {
262186570Sed		static const u_int mopts[] = {
263186570Sed			IFM_AUTO,
264186570Sed			IFM_MAKEMODE(IFM_IEEE80211_11A),
265186570Sed			IFM_MAKEMODE(IFM_IEEE80211_11B),
266186570Sed			IFM_MAKEMODE(IFM_IEEE80211_11G),
267186570Sed			IFM_MAKEMODE(IFM_IEEE80211_11A) | IFM_IEEE80211_TURBO,
268186570Sed		};
269186570Sed		if ((ic->ic_modecaps & (1<<mode)) == 0)
270186570Sed			continue;
271186570Sed		mopt = mopts[mode];
272186570Sed		ADD(ic, IFM_AUTO, mopt);	/* e.g. 11a auto */
273186570Sed		if (ic->ic_caps & IEEE80211_C_IBSS)
274186570Sed			ADD(ic, IFM_AUTO, mopt | IFM_IEEE80211_ADHOC);
275186570Sed		if (ic->ic_caps & IEEE80211_C_HOSTAP)
276186570Sed			ADD(ic, IFM_AUTO, mopt | IFM_IEEE80211_HOSTAP);
277186570Sed		if (ic->ic_caps & IEEE80211_C_AHDEMO)
278186570Sed			ADD(ic, IFM_AUTO, mopt | IFM_IEEE80211_ADHOC | IFM_FLAG0);
279186570Sed		if (mode == IEEE80211_MODE_AUTO)
280186570Sed			continue;
281186570Sed		if_printf(ifp, "%s rates: ", ieee80211_phymode_name[mode]);
282186570Sed		rs = &ic->ic_sup_rates[mode];
283186570Sed		for (i = 0; i < rs->rs_nrates; i++) {
284186570Sed			rate = rs->rs_rates[i];
285186570Sed			mword = ieee80211_rate2media(ic, rate, mode);
286186570Sed			if (mword == 0)
287186570Sed				continue;
288186570Sed			printf("%s%d%sMbps", (i != 0 ? " " : ""),
289186570Sed			    (rate & IEEE80211_RATE_VAL) / 2,
290186570Sed			    ((rate & 0x1) != 0 ? ".5" : ""));
291186570Sed			ADD(ic, mword, mopt);
292186570Sed			if (ic->ic_caps & IEEE80211_C_IBSS)
293186570Sed				ADD(ic, mword, mopt | IFM_IEEE80211_ADHOC);
294186570Sed			if (ic->ic_caps & IEEE80211_C_HOSTAP)
295186570Sed				ADD(ic, mword, mopt | IFM_IEEE80211_HOSTAP);
296186570Sed			if (ic->ic_caps & IEEE80211_C_AHDEMO)
297186570Sed				ADD(ic, mword, mopt | IFM_IEEE80211_ADHOC | IFM_FLAG0);
298186570Sed			/*
299186570Sed			 * Add rate to the collection of all rates.
300186570Sed			 */
301186570Sed			r = rate & IEEE80211_RATE_VAL;
302186570Sed			for (j = 0; j < allrates.rs_nrates; j++)
303186570Sed				if (allrates.rs_rates[j] == r)
304186570Sed					break;
305186570Sed			if (j == allrates.rs_nrates) {
306186570Sed				/* unique, add to the set */
307186570Sed				allrates.rs_rates[j] = r;
308186570Sed				allrates.rs_nrates++;
309186570Sed			}
310186570Sed			rate = (rate & IEEE80211_RATE_VAL) / 2;
311186570Sed			if (rate > maxrate)
312186570Sed				maxrate = rate;
313186570Sed		}
314186570Sed		printf("\n");
315186570Sed	}
316186570Sed	for (i = 0; i < allrates.rs_nrates; i++) {
317186570Sed		mword = ieee80211_rate2media(ic, allrates.rs_rates[i],
318186570Sed				IEEE80211_MODE_AUTO);
319186570Sed		if (mword == 0)
320186570Sed			continue;
321186570Sed		mword = IFM_SUBTYPE(mword);	/* remove media options */
322186570Sed		ADD(ic, mword, 0);
323186570Sed		if (ic->ic_caps & IEEE80211_C_IBSS)
324186570Sed			ADD(ic, mword, IFM_IEEE80211_ADHOC);
325186570Sed		if (ic->ic_caps & IEEE80211_C_HOSTAP)
326186570Sed			ADD(ic, mword, IFM_IEEE80211_HOSTAP);
327186570Sed		if (ic->ic_caps & IEEE80211_C_AHDEMO)
328186570Sed			ADD(ic, mword, IFM_IEEE80211_ADHOC | IFM_FLAG0);
329186570Sed	}
330186570Sed	ieee80211_media_status(ifp, &imr);
331186570Sed	ifmedia_set(&ic->ic_media, imr.ifm_active);
332186570Sed
333186570Sed	if (maxrate)
334186570Sed		ifp->if_baudrate = IF_Mbps(maxrate);
335186570Sed#undef ADD
336186570Sed}
337186570Sed
338186570Sedstatic int
339186570Sedfindrate(struct ieee80211com *ic, enum ieee80211_phymode mode, int rate)
340186570Sed{
341186570Sed#define	IEEERATE(_ic,_m,_i) \
342186570Sed	((_ic)->ic_sup_rates[_m].rs_rates[_i] & IEEE80211_RATE_VAL)
343186570Sed	int i, nrates = ic->ic_sup_rates[mode].rs_nrates;
344186570Sed	for (i = 0; i < nrates; i++)
345186570Sed		if (IEEERATE(ic, mode, i) == rate)
346186570Sed			return i;
347186570Sed	return -1;
348186570Sed#undef IEEERATE
3491541Srgrimes}
3501549Srgrimes
351184789Sed/*
35274729Speter * Handle a media change request.
353184789Sed */
354167232Srwatsonint
355167232Srwatsonieee80211_media_change(struct ifnet *ifp)
35674729Speter{
35774729Speter	struct ieee80211com *ic = (void *)ifp;
35874729Speter	struct ifmedia_entry *ime;
35974729Speter	enum ieee80211_opmode newopmode;
36012221Sbde	enum ieee80211_phymode newphymode;
3611549Srgrimes	int i, j, newrate, error = 0;
362180039Sjulian
3631549Srgrimes	ime = ic->ic_media.ifm_cur;
36412221Sbde	/*
3651549Srgrimes	 * First, identify the phy mode.
3661549Srgrimes	 */
367184789Sed	switch (IFM_MODE(ime->ifm_media)) {
3681549Srgrimes	case IFM_IEEE80211_11A:
36982717Sdillon		newphymode = IEEE80211_MODE_11A;
37038517Sdfr		break;
3711549Srgrimes	case IFM_IEEE80211_11B:
3721549Srgrimes		newphymode = IEEE80211_MODE_11B;
37312171Sphk		break;
37412171Sphk	case IFM_IEEE80211_11G:
37582717Sdillon		newphymode = IEEE80211_MODE_11G;
37683366Sjulian		break;
377136404Speter	case IFM_AUTO:
37882717Sdillon		newphymode = IEEE80211_MODE_AUTO;
379186564Sed		break;
3801549Srgrimes	default:
3811549Srgrimes		return EINVAL;
38212171Sphk	}
3831549Srgrimes	/*
38483366Sjulian	 * Turbo mode is an ``option''.  Eventually it
385136404Speter	 * needs to be applied to 11g too.
38682717Sdillon	 */
387186564Sed	if (ime->ifm_media & IFM_IEEE80211_TURBO) {
3881549Srgrimes		if (newphymode != IEEE80211_MODE_11A)
3891549Srgrimes			return EINVAL;
39012171Sphk		newphymode = IEEE80211_MODE_TURBO;
3911549Srgrimes	}
39283366Sjulian	/*
393136404Speter	 * Validate requested mode is available.
39482717Sdillon	 */
395186564Sed	if ((ic->ic_modecaps & (1<<newphymode)) == 0)
3961549Srgrimes		return EINVAL;
3971549Srgrimes
3981549Srgrimes	/*
3991549Srgrimes	 * Next, the fixed/variable rate.
4001549Srgrimes	 */
40183366Sjulian	i = -1;
402136404Speter	if (IFM_SUBTYPE(ime->ifm_media) != IFM_AUTO) {
40382717Sdillon		/*
404186564Sed		 * Convert media subtype to rate.
4051549Srgrimes		 */
4061549Srgrimes		newrate = ieee80211_media2rate(ime->ifm_media);
4071549Srgrimes		if (newrate == 0)
4081549Srgrimes			return EINVAL;
4091549Srgrimes		/*
4101549Srgrimes		 * Check the rate table for the specified/current phy.
4111549Srgrimes		 */
4121549Srgrimes		if (newphymode == IEEE80211_MODE_AUTO) {
4131549Srgrimes			/*
41482717Sdillon			 * In autoselect mode search for the rate.
41582717Sdillon			 */
416186564Sed			for (j = IEEE80211_MODE_11A;
4171549Srgrimes			     j < IEEE80211_MODE_MAX; j++) {
41882717Sdillon				if ((ic->ic_modecaps & (1<<j)) == 0)
41982717Sdillon					continue;
420186564Sed				i = findrate(ic, j, newrate);
4211549Srgrimes				if (i != -1) {
42238517Sdfr					/* lock mode too */
42312171Sphk					newphymode = j;
4241549Srgrimes					break;
42583366Sjulian				}
426136404Speter			}
42782717Sdillon		} else {
428186564Sed			i = findrate(ic, newphymode, newrate);
4291549Srgrimes		}
430186564Sed		if (i == -1)			/* mode/rate mismatch */
4311549Srgrimes			return EINVAL;
4321549Srgrimes	}
43312221Sbde	/* NB: defer rate setting to later */
4341549Srgrimes
435180039Sjulian	/*
436180039Sjulian	 * Deduce new operating mode but don't install it just yet.
4371549Srgrimes	 */
43812222Sbde	if ((ime->ifm_media & (IFM_IEEE80211_ADHOC|IFM_FLAG0)) ==
4391549Srgrimes	    (IFM_IEEE80211_ADHOC|IFM_FLAG0))
4401549Srgrimes		newopmode = IEEE80211_M_AHDEMO;
441184789Sed	else if (ime->ifm_media & IFM_IEEE80211_HOSTAP)
442184789Sed		newopmode = IEEE80211_M_HOSTAP;
4431549Srgrimes	else if (ime->ifm_media & IFM_IEEE80211_ADHOC)
444184789Sed		newopmode = IEEE80211_M_IBSS;
445184789Sed	else
44682717Sdillon		newopmode = IEEE80211_M_STA;
447184789Sed
448184789Sed	/*
449186564Sed	 * Autoselect doesn't make sense when operating as an AP.
450186564Sed	 * If no phy mode has been selected, pick one and lock it
4511549Srgrimes	 * down so rate tables can be used in forming beacon frames
4521549Srgrimes	 * and the like.
45312221Sbde	 */
4541549Srgrimes	if (newopmode == IEEE80211_M_HOSTAP &&
455180039Sjulian	    newphymode == IEEE80211_MODE_AUTO) {
456180039Sjulian		for (j = IEEE80211_MODE_11A; j < IEEE80211_MODE_MAX; j++)
4571549Srgrimes			if (ic->ic_modecaps & (1<<j)) {
45812221Sbde				newphymode = j;
4591549Srgrimes				break;
4601549Srgrimes			}
461184789Sed	}
462184789Sed
4631549Srgrimes	/*
464184789Sed	 * Handle phy mode change.
4651549Srgrimes	 */
466184789Sed	if (ic->ic_curmode != newphymode) {		/* change phy mode */
467184789Sed		error = ieee80211_setmode(ic, newphymode);
468186564Sed		if (error != 0)
469186564Sed			return error;
4701549Srgrimes		error = ENETRESET;
471184789Sed	}
472
473	/*
474	 * Committed to changes, install the rate setting.
475	 */
476	if (ic->ic_fixed_rate != i) {
477		ic->ic_fixed_rate = i;			/* set fixed tx rate */
478		error = ENETRESET;
479	}
480
481	/*
482	 * Handle operating mode change.
483	 */
484	if (ic->ic_opmode != newopmode) {
485		ic->ic_opmode = newopmode;
486		switch (newopmode) {
487		case IEEE80211_M_AHDEMO:
488		case IEEE80211_M_HOSTAP:
489		case IEEE80211_M_STA:
490			ic->ic_flags &= ~IEEE80211_F_IBSSON;
491			break;
492		case IEEE80211_M_IBSS:
493			ic->ic_flags |= IEEE80211_F_IBSSON;
494#ifdef notdef
495			if (ic->ic_curmode == IEEE80211_MODE_11G)
496				ieee80211_set11gbasicrates(
497					&ic->ic_suprates[newphymode],
498					IEEE80211_MODE_11B);
499#endif
500			break;
501		}
502		error = ENETRESET;
503	}
504#ifdef notdef
505	if (error == 0)
506		ifp->if_baudrate = ifmedia_baudrate(ime->ifm_media);
507#endif
508	return error;
509}
510
511void
512ieee80211_media_status(struct ifnet *ifp, struct ifmediareq *imr)
513{
514	struct ieee80211com *ic = (void *)ifp;
515	struct ieee80211_node *ni = NULL;
516
517	imr->ifm_status = IFM_AVALID;
518	imr->ifm_active = IFM_IEEE80211;
519	if (ic->ic_state == IEEE80211_S_RUN)
520		imr->ifm_status |= IFM_ACTIVE;
521	imr->ifm_active |= IFM_AUTO;
522	switch (ic->ic_opmode) {
523	case IEEE80211_M_STA:
524		ni = ic->ic_bss;
525		/* calculate rate subtype */
526		imr->ifm_active |= ieee80211_rate2media(ic,
527			ni->ni_rates.rs_rates[ni->ni_txrate], ic->ic_curmode);
528		break;
529	case IEEE80211_M_IBSS:
530		imr->ifm_active |= IFM_IEEE80211_ADHOC;
531		break;
532	case IEEE80211_M_AHDEMO:
533		/* should not come here */
534		break;
535	case IEEE80211_M_HOSTAP:
536		imr->ifm_active |= IFM_IEEE80211_HOSTAP;
537		break;
538	}
539	switch (ic->ic_curmode) {
540	case IEEE80211_MODE_11A:
541		imr->ifm_active |= IFM_MAKEMODE(IFM_IEEE80211_11A);
542		break;
543	case IEEE80211_MODE_11B:
544		imr->ifm_active |= IFM_MAKEMODE(IFM_IEEE80211_11B);
545		break;
546	case IEEE80211_MODE_11G:
547		imr->ifm_active |= IFM_MAKEMODE(IFM_IEEE80211_11G);
548		break;
549	case IEEE80211_MODE_TURBO:
550		imr->ifm_active |= IFM_MAKEMODE(IFM_IEEE80211_11A)
551				|  IFM_IEEE80211_TURBO;
552		break;
553	}
554}
555
556void
557ieee80211_watchdog(struct ifnet *ifp)
558{
559	struct ieee80211com *ic = (void *)ifp;
560
561	if (ic->ic_mgt_timer && --ic->ic_mgt_timer == 0)
562		ieee80211_new_state(ifp, IEEE80211_S_SCAN, -1);
563	if (ic->ic_inact_timer && --ic->ic_inact_timer == 0)
564		ieee80211_timeout_nodes(ic);
565
566	if (ic->ic_mgt_timer != 0 || ic->ic_inact_timer != 0)
567		ifp->if_timer = 1;
568}
569
570/*
571 * Mark the basic rates for the 11g rate table based on the
572 * operating mode.  For real 11g we mark all the 11b rates
573 * and 6, 12, and 24 OFDM.  For 11b compatibility we mark only
574 * 11b rates.  There's also a pseudo 11a-mode used to mark only
575 * the basic OFDM rates.
576 */
577static void
578ieee80211_set11gbasicrates(struct ieee80211_rateset *rs, enum ieee80211_phymode mode)
579{
580	static const struct ieee80211_rateset basic[] = {
581	    { 3, { 12, 24, 48 } },		/* IEEE80211_MODE_11A */
582	    { 4, { 2, 4, 11, 22 } },		/* IEEE80211_MODE_11B */
583	    { 7, { 2, 4, 11, 22, 12, 24, 48 } },/* IEEE80211_MODE_11G */
584	    { 0 },				/* IEEE80211_MODE_TURBO	*/
585	};
586	int i, j;
587
588	for (i = 0; i < rs->rs_nrates; i++) {
589		rs->rs_rates[i] &= IEEE80211_RATE_VAL;
590		for (j = 0; j < basic[mode].rs_nrates; j++)
591			if (basic[mode].rs_rates[j] == rs->rs_rates[i]) {
592				rs->rs_rates[i] |= IEEE80211_RATE_BASIC;
593				break;
594			}
595	}
596}
597
598/*
599 * Set the current phy mode and recalculate the active channel
600 * set based on the available channels for this mode.  Also
601 * select a new default/current channel if the current one is
602 * inappropriate for this mode.
603 */
604int
605ieee80211_setmode(struct ieee80211com *ic, enum ieee80211_phymode mode)
606{
607#define	N(a)	(sizeof(a) / sizeof(a[0]))
608	static const u_int chanflags[] = {
609		0,			/* IEEE80211_MODE_AUTO */
610		IEEE80211_CHAN_A,	/* IEEE80211_MODE_11A */
611		IEEE80211_CHAN_B,	/* IEEE80211_MODE_11B */
612		IEEE80211_CHAN_PUREG,	/* IEEE80211_MODE_11G */
613		IEEE80211_CHAN_T,	/* IEEE80211_MODE_TURBO	*/
614	};
615	struct ieee80211_channel *c;
616	u_int modeflags;
617	int i;
618
619	/* validate new mode */
620	if ((ic->ic_modecaps & (1<<mode)) == 0) {
621		IEEE80211_DPRINTF(("%s: mode %u not supported (caps 0x%x)\n",
622			__func__, mode, ic->ic_modecaps));
623		return EINVAL;
624	}
625
626	/*
627	 * Verify at least one channel is present in the available
628	 * channel list before committing to the new mode.
629	 */
630	KASSERT(mode < N(chanflags), ("Unexpected mode %u\n", mode));
631	modeflags = chanflags[mode];
632	for (i = 0; i <= IEEE80211_CHAN_MAX; i++) {
633		c = &ic->ic_channels[i];
634		if (mode == IEEE80211_MODE_AUTO) {
635			/* ignore turbo channels for autoselect */
636			if ((c->ic_flags &~ IEEE80211_CHAN_TURBO) != 0)
637				break;
638		} else {
639			if ((c->ic_flags & modeflags) == modeflags)
640				break;
641		}
642	}
643	if (i > IEEE80211_CHAN_MAX) {
644		IEEE80211_DPRINTF(("%s: no channels found for mode %u\n",
645			__func__, mode));
646		return EINVAL;
647	}
648
649	/*
650	 * Calculate the active channel set.
651	 */
652	memset(ic->ic_chan_active, 0, sizeof(ic->ic_chan_active));
653	for (i = 0; i <= IEEE80211_CHAN_MAX; i++) {
654		c = &ic->ic_channels[i];
655		if (mode == IEEE80211_MODE_AUTO) {
656			/* take anything but pure turbo channels */
657			if ((c->ic_flags &~ IEEE80211_CHAN_TURBO) != 0)
658				setbit(ic->ic_chan_active, i);
659		} else {
660			if ((c->ic_flags & modeflags) == modeflags)
661				setbit(ic->ic_chan_active, i);
662		}
663	}
664	/*
665	 * If no current/default channel is setup or the current
666	 * channel is wrong for the mode then pick the first
667	 * available channel from the active list.  This is likely
668	 * not the right one.
669	 */
670	if (ic->ic_ibss_chan == NULL ||
671	    isclr(ic->ic_chan_active, ieee80211_chan2ieee(ic, ic->ic_ibss_chan))) {
672		for (i = 0; i <= IEEE80211_CHAN_MAX; i++)
673			if (isset(ic->ic_chan_active, i)) {
674				ic->ic_ibss_chan = &ic->ic_channels[i];
675				break;
676			}
677	}
678
679	/*
680	 * Set/reset state flags that influence beacon contents, etc.
681	 *
682	 * XXX what if we have stations already associated???
683	 * XXX probably not right for autoselect?
684	 */
685	if (mode == IEEE80211_MODE_11G) {
686		if (ic->ic_caps & IEEE80211_C_SHSLOT)
687			ic->ic_flags |= IEEE80211_F_SHSLOT;
688		if (ic->ic_caps & IEEE80211_C_SHPREAMBLE)
689			ic->ic_flags |= IEEE80211_F_SHPREAMBLE;
690		ieee80211_set11gbasicrates(&ic->ic_sup_rates[mode],
691			IEEE80211_MODE_11G);
692	} else {
693		ic->ic_flags &= ~(IEEE80211_F_SHSLOT | IEEE80211_F_SHPREAMBLE);
694	}
695
696	ic->ic_curmode = mode;
697	return 0;
698#undef N
699}
700
701/*
702 * Return the phy mode for with the specified channel so the
703 * caller can select a rate set.  This is problematic and the
704 * work here assumes how things work elsewhere in this code.
705 */
706enum ieee80211_phymode
707ieee80211_chan2mode(struct ieee80211com *ic, struct ieee80211_channel *chan)
708{
709	/*
710	 * NB: this assumes the channel would not be supplied to us
711	 *     unless it was already compatible with the current mode.
712	 */
713	if (ic->ic_curmode != IEEE80211_MODE_AUTO)
714		return ic->ic_curmode;
715	/*
716	 * In autoselect mode; deduce a mode based on the channel
717	 * characteristics.  We assume that turbo-only channels
718	 * are not considered when the channel set is constructed.
719	 */
720	if (IEEE80211_IS_CHAN_5GHZ(chan))
721		return IEEE80211_MODE_11A;
722	else if (chan->ic_flags & (IEEE80211_CHAN_OFDM|IEEE80211_CHAN_DYN))
723		return IEEE80211_MODE_11G;
724	else
725		return IEEE80211_MODE_11B;
726}
727
728/*
729 * convert IEEE80211 rate value to ifmedia subtype.
730 * ieee80211 rate is in unit of 0.5Mbps.
731 */
732int
733ieee80211_rate2media(struct ieee80211com *ic, int rate, enum ieee80211_phymode mode)
734{
735#define	N(a)	(sizeof(a) / sizeof(a[0]))
736	static const struct {
737		u_int	m;	/* rate + mode */
738		u_int	r;	/* if_media rate */
739	} rates[] = {
740		{   2 | IFM_MAKEMODE(IFM_IEEE80211_11B), IFM_IEEE80211_DS1 },
741		{   4 | IFM_MAKEMODE(IFM_IEEE80211_11B), IFM_IEEE80211_DS2 },
742		{  11 | IFM_MAKEMODE(IFM_IEEE80211_11B), IFM_IEEE80211_DS5 },
743		{  22 | IFM_MAKEMODE(IFM_IEEE80211_11B), IFM_IEEE80211_DS11 },
744		{  44 | IFM_MAKEMODE(IFM_IEEE80211_11B), IFM_IEEE80211_DS22 },
745		{  12 | IFM_MAKEMODE(IFM_IEEE80211_11A), IFM_IEEE80211_OFDM6 },
746		{  18 | IFM_MAKEMODE(IFM_IEEE80211_11A), IFM_IEEE80211_OFDM9 },
747		{  24 | IFM_MAKEMODE(IFM_IEEE80211_11A), IFM_IEEE80211_OFDM12 },
748		{  36 | IFM_MAKEMODE(IFM_IEEE80211_11A), IFM_IEEE80211_OFDM18 },
749		{  48 | IFM_MAKEMODE(IFM_IEEE80211_11A), IFM_IEEE80211_OFDM24 },
750		{  72 | IFM_MAKEMODE(IFM_IEEE80211_11A), IFM_IEEE80211_OFDM36 },
751		{  96 | IFM_MAKEMODE(IFM_IEEE80211_11A), IFM_IEEE80211_OFDM48 },
752		{ 108 | IFM_MAKEMODE(IFM_IEEE80211_11A), IFM_IEEE80211_OFDM54 },
753		{   2 | IFM_MAKEMODE(IFM_IEEE80211_11G), IFM_IEEE80211_DS1 },
754		{   4 | IFM_MAKEMODE(IFM_IEEE80211_11G), IFM_IEEE80211_DS2 },
755		{  11 | IFM_MAKEMODE(IFM_IEEE80211_11G), IFM_IEEE80211_DS5 },
756		{  22 | IFM_MAKEMODE(IFM_IEEE80211_11G), IFM_IEEE80211_DS11 },
757		{  12 | IFM_MAKEMODE(IFM_IEEE80211_11G), IFM_IEEE80211_OFDM6 },
758		{  18 | IFM_MAKEMODE(IFM_IEEE80211_11G), IFM_IEEE80211_OFDM9 },
759		{  24 | IFM_MAKEMODE(IFM_IEEE80211_11G), IFM_IEEE80211_OFDM12 },
760		{  36 | IFM_MAKEMODE(IFM_IEEE80211_11G), IFM_IEEE80211_OFDM18 },
761		{  48 | IFM_MAKEMODE(IFM_IEEE80211_11G), IFM_IEEE80211_OFDM24 },
762		{  72 | IFM_MAKEMODE(IFM_IEEE80211_11G), IFM_IEEE80211_OFDM36 },
763		{  96 | IFM_MAKEMODE(IFM_IEEE80211_11G), IFM_IEEE80211_OFDM48 },
764		{ 108 | IFM_MAKEMODE(IFM_IEEE80211_11G), IFM_IEEE80211_OFDM54 },
765		/* NB: OFDM72 doesn't realy exist so we don't handle it */
766	};
767	u_int mask, i;
768
769	mask = rate & IEEE80211_RATE_VAL;
770	switch (mode) {
771	case IEEE80211_MODE_11A:
772	case IEEE80211_MODE_TURBO:
773		mask |= IFM_MAKEMODE(IFM_IEEE80211_11A);
774		break;
775	case IEEE80211_MODE_11B:
776		mask |= IFM_MAKEMODE(IFM_IEEE80211_11B);
777		break;
778	case IEEE80211_MODE_AUTO:
779		/* NB: ic may be NULL for some drivers */
780		if (ic && ic->ic_phytype == IEEE80211_T_FH) {
781			/* must handle these specially */
782			switch (mask) {
783			case 2:		return IFM_IEEE80211_FH1;
784			case 4:		return IFM_IEEE80211_FH2;
785			}
786			return IFM_AUTO;
787		}
788		/* NB: hack, 11g matches both 11b+11a rates */
789		/* fall thru... */
790	case IEEE80211_MODE_11G:
791		mask |= IFM_MAKEMODE(IFM_IEEE80211_11G);
792		break;
793	}
794	for (i = 0; i < N(rates); i++)
795		if (rates[i].m == mask)
796			return rates[i].r;
797	return IFM_AUTO;
798#undef N
799}
800
801int
802ieee80211_media2rate(int mword)
803{
804#define	N(a)	(sizeof(a) / sizeof(a[0]))
805	static const int ieeerates[] = {
806		-1,		/* IFM_AUTO */
807		0,		/* IFM_MANUAL */
808		0,		/* IFM_NONE */
809		2,		/* IFM_IEEE80211_FH1 */
810		4,		/* IFM_IEEE80211_FH2 */
811		2,		/* IFM_IEEE80211_DS1 */
812		4,		/* IFM_IEEE80211_DS2 */
813		11,		/* IFM_IEEE80211_DS5 */
814		22,		/* IFM_IEEE80211_DS11 */
815		44,		/* IFM_IEEE80211_DS22 */
816		12,		/* IFM_IEEE80211_OFDM6 */
817		18,		/* IFM_IEEE80211_OFDM9 */
818		24,		/* IFM_IEEE80211_OFDM12 */
819		36,		/* IFM_IEEE80211_OFDM18 */
820		48,		/* IFM_IEEE80211_OFDM24 */
821		72,		/* IFM_IEEE80211_OFDM36 */
822		96,		/* IFM_IEEE80211_OFDM48 */
823		108,		/* IFM_IEEE80211_OFDM54 */
824		144,		/* IFM_IEEE80211_OFDM72 */
825	};
826	return IFM_SUBTYPE(mword) < N(ieeerates) ?
827		ieeerates[IFM_SUBTYPE(mword)] : 0;
828#undef N
829}
830
831/*
832 * Module glue.
833 *
834 * NB: the module name is "wlan" for compatibility with NetBSD.
835 */
836
837static int
838ieee80211_modevent(module_t mod, int type, void *unused)
839{
840	switch (type) {
841	case MOD_LOAD:
842		if (bootverbose)
843			printf("wlan: <802.11 Link Layer>\n");
844		return 0;
845	case MOD_UNLOAD:
846		return 0;
847	}
848	return EINVAL;
849}
850
851static moduledata_t ieee80211_mod = {
852	"wlan",
853	ieee80211_modevent,
854	0
855};
856DECLARE_MODULE(wlan, ieee80211_mod, SI_SUB_DRIVERS, SI_ORDER_FIRST);
857MODULE_VERSION(wlan, 1);
858MODULE_DEPEND(wlan, rc4, 1, 1, 1);
859