Home | History | Annotate | Line # | Download | only in net80211
ieee80211.c revision 1.48.12.1
      1       1.48  jmcneill /*	$NetBSD: ieee80211.c,v 1.48.12.1 2008/02/22 16:50:25 skrll Exp $	*/
      2        1.1    dyoung /*-
      3        1.1    dyoung  * Copyright (c) 2001 Atsushi Onoe
      4  1.48.12.1     skrll  * Copyright (c) 2002-2007 Sam Leffler, Errno Consulting
      5        1.1    dyoung  * All rights reserved.
      6        1.1    dyoung  *
      7        1.1    dyoung  * Redistribution and use in source and binary forms, with or without
      8        1.1    dyoung  * modification, are permitted provided that the following conditions
      9        1.1    dyoung  * are met:
     10        1.1    dyoung  * 1. Redistributions of source code must retain the above copyright
     11        1.1    dyoung  *    notice, this list of conditions and the following disclaimer.
     12        1.1    dyoung  * 2. Redistributions in binary form must reproduce the above copyright
     13        1.1    dyoung  *    notice, this list of conditions and the following disclaimer in the
     14        1.1    dyoung  *    documentation and/or other materials provided with the distribution.
     15        1.1    dyoung  *
     16        1.1    dyoung  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
     17        1.1    dyoung  * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
     18        1.1    dyoung  * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
     19        1.1    dyoung  * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
     20        1.1    dyoung  * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
     21        1.1    dyoung  * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
     22        1.1    dyoung  * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
     23        1.1    dyoung  * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
     24        1.1    dyoung  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
     25        1.1    dyoung  * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
     26        1.1    dyoung  */
     27        1.1    dyoung 
     28        1.1    dyoung #include <sys/cdefs.h>
     29       1.37    dyoung #ifdef __NetBSD__
     30       1.48  jmcneill __KERNEL_RCSID(0, "$NetBSD: ieee80211.c,v 1.48.12.1 2008/02/22 16:50:25 skrll Exp $");
     31        1.3    dyoung #endif
     32  1.48.12.1     skrll #ifdef __FreeBSD__
     33  1.48.12.1     skrll __FBSDID("$FreeBSD: src/sys/net80211/ieee80211.c,v 1.45 2007/12/07 01:46:12 kmacy Exp $");
     34  1.48.12.1     skrll #endif
     35        1.1    dyoung 
     36        1.1    dyoung /*
     37        1.1    dyoung  * IEEE 802.11 generic handler
     38        1.1    dyoung  */
     39        1.1    dyoung 
     40        1.1    dyoung #include "opt_inet.h"
     41        1.7      matt #include "bpfilter.h"
     42        1.1    dyoung 
     43        1.1    dyoung #include <sys/param.h>
     44       1.37    dyoung #include <sys/systm.h>
     45        1.1    dyoung #include <sys/kernel.h>
     46       1.37    dyoung 
     47        1.1    dyoung #include <sys/socket.h>
     48        1.1    dyoung #include <sys/sockio.h>
     49        1.1    dyoung #include <sys/endian.h>
     50        1.1    dyoung #include <sys/errno.h>
     51        1.1    dyoung #include <sys/proc.h>
     52        1.1    dyoung #include <sys/sysctl.h>
     53        1.1    dyoung 
     54        1.1    dyoung #include <net/if.h>
     55        1.1    dyoung #include <net/if_media.h>
     56        1.1    dyoung #include <net/if_arp.h>
     57        1.4    dyoung #include <net/if_ether.h>
     58        1.1    dyoung #include <net/if_llc.h>
     59        1.1    dyoung 
     60       1.37    dyoung #include <net80211/ieee80211_netbsd.h>
     61        1.1    dyoung #include <net80211/ieee80211_var.h>
     62       1.22    dyoung #include <net80211/ieee80211_sysctl.h>
     63        1.1    dyoung 
     64        1.1    dyoung #include <net/bpf.h>
     65        1.1    dyoung 
     66        1.1    dyoung #ifdef INET
     67       1.37    dyoung #include <netinet/in.h>
     68        1.4    dyoung #include <net/if_ether.h>
     69        1.4    dyoung #endif
     70       1.11    dyoung 
     71       1.37    dyoung const char *ieee80211_phymode_name[] = {
     72       1.10    dyoung 	"auto",		/* IEEE80211_MODE_AUTO */
     73       1.10    dyoung 	"11a",		/* IEEE80211_MODE_11A */
     74       1.10    dyoung 	"11b",		/* IEEE80211_MODE_11B */
     75       1.10    dyoung 	"11g",		/* IEEE80211_MODE_11G */
     76       1.10    dyoung 	"FH",		/* IEEE80211_MODE_FH */
     77       1.37    dyoung 	"turboA",	/* IEEE80211_MODE_TURBO_A */
     78       1.37    dyoung 	"turboG",	/* IEEE80211_MODE_TURBO_G */
     79  1.48.12.1     skrll 	"sturboA",	/* IEEE80211_MODE_STURBO_A */
     80  1.48.12.1     skrll 	"11na",		/* IEEE80211_MODE_11NA */
     81  1.48.12.1     skrll 	"11ng",		/* IEEE80211_MODE_11NG */
     82       1.10    dyoung };
     83        1.1    dyoung 
     84  1.48.12.1     skrll /*
     85  1.48.12.1     skrll  * Default supported rates for 802.11 operation (in IEEE .5Mb units).
     86  1.48.12.1     skrll  */
     87  1.48.12.1     skrll #define	B(r)	((r) | IEEE80211_RATE_BASIC)
     88  1.48.12.1     skrll static const struct ieee80211_rateset ieee80211_rateset_11a =
     89  1.48.12.1     skrll 	{ 8, { B(12), 18, B(24), 36, B(48), 72, 96, 108 } };
     90  1.48.12.1     skrll static const struct ieee80211_rateset ieee80211_rateset_half =
     91  1.48.12.1     skrll 	{ 8, { B(6), 9, B(12), 18, B(24), 36, 48, 54 } };
     92  1.48.12.1     skrll static const struct ieee80211_rateset ieee80211_rateset_quarter =
     93  1.48.12.1     skrll 	{ 8, { B(3), 4, B(6), 9, B(12), 18, 24, 27 } };
     94  1.48.12.1     skrll static const struct ieee80211_rateset ieee80211_rateset_11b =
     95  1.48.12.1     skrll 	{ 4, { B(2), B(4), B(11), B(22) } };
     96  1.48.12.1     skrll /* NB: OFDM rates are handled specially based on mode */
     97  1.48.12.1     skrll static const struct ieee80211_rateset ieee80211_rateset_11g =
     98  1.48.12.1     skrll 	{ 12, { B(2), B(4), B(11), B(22), 12, 18, 24, 36, 48, 72, 96, 108 } };
     99  1.48.12.1     skrll #undef B
    100  1.48.12.1     skrll 
    101  1.48.12.1     skrll static	int media_status(enum ieee80211_opmode ,
    102  1.48.12.1     skrll 		const struct ieee80211_channel *);
    103  1.48.12.1     skrll 
    104       1.37    dyoung /* list of all instances */
    105  1.48.12.1     skrll struct ieee80211_list ieee80211_list =
    106       1.37    dyoung 	SLIST_HEAD_INITIALIZER(ieee80211_list);
    107  1.48.12.1     skrll static uint8_t ieee80211_vapmap[32];		/* enough for 256 */
    108       1.37    dyoung 
    109       1.37    dyoung static void
    110       1.37    dyoung ieee80211_add_vap(struct ieee80211com *ic)
    111       1.37    dyoung {
    112       1.37    dyoung #define	N(a)	(sizeof(a)/sizeof(a[0]))
    113       1.37    dyoung 	int i;
    114       1.37    dyoung 	int s;
    115  1.48.12.1     skrll 	uint8_t b;
    116       1.37    dyoung 
    117       1.37    dyoung 	s = splnet();
    118       1.37    dyoung 	ic->ic_vap = 0;
    119       1.37    dyoung 	for (i = 0; i < N(ieee80211_vapmap) && ieee80211_vapmap[i] == 0xff; i++)
    120       1.37    dyoung 		ic->ic_vap += NBBY;
    121       1.37    dyoung 	if (i == N(ieee80211_vapmap))
    122       1.37    dyoung 		panic("vap table full");
    123       1.37    dyoung 	for (b = ieee80211_vapmap[i]; b & 1; b >>= 1)
    124       1.37    dyoung 		ic->ic_vap++;
    125       1.37    dyoung 	setbit(ieee80211_vapmap, ic->ic_vap);
    126       1.37    dyoung 	SLIST_INSERT_HEAD(&ieee80211_list, ic, ic_next);
    127       1.37    dyoung 	splx(s);
    128       1.37    dyoung #undef N
    129       1.37    dyoung }
    130       1.37    dyoung 
    131       1.37    dyoung static void
    132       1.37    dyoung ieee80211_remove_vap(struct ieee80211com *ic)
    133       1.37    dyoung {
    134       1.37    dyoung 	int s;
    135       1.37    dyoung 
    136       1.37    dyoung 	s = splnet();
    137       1.37    dyoung 	SLIST_REMOVE(&ieee80211_list, ic, ieee80211com, ic_next);
    138       1.37    dyoung 	IASSERT(ic->ic_vap < sizeof(ieee80211_vapmap)*NBBY,
    139       1.37    dyoung 		("invalid vap id %d", ic->ic_vap));
    140       1.37    dyoung 	IASSERT(isset(ieee80211_vapmap, ic->ic_vap),
    141       1.37    dyoung 		("vap id %d not allocated", ic->ic_vap));
    142       1.37    dyoung 	clrbit(ieee80211_vapmap, ic->ic_vap);
    143       1.37    dyoung 	splx(s);
    144       1.37    dyoung }
    145       1.37    dyoung 
    146       1.37    dyoung /*
    147       1.37    dyoung  * Default reset method for use with the ioctl support.  This
    148       1.37    dyoung  * method is invoked after any state change in the 802.11
    149       1.37    dyoung  * layer that should be propagated to the hardware but not
    150       1.37    dyoung  * require re-initialization of the 802.11 state machine (e.g
    151       1.37    dyoung  * rescanning for an ap).  We always return ENETRESET which
    152       1.37    dyoung  * should cause the driver to re-initialize the device. Drivers
    153       1.37    dyoung  * can override this method to implement more optimized support.
    154       1.37    dyoung  */
    155       1.37    dyoung static int
    156       1.47  christos ieee80211_default_reset(struct ifnet *ifp)
    157       1.37    dyoung {
    158       1.37    dyoung 	return ENETRESET;
    159       1.37    dyoung }
    160       1.37    dyoung 
    161  1.48.12.1     skrll /*
    162  1.48.12.1     skrll  * Fill in 802.11 available channel set, mark
    163  1.48.12.1     skrll  * all available channels as active, and pick
    164  1.48.12.1     skrll  * a default channel if not already specified.
    165  1.48.12.1     skrll  */
    166  1.48.12.1     skrll static void
    167  1.48.12.1     skrll ieee80211_chan_init(struct ieee80211com *ic)
    168  1.48.12.1     skrll {
    169  1.48.12.1     skrll #define	DEFAULTRATES(m, def) do { \
    170  1.48.12.1     skrll 	if (isset(ic->ic_modecaps, m) && ic->ic_sup_rates[m].rs_nrates == 0) \
    171  1.48.12.1     skrll 		ic->ic_sup_rates[m] = def; \
    172  1.48.12.1     skrll } while (0)
    173  1.48.12.1     skrll 	struct ieee80211_channel *c;
    174  1.48.12.1     skrll 	int i;
    175  1.48.12.1     skrll 
    176  1.48.12.1     skrll 	IASSERT(0 < ic->ic_nchans && ic->ic_nchans < IEEE80211_CHAN_MAX,
    177  1.48.12.1     skrll 		("invalid number of channels specified: %u", ic->ic_nchans));
    178  1.48.12.1     skrll 	memset(ic->ic_chan_avail, 0, sizeof(ic->ic_chan_avail));
    179  1.48.12.1     skrll 	setbit(ic->ic_modecaps, IEEE80211_MODE_AUTO);
    180  1.48.12.1     skrll 	for (i = 0; i < ic->ic_nchans; i++) {
    181  1.48.12.1     skrll 		c = &ic->ic_channels[i];
    182  1.48.12.1     skrll 		IASSERT(c->ic_flags != 0, ("channel with no flags"));
    183  1.48.12.1     skrll 		IASSERT(c->ic_ieee < IEEE80211_CHAN_MAX,
    184  1.48.12.1     skrll 			("channel with bogus ieee number %u", c->ic_ieee));
    185  1.48.12.1     skrll 		setbit(ic->ic_chan_avail, c->ic_ieee);
    186  1.48.12.1     skrll 		/*
    187  1.48.12.1     skrll 		 * Identify mode capabilities.
    188  1.48.12.1     skrll 		 */
    189  1.48.12.1     skrll 		if (IEEE80211_IS_CHAN_A(c))
    190  1.48.12.1     skrll 			setbit(ic->ic_modecaps, IEEE80211_MODE_11A);
    191  1.48.12.1     skrll 		if (IEEE80211_IS_CHAN_B(c))
    192  1.48.12.1     skrll 			setbit(ic->ic_modecaps, IEEE80211_MODE_11B);
    193  1.48.12.1     skrll 		if (IEEE80211_IS_CHAN_ANYG(c))
    194  1.48.12.1     skrll 			setbit(ic->ic_modecaps, IEEE80211_MODE_11G);
    195  1.48.12.1     skrll 		if (IEEE80211_IS_CHAN_FHSS(c))
    196  1.48.12.1     skrll 			setbit(ic->ic_modecaps, IEEE80211_MODE_FH);
    197  1.48.12.1     skrll 		if (IEEE80211_IS_CHAN_108A(c))
    198  1.48.12.1     skrll 			setbit(ic->ic_modecaps, IEEE80211_MODE_TURBO_A);
    199  1.48.12.1     skrll 		if (IEEE80211_IS_CHAN_108G(c))
    200  1.48.12.1     skrll 			setbit(ic->ic_modecaps, IEEE80211_MODE_TURBO_G);
    201  1.48.12.1     skrll 		if (IEEE80211_IS_CHAN_ST(c))
    202  1.48.12.1     skrll 			setbit(ic->ic_modecaps, IEEE80211_MODE_STURBO_A);
    203  1.48.12.1     skrll 		if (IEEE80211_IS_CHAN_HTA(c))
    204  1.48.12.1     skrll 			setbit(ic->ic_modecaps, IEEE80211_MODE_11NA);
    205  1.48.12.1     skrll 		if (IEEE80211_IS_CHAN_HTG(c))
    206  1.48.12.1     skrll 			setbit(ic->ic_modecaps, IEEE80211_MODE_11NG);
    207  1.48.12.1     skrll 	}
    208  1.48.12.1     skrll 	/* initialize candidate channels to all available */
    209  1.48.12.1     skrll 	memcpy(ic->ic_chan_active, ic->ic_chan_avail,
    210  1.48.12.1     skrll 		sizeof(ic->ic_chan_avail));
    211  1.48.12.1     skrll 
    212  1.48.12.1     skrll 	ic->ic_des_chan = IEEE80211_CHAN_ANYC;	/* any channel is ok */
    213  1.48.12.1     skrll 	ic->ic_bsschan = IEEE80211_CHAN_ANYC;
    214  1.48.12.1     skrll 	ic->ic_prevchan = NULL;
    215  1.48.12.1     skrll 	/* arbitrarily pick the first channel */
    216  1.48.12.1     skrll 	ic->ic_curchan = &ic->ic_channels[0];
    217  1.48.12.1     skrll 
    218  1.48.12.1     skrll 	/* fillin well-known rate sets if driver has not specified */
    219  1.48.12.1     skrll 	DEFAULTRATES(IEEE80211_MODE_11B,	 ieee80211_rateset_11b);
    220  1.48.12.1     skrll 	DEFAULTRATES(IEEE80211_MODE_11G,	 ieee80211_rateset_11g);
    221  1.48.12.1     skrll 	DEFAULTRATES(IEEE80211_MODE_11A,	 ieee80211_rateset_11a);
    222  1.48.12.1     skrll 	DEFAULTRATES(IEEE80211_MODE_TURBO_A,	 ieee80211_rateset_11a);
    223  1.48.12.1     skrll 	DEFAULTRATES(IEEE80211_MODE_TURBO_G,	 ieee80211_rateset_11g);
    224  1.48.12.1     skrll 
    225  1.48.12.1     skrll 	/*
    226  1.48.12.1     skrll 	 * Set auto mode to reset active channel state and any desired channel.
    227  1.48.12.1     skrll 	 */
    228  1.48.12.1     skrll 	(void) ieee80211_setmode(ic, IEEE80211_MODE_AUTO);
    229  1.48.12.1     skrll #undef DEFAULTRATES
    230  1.48.12.1     skrll }
    231  1.48.12.1     skrll 
    232        1.1    dyoung void
    233       1.37    dyoung ieee80211_ifattach(struct ieee80211com *ic)
    234        1.1    dyoung {
    235       1.37    dyoung 	struct ifnet *ifp = ic->ic_ifp;
    236        1.1    dyoung 
    237       1.42   thorpej #ifdef __NetBSD__
    238  1.48.12.1     skrll 	net80211_init();
    239       1.42   thorpej #endif /* __NetBSD__ */
    240       1.42   thorpej 
    241        1.1    dyoung 	ether_ifattach(ifp, ic->ic_myaddr);
    242  1.48.12.1     skrll 	ifp->if_output = ieee80211_output;
    243  1.48.12.1     skrll 
    244        1.7      matt #if NBPFILTER > 0
    245        1.1    dyoung 	bpfattach2(ifp, DLT_IEEE802_11,
    246        1.1    dyoung 	    sizeof(struct ieee80211_frame_addr4), &ic->ic_rawbpf);
    247        1.7      matt #endif
    248       1.37    dyoung 
    249  1.48.12.1     skrll 	/* override the 802.3 setting */
    250  1.48.12.1     skrll 	ifp->if_hdrlen = ic->ic_headroom
    251  1.48.12.1     skrll 		+ sizeof(struct ieee80211_qosframe_addr4)
    252  1.48.12.1     skrll 		+ IEEE80211_WEP_IVLEN + IEEE80211_WEP_KIDLEN
    253  1.48.12.1     skrll 		+ IEEE80211_WEP_EXTIVLEN;
    254  1.48.12.1     skrll 	/* XXX no way to recalculate on ifdetach */
    255  1.48.12.1     skrll 	if (ALIGN(ifp->if_hdrlen) > max_linkhdr) {
    256  1.48.12.1     skrll 		/* XXX sanity check... */
    257  1.48.12.1     skrll 		max_linkhdr = ALIGN(ifp->if_hdrlen);
    258  1.48.12.1     skrll 		max_hdr = max_linkhdr + max_protohdr;
    259  1.48.12.1     skrll 		max_datalen = MHLEN - max_hdr;
    260  1.48.12.1     skrll 	}
    261        1.1    dyoung 
    262        1.1    dyoung 	/*
    263  1.48.12.1     skrll 	 * Fill in 802.11 available channel set, mark all
    264  1.48.12.1     skrll 	 * available channels as active, and pick a default
    265  1.48.12.1     skrll 	 * channel if not already specified.
    266        1.1    dyoung 	 */
    267  1.48.12.1     skrll 	ieee80211_chan_init(ic);
    268  1.48.12.1     skrll 
    269  1.48.12.1     skrll 	if (ic->ic_caps & IEEE80211_C_BGSCAN)	/* enable if capable */
    270  1.48.12.1     skrll 		ic->ic_flags |= IEEE80211_F_BGSCAN;
    271       1.37    dyoung #if 0
    272  1.48.12.1     skrll 	/* XXX not until WME+WPA issues resolved */
    273  1.48.12.1     skrll 	if (ic->ic_caps & IEEE80211_C_WME)	/* enable if capable */
    274       1.37    dyoung 		ic->ic_flags |= IEEE80211_F_WME;
    275       1.37    dyoung #endif
    276  1.48.12.1     skrll 	if (ic->ic_caps & IEEE80211_C_BURST)
    277  1.48.12.1     skrll 		ic->ic_flags |= IEEE80211_F_BURST;
    278  1.48.12.1     skrll 	ic->ic_flags |= IEEE80211_F_DOTH;	/* XXX out of caps, just ena */
    279        1.1    dyoung 
    280  1.48.12.1     skrll 	ic->ic_bintval = IEEE80211_BINTVAL_DEFAULT;
    281  1.48.12.1     skrll 	ic->ic_bmissthreshold = IEEE80211_HWBMISS_DEFAULT;
    282       1.37    dyoung 	ic->ic_dtim_period = IEEE80211_DTIM_DEFAULT;
    283  1.48.12.1     skrll 	IEEE80211_LOCK_INIT(ic, "ieee80211com");
    284       1.37    dyoung 	IEEE80211_BEACON_LOCK_INIT(ic, "beacon");
    285       1.37    dyoung 
    286  1.48.12.1     skrll 	ic->ic_lintval = ic->ic_bintval;
    287       1.37    dyoung 	ic->ic_txpowlimit = IEEE80211_TXPOWER_MAX;
    288        1.1    dyoung 
    289  1.48.12.1     skrll 	ieee80211_crypto_attach(ic);
    290       1.28   mycroft 	ieee80211_node_attach(ic);
    291  1.48.12.1     skrll 	ieee80211_power_attach(ic);
    292       1.37    dyoung 	ieee80211_proto_attach(ic);
    293  1.48.12.1     skrll 	ieee80211_ht_attach(ic);
    294  1.48.12.1     skrll 	ieee80211_scan_attach(ic);
    295       1.37    dyoung 
    296       1.37    dyoung 	ieee80211_add_vap(ic);
    297       1.37    dyoung 
    298       1.37    dyoung 	ieee80211_sysctl_attach(ic);		/* NB: requires ic_vap */
    299       1.37    dyoung 
    300       1.37    dyoung 	/*
    301       1.37    dyoung 	 * Install a default reset method for the ioctl support.
    302       1.37    dyoung 	 * The driver is expected to fill this in before calling us.
    303       1.37    dyoung 	 */
    304       1.37    dyoung 	if (ic->ic_reset == NULL)
    305       1.37    dyoung 		ic->ic_reset = ieee80211_default_reset;
    306  1.48.12.1     skrll 
    307  1.48.12.1     skrll #if !defined(__NetBSD__)
    308  1.48.12.1     skrll 	IASSERT(ifp->if_llsoftc == NULL, ("oops, hosed"));
    309  1.48.12.1     skrll 	ifp->if_llsoftc = ic;
    310  1.48.12.1     skrll #endif
    311        1.1    dyoung }
    312        1.1    dyoung 
    313        1.1    dyoung void
    314       1.37    dyoung ieee80211_ifdetach(struct ieee80211com *ic)
    315        1.1    dyoung {
    316       1.37    dyoung 	struct ifnet *ifp = ic->ic_ifp;
    317       1.37    dyoung 
    318       1.37    dyoung 	ieee80211_remove_vap(ic);
    319        1.1    dyoung 
    320       1.37    dyoung 	ieee80211_sysctl_detach(ic);
    321  1.48.12.1     skrll 	ieee80211_scan_detach(ic);
    322  1.48.12.1     skrll 	ieee80211_ht_detach(ic);
    323  1.48.12.1     skrll 	/* NB: must be called before ieee80211_node_detach */
    324       1.37    dyoung 	ieee80211_proto_detach(ic);
    325       1.37    dyoung 	ieee80211_crypto_detach(ic);
    326  1.48.12.1     skrll 	ieee80211_power_detach(ic);
    327       1.28   mycroft 	ieee80211_node_detach(ic);
    328       1.37    dyoung 	ifmedia_delete_instance(&ic->ic_media, IFM_INST_ANY);
    329       1.37    dyoung 
    330  1.48.12.1     skrll 	IEEE80211_LOCK_DESTROY(ic);
    331       1.37    dyoung 	IEEE80211_BEACON_LOCK_DESTROY(ic);
    332       1.37    dyoung 
    333        1.7      matt #if NBPFILTER > 0
    334        1.1    dyoung 	bpfdetach(ifp);
    335        1.7      matt #endif
    336        1.1    dyoung 	ether_ifdetach(ifp);
    337        1.1    dyoung }
    338        1.1    dyoung 
    339  1.48.12.1     skrll static __inline int
    340  1.48.12.1     skrll mapgsm(u_int freq, u_int flags)
    341  1.48.12.1     skrll {
    342  1.48.12.1     skrll 	freq *= 10;
    343  1.48.12.1     skrll 	if (flags & IEEE80211_CHAN_QUARTER)
    344  1.48.12.1     skrll 		freq += 5;
    345  1.48.12.1     skrll 	else if (flags & IEEE80211_CHAN_HALF)
    346  1.48.12.1     skrll 		freq += 10;
    347  1.48.12.1     skrll 	else
    348  1.48.12.1     skrll 		freq += 20;
    349  1.48.12.1     skrll 	/* NB: there is no 907/20 wide but leave room */
    350  1.48.12.1     skrll 	return (freq - 906*10) / 5;
    351  1.48.12.1     skrll }
    352  1.48.12.1     skrll 
    353  1.48.12.1     skrll static __inline int
    354  1.48.12.1     skrll mappsb(u_int freq, u_int flags)
    355  1.48.12.1     skrll {
    356  1.48.12.1     skrll 	return 37 + ((freq * 10) + ((freq % 5) == 2 ? 5 : 0) - 49400) / 5;
    357  1.48.12.1     skrll }
    358  1.48.12.1     skrll 
    359        1.1    dyoung /*
    360        1.1    dyoung  * Convert MHz frequency to IEEE channel number.
    361        1.1    dyoung  */
    362  1.48.12.1     skrll int
    363        1.1    dyoung ieee80211_mhz2ieee(u_int freq, u_int flags)
    364        1.1    dyoung {
    365  1.48.12.1     skrll #define	IS_FREQ_IN_PSB(_freq) ((_freq) > 4940 && (_freq) < 4990)
    366  1.48.12.1     skrll 	if (flags & IEEE80211_CHAN_GSM)
    367  1.48.12.1     skrll 		return mapgsm(freq, flags);
    368        1.1    dyoung 	if (flags & IEEE80211_CHAN_2GHZ) {	/* 2GHz band */
    369        1.1    dyoung 		if (freq == 2484)
    370        1.1    dyoung 			return 14;
    371        1.1    dyoung 		if (freq < 2484)
    372  1.48.12.1     skrll 			return ((int) freq - 2407) / 5;
    373        1.1    dyoung 		else
    374        1.1    dyoung 			return 15 + ((freq - 2512) / 20);
    375  1.48.12.1     skrll 	} else if (flags & IEEE80211_CHAN_5GHZ) {	/* 5Ghz band */
    376  1.48.12.1     skrll 		if (freq <= 5000) {
    377  1.48.12.1     skrll 			/* XXX check regdomain? */
    378  1.48.12.1     skrll 			if (IS_FREQ_IN_PSB(freq))
    379  1.48.12.1     skrll 				return mappsb(freq, flags);
    380  1.48.12.1     skrll 			return (freq - 4000) / 5;
    381  1.48.12.1     skrll 		} else
    382  1.48.12.1     skrll 			return (freq - 5000) / 5;
    383        1.1    dyoung 	} else {				/* either, guess */
    384        1.1    dyoung 		if (freq == 2484)
    385        1.1    dyoung 			return 14;
    386  1.48.12.1     skrll 		if (freq < 2484) {
    387  1.48.12.1     skrll 			if (907 <= freq && freq <= 922)
    388  1.48.12.1     skrll 				return mapgsm(freq, flags);
    389  1.48.12.1     skrll 			return ((int) freq - 2407) / 5;
    390  1.48.12.1     skrll 		}
    391  1.48.12.1     skrll 		if (freq < 5000) {
    392  1.48.12.1     skrll 			if (IS_FREQ_IN_PSB(freq))
    393  1.48.12.1     skrll 				return mappsb(freq, flags);
    394  1.48.12.1     skrll 			else if (freq > 4900)
    395  1.48.12.1     skrll 				return (freq - 4000) / 5;
    396  1.48.12.1     skrll 			else
    397  1.48.12.1     skrll 				return 15 + ((freq - 2512) / 20);
    398  1.48.12.1     skrll 		}
    399        1.1    dyoung 		return (freq - 5000) / 5;
    400        1.1    dyoung 	}
    401  1.48.12.1     skrll #undef IS_FREQ_IN_PSB
    402        1.1    dyoung }
    403        1.1    dyoung 
    404        1.1    dyoung /*
    405        1.1    dyoung  * Convert channel to IEEE channel number.
    406        1.1    dyoung  */
    407  1.48.12.1     skrll int
    408  1.48.12.1     skrll ieee80211_chan2ieee(struct ieee80211com *ic, const struct ieee80211_channel *c)
    409        1.1    dyoung {
    410  1.48.12.1     skrll 	if (c == NULL) {
    411       1.37    dyoung 		if_printf(ic->ic_ifp, "invalid channel (NULL)\n");
    412        1.1    dyoung 		return 0;		/* XXX */
    413        1.1    dyoung 	}
    414  1.48.12.1     skrll 	return (c == IEEE80211_CHAN_ANYC ?  IEEE80211_CHAN_ANY : c->ic_ieee);
    415        1.1    dyoung }
    416        1.1    dyoung 
    417        1.1    dyoung /*
    418        1.1    dyoung  * Convert IEEE channel number to MHz frequency.
    419        1.1    dyoung  */
    420        1.1    dyoung u_int
    421        1.1    dyoung ieee80211_ieee2mhz(u_int chan, u_int flags)
    422        1.1    dyoung {
    423  1.48.12.1     skrll 	if (flags & IEEE80211_CHAN_GSM)
    424  1.48.12.1     skrll 		return 907 + 5 * (chan / 10);
    425        1.1    dyoung 	if (flags & IEEE80211_CHAN_2GHZ) {	/* 2GHz band */
    426        1.1    dyoung 		if (chan == 14)
    427        1.1    dyoung 			return 2484;
    428        1.1    dyoung 		if (chan < 14)
    429        1.1    dyoung 			return 2407 + chan*5;
    430        1.1    dyoung 		else
    431        1.1    dyoung 			return 2512 + ((chan-15)*20);
    432  1.48.12.1     skrll 	} else if (flags & IEEE80211_CHAN_5GHZ) {/* 5Ghz band */
    433  1.48.12.1     skrll 		if (flags & (IEEE80211_CHAN_HALF|IEEE80211_CHAN_QUARTER)) {
    434  1.48.12.1     skrll 			chan -= 37;
    435  1.48.12.1     skrll 			return 4940 + chan*5 + (chan % 5 ? 2 : 0);
    436  1.48.12.1     skrll 		}
    437        1.1    dyoung 		return 5000 + (chan*5);
    438        1.1    dyoung 	} else {				/* either, guess */
    439  1.48.12.1     skrll 		/* XXX can't distinguish PSB+GSM channels */
    440        1.1    dyoung 		if (chan == 14)
    441        1.1    dyoung 			return 2484;
    442        1.1    dyoung 		if (chan < 14)			/* 0-13 */
    443        1.1    dyoung 			return 2407 + chan*5;
    444        1.1    dyoung 		if (chan < 27)			/* 15-26 */
    445        1.1    dyoung 			return 2512 + ((chan-15)*20);
    446        1.1    dyoung 		return 5000 + (chan*5);
    447        1.1    dyoung 	}
    448        1.1    dyoung }
    449        1.1    dyoung 
    450        1.1    dyoung /*
    451  1.48.12.1     skrll  * Locate a channel given a frequency+flags.  We cache
    452  1.48.12.1     skrll  * the previous lookup to optimize swithing between two
    453  1.48.12.1     skrll  * channels--as happens with dynamic turbo.
    454  1.48.12.1     skrll  */
    455  1.48.12.1     skrll struct ieee80211_channel *
    456  1.48.12.1     skrll ieee80211_find_channel(struct ieee80211com *ic, int freq, int flags)
    457  1.48.12.1     skrll {
    458  1.48.12.1     skrll 	struct ieee80211_channel *c;
    459  1.48.12.1     skrll 	int i;
    460  1.48.12.1     skrll 
    461  1.48.12.1     skrll 	flags &= IEEE80211_CHAN_ALLTURBO;
    462  1.48.12.1     skrll 	c = ic->ic_prevchan;
    463  1.48.12.1     skrll 	if (c != NULL && c->ic_freq == freq &&
    464  1.48.12.1     skrll 	    (c->ic_flags & IEEE80211_CHAN_ALLTURBO) == flags)
    465  1.48.12.1     skrll 		return c;
    466  1.48.12.1     skrll 	/* brute force search */
    467  1.48.12.1     skrll 	for (i = 0; i < ic->ic_nchans; i++) {
    468  1.48.12.1     skrll 		c = &ic->ic_channels[i];
    469  1.48.12.1     skrll 		if (c->ic_freq == freq &&
    470  1.48.12.1     skrll 		    (c->ic_flags & IEEE80211_CHAN_ALLTURBO) == flags)
    471  1.48.12.1     skrll 			return c;
    472  1.48.12.1     skrll 	}
    473  1.48.12.1     skrll 	return NULL;
    474  1.48.12.1     skrll }
    475  1.48.12.1     skrll 
    476  1.48.12.1     skrll /*
    477  1.48.12.1     skrll  * Locate a channel given a channel number+flags.  We cache
    478  1.48.12.1     skrll  * the previous lookup to optimize switching between two
    479  1.48.12.1     skrll  * channels--as happens with dynamic turbo.
    480  1.48.12.1     skrll  */
    481  1.48.12.1     skrll struct ieee80211_channel *
    482  1.48.12.1     skrll ieee80211_find_channel_byieee(struct ieee80211com *ic, int ieee, int flags)
    483  1.48.12.1     skrll {
    484  1.48.12.1     skrll 	struct ieee80211_channel *c;
    485  1.48.12.1     skrll 	int i;
    486  1.48.12.1     skrll 
    487  1.48.12.1     skrll 	flags &= IEEE80211_CHAN_ALLTURBO;
    488  1.48.12.1     skrll 	c = ic->ic_prevchan;
    489  1.48.12.1     skrll 	if (c != NULL && c->ic_ieee == ieee &&
    490  1.48.12.1     skrll 	    (c->ic_flags & IEEE80211_CHAN_ALLTURBO) == flags)
    491  1.48.12.1     skrll 		return c;
    492  1.48.12.1     skrll 	/* brute force search */
    493  1.48.12.1     skrll 	for (i = 0; i < ic->ic_nchans; i++) {
    494  1.48.12.1     skrll 		c = &ic->ic_channels[i];
    495  1.48.12.1     skrll 		if (c->ic_ieee == ieee &&
    496  1.48.12.1     skrll 		    (c->ic_flags & IEEE80211_CHAN_ALLTURBO) == flags)
    497  1.48.12.1     skrll 			return c;
    498  1.48.12.1     skrll 	}
    499  1.48.12.1     skrll 	return NULL;
    500  1.48.12.1     skrll }
    501  1.48.12.1     skrll 
    502  1.48.12.1     skrll static void
    503  1.48.12.1     skrll addmedia(struct ieee80211com *ic, int mode, int mword)
    504  1.48.12.1     skrll {
    505  1.48.12.1     skrll #define	TURBO(m)	((m) | IFM_IEEE80211_TURBO)
    506  1.48.12.1     skrll #define	ADD(_ic, _s, _o) \
    507  1.48.12.1     skrll 	ifmedia_add(&(_ic)->ic_media, \
    508  1.48.12.1     skrll 		IFM_MAKEWORD(IFM_IEEE80211, (_s), (_o), 0), 0, NULL)
    509  1.48.12.1     skrll 	static const u_int mopts[IEEE80211_MODE_MAX] = {
    510  1.48.12.1     skrll 		IFM_AUTO,			/* IEEE80211_MODE_AUTO */
    511  1.48.12.1     skrll 		IFM_IEEE80211_11A,		/* IEEE80211_MODE_11A */
    512  1.48.12.1     skrll 		IFM_IEEE80211_11B,		/* IEEE80211_MODE_11B */
    513  1.48.12.1     skrll 		IFM_IEEE80211_11G,		/* IEEE80211_MODE_11G */
    514  1.48.12.1     skrll 		IFM_IEEE80211_FH,		/* IEEE80211_MODE_FH */
    515  1.48.12.1     skrll 		TURBO(IFM_IEEE80211_11A),	/* IEEE80211_MODE_TURBO_A */
    516  1.48.12.1     skrll 		TURBO(IFM_IEEE80211_11G),	/* IEEE80211_MODE_TURBO_G */
    517  1.48.12.1     skrll 		TURBO(IFM_IEEE80211_11A),	/* IEEE80211_MODE_STURBO_A */
    518  1.48.12.1     skrll 		IFM_IEEE80211_11NA,		/* IEEE80211_MODE_11NA */
    519  1.48.12.1     skrll 		IFM_IEEE80211_11NG,		/* IEEE80211_MODE_11NG */
    520  1.48.12.1     skrll 	};
    521  1.48.12.1     skrll 	u_int mopt;
    522  1.48.12.1     skrll 
    523  1.48.12.1     skrll 	IASSERT(mode < IEEE80211_MODE_MAX, ("bad mode %u", mode));
    524  1.48.12.1     skrll 	mopt = mopts[mode];
    525  1.48.12.1     skrll 	IASSERT(mopt != 0 || mode == IEEE80211_MODE_AUTO,
    526  1.48.12.1     skrll 	    ("no media mapping for mode %u", mode));
    527  1.48.12.1     skrll 
    528  1.48.12.1     skrll 	ADD(ic, mword, mopt);	/* e.g. 11a auto */
    529  1.48.12.1     skrll 	if (ic->ic_caps & IEEE80211_C_IBSS)
    530  1.48.12.1     skrll 		ADD(ic, mword, mopt | IFM_IEEE80211_ADHOC);
    531  1.48.12.1     skrll 	if (ic->ic_caps & IEEE80211_C_HOSTAP)
    532  1.48.12.1     skrll 		ADD(ic, mword, mopt | IFM_IEEE80211_HOSTAP);
    533  1.48.12.1     skrll 	if (ic->ic_caps & IEEE80211_C_AHDEMO)
    534  1.48.12.1     skrll 		ADD(ic, mword, mopt | IFM_IEEE80211_ADHOC | IFM_FLAG0);
    535  1.48.12.1     skrll 	if (ic->ic_caps & IEEE80211_C_MONITOR)
    536  1.48.12.1     skrll 		ADD(ic, mword, mopt | IFM_IEEE80211_MONITOR);
    537  1.48.12.1     skrll #undef ADD
    538  1.48.12.1     skrll #undef TURBO
    539  1.48.12.1     skrll }
    540  1.48.12.1     skrll 
    541  1.48.12.1     skrll /*
    542        1.1    dyoung  * Setup the media data structures according to the channel and
    543        1.1    dyoung  * rate tables.  This must be called by the driver after
    544        1.1    dyoung  * ieee80211_attach and before most anything else.
    545        1.1    dyoung  */
    546        1.1    dyoung void
    547       1.37    dyoung ieee80211_media_init(struct ieee80211com *ic,
    548        1.1    dyoung 	ifm_change_cb_t media_change, ifm_stat_cb_t media_stat)
    549        1.1    dyoung {
    550       1.37    dyoung 	struct ifnet *ifp = ic->ic_ifp;
    551  1.48.12.1     skrll 	int i, j, mode, rate, maxrate, mword, r;
    552  1.48.12.1     skrll 	const struct ieee80211_rateset *rs;
    553        1.1    dyoung 	struct ieee80211_rateset allrates;
    554        1.1    dyoung 
    555  1.48.12.1     skrll 	/* XXXNH */
    556  1.48.12.1     skrll 	/* NB: this works because the structure is initialized to zero */
    557  1.48.12.1     skrll 	if (TAILQ_EMPTY(&ic->ic_media.ifm_list)) {
    558  1.48.12.1     skrll 		/*
    559  1.48.12.1     skrll 		 * Do late attach work that must wait for any subclass
    560  1.48.12.1     skrll 		 * (i.e. driver) work such as overriding methods.
    561  1.48.12.1     skrll 		 */
    562  1.48.12.1     skrll 		ieee80211_node_lateattach(ic);
    563  1.48.12.1     skrll 	} else {
    564  1.48.12.1     skrll 		/*
    565  1.48.12.1     skrll 		 * We are re-initializing the channel list; clear
    566  1.48.12.1     skrll 		 * the existing media state as the media routines
    567  1.48.12.1     skrll 		 * don't suppress duplicates.
    568  1.48.12.1     skrll 		 */
    569  1.48.12.1     skrll 		ifmedia_delete_instance(&ic->ic_media, IFM_INST_ANY);
    570  1.48.12.1     skrll 		ieee80211_chan_init(ic);
    571  1.48.12.1     skrll 	}
    572  1.48.12.1     skrll 	ieee80211_power_lateattach(ic);
    573        1.1    dyoung 
    574       1.38    dyoung #ifdef IEEE80211_NO_HOSTAP
    575       1.38    dyoung 	ic->ic_caps &= ~IEEE80211_C_HOSTAP;
    576       1.38    dyoung #endif /* IEEE80211_NO_HOSTAP */
    577       1.38    dyoung 
    578        1.1    dyoung 	/*
    579        1.1    dyoung 	 * Fill in media characteristics.
    580        1.1    dyoung 	 */
    581        1.1    dyoung 	ifmedia_init(&ic->ic_media, 0, media_change, media_stat);
    582        1.1    dyoung 	maxrate = 0;
    583  1.48.12.1     skrll 	/*
    584  1.48.12.1     skrll 	 * Add media for legacy operating modes.
    585  1.48.12.1     skrll 	 */
    586        1.1    dyoung 	memset(&allrates, 0, sizeof(allrates));
    587  1.48.12.1     skrll 	for (mode = IEEE80211_MODE_AUTO; mode < IEEE80211_MODE_11NA; mode++) {
    588  1.48.12.1     skrll 		if (isclr(ic->ic_modecaps, mode))
    589        1.1    dyoung 			continue;
    590  1.48.12.1     skrll 		addmedia(ic, mode, IFM_AUTO);
    591        1.1    dyoung 		if (mode == IEEE80211_MODE_AUTO)
    592        1.1    dyoung 			continue;
    593        1.1    dyoung 		rs = &ic->ic_sup_rates[mode];
    594        1.1    dyoung 		for (i = 0; i < rs->rs_nrates; i++) {
    595        1.1    dyoung 			rate = rs->rs_rates[i];
    596        1.1    dyoung 			mword = ieee80211_rate2media(ic, rate, mode);
    597        1.1    dyoung 			if (mword == 0)
    598        1.1    dyoung 				continue;
    599  1.48.12.1     skrll 			addmedia(ic, mode, mword);
    600        1.1    dyoung 			/*
    601  1.48.12.1     skrll 			 * Add legacy rate to the collection of all rates.
    602        1.1    dyoung 			 */
    603        1.1    dyoung 			r = rate & IEEE80211_RATE_VAL;
    604        1.1    dyoung 			for (j = 0; j < allrates.rs_nrates; j++)
    605        1.1    dyoung 				if (allrates.rs_rates[j] == r)
    606        1.1    dyoung 					break;
    607        1.1    dyoung 			if (j == allrates.rs_nrates) {
    608        1.1    dyoung 				/* unique, add to the set */
    609        1.1    dyoung 				allrates.rs_rates[j] = r;
    610        1.1    dyoung 				allrates.rs_nrates++;
    611        1.1    dyoung 			}
    612        1.1    dyoung 			rate = (rate & IEEE80211_RATE_VAL) / 2;
    613        1.1    dyoung 			if (rate > maxrate)
    614        1.1    dyoung 				maxrate = rate;
    615        1.1    dyoung 		}
    616        1.1    dyoung 	}
    617        1.1    dyoung 	for (i = 0; i < allrates.rs_nrates; i++) {
    618        1.1    dyoung 		mword = ieee80211_rate2media(ic, allrates.rs_rates[i],
    619        1.1    dyoung 				IEEE80211_MODE_AUTO);
    620        1.1    dyoung 		if (mword == 0)
    621        1.1    dyoung 			continue;
    622  1.48.12.1     skrll 		/* NB: remove media options from mword */
    623  1.48.12.1     skrll 		addmedia(ic, IEEE80211_MODE_AUTO, IFM_SUBTYPE(mword));
    624  1.48.12.1     skrll 	}
    625  1.48.12.1     skrll 	/*
    626  1.48.12.1     skrll 	 * Add HT/11n media.  Note that we do not have enough
    627  1.48.12.1     skrll 	 * bits in the media subtype to express the MCS so we
    628  1.48.12.1     skrll 	 * use a "placeholder" media subtype and any fixed MCS
    629  1.48.12.1     skrll 	 * must be specified with a different mechanism.
    630  1.48.12.1     skrll 	 */
    631  1.48.12.1     skrll 	for (; mode < IEEE80211_MODE_MAX; mode++) {
    632  1.48.12.1     skrll 		if (isclr(ic->ic_modecaps, mode))
    633  1.48.12.1     skrll 			continue;
    634  1.48.12.1     skrll 		addmedia(ic, mode, IFM_AUTO);
    635  1.48.12.1     skrll 		addmedia(ic, mode, IFM_IEEE80211_MCS);
    636        1.1    dyoung 	}
    637  1.48.12.1     skrll 	if (isset(ic->ic_modecaps, IEEE80211_MODE_11NA) ||
    638  1.48.12.1     skrll 	    isset(ic->ic_modecaps, IEEE80211_MODE_11NG)) {
    639  1.48.12.1     skrll 		addmedia(ic, IEEE80211_MODE_AUTO, IFM_IEEE80211_MCS);
    640  1.48.12.1     skrll 		/* XXX could walk htrates */
    641  1.48.12.1     skrll 		/* XXX known array size */
    642  1.48.12.1     skrll 		if (ieee80211_htrates[15] > maxrate)
    643  1.48.12.1     skrll 			maxrate = ieee80211_htrates[15];
    644  1.48.12.1     skrll 	}
    645  1.48.12.1     skrll 
    646  1.48.12.1     skrll 	/* NB: strip explicit mode; we're actually in autoselect */
    647  1.48.12.1     skrll 	ifmedia_set(&ic->ic_media,
    648  1.48.12.1     skrll 		media_status(ic->ic_opmode, ic->ic_curchan) &~ IFM_MMASK);
    649       1.37    dyoung 
    650        1.1    dyoung 	if (maxrate)
    651        1.1    dyoung 		ifp->if_baudrate = IF_Mbps(maxrate);
    652  1.48.12.1     skrll }
    653  1.48.12.1     skrll 
    654  1.48.12.1     skrll const struct ieee80211_rateset *
    655  1.48.12.1     skrll ieee80211_get_suprates(struct ieee80211com *ic, const struct ieee80211_channel *c)
    656  1.48.12.1     skrll {
    657  1.48.12.1     skrll 	if (IEEE80211_IS_CHAN_HALF(c))
    658  1.48.12.1     skrll 		return &ieee80211_rateset_half;
    659  1.48.12.1     skrll 	if (IEEE80211_IS_CHAN_QUARTER(c))
    660  1.48.12.1     skrll 		return &ieee80211_rateset_quarter;
    661  1.48.12.1     skrll 	if (IEEE80211_IS_CHAN_HTA(c))
    662  1.48.12.1     skrll 		return &ic->ic_sup_rates[IEEE80211_MODE_11A];
    663  1.48.12.1     skrll 	if (IEEE80211_IS_CHAN_HTG(c)) {
    664  1.48.12.1     skrll 		/* XXX does this work for basic rates? */
    665  1.48.12.1     skrll 		return &ic->ic_sup_rates[IEEE80211_MODE_11G];
    666  1.48.12.1     skrll 	}
    667  1.48.12.1     skrll 	return &ic->ic_sup_rates[ieee80211_chan2mode(c)];
    668        1.1    dyoung }
    669        1.1    dyoung 
    670       1.37    dyoung void
    671       1.37    dyoung ieee80211_announce(struct ieee80211com *ic)
    672       1.37    dyoung {
    673       1.37    dyoung 	struct ifnet *ifp = ic->ic_ifp;
    674       1.37    dyoung 	int i, mode, rate, mword;
    675  1.48.12.1     skrll 	const struct ieee80211_rateset *rs;
    676       1.37    dyoung 
    677  1.48.12.1     skrll 	/* NB: skip AUTO since it has no rates */
    678  1.48.12.1     skrll 	for (mode = IEEE80211_MODE_AUTO+1; mode < IEEE80211_MODE_11NA; mode++) {
    679  1.48.12.1     skrll 		if (isclr(ic->ic_modecaps, mode))
    680       1.37    dyoung 			continue;
    681       1.48  jmcneill 		aprint_normal("%s: %s rates: ", ifp->if_xname,
    682       1.48  jmcneill 		    ieee80211_phymode_name[mode]);
    683       1.37    dyoung 		rs = &ic->ic_sup_rates[mode];
    684       1.37    dyoung 		for (i = 0; i < rs->rs_nrates; i++) {
    685  1.48.12.1     skrll 			mword = ieee80211_rate2media(ic, rs->rs_rates[i], mode);
    686       1.37    dyoung 			if (mword == 0)
    687       1.37    dyoung 				continue;
    688  1.48.12.1     skrll 			rate = ieee80211_media2rate(mword);
    689       1.48  jmcneill 			aprint_normal("%s%d%sMbps", (i != 0 ? " " : ""),
    690  1.48.12.1     skrll 			    rate / 2, ((rate & 0x1) != 0 ? ".5" : ""));
    691       1.37    dyoung 		}
    692       1.48  jmcneill 		aprint_normal("\n");
    693       1.37    dyoung 	}
    694  1.48.12.1     skrll 	ieee80211_ht_announce(ic);
    695       1.37    dyoung }
    696       1.37    dyoung 
    697  1.48.12.1     skrll void
    698  1.48.12.1     skrll ieee80211_announce_channels(struct ieee80211com *ic)
    699        1.1    dyoung {
    700  1.48.12.1     skrll 	const struct ieee80211_channel *c;
    701  1.48.12.1     skrll 	char type;
    702  1.48.12.1     skrll 	int i, cw;
    703  1.48.12.1     skrll 
    704  1.48.12.1     skrll 	printf("Chan  Freq  CW  RegPwr  MinPwr  MaxPwr\n");
    705  1.48.12.1     skrll 	for (i = 0; i < ic->ic_nchans; i++) {
    706  1.48.12.1     skrll 		c = &ic->ic_channels[i];
    707  1.48.12.1     skrll 		if (IEEE80211_IS_CHAN_ST(c))
    708  1.48.12.1     skrll 			type = 'S';
    709  1.48.12.1     skrll 		else if (IEEE80211_IS_CHAN_108A(c))
    710  1.48.12.1     skrll 			type = 'T';
    711  1.48.12.1     skrll 		else if (IEEE80211_IS_CHAN_108G(c))
    712  1.48.12.1     skrll 			type = 'G';
    713  1.48.12.1     skrll 		else if (IEEE80211_IS_CHAN_HT(c))
    714  1.48.12.1     skrll 			type = 'n';
    715  1.48.12.1     skrll 		else if (IEEE80211_IS_CHAN_A(c))
    716  1.48.12.1     skrll 			type = 'a';
    717  1.48.12.1     skrll 		else if (IEEE80211_IS_CHAN_ANYG(c))
    718  1.48.12.1     skrll 			type = 'g';
    719  1.48.12.1     skrll 		else if (IEEE80211_IS_CHAN_B(c))
    720  1.48.12.1     skrll 			type = 'b';
    721  1.48.12.1     skrll 		else
    722  1.48.12.1     skrll 			type = 'f';
    723  1.48.12.1     skrll 		if (IEEE80211_IS_CHAN_HT40(c) || IEEE80211_IS_CHAN_TURBO(c))
    724  1.48.12.1     skrll 			cw = 40;
    725  1.48.12.1     skrll 		else if (IEEE80211_IS_CHAN_HALF(c))
    726  1.48.12.1     skrll 			cw = 10;
    727  1.48.12.1     skrll 		else if (IEEE80211_IS_CHAN_QUARTER(c))
    728  1.48.12.1     skrll 			cw = 5;
    729  1.48.12.1     skrll 		else
    730  1.48.12.1     skrll 			cw = 20;
    731  1.48.12.1     skrll 		printf("%4d  %4d%c %2d%c %6d  %4d.%d  %4d.%d\n"
    732  1.48.12.1     skrll 			, c->ic_ieee, c->ic_freq, type
    733  1.48.12.1     skrll 			, cw
    734  1.48.12.1     skrll 			, IEEE80211_IS_CHAN_HT40U(c) ? '+' :
    735  1.48.12.1     skrll 			  IEEE80211_IS_CHAN_HT40D(c) ? '-' : ' '
    736  1.48.12.1     skrll 			, c->ic_maxregpower
    737  1.48.12.1     skrll 			, c->ic_minpower / 2, c->ic_minpower & 1 ? 5 : 0
    738  1.48.12.1     skrll 			, c->ic_maxpower / 2, c->ic_maxpower & 1 ? 5 : 0
    739  1.48.12.1     skrll 		);
    740  1.48.12.1     skrll 	}
    741        1.1    dyoung }
    742        1.1    dyoung 
    743        1.1    dyoung /*
    744       1.37    dyoung  * Find an instance by it's mac address.
    745       1.37    dyoung  */
    746       1.37    dyoung struct ieee80211com *
    747  1.48.12.1     skrll ieee80211_find_vap(const uint8_t mac[IEEE80211_ADDR_LEN])
    748       1.37    dyoung {
    749       1.39    dyoung 	int s;
    750       1.37    dyoung 	struct ieee80211com *ic;
    751       1.37    dyoung 
    752       1.39    dyoung 	s = splnet();
    753       1.37    dyoung 	SLIST_FOREACH(ic, &ieee80211_list, ic_next)
    754       1.37    dyoung 		if (IEEE80211_ADDR_EQ(mac, ic->ic_myaddr))
    755       1.39    dyoung 			break;
    756       1.39    dyoung 	splx(s);
    757       1.39    dyoung 	return ic;
    758       1.37    dyoung }
    759       1.37    dyoung 
    760       1.37    dyoung static struct ieee80211com *
    761       1.37    dyoung ieee80211_find_instance(struct ifnet *ifp)
    762       1.37    dyoung {
    763       1.39    dyoung 	int s;
    764       1.37    dyoung 	struct ieee80211com *ic;
    765       1.37    dyoung 
    766       1.39    dyoung 	s = splnet();
    767       1.37    dyoung 	/* XXX not right for multiple instances but works for now */
    768       1.37    dyoung 	SLIST_FOREACH(ic, &ieee80211_list, ic_next)
    769       1.37    dyoung 		if (ic->ic_ifp == ifp)
    770       1.39    dyoung 			break;
    771       1.39    dyoung 	splx(s);
    772       1.39    dyoung 	return ic;
    773       1.37    dyoung }
    774       1.37    dyoung 
    775  1.48.12.1     skrll static int
    776  1.48.12.1     skrll findrate(struct ieee80211com *ic, enum ieee80211_phymode mode, int rate)
    777  1.48.12.1     skrll {
    778  1.48.12.1     skrll #define	IEEERATE(_ic,_m,_i) \
    779  1.48.12.1     skrll 	((_ic)->ic_sup_rates[_m].rs_rates[_i] & IEEE80211_RATE_VAL)
    780  1.48.12.1     skrll 	int i, nrates = ic->ic_sup_rates[mode].rs_nrates;
    781  1.48.12.1     skrll 	for (i = 0; i < nrates; i++)
    782  1.48.12.1     skrll 		if (IEEERATE(ic, mode, i) == rate)
    783  1.48.12.1     skrll 			return i;
    784  1.48.12.1     skrll 	return -1;
    785  1.48.12.1     skrll #undef IEEERATE
    786  1.48.12.1     skrll }
    787  1.48.12.1     skrll 
    788  1.48.12.1     skrll /*
    789  1.48.12.1     skrll  * Convert a media specification to a rate index and possibly a mode
    790  1.48.12.1     skrll  * (if the rate is fixed and the mode is specified as ``auto'' then
    791  1.48.12.1     skrll  * we need to lock down the mode so the index is meanginful).
    792  1.48.12.1     skrll  */
    793  1.48.12.1     skrll static int
    794  1.48.12.1     skrll checkrate(struct ieee80211com *ic, enum ieee80211_phymode mode, int rate)
    795  1.48.12.1     skrll {
    796  1.48.12.1     skrll 
    797  1.48.12.1     skrll 	/*
    798  1.48.12.1     skrll 	 * Check the rate table for the specified/current phy.
    799  1.48.12.1     skrll 	 */
    800  1.48.12.1     skrll 	if (mode == IEEE80211_MODE_AUTO) {
    801  1.48.12.1     skrll 		int i;
    802  1.48.12.1     skrll 		/*
    803  1.48.12.1     skrll 		 * In autoselect mode search for the rate.
    804  1.48.12.1     skrll 		 */
    805  1.48.12.1     skrll 		for (i = IEEE80211_MODE_11A; i < IEEE80211_MODE_MAX; i++) {
    806  1.48.12.1     skrll 			if (isset(ic->ic_modecaps, i) &&
    807  1.48.12.1     skrll 			    findrate(ic, i, rate) != -1)
    808  1.48.12.1     skrll 				return 1;
    809  1.48.12.1     skrll 		}
    810  1.48.12.1     skrll 		return 0;
    811  1.48.12.1     skrll 	} else {
    812  1.48.12.1     skrll 		/*
    813  1.48.12.1     skrll 		 * Mode is fixed, check for rate.
    814  1.48.12.1     skrll 		 */
    815  1.48.12.1     skrll 		return (findrate(ic, mode, rate) != -1);
    816  1.48.12.1     skrll 	}
    817  1.48.12.1     skrll }
    818  1.48.12.1     skrll 
    819       1.37    dyoung /*
    820        1.1    dyoung  * Handle a media change request.
    821        1.1    dyoung  */
    822        1.1    dyoung int
    823        1.1    dyoung ieee80211_media_change(struct ifnet *ifp)
    824        1.1    dyoung {
    825       1.37    dyoung 	struct ieee80211com *ic;
    826        1.1    dyoung 	struct ifmedia_entry *ime;
    827        1.1    dyoung 	enum ieee80211_opmode newopmode;
    828        1.1    dyoung 	enum ieee80211_phymode newphymode;
    829  1.48.12.1     skrll 	int newrate, error = 0;
    830        1.1    dyoung 
    831       1.37    dyoung 	ic = ieee80211_find_instance(ifp);
    832       1.37    dyoung 	if (!ic) {
    833       1.37    dyoung 		if_printf(ifp, "%s: no 802.11 instance!\n", __func__);
    834       1.37    dyoung 		return EINVAL;
    835       1.37    dyoung 	}
    836        1.1    dyoung 	ime = ic->ic_media.ifm_cur;
    837        1.1    dyoung 	/*
    838        1.1    dyoung 	 * First, identify the phy mode.
    839        1.1    dyoung 	 */
    840        1.1    dyoung 	switch (IFM_MODE(ime->ifm_media)) {
    841        1.1    dyoung 	case IFM_IEEE80211_11A:
    842        1.1    dyoung 		newphymode = IEEE80211_MODE_11A;
    843        1.1    dyoung 		break;
    844        1.1    dyoung 	case IFM_IEEE80211_11B:
    845        1.1    dyoung 		newphymode = IEEE80211_MODE_11B;
    846        1.1    dyoung 		break;
    847        1.1    dyoung 	case IFM_IEEE80211_11G:
    848        1.1    dyoung 		newphymode = IEEE80211_MODE_11G;
    849        1.1    dyoung 		break;
    850        1.5    dyoung 	case IFM_IEEE80211_FH:
    851        1.5    dyoung 		newphymode = IEEE80211_MODE_FH;
    852        1.5    dyoung 		break;
    853  1.48.12.1     skrll 	case IFM_IEEE80211_11NA:
    854  1.48.12.1     skrll 		newphymode = IEEE80211_MODE_11NA;
    855  1.48.12.1     skrll 		break;
    856  1.48.12.1     skrll 	case IFM_IEEE80211_11NG:
    857  1.48.12.1     skrll 		newphymode = IEEE80211_MODE_11NG;
    858  1.48.12.1     skrll 		break;
    859        1.1    dyoung 	case IFM_AUTO:
    860        1.1    dyoung 		newphymode = IEEE80211_MODE_AUTO;
    861        1.1    dyoung 		break;
    862        1.1    dyoung 	default:
    863        1.1    dyoung 		return EINVAL;
    864        1.1    dyoung 	}
    865        1.1    dyoung 	/*
    866       1.37    dyoung 	 * Turbo mode is an ``option''.
    867       1.37    dyoung 	 * XXX does not apply to AUTO
    868        1.1    dyoung 	 */
    869        1.1    dyoung 	if (ime->ifm_media & IFM_IEEE80211_TURBO) {
    870  1.48.12.1     skrll 		if (newphymode == IEEE80211_MODE_11A) {
    871  1.48.12.1     skrll 			if (ic->ic_flags & IEEE80211_F_TURBOP)
    872  1.48.12.1     skrll 				newphymode = IEEE80211_MODE_TURBO_A;
    873  1.48.12.1     skrll 			else
    874  1.48.12.1     skrll 				newphymode = IEEE80211_MODE_STURBO_A;
    875  1.48.12.1     skrll 		} else if (newphymode == IEEE80211_MODE_11G)
    876       1.37    dyoung 			newphymode = IEEE80211_MODE_TURBO_G;
    877       1.37    dyoung 		else
    878        1.1    dyoung 			return EINVAL;
    879        1.1    dyoung 	}
    880  1.48.12.1     skrll 	/* XXX HT40 +/- */
    881        1.1    dyoung 	/*
    882        1.1    dyoung 	 * Next, the fixed/variable rate.
    883        1.1    dyoung 	 */
    884  1.48.12.1     skrll 	newrate = ic->ic_fixed_rate;
    885        1.1    dyoung 	if (IFM_SUBTYPE(ime->ifm_media) != IFM_AUTO) {
    886        1.1    dyoung 		/*
    887        1.1    dyoung 		 * Convert media subtype to rate.
    888        1.1    dyoung 		 */
    889        1.1    dyoung 		newrate = ieee80211_media2rate(ime->ifm_media);
    890  1.48.12.1     skrll 		if (newrate == 0 || !checkrate(ic, newphymode, newrate))
    891        1.1    dyoung 			return EINVAL;
    892  1.48.12.1     skrll 	} else
    893  1.48.12.1     skrll 		newrate = IEEE80211_FIXED_RATE_NONE;
    894        1.1    dyoung 
    895        1.1    dyoung 	/*
    896        1.1    dyoung 	 * Deduce new operating mode but don't install it just yet.
    897        1.1    dyoung 	 */
    898        1.1    dyoung 	if ((ime->ifm_media & (IFM_IEEE80211_ADHOC|IFM_FLAG0)) ==
    899        1.1    dyoung 	    (IFM_IEEE80211_ADHOC|IFM_FLAG0))
    900        1.1    dyoung 		newopmode = IEEE80211_M_AHDEMO;
    901        1.1    dyoung 	else if (ime->ifm_media & IFM_IEEE80211_HOSTAP)
    902        1.1    dyoung 		newopmode = IEEE80211_M_HOSTAP;
    903        1.1    dyoung 	else if (ime->ifm_media & IFM_IEEE80211_ADHOC)
    904        1.1    dyoung 		newopmode = IEEE80211_M_IBSS;
    905        1.1    dyoung 	else if (ime->ifm_media & IFM_IEEE80211_MONITOR)
    906        1.1    dyoung 		newopmode = IEEE80211_M_MONITOR;
    907        1.1    dyoung 	else
    908        1.1    dyoung 		newopmode = IEEE80211_M_STA;
    909        1.1    dyoung 
    910        1.1    dyoung 	/*
    911        1.1    dyoung 	 * Handle phy mode change.
    912        1.1    dyoung 	 */
    913  1.48.12.1     skrll 	if (ic->ic_des_mode != newphymode) {		/* change phy mode */
    914  1.48.12.1     skrll 		ic->ic_des_mode = newphymode;
    915        1.1    dyoung 		error = ENETRESET;
    916        1.1    dyoung 	}
    917        1.1    dyoung 
    918        1.1    dyoung 	/*
    919        1.1    dyoung 	 * Committed to changes, install the rate setting.
    920        1.1    dyoung 	 */
    921  1.48.12.1     skrll 	if (ic->ic_fixed_rate != newrate) {
    922  1.48.12.1     skrll 		ic->ic_fixed_rate = newrate;		/* set fixed tx rate */
    923        1.1    dyoung 		error = ENETRESET;
    924        1.1    dyoung 	}
    925        1.1    dyoung 
    926        1.1    dyoung 	/*
    927        1.1    dyoung 	 * Handle operating mode change.
    928        1.1    dyoung 	 */
    929        1.1    dyoung 	if (ic->ic_opmode != newopmode) {
    930        1.1    dyoung 		ic->ic_opmode = newopmode;
    931        1.1    dyoung 		switch (newopmode) {
    932        1.1    dyoung 		case IEEE80211_M_AHDEMO:
    933        1.1    dyoung 		case IEEE80211_M_HOSTAP:
    934        1.1    dyoung 		case IEEE80211_M_STA:
    935        1.1    dyoung 		case IEEE80211_M_MONITOR:
    936  1.48.12.1     skrll 		case IEEE80211_M_WDS:
    937        1.1    dyoung 			ic->ic_flags &= ~IEEE80211_F_IBSSON;
    938        1.1    dyoung 			break;
    939        1.1    dyoung 		case IEEE80211_M_IBSS:
    940        1.1    dyoung 			ic->ic_flags |= IEEE80211_F_IBSSON;
    941        1.1    dyoung 			break;
    942        1.1    dyoung 		}
    943       1.37    dyoung 		/*
    944       1.37    dyoung 		 * Yech, slot time may change depending on the
    945       1.37    dyoung 		 * operating mode so reset it to be sure everything
    946       1.37    dyoung 		 * is setup appropriately.
    947       1.37    dyoung 		 */
    948       1.37    dyoung 		ieee80211_reset_erp(ic);
    949       1.37    dyoung 		ieee80211_wme_initparams(ic);	/* after opmode change */
    950        1.1    dyoung 		error = ENETRESET;
    951        1.1    dyoung 	}
    952        1.1    dyoung #ifdef notdef
    953        1.1    dyoung 	if (error == 0)
    954        1.1    dyoung 		ifp->if_baudrate = ifmedia_baudrate(ime->ifm_media);
    955        1.1    dyoung #endif
    956        1.1    dyoung 	return error;
    957        1.1    dyoung }
    958        1.1    dyoung 
    959  1.48.12.1     skrll /*
    960  1.48.12.1     skrll  * Common code to calculate the media status word
    961  1.48.12.1     skrll  * from the operating mode and channel state.
    962  1.48.12.1     skrll  */
    963  1.48.12.1     skrll static int
    964  1.48.12.1     skrll media_status(enum ieee80211_opmode opmode, const struct ieee80211_channel *chan)
    965  1.48.12.1     skrll {
    966  1.48.12.1     skrll 	int status;
    967  1.48.12.1     skrll 
    968  1.48.12.1     skrll 	status = IFM_IEEE80211;
    969  1.48.12.1     skrll 	switch (opmode) {
    970  1.48.12.1     skrll 	case IEEE80211_M_STA:
    971  1.48.12.1     skrll 		break;
    972  1.48.12.1     skrll 	case IEEE80211_M_IBSS:
    973  1.48.12.1     skrll 		status |= IFM_IEEE80211_ADHOC;
    974  1.48.12.1     skrll 		break;
    975  1.48.12.1     skrll 	case IEEE80211_M_HOSTAP:
    976  1.48.12.1     skrll 		status |= IFM_IEEE80211_HOSTAP;
    977  1.48.12.1     skrll 		break;
    978  1.48.12.1     skrll 	case IEEE80211_M_MONITOR:
    979  1.48.12.1     skrll 		status |= IFM_IEEE80211_MONITOR;
    980  1.48.12.1     skrll 		break;
    981  1.48.12.1     skrll 	case IEEE80211_M_AHDEMO:
    982  1.48.12.1     skrll 		status |= IFM_IEEE80211_ADHOC | IFM_FLAG0;
    983  1.48.12.1     skrll 		break;
    984  1.48.12.1     skrll 	case IEEE80211_M_WDS:
    985  1.48.12.1     skrll 		/* should not come here */
    986  1.48.12.1     skrll 		break;
    987  1.48.12.1     skrll 	}
    988  1.48.12.1     skrll 	if (IEEE80211_IS_CHAN_HTA(chan)) {
    989  1.48.12.1     skrll 		status |= IFM_IEEE80211_11NA;
    990  1.48.12.1     skrll 	} else if (IEEE80211_IS_CHAN_HTG(chan)) {
    991  1.48.12.1     skrll 		status |= IFM_IEEE80211_11NG;
    992  1.48.12.1     skrll 	} else if (IEEE80211_IS_CHAN_A(chan)) {
    993  1.48.12.1     skrll 		status |= IFM_IEEE80211_11A;
    994  1.48.12.1     skrll 	} else if (IEEE80211_IS_CHAN_B(chan)) {
    995  1.48.12.1     skrll 		status |= IFM_IEEE80211_11B;
    996  1.48.12.1     skrll 	} else if (IEEE80211_IS_CHAN_ANYG(chan)) {
    997  1.48.12.1     skrll 		status |= IFM_IEEE80211_11G;
    998  1.48.12.1     skrll 	} else if (IEEE80211_IS_CHAN_FHSS(chan)) {
    999  1.48.12.1     skrll 		status |= IFM_IEEE80211_FH;
   1000  1.48.12.1     skrll 	}
   1001  1.48.12.1     skrll 	/* XXX else complain? */
   1002  1.48.12.1     skrll 
   1003  1.48.12.1     skrll 	if (IEEE80211_IS_CHAN_TURBO(chan))
   1004  1.48.12.1     skrll 		status |= IFM_IEEE80211_TURBO;
   1005  1.48.12.1     skrll 
   1006  1.48.12.1     skrll 	return status;
   1007  1.48.12.1     skrll }
   1008  1.48.12.1     skrll 
   1009        1.1    dyoung void
   1010        1.1    dyoung ieee80211_media_status(struct ifnet *ifp, struct ifmediareq *imr)
   1011        1.1    dyoung {
   1012       1.37    dyoung 	struct ieee80211com *ic;
   1013  1.48.12.1     skrll 	enum ieee80211_phymode mode;
   1014  1.48.12.1     skrll 	const struct ieee80211_rateset *rs;
   1015        1.1    dyoung 
   1016       1.37    dyoung 	ic = ieee80211_find_instance(ifp);
   1017       1.37    dyoung 	if (!ic) {
   1018       1.37    dyoung 		if_printf(ifp, "%s: no 802.11 instance!\n", __func__);
   1019       1.37    dyoung 		return;
   1020       1.37    dyoung 	}
   1021        1.1    dyoung 	imr->ifm_status = IFM_AVALID;
   1022  1.48.12.1     skrll 	/*
   1023  1.48.12.1     skrll 	 * NB: use the current channel's mode to lock down a xmit
   1024  1.48.12.1     skrll 	 * rate only when running; otherwise we may have a mismatch
   1025  1.48.12.1     skrll 	 * in which case the rate will not be convertible.
   1026  1.48.12.1     skrll 	 */
   1027  1.48.12.1     skrll 	if (ic->ic_state == IEEE80211_S_RUN) {
   1028        1.1    dyoung 		imr->ifm_status |= IFM_ACTIVE;
   1029  1.48.12.1     skrll 		mode = ieee80211_chan2mode(ic->ic_curchan);
   1030  1.48.12.1     skrll 	} else
   1031  1.48.12.1     skrll 		mode = IEEE80211_MODE_AUTO;
   1032  1.48.12.1     skrll 	imr->ifm_active = media_status(ic->ic_opmode, ic->ic_curchan);
   1033       1.37    dyoung 	/*
   1034       1.37    dyoung 	 * Calculate a current rate if possible.
   1035       1.37    dyoung 	 */
   1036       1.41     skrll 	if (ic->ic_fixed_rate != IEEE80211_FIXED_RATE_NONE) {
   1037       1.37    dyoung 		/*
   1038       1.37    dyoung 		 * A fixed rate is set, report that.
   1039       1.37    dyoung 		 */
   1040       1.37    dyoung 		imr->ifm_active |= ieee80211_rate2media(ic,
   1041  1.48.12.1     skrll 			ic->ic_fixed_rate, mode);
   1042       1.37    dyoung 	} else if (ic->ic_opmode == IEEE80211_M_STA) {
   1043       1.37    dyoung 		/*
   1044       1.37    dyoung 		 * In station mode report the current transmit rate.
   1045  1.48.12.1     skrll 		 * XXX HT rate
   1046       1.37    dyoung 		 */
   1047       1.37    dyoung 		rs = &ic->ic_bss->ni_rates;
   1048       1.37    dyoung 		imr->ifm_active |= ieee80211_rate2media(ic,
   1049  1.48.12.1     skrll 			rs->rs_rates[ic->ic_bss->ni_txrate], mode);
   1050       1.37    dyoung 	} else
   1051       1.37    dyoung 		imr->ifm_active |= IFM_AUTO;
   1052        1.1    dyoung }
   1053        1.1    dyoung 
   1054        1.1    dyoung /*
   1055        1.1    dyoung  * Set the current phy mode and recalculate the active channel
   1056        1.1    dyoung  * set based on the available channels for this mode.  Also
   1057        1.1    dyoung  * select a new default/current channel if the current one is
   1058        1.1    dyoung  * inappropriate for this mode.
   1059        1.1    dyoung  */
   1060        1.1    dyoung int
   1061        1.1    dyoung ieee80211_setmode(struct ieee80211com *ic, enum ieee80211_phymode mode)
   1062        1.1    dyoung {
   1063        1.1    dyoung 	/*
   1064  1.48.12.1     skrll 	 * Adjust basic rates in 11b/11g supported rate set.
   1065  1.48.12.1     skrll 	 * Note that if operating on a hal/quarter rate channel
   1066  1.48.12.1     skrll 	 * this is a noop as those rates sets are different
   1067  1.48.12.1     skrll 	 * and used instead.
   1068        1.1    dyoung 	 */
   1069  1.48.12.1     skrll 	if (mode == IEEE80211_MODE_11G || mode == IEEE80211_MODE_11B)
   1070  1.48.12.1     skrll 		ieee80211_set11gbasicrates(&ic->ic_sup_rates[mode], mode);
   1071        1.1    dyoung 
   1072        1.1    dyoung 	ic->ic_curmode = mode;
   1073       1.37    dyoung 	ieee80211_reset_erp(ic);	/* reset ERP state */
   1074       1.37    dyoung 	ieee80211_wme_initparams(ic);	/* reset WME stat */
   1075       1.37    dyoung 
   1076        1.1    dyoung 	return 0;
   1077        1.1    dyoung }
   1078        1.1    dyoung 
   1079        1.1    dyoung /*
   1080  1.48.12.1     skrll  * Return the phy mode for with the specified channel.
   1081        1.1    dyoung  */
   1082        1.1    dyoung enum ieee80211_phymode
   1083  1.48.12.1     skrll ieee80211_chan2mode(const struct ieee80211_channel *chan)
   1084        1.1    dyoung {
   1085  1.48.12.1     skrll 	if (IEEE80211_IS_CHAN_HTA(chan))
   1086  1.48.12.1     skrll 		return IEEE80211_MODE_11NA;
   1087  1.48.12.1     skrll 	else if (IEEE80211_IS_CHAN_HTG(chan))
   1088  1.48.12.1     skrll 		return IEEE80211_MODE_11NG;
   1089  1.48.12.1     skrll 	else if (IEEE80211_IS_CHAN_108G(chan))
   1090  1.48.12.1     skrll 		return IEEE80211_MODE_TURBO_G;
   1091  1.48.12.1     skrll 	else if (IEEE80211_IS_CHAN_ST(chan))
   1092  1.48.12.1     skrll 		return IEEE80211_MODE_STURBO_A;
   1093  1.48.12.1     skrll 	else if (IEEE80211_IS_CHAN_TURBO(chan))
   1094       1.44    dyoung 		return IEEE80211_MODE_TURBO_A;
   1095  1.48.12.1     skrll 	else if (IEEE80211_IS_CHAN_A(chan))
   1096        1.1    dyoung 		return IEEE80211_MODE_11A;
   1097  1.48.12.1     skrll 	else if (IEEE80211_IS_CHAN_ANYG(chan))
   1098        1.1    dyoung 		return IEEE80211_MODE_11G;
   1099  1.48.12.1     skrll 	else if (IEEE80211_IS_CHAN_B(chan))
   1100        1.1    dyoung 		return IEEE80211_MODE_11B;
   1101  1.48.12.1     skrll 	else if (IEEE80211_IS_CHAN_FHSS(chan))
   1102  1.48.12.1     skrll 		return IEEE80211_MODE_FH;
   1103  1.48.12.1     skrll 
   1104  1.48.12.1     skrll 	/* NB: should not get here */
   1105  1.48.12.1     skrll 	printf("%s: cannot map channel to mode; freq %u flags 0x%x\n",
   1106  1.48.12.1     skrll 		__func__, chan->ic_freq, chan->ic_flags);
   1107  1.48.12.1     skrll 	return IEEE80211_MODE_11B;
   1108  1.48.12.1     skrll }
   1109  1.48.12.1     skrll 
   1110  1.48.12.1     skrll struct ratemedia {
   1111  1.48.12.1     skrll 	u_int	match;	/* rate + mode */
   1112  1.48.12.1     skrll 	u_int	media;	/* if_media rate */
   1113  1.48.12.1     skrll };
   1114  1.48.12.1     skrll 
   1115  1.48.12.1     skrll static int
   1116  1.48.12.1     skrll findmedia(const struct ratemedia rates[], int n, u_int match)
   1117  1.48.12.1     skrll {
   1118  1.48.12.1     skrll 	int i;
   1119  1.48.12.1     skrll 
   1120  1.48.12.1     skrll 	for (i = 0; i < n; i++)
   1121  1.48.12.1     skrll 		if (rates[i].match == match)
   1122  1.48.12.1     skrll 			return rates[i].media;
   1123  1.48.12.1     skrll 	return IFM_AUTO;
   1124        1.1    dyoung }
   1125        1.1    dyoung 
   1126        1.1    dyoung /*
   1127  1.48.12.1     skrll  * Convert IEEE80211 rate value to ifmedia subtype.
   1128  1.48.12.1     skrll  * Rate is either a legacy rate in units of 0.5Mbps
   1129  1.48.12.1     skrll  * or an MCS index.
   1130        1.1    dyoung  */
   1131        1.1    dyoung int
   1132        1.1    dyoung ieee80211_rate2media(struct ieee80211com *ic, int rate, enum ieee80211_phymode mode)
   1133        1.1    dyoung {
   1134        1.1    dyoung #define	N(a)	(sizeof(a) / sizeof(a[0]))
   1135  1.48.12.1     skrll 	static const struct ratemedia rates[] = {
   1136        1.5    dyoung 		{   2 | IFM_IEEE80211_FH, IFM_IEEE80211_FH1 },
   1137        1.5    dyoung 		{   4 | IFM_IEEE80211_FH, IFM_IEEE80211_FH2 },
   1138        1.5    dyoung 		{   2 | IFM_IEEE80211_11B, IFM_IEEE80211_DS1 },
   1139        1.5    dyoung 		{   4 | IFM_IEEE80211_11B, IFM_IEEE80211_DS2 },
   1140        1.5    dyoung 		{  11 | IFM_IEEE80211_11B, IFM_IEEE80211_DS5 },
   1141        1.5    dyoung 		{  22 | IFM_IEEE80211_11B, IFM_IEEE80211_DS11 },
   1142        1.5    dyoung 		{  44 | IFM_IEEE80211_11B, IFM_IEEE80211_DS22 },
   1143        1.5    dyoung 		{  12 | IFM_IEEE80211_11A, IFM_IEEE80211_OFDM6 },
   1144        1.5    dyoung 		{  18 | IFM_IEEE80211_11A, IFM_IEEE80211_OFDM9 },
   1145        1.5    dyoung 		{  24 | IFM_IEEE80211_11A, IFM_IEEE80211_OFDM12 },
   1146        1.5    dyoung 		{  36 | IFM_IEEE80211_11A, IFM_IEEE80211_OFDM18 },
   1147        1.5    dyoung 		{  48 | IFM_IEEE80211_11A, IFM_IEEE80211_OFDM24 },
   1148        1.5    dyoung 		{  72 | IFM_IEEE80211_11A, IFM_IEEE80211_OFDM36 },
   1149        1.5    dyoung 		{  96 | IFM_IEEE80211_11A, IFM_IEEE80211_OFDM48 },
   1150        1.5    dyoung 		{ 108 | IFM_IEEE80211_11A, IFM_IEEE80211_OFDM54 },
   1151        1.5    dyoung 		{   2 | IFM_IEEE80211_11G, IFM_IEEE80211_DS1 },
   1152        1.5    dyoung 		{   4 | IFM_IEEE80211_11G, IFM_IEEE80211_DS2 },
   1153        1.5    dyoung 		{  11 | IFM_IEEE80211_11G, IFM_IEEE80211_DS5 },
   1154        1.5    dyoung 		{  22 | IFM_IEEE80211_11G, IFM_IEEE80211_DS11 },
   1155        1.5    dyoung 		{  12 | IFM_IEEE80211_11G, IFM_IEEE80211_OFDM6 },
   1156        1.5    dyoung 		{  18 | IFM_IEEE80211_11G, IFM_IEEE80211_OFDM9 },
   1157        1.5    dyoung 		{  24 | IFM_IEEE80211_11G, IFM_IEEE80211_OFDM12 },
   1158        1.5    dyoung 		{  36 | IFM_IEEE80211_11G, IFM_IEEE80211_OFDM18 },
   1159        1.5    dyoung 		{  48 | IFM_IEEE80211_11G, IFM_IEEE80211_OFDM24 },
   1160        1.5    dyoung 		{  72 | IFM_IEEE80211_11G, IFM_IEEE80211_OFDM36 },
   1161        1.5    dyoung 		{  96 | IFM_IEEE80211_11G, IFM_IEEE80211_OFDM48 },
   1162        1.5    dyoung 		{ 108 | IFM_IEEE80211_11G, IFM_IEEE80211_OFDM54 },
   1163  1.48.12.1     skrll 		{   6 | IFM_IEEE80211_11A, IFM_IEEE80211_OFDM3 },
   1164  1.48.12.1     skrll 		{   9 | IFM_IEEE80211_11A, IFM_IEEE80211_OFDM4 },
   1165  1.48.12.1     skrll 		{  54 | IFM_IEEE80211_11A, IFM_IEEE80211_OFDM27 },
   1166        1.1    dyoung 		/* NB: OFDM72 doesn't realy exist so we don't handle it */
   1167        1.1    dyoung 	};
   1168  1.48.12.1     skrll 	static const struct ratemedia htrates[] = {
   1169  1.48.12.1     skrll 		{   0, IFM_IEEE80211_MCS },
   1170  1.48.12.1     skrll 		{   1, IFM_IEEE80211_MCS },
   1171  1.48.12.1     skrll 		{   2, IFM_IEEE80211_MCS },
   1172  1.48.12.1     skrll 		{   3, IFM_IEEE80211_MCS },
   1173  1.48.12.1     skrll 		{   4, IFM_IEEE80211_MCS },
   1174  1.48.12.1     skrll 		{   5, IFM_IEEE80211_MCS },
   1175  1.48.12.1     skrll 		{   6, IFM_IEEE80211_MCS },
   1176  1.48.12.1     skrll 		{   7, IFM_IEEE80211_MCS },
   1177  1.48.12.1     skrll 		{   8, IFM_IEEE80211_MCS },
   1178  1.48.12.1     skrll 		{   9, IFM_IEEE80211_MCS },
   1179  1.48.12.1     skrll 		{  10, IFM_IEEE80211_MCS },
   1180  1.48.12.1     skrll 		{  11, IFM_IEEE80211_MCS },
   1181  1.48.12.1     skrll 		{  12, IFM_IEEE80211_MCS },
   1182  1.48.12.1     skrll 		{  13, IFM_IEEE80211_MCS },
   1183  1.48.12.1     skrll 		{  14, IFM_IEEE80211_MCS },
   1184  1.48.12.1     skrll 		{  15, IFM_IEEE80211_MCS },
   1185  1.48.12.1     skrll 	};
   1186  1.48.12.1     skrll 	int m;
   1187        1.1    dyoung 
   1188  1.48.12.1     skrll 	/*
   1189  1.48.12.1     skrll 	 * Check 11n rates first for match as an MCS.
   1190  1.48.12.1     skrll 	 */
   1191  1.48.12.1     skrll 	if (mode == IEEE80211_MODE_11NA) {
   1192  1.48.12.1     skrll 		if (rate & IEEE80211_RATE_MCS) {
   1193  1.48.12.1     skrll 			rate &= ~IEEE80211_RATE_MCS;
   1194  1.48.12.1     skrll 			m = findmedia(htrates, N(htrates), rate);
   1195  1.48.12.1     skrll 			if (m != IFM_AUTO)
   1196  1.48.12.1     skrll 				return m | IFM_IEEE80211_11NA;
   1197  1.48.12.1     skrll 		}
   1198  1.48.12.1     skrll 	} else if (mode == IEEE80211_MODE_11NG) {
   1199  1.48.12.1     skrll 		/* NB: 12 is ambiguous, it will be treated as an MCS */
   1200  1.48.12.1     skrll 		if (rate & IEEE80211_RATE_MCS) {
   1201  1.48.12.1     skrll 			rate &= ~IEEE80211_RATE_MCS;
   1202  1.48.12.1     skrll 			m = findmedia(htrates, N(htrates), rate);
   1203  1.48.12.1     skrll 			if (m != IFM_AUTO)
   1204  1.48.12.1     skrll 				return m | IFM_IEEE80211_11NG;
   1205  1.48.12.1     skrll 		}
   1206  1.48.12.1     skrll 	}
   1207  1.48.12.1     skrll 	rate &= IEEE80211_RATE_VAL;
   1208        1.1    dyoung 	switch (mode) {
   1209        1.1    dyoung 	case IEEE80211_MODE_11A:
   1210  1.48.12.1     skrll 	case IEEE80211_MODE_11NA:
   1211       1.37    dyoung 	case IEEE80211_MODE_TURBO_A:
   1212  1.48.12.1     skrll 	case IEEE80211_MODE_STURBO_A:
   1213  1.48.12.1     skrll 		return findmedia(rates, N(rates), rate | IFM_IEEE80211_11A);
   1214        1.1    dyoung 	case IEEE80211_MODE_11B:
   1215  1.48.12.1     skrll 		return findmedia(rates, N(rates), rate | IFM_IEEE80211_11B);
   1216        1.5    dyoung 	case IEEE80211_MODE_FH:
   1217  1.48.12.1     skrll 		return findmedia(rates, N(rates), rate | IFM_IEEE80211_FH);
   1218        1.1    dyoung 	case IEEE80211_MODE_AUTO:
   1219       1.10    dyoung 		/* NB: ic may be NULL for some drivers */
   1220  1.48.12.1     skrll 		if (ic && ic->ic_phytype == IEEE80211_T_FH)
   1221  1.48.12.1     skrll 			return findmedia(rates, N(rates),
   1222  1.48.12.1     skrll 			    rate | IFM_IEEE80211_FH);
   1223       1.10    dyoung 		/* NB: hack, 11g matches both 11b+11a rates */
   1224       1.10    dyoung 		/* fall thru... */
   1225       1.10    dyoung 	case IEEE80211_MODE_11G:
   1226  1.48.12.1     skrll 	case IEEE80211_MODE_11NG:
   1227       1.37    dyoung 	case IEEE80211_MODE_TURBO_G:
   1228  1.48.12.1     skrll 		return findmedia(rates, N(rates), rate | IFM_IEEE80211_11G);
   1229        1.1    dyoung 	}
   1230        1.1    dyoung 	return IFM_AUTO;
   1231        1.1    dyoung #undef N
   1232        1.1    dyoung }
   1233        1.1    dyoung 
   1234        1.1    dyoung int
   1235        1.1    dyoung ieee80211_media2rate(int mword)
   1236        1.1    dyoung {
   1237        1.1    dyoung #define	N(a)	(sizeof(a) / sizeof(a[0]))
   1238       1.26   mycroft 	static const int ieeerates[] = {
   1239       1.26   mycroft 		-1,		/* IFM_AUTO */
   1240       1.26   mycroft 		0,		/* IFM_MANUAL */
   1241       1.26   mycroft 		0,		/* IFM_NONE */
   1242       1.26   mycroft 		2,		/* IFM_IEEE80211_FH1 */
   1243       1.26   mycroft 		4,		/* IFM_IEEE80211_FH2 */
   1244       1.26   mycroft 		4,		/* IFM_IEEE80211_DS2 */
   1245       1.26   mycroft 		11,		/* IFM_IEEE80211_DS5 */
   1246       1.26   mycroft 		22,		/* IFM_IEEE80211_DS11 */
   1247       1.43    dyoung 		2,		/* IFM_IEEE80211_DS1 */
   1248       1.26   mycroft 		44,		/* IFM_IEEE80211_DS22 */
   1249       1.26   mycroft 		12,		/* IFM_IEEE80211_OFDM6 */
   1250       1.26   mycroft 		18,		/* IFM_IEEE80211_OFDM9 */
   1251       1.26   mycroft 		24,		/* IFM_IEEE80211_OFDM12 */
   1252       1.26   mycroft 		36,		/* IFM_IEEE80211_OFDM18 */
   1253       1.26   mycroft 		48,		/* IFM_IEEE80211_OFDM24 */
   1254       1.26   mycroft 		72,		/* IFM_IEEE80211_OFDM36 */
   1255       1.26   mycroft 		96,		/* IFM_IEEE80211_OFDM48 */
   1256       1.26   mycroft 		108,		/* IFM_IEEE80211_OFDM54 */
   1257       1.26   mycroft 		144,		/* IFM_IEEE80211_OFDM72 */
   1258  1.48.12.1     skrll 		0,		/* IFM_IEEE80211_DS354k */
   1259  1.48.12.1     skrll 		0,		/* IFM_IEEE80211_DS512k */
   1260  1.48.12.1     skrll 		6,		/* IFM_IEEE80211_OFDM3 */
   1261  1.48.12.1     skrll 		9,		/* IFM_IEEE80211_OFDM4 */
   1262  1.48.12.1     skrll 		54,		/* IFM_IEEE80211_OFDM27 */
   1263  1.48.12.1     skrll 		-1,		/* IFM_IEEE80211_MCS */
   1264        1.1    dyoung 	};
   1265       1.26   mycroft 	return IFM_SUBTYPE(mword) < N(ieeerates) ?
   1266       1.26   mycroft 		ieeerates[IFM_SUBTYPE(mword)] : 0;
   1267        1.1    dyoung #undef N
   1268        1.1    dyoung }
   1269