Home | History | Annotate | Line # | Download | only in net80211
ieee80211.c revision 1.32.4.1
      1  1.32.4.1     kent /*	$NetBSD: ieee80211.c,v 1.32.4.1 2005/04/29 11:29:32 kent Exp $	*/
      2       1.1   dyoung /*-
      3       1.1   dyoung  * Copyright (c) 2001 Atsushi Onoe
      4       1.1   dyoung  * Copyright (c) 2002, 2003 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  * 3. The name of the author may not be used to endorse or promote products
     16       1.1   dyoung  *    derived from this software without specific prior written permission.
     17       1.1   dyoung  *
     18       1.1   dyoung  * Alternatively, this software may be distributed under the terms of the
     19       1.1   dyoung  * GNU General Public License ("GPL") version 2 as published by the Free
     20       1.1   dyoung  * Software Foundation.
     21       1.1   dyoung  *
     22       1.1   dyoung  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
     23       1.1   dyoung  * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
     24       1.1   dyoung  * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
     25       1.1   dyoung  * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
     26       1.1   dyoung  * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
     27       1.1   dyoung  * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
     28       1.1   dyoung  * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
     29       1.1   dyoung  * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
     30       1.1   dyoung  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
     31       1.1   dyoung  * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
     32       1.1   dyoung  */
     33       1.1   dyoung 
     34       1.1   dyoung #include <sys/cdefs.h>
     35       1.3   dyoung #ifdef __FreeBSD__
     36      1.10   dyoung __FBSDID("$FreeBSD: src/sys/net80211/ieee80211.c,v 1.11 2004/04/02 20:19:20 sam Exp $");
     37       1.3   dyoung #else
     38  1.32.4.1     kent __KERNEL_RCSID(0, "$NetBSD: ieee80211.c,v 1.32.4.1 2005/04/29 11:29:32 kent Exp $");
     39       1.3   dyoung #endif
     40       1.1   dyoung 
     41       1.1   dyoung /*
     42       1.1   dyoung  * IEEE 802.11 generic handler
     43       1.1   dyoung  */
     44       1.1   dyoung 
     45       1.1   dyoung #include "opt_inet.h"
     46       1.7     matt #include "bpfilter.h"
     47       1.1   dyoung 
     48       1.1   dyoung #include <sys/param.h>
     49  1.32.4.1     kent #include <sys/systm.h>
     50  1.32.4.1     kent #include <sys/mbuf.h>
     51       1.1   dyoung #include <sys/malloc.h>
     52       1.1   dyoung #include <sys/kernel.h>
     53       1.1   dyoung #include <sys/socket.h>
     54       1.1   dyoung #include <sys/sockio.h>
     55       1.1   dyoung #include <sys/endian.h>
     56       1.1   dyoung #include <sys/errno.h>
     57       1.4   dyoung #ifdef __FreeBSD__
     58       1.1   dyoung #include <sys/bus.h>
     59       1.4   dyoung #endif
     60       1.1   dyoung #include <sys/proc.h>
     61       1.1   dyoung #include <sys/sysctl.h>
     62       1.1   dyoung 
     63       1.2   dyoung #ifdef __FreeBSD__
     64       1.1   dyoung #include <machine/atomic.h>
     65       1.2   dyoung #endif
     66  1.32.4.1     kent 
     67       1.1   dyoung #include <net/if.h>
     68       1.1   dyoung #include <net/if_dl.h>
     69       1.1   dyoung #include <net/if_media.h>
     70       1.1   dyoung #include <net/if_arp.h>
     71       1.2   dyoung #ifdef __FreeBSD__
     72       1.1   dyoung #include <net/ethernet.h>
     73       1.4   dyoung #else
     74       1.4   dyoung #include <net/if_ether.h>
     75       1.2   dyoung #endif
     76       1.1   dyoung #include <net/if_llc.h>
     77       1.1   dyoung 
     78       1.1   dyoung #include <net80211/ieee80211_var.h>
     79       1.4   dyoung #include <net80211/ieee80211_compat.h>
     80      1.22   dyoung #include <net80211/ieee80211_sysctl.h>
     81       1.1   dyoung 
     82       1.1   dyoung #include <net/bpf.h>
     83       1.1   dyoung 
     84       1.1   dyoung #ifdef INET
     85  1.32.4.1     kent #include <netinet/in.h>
     86       1.4   dyoung #ifdef __FreeBSD__
     87       1.1   dyoung #include <netinet/if_ether.h>
     88       1.4   dyoung #else
     89       1.4   dyoung #include <net/if_ether.h>
     90       1.4   dyoung #endif
     91       1.1   dyoung #endif
     92       1.1   dyoung 
     93       1.1   dyoung #ifdef IEEE80211_DEBUG
     94       1.1   dyoung int	ieee80211_debug = 0;
     95      1.11   dyoung #ifdef __NetBSD__
     96      1.11   dyoung static int ieee80211_debug_nodenum;
     97      1.11   dyoung #endif /* __NetBSD__ */
     98      1.11   dyoung 
     99       1.4   dyoung #ifdef __FreeBSD__
    100       1.1   dyoung SYSCTL_INT(_debug, OID_AUTO, ieee80211, CTLFLAG_RW, &ieee80211_debug,
    101       1.1   dyoung 	    0, "IEEE 802.11 media debugging printfs");
    102       1.1   dyoung #endif
    103       1.4   dyoung #endif
    104       1.1   dyoung 
    105      1.32   dyoung int	ieee80211_cache_size = IEEE80211_CACHE_SIZE;
    106      1.32   dyoung static int ieee80211_cache_size_nodenum;
    107      1.11   dyoung 
    108      1.20   dyoung struct ieee80211com_head ieee80211com_head =
    109      1.20   dyoung     LIST_HEAD_INITIALIZER(ieee80211com_head);
    110      1.20   dyoung 
    111      1.23  mycroft static void ieee80211_setbasicrates(struct ieee80211com *);
    112       1.1   dyoung 
    113      1.22   dyoung #ifdef __NetBSD__
    114      1.22   dyoung static void sysctl_ieee80211_fill_node(struct ieee80211_node *,
    115      1.22   dyoung     struct ieee80211_node_sysctl *, int, struct ieee80211_channel *, int);
    116      1.22   dyoung static struct ieee80211_node *ieee80211_node_walknext(
    117      1.22   dyoung     struct ieee80211_node_walk *);
    118      1.22   dyoung static struct ieee80211_node *ieee80211_node_walkfirst(
    119      1.22   dyoung     struct ieee80211_node_walk *, u_short);
    120      1.22   dyoung static int sysctl_ieee80211_verify(SYSCTLFN_ARGS);
    121      1.22   dyoung static int sysctl_ieee80211_node(SYSCTLFN_ARGS);
    122      1.22   dyoung #endif /* __NetBSD__ */
    123      1.22   dyoung 
    124      1.22   dyoung #define	LOGICALLY_EQUAL(x, y)	(!(x) == !(y))
    125      1.22   dyoung 
    126      1.10   dyoung static const char *ieee80211_phymode_name[] = {
    127      1.10   dyoung 	"auto",		/* IEEE80211_MODE_AUTO */
    128      1.10   dyoung 	"11a",		/* IEEE80211_MODE_11A */
    129      1.10   dyoung 	"11b",		/* IEEE80211_MODE_11B */
    130      1.10   dyoung 	"11g",		/* IEEE80211_MODE_11G */
    131      1.10   dyoung 	"FH",		/* IEEE80211_MODE_FH */
    132      1.10   dyoung 	"turbo",	/* IEEE80211_MODE_TURBO */
    133      1.10   dyoung };
    134       1.1   dyoung 
    135       1.1   dyoung void
    136       1.1   dyoung ieee80211_ifattach(struct ifnet *ifp)
    137       1.1   dyoung {
    138       1.1   dyoung 	struct ieee80211com *ic = (void *)ifp;
    139       1.1   dyoung 	struct ieee80211_channel *c;
    140       1.1   dyoung 	int i;
    141       1.1   dyoung 
    142       1.1   dyoung 	ether_ifattach(ifp, ic->ic_myaddr);
    143       1.7     matt #if NBPFILTER > 0
    144       1.1   dyoung 	bpfattach2(ifp, DLT_IEEE802_11,
    145       1.1   dyoung 	    sizeof(struct ieee80211_frame_addr4), &ic->ic_rawbpf);
    146       1.7     matt #endif
    147       1.1   dyoung 	ieee80211_crypto_attach(ifp);
    148       1.1   dyoung 
    149       1.1   dyoung 	/*
    150       1.1   dyoung 	 * Fill in 802.11 available channel set, mark
    151       1.1   dyoung 	 * all available channels as active, and pick
    152       1.1   dyoung 	 * a default channel if not already specified.
    153       1.1   dyoung 	 */
    154       1.1   dyoung 	memset(ic->ic_chan_avail, 0, sizeof(ic->ic_chan_avail));
    155       1.1   dyoung 	ic->ic_modecaps |= 1<<IEEE80211_MODE_AUTO;
    156       1.1   dyoung 	for (i = 0; i <= IEEE80211_CHAN_MAX; i++) {
    157       1.1   dyoung 		c = &ic->ic_channels[i];
    158       1.1   dyoung 		if (c->ic_flags) {
    159       1.1   dyoung 			/*
    160       1.1   dyoung 			 * Verify driver passed us valid data.
    161       1.1   dyoung 			 */
    162       1.1   dyoung 			if (i != ieee80211_chan2ieee(ic, c)) {
    163       1.1   dyoung 				if_printf(ifp, "bad channel ignored; "
    164       1.1   dyoung 					"freq %u flags %x number %u\n",
    165       1.1   dyoung 					c->ic_freq, c->ic_flags, i);
    166       1.1   dyoung 				c->ic_flags = 0;	/* NB: remove */
    167       1.1   dyoung 				continue;
    168       1.1   dyoung 			}
    169       1.1   dyoung 			setbit(ic->ic_chan_avail, i);
    170       1.1   dyoung 			/*
    171       1.1   dyoung 			 * Identify mode capabilities.
    172       1.1   dyoung 			 */
    173       1.1   dyoung 			if (IEEE80211_IS_CHAN_A(c))
    174       1.1   dyoung 				ic->ic_modecaps |= 1<<IEEE80211_MODE_11A;
    175       1.1   dyoung 			if (IEEE80211_IS_CHAN_B(c))
    176       1.1   dyoung 				ic->ic_modecaps |= 1<<IEEE80211_MODE_11B;
    177       1.1   dyoung 			if (IEEE80211_IS_CHAN_PUREG(c))
    178       1.1   dyoung 				ic->ic_modecaps |= 1<<IEEE80211_MODE_11G;
    179       1.5   dyoung 			if (IEEE80211_IS_CHAN_FHSS(c))
    180       1.5   dyoung 				ic->ic_modecaps |= 1<<IEEE80211_MODE_FH;
    181       1.1   dyoung 			if (IEEE80211_IS_CHAN_T(c))
    182       1.1   dyoung 				ic->ic_modecaps |= 1<<IEEE80211_MODE_TURBO;
    183       1.1   dyoung 		}
    184       1.1   dyoung 	}
    185       1.1   dyoung 	/* validate ic->ic_curmode */
    186       1.1   dyoung 	if ((ic->ic_modecaps & (1<<ic->ic_curmode)) == 0)
    187       1.1   dyoung 		ic->ic_curmode = IEEE80211_MODE_AUTO;
    188      1.10   dyoung 	ic->ic_des_chan = IEEE80211_CHAN_ANYC;	/* any channel is ok */
    189       1.1   dyoung 
    190      1.23  mycroft 	ieee80211_setbasicrates(ic);
    191       1.1   dyoung 	(void) ieee80211_setmode(ic, ic->ic_curmode);
    192       1.1   dyoung 
    193       1.1   dyoung 	if (ic->ic_lintval == 0)
    194       1.1   dyoung 		ic->ic_lintval = 100;		/* default sleep */
    195       1.1   dyoung 	ic->ic_bmisstimeout = 7*ic->ic_lintval;	/* default 7 beacons */
    196       1.1   dyoung 
    197      1.21   dyoung 	LIST_INSERT_HEAD(&ieee80211com_head, ic, ic_list);
    198      1.28  mycroft 	ieee80211_node_attach(ic);
    199       1.1   dyoung 	ieee80211_proto_attach(ifp);
    200       1.1   dyoung }
    201       1.1   dyoung 
    202       1.1   dyoung void
    203       1.1   dyoung ieee80211_ifdetach(struct ifnet *ifp)
    204       1.1   dyoung {
    205       1.1   dyoung 	struct ieee80211com *ic = (void *)ifp;
    206       1.1   dyoung 
    207       1.1   dyoung 	ieee80211_proto_detach(ifp);
    208       1.1   dyoung 	ieee80211_crypto_detach(ifp);
    209      1.28  mycroft 	ieee80211_node_detach(ic);
    210      1.21   dyoung 	LIST_REMOVE(ic, ic_list);
    211       1.4   dyoung #ifdef __FreeBSD__
    212       1.1   dyoung 	ifmedia_removeall(&ic->ic_media);
    213       1.4   dyoung #else
    214       1.4   dyoung         ifmedia_delete_instance(&ic->ic_media, IFM_INST_ANY);
    215       1.4   dyoung #endif
    216       1.7     matt #if NBPFILTER > 0
    217       1.1   dyoung 	bpfdetach(ifp);
    218       1.7     matt #endif
    219       1.1   dyoung 	ether_ifdetach(ifp);
    220       1.1   dyoung }
    221       1.1   dyoung 
    222       1.1   dyoung /*
    223       1.1   dyoung  * Convert MHz frequency to IEEE channel number.
    224       1.1   dyoung  */
    225       1.1   dyoung u_int
    226       1.1   dyoung ieee80211_mhz2ieee(u_int freq, u_int flags)
    227       1.1   dyoung {
    228       1.1   dyoung 	if (flags & IEEE80211_CHAN_2GHZ) {	/* 2GHz band */
    229       1.1   dyoung 		if (freq == 2484)
    230       1.1   dyoung 			return 14;
    231       1.1   dyoung 		if (freq < 2484)
    232       1.1   dyoung 			return (freq - 2407) / 5;
    233       1.1   dyoung 		else
    234       1.1   dyoung 			return 15 + ((freq - 2512) / 20);
    235       1.1   dyoung 	} else if (flags & IEEE80211_CHAN_5GHZ) {	/* 5Ghz band */
    236       1.1   dyoung 		return (freq - 5000) / 5;
    237       1.1   dyoung 	} else {				/* either, guess */
    238       1.1   dyoung 		if (freq == 2484)
    239       1.1   dyoung 			return 14;
    240       1.1   dyoung 		if (freq < 2484)
    241       1.1   dyoung 			return (freq - 2407) / 5;
    242       1.1   dyoung 		if (freq < 5000)
    243       1.1   dyoung 			return 15 + ((freq - 2512) / 20);
    244       1.1   dyoung 		return (freq - 5000) / 5;
    245       1.1   dyoung 	}
    246       1.1   dyoung }
    247       1.1   dyoung 
    248       1.1   dyoung /*
    249       1.1   dyoung  * Convert channel to IEEE channel number.
    250       1.1   dyoung  */
    251       1.1   dyoung u_int
    252       1.1   dyoung ieee80211_chan2ieee(struct ieee80211com *ic, struct ieee80211_channel *c)
    253       1.1   dyoung {
    254       1.1   dyoung 	if (ic->ic_channels <= c && c <= &ic->ic_channels[IEEE80211_CHAN_MAX])
    255       1.1   dyoung 		return c - ic->ic_channels;
    256       1.1   dyoung 	else if (c == IEEE80211_CHAN_ANYC)
    257       1.1   dyoung 		return IEEE80211_CHAN_ANY;
    258       1.1   dyoung 	else if (c != NULL) {
    259       1.1   dyoung 		if_printf(&ic->ic_if, "invalid channel freq %u flags %x\n",
    260       1.1   dyoung 			c->ic_freq, c->ic_flags);
    261       1.1   dyoung 		return 0;		/* XXX */
    262       1.1   dyoung 	} else {
    263       1.1   dyoung 		if_printf(&ic->ic_if, "invalid channel (NULL)\n");
    264       1.1   dyoung 		return 0;		/* XXX */
    265       1.1   dyoung 	}
    266       1.1   dyoung }
    267       1.1   dyoung 
    268       1.1   dyoung /*
    269       1.1   dyoung  * Convert IEEE channel number to MHz frequency.
    270       1.1   dyoung  */
    271       1.1   dyoung u_int
    272       1.1   dyoung ieee80211_ieee2mhz(u_int chan, u_int flags)
    273       1.1   dyoung {
    274       1.1   dyoung 	if (flags & IEEE80211_CHAN_2GHZ) {	/* 2GHz band */
    275       1.1   dyoung 		if (chan == 14)
    276       1.1   dyoung 			return 2484;
    277       1.1   dyoung 		if (chan < 14)
    278       1.1   dyoung 			return 2407 + chan*5;
    279       1.1   dyoung 		else
    280       1.1   dyoung 			return 2512 + ((chan-15)*20);
    281       1.1   dyoung 	} else if (flags & IEEE80211_CHAN_5GHZ) {/* 5Ghz band */
    282       1.1   dyoung 		return 5000 + (chan*5);
    283       1.1   dyoung 	} else {				/* either, guess */
    284       1.1   dyoung 		if (chan == 14)
    285       1.1   dyoung 			return 2484;
    286       1.1   dyoung 		if (chan < 14)			/* 0-13 */
    287       1.1   dyoung 			return 2407 + chan*5;
    288       1.1   dyoung 		if (chan < 27)			/* 15-26 */
    289       1.1   dyoung 			return 2512 + ((chan-15)*20);
    290       1.1   dyoung 		return 5000 + (chan*5);
    291       1.1   dyoung 	}
    292       1.1   dyoung }
    293       1.1   dyoung 
    294       1.1   dyoung /*
    295       1.1   dyoung  * Setup the media data structures according to the channel and
    296       1.1   dyoung  * rate tables.  This must be called by the driver after
    297       1.1   dyoung  * ieee80211_attach and before most anything else.
    298       1.1   dyoung  */
    299       1.1   dyoung void
    300       1.1   dyoung ieee80211_media_init(struct ifnet *ifp,
    301       1.1   dyoung 	ifm_change_cb_t media_change, ifm_stat_cb_t media_stat)
    302       1.1   dyoung {
    303       1.1   dyoung #define	ADD(_ic, _s, _o) \
    304       1.1   dyoung 	ifmedia_add(&(_ic)->ic_media, \
    305       1.1   dyoung 		IFM_MAKEWORD(IFM_IEEE80211, (_s), (_o), 0), 0, NULL)
    306       1.1   dyoung 	struct ieee80211com *ic = (void *)ifp;
    307       1.1   dyoung 	struct ifmediareq imr;
    308       1.1   dyoung 	int i, j, mode, rate, maxrate, mword, mopt, r;
    309       1.1   dyoung 	struct ieee80211_rateset *rs;
    310       1.1   dyoung 	struct ieee80211_rateset allrates;
    311       1.1   dyoung 
    312       1.1   dyoung 	/*
    313       1.1   dyoung 	 * Do late attach work that must wait for any subclass
    314       1.1   dyoung 	 * (i.e. driver) work such as overriding methods.
    315       1.1   dyoung 	 */
    316      1.28  mycroft 	ieee80211_node_lateattach(ic);
    317       1.1   dyoung 
    318       1.1   dyoung 	/*
    319       1.1   dyoung 	 * Fill in media characteristics.
    320       1.1   dyoung 	 */
    321       1.1   dyoung 	ifmedia_init(&ic->ic_media, 0, media_change, media_stat);
    322       1.1   dyoung 	maxrate = 0;
    323       1.1   dyoung 	memset(&allrates, 0, sizeof(allrates));
    324       1.1   dyoung 	for (mode = IEEE80211_MODE_AUTO; mode < IEEE80211_MODE_MAX; mode++) {
    325  1.32.4.1     kent 		static const u_int mopts[] = {
    326       1.1   dyoung 			IFM_AUTO,
    327       1.5   dyoung 			IFM_IEEE80211_11A,
    328       1.5   dyoung 			IFM_IEEE80211_11B,
    329       1.5   dyoung 			IFM_IEEE80211_11G,
    330       1.5   dyoung 			IFM_IEEE80211_FH,
    331       1.5   dyoung 			IFM_IEEE80211_11A | IFM_IEEE80211_TURBO,
    332       1.1   dyoung 		};
    333       1.1   dyoung 		if ((ic->ic_modecaps & (1<<mode)) == 0)
    334       1.1   dyoung 			continue;
    335       1.1   dyoung 		mopt = mopts[mode];
    336       1.1   dyoung 		ADD(ic, IFM_AUTO, mopt);	/* e.g. 11a auto */
    337       1.1   dyoung 		if (ic->ic_caps & IEEE80211_C_IBSS)
    338       1.1   dyoung 			ADD(ic, IFM_AUTO, mopt | IFM_IEEE80211_ADHOC);
    339       1.1   dyoung 		if (ic->ic_caps & IEEE80211_C_HOSTAP)
    340       1.1   dyoung 			ADD(ic, IFM_AUTO, mopt | IFM_IEEE80211_HOSTAP);
    341       1.1   dyoung 		if (ic->ic_caps & IEEE80211_C_AHDEMO)
    342       1.1   dyoung 			ADD(ic, IFM_AUTO, mopt | IFM_IEEE80211_ADHOC | IFM_FLAG0);
    343       1.1   dyoung 		if (ic->ic_caps & IEEE80211_C_MONITOR)
    344       1.1   dyoung 			ADD(ic, IFM_AUTO, mopt | IFM_IEEE80211_MONITOR);
    345       1.1   dyoung 		if (mode == IEEE80211_MODE_AUTO)
    346       1.1   dyoung 			continue;
    347      1.10   dyoung 		if_printf(ifp, "%s rates: ", ieee80211_phymode_name[mode]);
    348       1.1   dyoung 		rs = &ic->ic_sup_rates[mode];
    349       1.1   dyoung 		for (i = 0; i < rs->rs_nrates; i++) {
    350       1.1   dyoung 			rate = rs->rs_rates[i];
    351       1.1   dyoung 			mword = ieee80211_rate2media(ic, rate, mode);
    352       1.1   dyoung 			if (mword == 0)
    353       1.1   dyoung 				continue;
    354       1.1   dyoung 			printf("%s%d%sMbps", (i != 0 ? " " : ""),
    355       1.1   dyoung 			    (rate & IEEE80211_RATE_VAL) / 2,
    356       1.1   dyoung 			    ((rate & 0x1) != 0 ? ".5" : ""));
    357       1.1   dyoung 			ADD(ic, mword, mopt);
    358       1.1   dyoung 			if (ic->ic_caps & IEEE80211_C_IBSS)
    359       1.1   dyoung 				ADD(ic, mword, mopt | IFM_IEEE80211_ADHOC);
    360       1.1   dyoung 			if (ic->ic_caps & IEEE80211_C_HOSTAP)
    361       1.1   dyoung 				ADD(ic, mword, mopt | IFM_IEEE80211_HOSTAP);
    362       1.1   dyoung 			if (ic->ic_caps & IEEE80211_C_AHDEMO)
    363       1.1   dyoung 				ADD(ic, mword, mopt | IFM_IEEE80211_ADHOC | IFM_FLAG0);
    364       1.1   dyoung 			if (ic->ic_caps & IEEE80211_C_MONITOR)
    365       1.1   dyoung 				ADD(ic, mword, mopt | IFM_IEEE80211_MONITOR);
    366       1.1   dyoung 			/*
    367       1.1   dyoung 			 * Add rate to the collection of all rates.
    368       1.1   dyoung 			 */
    369       1.1   dyoung 			r = rate & IEEE80211_RATE_VAL;
    370       1.1   dyoung 			for (j = 0; j < allrates.rs_nrates; j++)
    371       1.1   dyoung 				if (allrates.rs_rates[j] == r)
    372       1.1   dyoung 					break;
    373       1.1   dyoung 			if (j == allrates.rs_nrates) {
    374       1.1   dyoung 				/* unique, add to the set */
    375       1.1   dyoung 				allrates.rs_rates[j] = r;
    376       1.1   dyoung 				allrates.rs_nrates++;
    377       1.1   dyoung 			}
    378       1.1   dyoung 			rate = (rate & IEEE80211_RATE_VAL) / 2;
    379       1.1   dyoung 			if (rate > maxrate)
    380       1.1   dyoung 				maxrate = rate;
    381       1.1   dyoung 		}
    382       1.1   dyoung 		printf("\n");
    383       1.1   dyoung 	}
    384       1.1   dyoung 	for (i = 0; i < allrates.rs_nrates; i++) {
    385       1.1   dyoung 		mword = ieee80211_rate2media(ic, allrates.rs_rates[i],
    386       1.1   dyoung 				IEEE80211_MODE_AUTO);
    387       1.1   dyoung 		if (mword == 0)
    388       1.1   dyoung 			continue;
    389       1.1   dyoung 		mword = IFM_SUBTYPE(mword);	/* remove media options */
    390       1.1   dyoung 		ADD(ic, mword, 0);
    391       1.1   dyoung 		if (ic->ic_caps & IEEE80211_C_IBSS)
    392       1.1   dyoung 			ADD(ic, mword, IFM_IEEE80211_ADHOC);
    393       1.1   dyoung 		if (ic->ic_caps & IEEE80211_C_HOSTAP)
    394       1.1   dyoung 			ADD(ic, mword, IFM_IEEE80211_HOSTAP);
    395       1.1   dyoung 		if (ic->ic_caps & IEEE80211_C_AHDEMO)
    396       1.1   dyoung 			ADD(ic, mword, IFM_IEEE80211_ADHOC | IFM_FLAG0);
    397       1.1   dyoung 		if (ic->ic_caps & IEEE80211_C_MONITOR)
    398       1.1   dyoung 			ADD(ic, mword, IFM_IEEE80211_MONITOR);
    399       1.1   dyoung 	}
    400       1.1   dyoung 	ieee80211_media_status(ifp, &imr);
    401       1.1   dyoung 	ifmedia_set(&ic->ic_media, imr.ifm_active);
    402      1.27  mycroft #ifndef __linux__
    403       1.1   dyoung 	if (maxrate)
    404       1.1   dyoung 		ifp->if_baudrate = IF_Mbps(maxrate);
    405      1.27  mycroft #endif
    406       1.1   dyoung #undef ADD
    407       1.1   dyoung }
    408       1.1   dyoung 
    409       1.1   dyoung static int
    410       1.1   dyoung findrate(struct ieee80211com *ic, enum ieee80211_phymode mode, int rate)
    411       1.1   dyoung {
    412       1.1   dyoung #define	IEEERATE(_ic,_m,_i) \
    413       1.1   dyoung 	((_ic)->ic_sup_rates[_m].rs_rates[_i] & IEEE80211_RATE_VAL)
    414       1.1   dyoung 	int i, nrates = ic->ic_sup_rates[mode].rs_nrates;
    415       1.1   dyoung 	for (i = 0; i < nrates; i++)
    416       1.1   dyoung 		if (IEEERATE(ic, mode, i) == rate)
    417       1.1   dyoung 			return i;
    418       1.1   dyoung 	return -1;
    419       1.1   dyoung #undef IEEERATE
    420       1.1   dyoung }
    421       1.1   dyoung 
    422       1.1   dyoung /*
    423       1.1   dyoung  * Handle a media change request.
    424       1.1   dyoung  */
    425       1.1   dyoung int
    426       1.1   dyoung ieee80211_media_change(struct ifnet *ifp)
    427       1.1   dyoung {
    428       1.1   dyoung 	struct ieee80211com *ic = (void *)ifp;
    429       1.1   dyoung 	struct ifmedia_entry *ime;
    430       1.1   dyoung 	enum ieee80211_opmode newopmode;
    431       1.1   dyoung 	enum ieee80211_phymode newphymode;
    432       1.1   dyoung 	int i, j, newrate, error = 0;
    433       1.1   dyoung 
    434       1.1   dyoung 	ime = ic->ic_media.ifm_cur;
    435       1.1   dyoung 	/*
    436       1.1   dyoung 	 * First, identify the phy mode.
    437       1.1   dyoung 	 */
    438       1.1   dyoung 	switch (IFM_MODE(ime->ifm_media)) {
    439       1.1   dyoung 	case IFM_IEEE80211_11A:
    440       1.1   dyoung 		newphymode = IEEE80211_MODE_11A;
    441       1.1   dyoung 		break;
    442       1.1   dyoung 	case IFM_IEEE80211_11B:
    443       1.1   dyoung 		newphymode = IEEE80211_MODE_11B;
    444       1.1   dyoung 		break;
    445       1.1   dyoung 	case IFM_IEEE80211_11G:
    446       1.1   dyoung 		newphymode = IEEE80211_MODE_11G;
    447       1.1   dyoung 		break;
    448       1.5   dyoung 	case IFM_IEEE80211_FH:
    449       1.5   dyoung 		newphymode = IEEE80211_MODE_FH;
    450       1.5   dyoung 		break;
    451       1.1   dyoung 	case IFM_AUTO:
    452       1.1   dyoung 		newphymode = IEEE80211_MODE_AUTO;
    453       1.1   dyoung 		break;
    454       1.1   dyoung 	default:
    455       1.1   dyoung 		return EINVAL;
    456       1.1   dyoung 	}
    457       1.1   dyoung 	/*
    458       1.1   dyoung 	 * Turbo mode is an ``option''.  Eventually it
    459       1.1   dyoung 	 * needs to be applied to 11g too.
    460       1.1   dyoung 	 */
    461       1.1   dyoung 	if (ime->ifm_media & IFM_IEEE80211_TURBO) {
    462       1.1   dyoung 		if (newphymode != IEEE80211_MODE_11A)
    463       1.1   dyoung 			return EINVAL;
    464       1.1   dyoung 		newphymode = IEEE80211_MODE_TURBO;
    465       1.1   dyoung 	}
    466       1.1   dyoung 	/*
    467       1.1   dyoung 	 * Validate requested mode is available.
    468       1.1   dyoung 	 */
    469       1.1   dyoung 	if ((ic->ic_modecaps & (1<<newphymode)) == 0)
    470       1.1   dyoung 		return EINVAL;
    471       1.1   dyoung 
    472       1.1   dyoung 	/*
    473       1.1   dyoung 	 * Next, the fixed/variable rate.
    474       1.1   dyoung 	 */
    475       1.1   dyoung 	i = -1;
    476       1.1   dyoung 	if (IFM_SUBTYPE(ime->ifm_media) != IFM_AUTO) {
    477       1.1   dyoung 		/*
    478       1.1   dyoung 		 * Convert media subtype to rate.
    479       1.1   dyoung 		 */
    480       1.1   dyoung 		newrate = ieee80211_media2rate(ime->ifm_media);
    481       1.1   dyoung 		if (newrate == 0)
    482       1.1   dyoung 			return EINVAL;
    483       1.1   dyoung 		/*
    484       1.1   dyoung 		 * Check the rate table for the specified/current phy.
    485       1.1   dyoung 		 */
    486       1.1   dyoung 		if (newphymode == IEEE80211_MODE_AUTO) {
    487       1.1   dyoung 			/*
    488       1.1   dyoung 			 * In autoselect mode search for the rate.
    489       1.1   dyoung 			 */
    490       1.1   dyoung 			for (j = IEEE80211_MODE_11A;
    491       1.1   dyoung 			     j < IEEE80211_MODE_MAX; j++) {
    492       1.1   dyoung 				if ((ic->ic_modecaps & (1<<j)) == 0)
    493       1.1   dyoung 					continue;
    494       1.1   dyoung 				i = findrate(ic, j, newrate);
    495       1.1   dyoung 				if (i != -1) {
    496       1.1   dyoung 					/* lock mode too */
    497       1.1   dyoung 					newphymode = j;
    498       1.1   dyoung 					break;
    499       1.1   dyoung 				}
    500       1.1   dyoung 			}
    501       1.1   dyoung 		} else {
    502       1.1   dyoung 			i = findrate(ic, newphymode, newrate);
    503       1.1   dyoung 		}
    504       1.1   dyoung 		if (i == -1)			/* mode/rate mismatch */
    505       1.1   dyoung 			return EINVAL;
    506       1.1   dyoung 	}
    507       1.1   dyoung 	/* NB: defer rate setting to later */
    508       1.1   dyoung 
    509       1.1   dyoung 	/*
    510       1.1   dyoung 	 * Deduce new operating mode but don't install it just yet.
    511       1.1   dyoung 	 */
    512       1.1   dyoung 	if ((ime->ifm_media & (IFM_IEEE80211_ADHOC|IFM_FLAG0)) ==
    513       1.1   dyoung 	    (IFM_IEEE80211_ADHOC|IFM_FLAG0))
    514       1.1   dyoung 		newopmode = IEEE80211_M_AHDEMO;
    515       1.1   dyoung 	else if (ime->ifm_media & IFM_IEEE80211_HOSTAP)
    516       1.1   dyoung 		newopmode = IEEE80211_M_HOSTAP;
    517       1.1   dyoung 	else if (ime->ifm_media & IFM_IEEE80211_ADHOC)
    518       1.1   dyoung 		newopmode = IEEE80211_M_IBSS;
    519       1.1   dyoung 	else if (ime->ifm_media & IFM_IEEE80211_MONITOR)
    520       1.1   dyoung 		newopmode = IEEE80211_M_MONITOR;
    521       1.1   dyoung 	else
    522       1.1   dyoung 		newopmode = IEEE80211_M_STA;
    523       1.1   dyoung 
    524       1.1   dyoung 	/*
    525       1.1   dyoung 	 * Autoselect doesn't make sense when operating as an AP.
    526       1.1   dyoung 	 * If no phy mode has been selected, pick one and lock it
    527       1.1   dyoung 	 * down so rate tables can be used in forming beacon frames
    528       1.1   dyoung 	 * and the like.
    529       1.1   dyoung 	 */
    530       1.1   dyoung 	if (newopmode == IEEE80211_M_HOSTAP &&
    531       1.1   dyoung 	    newphymode == IEEE80211_MODE_AUTO) {
    532       1.1   dyoung 		for (j = IEEE80211_MODE_11A; j < IEEE80211_MODE_MAX; j++)
    533       1.1   dyoung 			if (ic->ic_modecaps & (1<<j)) {
    534       1.1   dyoung 				newphymode = j;
    535       1.1   dyoung 				break;
    536       1.1   dyoung 			}
    537       1.1   dyoung 	}
    538       1.1   dyoung 
    539       1.1   dyoung 	/*
    540       1.1   dyoung 	 * Handle phy mode change.
    541       1.1   dyoung 	 */
    542       1.1   dyoung 	if (ic->ic_curmode != newphymode) {		/* change phy mode */
    543       1.1   dyoung 		error = ieee80211_setmode(ic, newphymode);
    544       1.1   dyoung 		if (error != 0)
    545       1.1   dyoung 			return error;
    546       1.1   dyoung 		error = ENETRESET;
    547       1.1   dyoung 	}
    548       1.1   dyoung 
    549       1.1   dyoung 	/*
    550       1.1   dyoung 	 * Committed to changes, install the rate setting.
    551       1.1   dyoung 	 */
    552       1.1   dyoung 	if (ic->ic_fixed_rate != i) {
    553       1.1   dyoung 		ic->ic_fixed_rate = i;			/* set fixed tx rate */
    554       1.1   dyoung 		error = ENETRESET;
    555       1.1   dyoung 	}
    556       1.1   dyoung 
    557       1.1   dyoung 	/*
    558       1.1   dyoung 	 * Handle operating mode change.
    559       1.1   dyoung 	 */
    560       1.1   dyoung 	if (ic->ic_opmode != newopmode) {
    561       1.1   dyoung 		ic->ic_opmode = newopmode;
    562       1.1   dyoung 		switch (newopmode) {
    563       1.1   dyoung 		case IEEE80211_M_AHDEMO:
    564       1.1   dyoung 		case IEEE80211_M_HOSTAP:
    565       1.1   dyoung 		case IEEE80211_M_STA:
    566       1.1   dyoung 		case IEEE80211_M_MONITOR:
    567       1.1   dyoung 			ic->ic_flags &= ~IEEE80211_F_IBSSON;
    568       1.1   dyoung 			break;
    569       1.1   dyoung 		case IEEE80211_M_IBSS:
    570       1.1   dyoung 			ic->ic_flags |= IEEE80211_F_IBSSON;
    571       1.1   dyoung 			break;
    572       1.1   dyoung 		}
    573       1.1   dyoung 		error = ENETRESET;
    574       1.1   dyoung 	}
    575       1.1   dyoung #ifdef notdef
    576       1.1   dyoung 	if (error == 0)
    577       1.1   dyoung 		ifp->if_baudrate = ifmedia_baudrate(ime->ifm_media);
    578       1.1   dyoung #endif
    579       1.1   dyoung 	return error;
    580       1.1   dyoung }
    581       1.1   dyoung 
    582       1.1   dyoung void
    583       1.1   dyoung ieee80211_media_status(struct ifnet *ifp, struct ifmediareq *imr)
    584       1.1   dyoung {
    585       1.1   dyoung 	struct ieee80211com *ic = (void *)ifp;
    586       1.1   dyoung 	struct ieee80211_node *ni = NULL;
    587       1.1   dyoung 
    588       1.1   dyoung 	imr->ifm_status = IFM_AVALID;
    589       1.1   dyoung 	imr->ifm_active = IFM_IEEE80211;
    590       1.1   dyoung 	if (ic->ic_state == IEEE80211_S_RUN)
    591       1.1   dyoung 		imr->ifm_status |= IFM_ACTIVE;
    592       1.1   dyoung 	imr->ifm_active |= IFM_AUTO;
    593       1.1   dyoung 	switch (ic->ic_opmode) {
    594       1.1   dyoung 	case IEEE80211_M_STA:
    595       1.1   dyoung 		ni = ic->ic_bss;
    596       1.1   dyoung 		/* calculate rate subtype */
    597       1.1   dyoung 		imr->ifm_active |= ieee80211_rate2media(ic,
    598       1.1   dyoung 			ni->ni_rates.rs_rates[ni->ni_txrate], ic->ic_curmode);
    599       1.1   dyoung 		break;
    600       1.1   dyoung 	case IEEE80211_M_IBSS:
    601       1.1   dyoung 		imr->ifm_active |= IFM_IEEE80211_ADHOC;
    602       1.1   dyoung 		break;
    603       1.1   dyoung 	case IEEE80211_M_AHDEMO:
    604       1.1   dyoung 		/* should not come here */
    605       1.1   dyoung 		break;
    606       1.1   dyoung 	case IEEE80211_M_HOSTAP:
    607       1.1   dyoung 		imr->ifm_active |= IFM_IEEE80211_HOSTAP;
    608       1.1   dyoung 		break;
    609       1.1   dyoung 	case IEEE80211_M_MONITOR:
    610       1.1   dyoung 		imr->ifm_active |= IFM_IEEE80211_MONITOR;
    611       1.1   dyoung 		break;
    612       1.1   dyoung 	}
    613       1.1   dyoung 	switch (ic->ic_curmode) {
    614       1.1   dyoung 	case IEEE80211_MODE_11A:
    615       1.5   dyoung 		imr->ifm_active |= IFM_IEEE80211_11A;
    616       1.1   dyoung 		break;
    617       1.1   dyoung 	case IEEE80211_MODE_11B:
    618       1.5   dyoung 		imr->ifm_active |= IFM_IEEE80211_11B;
    619       1.1   dyoung 		break;
    620       1.1   dyoung 	case IEEE80211_MODE_11G:
    621       1.5   dyoung 		imr->ifm_active |= IFM_IEEE80211_11G;
    622       1.5   dyoung 		break;
    623       1.5   dyoung 	case IEEE80211_MODE_FH:
    624       1.5   dyoung 		imr->ifm_active |= IFM_IEEE80211_FH;
    625       1.1   dyoung 		break;
    626       1.1   dyoung 	case IEEE80211_MODE_TURBO:
    627       1.5   dyoung 		imr->ifm_active |= IFM_IEEE80211_11A
    628       1.1   dyoung 				|  IFM_IEEE80211_TURBO;
    629       1.1   dyoung 		break;
    630       1.1   dyoung 	}
    631       1.1   dyoung }
    632       1.1   dyoung 
    633       1.1   dyoung void
    634       1.1   dyoung ieee80211_watchdog(struct ifnet *ifp)
    635       1.1   dyoung {
    636       1.1   dyoung 	struct ieee80211com *ic = (void *)ifp;
    637       1.1   dyoung 
    638       1.1   dyoung 	if (ic->ic_mgt_timer && --ic->ic_mgt_timer == 0)
    639       1.1   dyoung 		ieee80211_new_state(ic, IEEE80211_S_SCAN, -1);
    640       1.1   dyoung 
    641      1.32   dyoung 	if (ic->ic_mgt_timer != 0)
    642       1.1   dyoung 		ifp->if_timer = 1;
    643       1.1   dyoung }
    644       1.1   dyoung 
    645       1.1   dyoung /*
    646       1.1   dyoung  * Mark the basic rates for the 11g rate table based on the
    647       1.1   dyoung  * operating mode.  For real 11g we mark all the 11b rates
    648       1.1   dyoung  * and 6, 12, and 24 OFDM.  For 11b compatibility we mark only
    649       1.1   dyoung  * 11b rates.  There's also a pseudo 11a-mode used to mark only
    650       1.1   dyoung  * the basic OFDM rates.
    651       1.1   dyoung  */
    652       1.1   dyoung static void
    653      1.23  mycroft ieee80211_setbasicrates(struct ieee80211com *ic)
    654       1.1   dyoung {
    655       1.1   dyoung 	static const struct ieee80211_rateset basic[] = {
    656      1.23  mycroft 	    { 0 },				/* IEEE80211_MODE_AUTO */
    657       1.1   dyoung 	    { 3, { 12, 24, 48 } },		/* IEEE80211_MODE_11A */
    658      1.23  mycroft 	    { 2, { 2, 4 } },			/* IEEE80211_MODE_11B */
    659      1.31  mycroft 	    { 4, { 2, 4, 11, 22 } },		/* IEEE80211_MODE_11G */
    660      1.23  mycroft 	    { 2, { 2, 4 } },			/* IEEE80211_MODE_FH */
    661       1.1   dyoung 	    { 0 },				/* IEEE80211_MODE_TURBO	*/
    662       1.1   dyoung 	};
    663      1.23  mycroft 	enum ieee80211_phymode mode;
    664      1.23  mycroft 	struct ieee80211_rateset *rs;
    665       1.1   dyoung 	int i, j;
    666       1.1   dyoung 
    667      1.23  mycroft 	for (mode = 0; mode < IEEE80211_MODE_MAX; mode++) {
    668      1.23  mycroft 		rs = &ic->ic_sup_rates[mode];
    669      1.23  mycroft 		for (i = 0; i < rs->rs_nrates; i++) {
    670      1.23  mycroft 			rs->rs_rates[i] &= IEEE80211_RATE_VAL;
    671      1.23  mycroft 			for (j = 0; j < basic[mode].rs_nrates; j++)
    672      1.23  mycroft 				if (basic[mode].rs_rates[j] == rs->rs_rates[i]) {
    673      1.23  mycroft 					rs->rs_rates[i] |= IEEE80211_RATE_BASIC;
    674      1.23  mycroft 					break;
    675      1.23  mycroft 				}
    676      1.23  mycroft 		}
    677       1.1   dyoung 	}
    678       1.1   dyoung }
    679       1.1   dyoung 
    680       1.1   dyoung /*
    681       1.1   dyoung  * Set the current phy mode and recalculate the active channel
    682       1.1   dyoung  * set based on the available channels for this mode.  Also
    683       1.1   dyoung  * select a new default/current channel if the current one is
    684       1.1   dyoung  * inappropriate for this mode.
    685       1.1   dyoung  */
    686       1.1   dyoung int
    687       1.1   dyoung ieee80211_setmode(struct ieee80211com *ic, enum ieee80211_phymode mode)
    688       1.1   dyoung {
    689       1.1   dyoung #define	N(a)	(sizeof(a) / sizeof(a[0]))
    690       1.1   dyoung 	static const u_int chanflags[] = {
    691       1.1   dyoung 		0,			/* IEEE80211_MODE_AUTO */
    692       1.1   dyoung 		IEEE80211_CHAN_A,	/* IEEE80211_MODE_11A */
    693       1.1   dyoung 		IEEE80211_CHAN_B,	/* IEEE80211_MODE_11B */
    694       1.1   dyoung 		IEEE80211_CHAN_PUREG,	/* IEEE80211_MODE_11G */
    695       1.5   dyoung 		IEEE80211_CHAN_FHSS,	/* IEEE80211_MODE_FH */
    696       1.1   dyoung 		IEEE80211_CHAN_T,	/* IEEE80211_MODE_TURBO	*/
    697       1.1   dyoung 	};
    698       1.1   dyoung 	struct ieee80211_channel *c;
    699       1.1   dyoung 	u_int modeflags;
    700       1.1   dyoung 	int i;
    701       1.1   dyoung 
    702       1.1   dyoung 	/* validate new mode */
    703       1.1   dyoung 	if ((ic->ic_modecaps & (1<<mode)) == 0) {
    704      1.25  mycroft 		IEEE80211_DPRINTF(ic, IEEE80211_MSG_ANY,
    705      1.25  mycroft 			("%s: mode %u not supported (caps 0x%x)\n",
    706       1.1   dyoung 			__func__, mode, ic->ic_modecaps));
    707       1.1   dyoung 		return EINVAL;
    708       1.1   dyoung 	}
    709       1.1   dyoung 
    710       1.1   dyoung 	/*
    711       1.1   dyoung 	 * Verify at least one channel is present in the available
    712       1.1   dyoung 	 * channel list before committing to the new mode.
    713       1.1   dyoung 	 */
    714      1.10   dyoung 	IASSERT(mode < N(chanflags), ("Unexpected mode %u", mode));
    715       1.1   dyoung 	modeflags = chanflags[mode];
    716       1.1   dyoung 	for (i = 0; i <= IEEE80211_CHAN_MAX; i++) {
    717       1.1   dyoung 		c = &ic->ic_channels[i];
    718       1.1   dyoung 		if (mode == IEEE80211_MODE_AUTO) {
    719       1.1   dyoung 			/* ignore turbo channels for autoselect */
    720       1.1   dyoung 			if ((c->ic_flags &~ IEEE80211_CHAN_TURBO) != 0)
    721       1.1   dyoung 				break;
    722       1.1   dyoung 		} else {
    723       1.1   dyoung 			if ((c->ic_flags & modeflags) == modeflags)
    724       1.1   dyoung 				break;
    725       1.1   dyoung 		}
    726       1.1   dyoung 	}
    727       1.1   dyoung 	if (i > IEEE80211_CHAN_MAX) {
    728      1.25  mycroft 		IEEE80211_DPRINTF(ic, IEEE80211_MSG_ANY,
    729      1.25  mycroft 			("%s: no channels found for mode %u\n", __func__, mode));
    730       1.1   dyoung 		return EINVAL;
    731       1.1   dyoung 	}
    732       1.1   dyoung 
    733       1.1   dyoung 	/*
    734       1.1   dyoung 	 * Calculate the active channel set.
    735       1.1   dyoung 	 */
    736       1.1   dyoung 	memset(ic->ic_chan_active, 0, sizeof(ic->ic_chan_active));
    737       1.1   dyoung 	for (i = 0; i <= IEEE80211_CHAN_MAX; i++) {
    738       1.1   dyoung 		c = &ic->ic_channels[i];
    739       1.1   dyoung 		if (mode == IEEE80211_MODE_AUTO) {
    740       1.1   dyoung 			/* take anything but pure turbo channels */
    741       1.1   dyoung 			if ((c->ic_flags &~ IEEE80211_CHAN_TURBO) != 0)
    742       1.1   dyoung 				setbit(ic->ic_chan_active, i);
    743       1.1   dyoung 		} else {
    744       1.1   dyoung 			if ((c->ic_flags & modeflags) == modeflags)
    745       1.1   dyoung 				setbit(ic->ic_chan_active, i);
    746       1.1   dyoung 		}
    747       1.1   dyoung 	}
    748       1.1   dyoung 	/*
    749       1.1   dyoung 	 * If no current/default channel is setup or the current
    750       1.1   dyoung 	 * channel is wrong for the mode then pick the first
    751       1.1   dyoung 	 * available channel from the active list.  This is likely
    752       1.1   dyoung 	 * not the right one.
    753       1.1   dyoung 	 */
    754       1.1   dyoung 	if (ic->ic_ibss_chan == NULL ||
    755       1.1   dyoung 	    isclr(ic->ic_chan_active, ieee80211_chan2ieee(ic, ic->ic_ibss_chan))) {
    756       1.1   dyoung 		for (i = 0; i <= IEEE80211_CHAN_MAX; i++)
    757       1.1   dyoung 			if (isset(ic->ic_chan_active, i)) {
    758       1.1   dyoung 				ic->ic_ibss_chan = &ic->ic_channels[i];
    759       1.1   dyoung 				break;
    760       1.1   dyoung 			}
    761       1.9   dyoung 		IASSERT(ic->ic_ibss_chan != NULL &&
    762       1.5   dyoung 		    isset(ic->ic_chan_active,
    763       1.5   dyoung 			ieee80211_chan2ieee(ic, ic->ic_ibss_chan)),
    764      1.26  mycroft 		    ("Bad IBSS channel %u",
    765       1.5   dyoung 		     ieee80211_chan2ieee(ic, ic->ic_ibss_chan)));
    766       1.1   dyoung 	}
    767       1.1   dyoung 
    768       1.1   dyoung 	/*
    769       1.1   dyoung 	 * Set/reset state flags that influence beacon contents, etc.
    770       1.1   dyoung 	 *
    771       1.1   dyoung 	 * XXX what if we have stations already associated???
    772       1.1   dyoung 	 * XXX probably not right for autoselect?
    773      1.30   dyoung 	 *
    774      1.30   dyoung 	 * Short preamble is not interoperable with legacy .11b
    775      1.30   dyoung 	 * equipment, so it should not be the default for b or
    776      1.30   dyoung 	 * mixed b/g networks. -dcy
    777       1.1   dyoung 	 */
    778      1.30   dyoung #if 0
    779       1.8   dyoung 	if (ic->ic_caps & IEEE80211_C_SHPREAMBLE)
    780       1.8   dyoung 		ic->ic_flags |= IEEE80211_F_SHPREAMBLE;
    781      1.30   dyoung #endif
    782       1.1   dyoung 	if (mode == IEEE80211_MODE_11G) {
    783       1.1   dyoung 		if (ic->ic_caps & IEEE80211_C_SHSLOT)
    784       1.1   dyoung 			ic->ic_flags |= IEEE80211_F_SHSLOT;
    785      1.23  mycroft 	} else
    786       1.8   dyoung 		ic->ic_flags &= ~IEEE80211_F_SHSLOT;
    787       1.1   dyoung 
    788       1.1   dyoung 	ic->ic_curmode = mode;
    789       1.1   dyoung 	return 0;
    790       1.1   dyoung #undef N
    791       1.1   dyoung }
    792       1.1   dyoung 
    793       1.1   dyoung /*
    794       1.1   dyoung  * Return the phy mode for with the specified channel so the
    795       1.1   dyoung  * caller can select a rate set.  This is problematic and the
    796       1.1   dyoung  * work here assumes how things work elsewhere in this code.
    797       1.5   dyoung  *
    798       1.5   dyoung  * XXX never returns turbo modes -dcy
    799       1.1   dyoung  */
    800       1.1   dyoung enum ieee80211_phymode
    801       1.1   dyoung ieee80211_chan2mode(struct ieee80211com *ic, struct ieee80211_channel *chan)
    802       1.1   dyoung {
    803       1.1   dyoung 	/*
    804       1.1   dyoung 	 * NB: this assumes the channel would not be supplied to us
    805       1.1   dyoung 	 *     unless it was already compatible with the current mode.
    806       1.1   dyoung 	 */
    807      1.16   dyoung 	if (ic->ic_curmode != IEEE80211_MODE_AUTO ||
    808      1.16   dyoung 	    chan == IEEE80211_CHAN_ANYC)
    809       1.1   dyoung 		return ic->ic_curmode;
    810       1.1   dyoung 	/*
    811       1.1   dyoung 	 * In autoselect mode; deduce a mode based on the channel
    812       1.1   dyoung 	 * characteristics.  We assume that turbo-only channels
    813       1.1   dyoung 	 * are not considered when the channel set is constructed.
    814       1.1   dyoung 	 */
    815       1.1   dyoung 	if (IEEE80211_IS_CHAN_5GHZ(chan))
    816       1.1   dyoung 		return IEEE80211_MODE_11A;
    817       1.5   dyoung 	else if (IEEE80211_IS_CHAN_FHSS(chan))
    818       1.5   dyoung 		return IEEE80211_MODE_FH;
    819       1.1   dyoung 	else if (chan->ic_flags & (IEEE80211_CHAN_OFDM|IEEE80211_CHAN_DYN))
    820       1.1   dyoung 		return IEEE80211_MODE_11G;
    821       1.1   dyoung 	else
    822       1.1   dyoung 		return IEEE80211_MODE_11B;
    823       1.1   dyoung }
    824       1.1   dyoung 
    825       1.1   dyoung /*
    826       1.1   dyoung  * convert IEEE80211 rate value to ifmedia subtype.
    827       1.1   dyoung  * ieee80211 rate is in unit of 0.5Mbps.
    828       1.1   dyoung  */
    829       1.1   dyoung int
    830       1.1   dyoung ieee80211_rate2media(struct ieee80211com *ic, int rate, enum ieee80211_phymode mode)
    831       1.1   dyoung {
    832       1.1   dyoung #define	N(a)	(sizeof(a) / sizeof(a[0]))
    833       1.1   dyoung 	static const struct {
    834       1.1   dyoung 		u_int	m;	/* rate + mode */
    835       1.1   dyoung 		u_int	r;	/* if_media rate */
    836       1.1   dyoung 	} rates[] = {
    837       1.5   dyoung 		{   2 | IFM_IEEE80211_FH, IFM_IEEE80211_FH1 },
    838       1.5   dyoung 		{   4 | IFM_IEEE80211_FH, IFM_IEEE80211_FH2 },
    839       1.5   dyoung 		{   2 | IFM_IEEE80211_11B, IFM_IEEE80211_DS1 },
    840       1.5   dyoung 		{   4 | IFM_IEEE80211_11B, IFM_IEEE80211_DS2 },
    841       1.5   dyoung 		{  11 | IFM_IEEE80211_11B, IFM_IEEE80211_DS5 },
    842       1.5   dyoung 		{  22 | IFM_IEEE80211_11B, IFM_IEEE80211_DS11 },
    843       1.5   dyoung 		{  44 | IFM_IEEE80211_11B, IFM_IEEE80211_DS22 },
    844       1.5   dyoung 		{  12 | IFM_IEEE80211_11A, IFM_IEEE80211_OFDM6 },
    845       1.5   dyoung 		{  18 | IFM_IEEE80211_11A, IFM_IEEE80211_OFDM9 },
    846       1.5   dyoung 		{  24 | IFM_IEEE80211_11A, IFM_IEEE80211_OFDM12 },
    847       1.5   dyoung 		{  36 | IFM_IEEE80211_11A, IFM_IEEE80211_OFDM18 },
    848       1.5   dyoung 		{  48 | IFM_IEEE80211_11A, IFM_IEEE80211_OFDM24 },
    849       1.5   dyoung 		{  72 | IFM_IEEE80211_11A, IFM_IEEE80211_OFDM36 },
    850       1.5   dyoung 		{  96 | IFM_IEEE80211_11A, IFM_IEEE80211_OFDM48 },
    851       1.5   dyoung 		{ 108 | IFM_IEEE80211_11A, IFM_IEEE80211_OFDM54 },
    852       1.5   dyoung 		{   2 | IFM_IEEE80211_11G, IFM_IEEE80211_DS1 },
    853       1.5   dyoung 		{   4 | IFM_IEEE80211_11G, IFM_IEEE80211_DS2 },
    854       1.5   dyoung 		{  11 | IFM_IEEE80211_11G, IFM_IEEE80211_DS5 },
    855       1.5   dyoung 		{  22 | IFM_IEEE80211_11G, IFM_IEEE80211_DS11 },
    856       1.5   dyoung 		{  12 | IFM_IEEE80211_11G, IFM_IEEE80211_OFDM6 },
    857       1.5   dyoung 		{  18 | IFM_IEEE80211_11G, IFM_IEEE80211_OFDM9 },
    858       1.5   dyoung 		{  24 | IFM_IEEE80211_11G, IFM_IEEE80211_OFDM12 },
    859       1.5   dyoung 		{  36 | IFM_IEEE80211_11G, IFM_IEEE80211_OFDM18 },
    860       1.5   dyoung 		{  48 | IFM_IEEE80211_11G, IFM_IEEE80211_OFDM24 },
    861       1.5   dyoung 		{  72 | IFM_IEEE80211_11G, IFM_IEEE80211_OFDM36 },
    862       1.5   dyoung 		{  96 | IFM_IEEE80211_11G, IFM_IEEE80211_OFDM48 },
    863       1.5   dyoung 		{ 108 | IFM_IEEE80211_11G, IFM_IEEE80211_OFDM54 },
    864       1.1   dyoung 		/* NB: OFDM72 doesn't realy exist so we don't handle it */
    865       1.1   dyoung 	};
    866       1.1   dyoung 	u_int mask, i;
    867       1.1   dyoung 
    868       1.1   dyoung 	mask = rate & IEEE80211_RATE_VAL;
    869       1.1   dyoung 	switch (mode) {
    870       1.1   dyoung 	case IEEE80211_MODE_11A:
    871       1.1   dyoung 	case IEEE80211_MODE_TURBO:
    872       1.5   dyoung 		mask |= IFM_IEEE80211_11A;
    873       1.1   dyoung 		break;
    874       1.1   dyoung 	case IEEE80211_MODE_11B:
    875       1.5   dyoung 		mask |= IFM_IEEE80211_11B;
    876       1.5   dyoung 		break;
    877       1.5   dyoung 	case IEEE80211_MODE_FH:
    878       1.5   dyoung 		mask |= IFM_IEEE80211_FH;
    879       1.5   dyoung 		break;
    880       1.1   dyoung 	case IEEE80211_MODE_AUTO:
    881      1.10   dyoung 		/* NB: ic may be NULL for some drivers */
    882      1.10   dyoung 		if (ic && ic->ic_phytype == IEEE80211_T_FH) {
    883       1.5   dyoung 			mask |= IFM_IEEE80211_FH;
    884       1.5   dyoung 			break;
    885       1.1   dyoung 		}
    886      1.10   dyoung 		/* NB: hack, 11g matches both 11b+11a rates */
    887      1.10   dyoung 		/* fall thru... */
    888      1.10   dyoung 	case IEEE80211_MODE_11G:
    889      1.10   dyoung 		mask |= IFM_IEEE80211_11G;
    890      1.10   dyoung 		break;
    891       1.1   dyoung 	}
    892       1.1   dyoung 	for (i = 0; i < N(rates); i++)
    893       1.1   dyoung 		if (rates[i].m == mask)
    894       1.1   dyoung 			return rates[i].r;
    895       1.1   dyoung 	return IFM_AUTO;
    896       1.1   dyoung #undef N
    897       1.1   dyoung }
    898       1.1   dyoung 
    899       1.1   dyoung int
    900       1.1   dyoung ieee80211_media2rate(int mword)
    901       1.1   dyoung {
    902       1.1   dyoung #define	N(a)	(sizeof(a) / sizeof(a[0]))
    903      1.26  mycroft 	static const int ieeerates[] = {
    904      1.26  mycroft 		-1,		/* IFM_AUTO */
    905      1.26  mycroft 		0,		/* IFM_MANUAL */
    906      1.26  mycroft 		0,		/* IFM_NONE */
    907      1.26  mycroft 		2,		/* IFM_IEEE80211_FH1 */
    908      1.26  mycroft 		4,		/* IFM_IEEE80211_FH2 */
    909      1.26  mycroft 		4,		/* IFM_IEEE80211_DS2 */
    910      1.26  mycroft 		11,		/* IFM_IEEE80211_DS5 */
    911      1.26  mycroft 		22,		/* IFM_IEEE80211_DS11 */
    912      1.26  mycroft 		2,		/* IFM_IEEE80211_DS1 */
    913      1.26  mycroft 		44,		/* IFM_IEEE80211_DS22 */
    914      1.26  mycroft 		12,		/* IFM_IEEE80211_OFDM6 */
    915      1.26  mycroft 		18,		/* IFM_IEEE80211_OFDM9 */
    916      1.26  mycroft 		24,		/* IFM_IEEE80211_OFDM12 */
    917      1.26  mycroft 		36,		/* IFM_IEEE80211_OFDM18 */
    918      1.26  mycroft 		48,		/* IFM_IEEE80211_OFDM24 */
    919      1.26  mycroft 		72,		/* IFM_IEEE80211_OFDM36 */
    920      1.26  mycroft 		96,		/* IFM_IEEE80211_OFDM48 */
    921      1.26  mycroft 		108,		/* IFM_IEEE80211_OFDM54 */
    922      1.26  mycroft 		144,		/* IFM_IEEE80211_OFDM72 */
    923       1.1   dyoung 	};
    924      1.26  mycroft 	return IFM_SUBTYPE(mword) < N(ieeerates) ?
    925      1.26  mycroft 		ieeerates[IFM_SUBTYPE(mword)] : 0;
    926       1.1   dyoung #undef N
    927       1.1   dyoung }
    928       1.1   dyoung 
    929      1.11   dyoung #ifdef __NetBSD__
    930      1.32   dyoung static void
    931      1.32   dyoung ieee80211_clean_all_nodes(int cache_size)
    932      1.32   dyoung {
    933      1.32   dyoung 	struct ieee80211com *ic;
    934      1.32   dyoung 	LIST_FOREACH(ic, &ieee80211com_head, ic_list) {
    935      1.32   dyoung 		ic->ic_max_nnodes = cache_size;
    936      1.32   dyoung 		ieee80211_clean_nodes(ic);
    937      1.32   dyoung 	}
    938      1.32   dyoung }
    939      1.32   dyoung 
    940      1.11   dyoung /* TBD factor with sysctl_ath_verify. */
    941      1.11   dyoung static int
    942      1.11   dyoung sysctl_ieee80211_verify(SYSCTLFN_ARGS)
    943      1.11   dyoung {
    944      1.11   dyoung 	int error, t;
    945      1.11   dyoung 	struct sysctlnode node;
    946      1.11   dyoung 
    947      1.11   dyoung 	node = *rnode;
    948      1.11   dyoung 	t = *(int*)rnode->sysctl_data;
    949      1.11   dyoung 	node.sysctl_data = &t;
    950      1.11   dyoung 	error = sysctl_lookup(SYSCTLFN_CALL(&node));
    951      1.11   dyoung 	if (error || newp == NULL)
    952      1.11   dyoung 		return (error);
    953      1.11   dyoung 
    954      1.32   dyoung 	if (node.sysctl_num == ieee80211_cache_size_nodenum) {
    955      1.32   dyoung 		if (t < 0)
    956      1.11   dyoung 			return (EINVAL);
    957      1.11   dyoung #ifdef IEEE80211_DEBUG
    958      1.29   dyoung 	} else if (node.sysctl_num != ieee80211_debug_nodenum)
    959      1.29   dyoung #else /* IEEE80211_DEBUG */
    960      1.29   dyoung 	} else
    961      1.11   dyoung #endif /* IEEE80211_DEBUG */
    962      1.11   dyoung 		return (EINVAL);
    963      1.11   dyoung 
    964      1.11   dyoung 	*(int*)rnode->sysctl_data = t;
    965      1.11   dyoung 
    966      1.32   dyoung 	if (node.sysctl_num == ieee80211_cache_size_nodenum)
    967      1.32   dyoung 		ieee80211_clean_all_nodes(t);
    968      1.11   dyoung 	return (0);
    969      1.11   dyoung }
    970      1.11   dyoung 
    971      1.11   dyoung /*
    972      1.22   dyoung  * Pointers for testing:
    973      1.22   dyoung  *
    974      1.22   dyoung  *	If there are no interfaces, or else no 802.11 interfaces,
    975      1.22   dyoung  *	ieee80211_node_walkfirst must return NULL.
    976      1.22   dyoung  *
    977      1.22   dyoung  *	If there is any single 802.11 interface, ieee80211_node_walkfirst
    978      1.22   dyoung  *	must not return NULL.
    979  1.32.4.1     kent  */
    980      1.22   dyoung static struct ieee80211_node *
    981      1.22   dyoung ieee80211_node_walkfirst(struct ieee80211_node_walk *nw,
    982      1.22   dyoung     u_short if_index)
    983      1.22   dyoung {
    984      1.22   dyoung 	struct ieee80211com *ic;
    985      1.22   dyoung 	(void)memset(nw, 0, sizeof(*nw));
    986      1.22   dyoung 
    987      1.22   dyoung 	nw->nw_ifindex = if_index;
    988      1.22   dyoung 
    989      1.22   dyoung 	LIST_FOREACH(ic, &ieee80211com_head, ic_list) {
    990      1.25  mycroft 		if (if_index != 0 && ic->ic_if.if_index != if_index)
    991      1.22   dyoung 			continue;
    992      1.22   dyoung 		nw->nw_ic = ic;
    993      1.22   dyoung 		nw->nw_ni = ic->ic_bss;
    994      1.22   dyoung 		break;
    995      1.22   dyoung 	}
    996      1.22   dyoung 
    997      1.22   dyoung 	KASSERT(LOGICALLY_EQUAL(nw->nw_ni == NULL, nw->nw_ic == NULL));
    998      1.22   dyoung 
    999      1.22   dyoung 	return nw->nw_ni;
   1000      1.22   dyoung }
   1001      1.22   dyoung 
   1002      1.22   dyoung static struct ieee80211_node *
   1003      1.22   dyoung ieee80211_node_walknext(struct ieee80211_node_walk *nw)
   1004      1.22   dyoung {
   1005      1.22   dyoung 	KASSERT(LOGICALLY_EQUAL(nw->nw_ni == NULL, nw->nw_ic == NULL));
   1006      1.22   dyoung 
   1007      1.22   dyoung 	if (nw->nw_ic == NULL && nw->nw_ni == NULL)
   1008      1.22   dyoung 		return NULL;
   1009      1.22   dyoung 
   1010      1.22   dyoung 	if (nw->nw_ni == nw->nw_ic->ic_bss)
   1011      1.22   dyoung 		nw->nw_ni = TAILQ_FIRST(&nw->nw_ic->ic_node);
   1012      1.22   dyoung 	else
   1013      1.22   dyoung 		nw->nw_ni = TAILQ_NEXT(nw->nw_ni, ni_list);
   1014      1.22   dyoung 
   1015      1.22   dyoung 	if (nw->nw_ni == NULL) {
   1016      1.22   dyoung 		if (nw->nw_ifindex != 0)
   1017      1.22   dyoung 			return NULL;
   1018      1.22   dyoung 
   1019      1.22   dyoung 		nw->nw_ic = LIST_NEXT(nw->nw_ic, ic_list);
   1020      1.22   dyoung 		if (nw->nw_ic == NULL)
   1021      1.22   dyoung 			return NULL;
   1022      1.22   dyoung 
   1023      1.22   dyoung 		nw->nw_ni = nw->nw_ic->ic_bss;
   1024      1.22   dyoung 	}
   1025      1.22   dyoung 
   1026      1.22   dyoung 	KASSERT(LOGICALLY_EQUAL(nw->nw_ni == NULL, nw->nw_ic == NULL));
   1027      1.22   dyoung 
   1028      1.22   dyoung 	return nw->nw_ni;
   1029      1.22   dyoung }
   1030      1.22   dyoung 
   1031      1.22   dyoung static void
   1032      1.22   dyoung sysctl_ieee80211_fill_node(struct ieee80211_node *ni,
   1033      1.22   dyoung     struct ieee80211_node_sysctl *ns, int ifindex,
   1034      1.22   dyoung     struct ieee80211_channel *chan0, int is_bss)
   1035      1.22   dyoung {
   1036      1.22   dyoung 	ns->ns_ifindex = ifindex;
   1037      1.22   dyoung 	ns->ns_capinfo = ni->ni_capinfo;
   1038      1.22   dyoung 	ns->ns_flags = (is_bss) ? IEEE80211_NODE_SYSCTL_F_BSS : 0;
   1039      1.22   dyoung 	(void)memcpy(ns->ns_macaddr, ni->ni_macaddr, sizeof(ns->ns_macaddr));
   1040      1.22   dyoung 	(void)memcpy(ns->ns_bssid, ni->ni_bssid, sizeof(ns->ns_bssid));
   1041      1.22   dyoung 	if (ni->ni_chan != IEEE80211_CHAN_ANYC) {
   1042      1.22   dyoung 		ns->ns_freq = ni->ni_chan->ic_freq;
   1043      1.22   dyoung 		ns->ns_chanflags = ni->ni_chan->ic_flags;
   1044      1.22   dyoung 		ns->ns_chanidx = ni->ni_chan - chan0;
   1045      1.22   dyoung 	} else {
   1046      1.22   dyoung 		ns->ns_freq = ns->ns_chanflags = 0;
   1047      1.22   dyoung 		ns->ns_chanidx = 0;
   1048      1.22   dyoung 	}
   1049      1.22   dyoung 	ns->ns_rssi = ni->ni_rssi;
   1050      1.22   dyoung 	ns->ns_esslen = ni->ni_esslen;
   1051      1.22   dyoung 	(void)memcpy(ns->ns_essid, ni->ni_essid, sizeof(ns->ns_essid));
   1052      1.22   dyoung 	ns->ns_pwrsave = ni->ni_pwrsave;
   1053      1.22   dyoung 	ns->ns_erp = ni->ni_erp;
   1054      1.22   dyoung 	ns->ns_associd = ni->ni_associd;
   1055      1.22   dyoung 	ns->ns_inact = ni->ni_inact * IEEE80211_INACT_WAIT;
   1056      1.22   dyoung 	ns->ns_rstamp = ni->ni_rstamp;
   1057      1.22   dyoung 	ns->ns_rates = ni->ni_rates;
   1058      1.22   dyoung 	ns->ns_txrate = ni->ni_txrate;
   1059      1.22   dyoung 	ns->ns_intval = ni->ni_intval;
   1060      1.22   dyoung 	(void)memcpy(ns->ns_tstamp, ni->ni_tstamp, sizeof(ns->ns_tstamp));
   1061      1.22   dyoung 	ns->ns_txseq = ni->ni_txseq;
   1062      1.22   dyoung 	ns->ns_rxseq = ni->ni_rxseq;
   1063      1.22   dyoung 	ns->ns_fhdwell = ni->ni_fhdwell;
   1064      1.22   dyoung 	ns->ns_fhindex = ni->ni_fhindex;
   1065      1.22   dyoung 	ns->ns_fails = ni->ni_fails;
   1066      1.22   dyoung }
   1067      1.22   dyoung 
   1068      1.22   dyoung /* Between two examinations of the sysctl tree, I expect each
   1069      1.22   dyoung  * interface to add no more than 5 nodes.
   1070      1.22   dyoung  */
   1071      1.22   dyoung #define IEEE80211_SYSCTL_NODE_GROWTH	5
   1072      1.22   dyoung 
   1073      1.22   dyoung static int
   1074      1.22   dyoung sysctl_ieee80211_node(SYSCTLFN_ARGS)
   1075      1.22   dyoung {
   1076      1.22   dyoung 	struct ieee80211_node_walk nw;
   1077      1.22   dyoung 	struct ieee80211_node *ni;
   1078      1.22   dyoung 	struct ieee80211_node_sysctl ns;
   1079      1.22   dyoung 	char *dp;
   1080      1.22   dyoung 	u_int cur_ifindex, ifcount, ifindex, last_ifindex, op, arg, hdr_type;
   1081      1.22   dyoung 	size_t len, needed, eltsize, out_size;
   1082      1.22   dyoung 	int error, s, nelt;
   1083      1.22   dyoung 
   1084      1.22   dyoung 	if (namelen == 1 && name[0] == CTL_QUERY)
   1085      1.22   dyoung 		return (sysctl_query(SYSCTLFN_CALL(rnode)));
   1086      1.22   dyoung 
   1087      1.22   dyoung 	if (namelen != IEEE80211_SYSCTL_NODENAMELEN)
   1088      1.22   dyoung 		return (EINVAL);
   1089      1.22   dyoung 
   1090      1.22   dyoung 	/* ifindex.op.arg.header-type.eltsize.nelt */
   1091      1.22   dyoung 	dp = oldp;
   1092      1.22   dyoung 	len = (oldp != NULL) ? *oldlenp : 0;
   1093      1.22   dyoung 	ifindex = name[IEEE80211_SYSCTL_NODENAME_IF];
   1094      1.22   dyoung 	op = name[IEEE80211_SYSCTL_NODENAME_OP];
   1095      1.22   dyoung 	arg = name[IEEE80211_SYSCTL_NODENAME_ARG];
   1096      1.22   dyoung 	hdr_type = name[IEEE80211_SYSCTL_NODENAME_TYPE];
   1097      1.22   dyoung 	eltsize = name[IEEE80211_SYSCTL_NODENAME_ELTSIZE];
   1098      1.22   dyoung 	nelt = name[IEEE80211_SYSCTL_NODENAME_ELTCOUNT];
   1099      1.22   dyoung 	out_size = MIN(sizeof(ns), eltsize);
   1100      1.22   dyoung 
   1101      1.22   dyoung 	if (op != IEEE80211_SYSCTL_OP_ALL || arg != 0 ||
   1102      1.22   dyoung 	    hdr_type != IEEE80211_SYSCTL_T_NODE || eltsize < 1 || nelt < 0)
   1103      1.22   dyoung 		return (EINVAL);
   1104      1.22   dyoung 
   1105      1.22   dyoung 	error = 0;
   1106      1.22   dyoung 	needed = 0;
   1107      1.22   dyoung 	ifcount = 0;
   1108      1.22   dyoung 	last_ifindex = 0;
   1109      1.22   dyoung 
   1110      1.22   dyoung 	s = splnet();
   1111      1.22   dyoung 
   1112      1.22   dyoung 	for (ni = ieee80211_node_walkfirst(&nw, ifindex); ni != NULL;
   1113      1.22   dyoung 	     ni = ieee80211_node_walknext(&nw)) {
   1114      1.22   dyoung 		struct ieee80211com *ic;
   1115      1.22   dyoung 
   1116      1.22   dyoung 		ic = nw.nw_ic;
   1117      1.22   dyoung 		cur_ifindex = ic->ic_if.if_index;
   1118      1.22   dyoung 
   1119      1.22   dyoung 		if (cur_ifindex != last_ifindex) {
   1120      1.22   dyoung 			ifcount++;
   1121      1.22   dyoung 			last_ifindex = cur_ifindex;
   1122      1.22   dyoung 		}
   1123      1.22   dyoung 
   1124      1.22   dyoung 		if (nelt <= 0)
   1125      1.22   dyoung 			continue;
   1126      1.22   dyoung 
   1127      1.22   dyoung 		if (len >= eltsize) {
   1128      1.22   dyoung 			sysctl_ieee80211_fill_node(ni, &ns, cur_ifindex,
   1129      1.22   dyoung 			    &ic->ic_channels[0], ni == ic->ic_bss);
   1130      1.22   dyoung 			error = copyout(&ns, dp, out_size);
   1131      1.22   dyoung 			if (error)
   1132      1.22   dyoung 				goto cleanup;
   1133      1.22   dyoung 			dp += eltsize;
   1134      1.22   dyoung 			len -= eltsize;
   1135      1.22   dyoung 		}
   1136      1.22   dyoung 		needed += eltsize;
   1137      1.22   dyoung 		if (nelt != INT_MAX)
   1138      1.22   dyoung 			nelt--;
   1139      1.22   dyoung 	}
   1140      1.22   dyoung cleanup:
   1141      1.22   dyoung 	splx(s);
   1142      1.22   dyoung 
   1143      1.22   dyoung 	*oldlenp = needed;
   1144      1.22   dyoung 	if (oldp == NULL)
   1145      1.22   dyoung 		*oldlenp += ifcount * IEEE80211_SYSCTL_NODE_GROWTH * eltsize;
   1146      1.22   dyoung 
   1147      1.22   dyoung 	return (error);
   1148      1.22   dyoung }
   1149      1.22   dyoung 
   1150      1.22   dyoung /*
   1151      1.11   dyoung  * Setup sysctl(3) MIB, net.ieee80211.*
   1152      1.11   dyoung  *
   1153      1.11   dyoung  * TBD condition CTLFLAG_PERMANENT on being an LKM or not
   1154      1.11   dyoung  */
   1155      1.11   dyoung SYSCTL_SETUP(sysctl_ieee80211, "sysctl ieee80211 subtree setup")
   1156      1.11   dyoung {
   1157      1.12   dyoung 	int rc;
   1158      1.12   dyoung 	struct sysctlnode *cnode, *rnode;
   1159      1.11   dyoung 
   1160      1.12   dyoung 	if ((rc = sysctl_createv(clog, 0, NULL, &rnode,
   1161      1.11   dyoung 	    CTLFLAG_PERMANENT, CTLTYPE_NODE, "net", NULL,
   1162      1.11   dyoung 	    NULL, 0, NULL, 0, CTL_NET, CTL_EOL)) != 0)
   1163      1.11   dyoung 		goto err;
   1164      1.11   dyoung 
   1165      1.12   dyoung 	if ((rc = sysctl_createv(clog, 0, &rnode, &rnode,
   1166      1.19   dyoung 	    CTLFLAG_PERMANENT, CTLTYPE_NODE, "link",
   1167      1.19   dyoung 	    "link-layer statistics and controls",
   1168      1.12   dyoung 	    NULL, 0, NULL, 0, PF_LINK, CTL_EOL)) != 0)
   1169      1.12   dyoung 		goto err;
   1170      1.12   dyoung 
   1171      1.12   dyoung 	if ((rc = sysctl_createv(clog, 0, &rnode, &rnode,
   1172      1.19   dyoung 	    CTLFLAG_PERMANENT, CTLTYPE_NODE, "ieee80211",
   1173      1.19   dyoung 	    "IEEE 802.11 WLAN statistics and controls",
   1174      1.12   dyoung 	    NULL, 0, NULL, 0, CTL_CREATE, CTL_EOL)) != 0)
   1175      1.11   dyoung 		goto err;
   1176      1.11   dyoung 
   1177      1.22   dyoung 	if ((rc = sysctl_createv(clog, 0, &rnode, NULL,
   1178      1.22   dyoung 	    CTLFLAG_PERMANENT, CTLTYPE_NODE, "nodes", "client/peer stations",
   1179      1.22   dyoung 	    sysctl_ieee80211_node, 0, NULL, 0, CTL_CREATE, CTL_EOL)) != 0)
   1180      1.22   dyoung 		goto err;
   1181      1.22   dyoung 
   1182      1.11   dyoung #ifdef IEEE80211_DEBUG
   1183      1.11   dyoung 
   1184      1.11   dyoung 	/* control debugging printfs */
   1185      1.12   dyoung 	if ((rc = sysctl_createv(clog, 0, &rnode, &cnode,
   1186      1.11   dyoung 	    CTLFLAG_PERMANENT|CTLFLAG_READWRITE, CTLTYPE_INT,
   1187      1.15   atatat 	    "debug", SYSCTL_DESCR("Enable IEEE 802.11 debugging output"),
   1188      1.15   atatat 	    sysctl_ieee80211_verify, 0, &ieee80211_debug, 0,
   1189      1.12   dyoung 	    CTL_CREATE, CTL_EOL)) != 0)
   1190      1.11   dyoung 		goto err;
   1191      1.11   dyoung 
   1192      1.12   dyoung 	ieee80211_debug_nodenum = cnode->sysctl_num;
   1193      1.11   dyoung 
   1194      1.11   dyoung #endif /* IEEE80211_DEBUG */
   1195      1.11   dyoung 
   1196      1.32   dyoung 	/* control LRU cache size */
   1197      1.12   dyoung 	if ((rc = sysctl_createv(clog, 0, &rnode, &cnode,
   1198      1.11   dyoung 	    CTLFLAG_PERMANENT|CTLFLAG_READWRITE, CTLTYPE_INT,
   1199      1.32   dyoung 	    "maxnodecache", SYSCTL_DESCR("Maximum station cache size"),
   1200      1.32   dyoung 	    sysctl_ieee80211_verify, 0, &ieee80211_cache_size,
   1201      1.12   dyoung 	    0, CTL_CREATE, CTL_EOL)) != 0)
   1202      1.11   dyoung 		goto err;
   1203      1.11   dyoung 
   1204      1.32   dyoung 	ieee80211_cache_size_nodenum = cnode->sysctl_num;
   1205      1.11   dyoung 
   1206      1.11   dyoung 	return;
   1207      1.11   dyoung err:
   1208      1.11   dyoung 	printf("%s: sysctl_createv failed (rc = %d)\n", __func__, rc);
   1209      1.11   dyoung }
   1210      1.11   dyoung #endif /* __NetBSD__ */
   1211      1.11   dyoung 
   1212       1.2   dyoung #ifdef __FreeBSD__
   1213       1.1   dyoung /*
   1214       1.1   dyoung  * Module glue.
   1215       1.1   dyoung  *
   1216       1.1   dyoung  * NB: the module name is "wlan" for compatibility with NetBSD.
   1217       1.1   dyoung  */
   1218       1.1   dyoung 
   1219       1.1   dyoung static int
   1220       1.1   dyoung ieee80211_modevent(module_t mod, int type, void *unused)
   1221       1.1   dyoung {
   1222       1.1   dyoung 	switch (type) {
   1223       1.1   dyoung 	case MOD_LOAD:
   1224       1.1   dyoung 		if (bootverbose)
   1225       1.1   dyoung 			printf("wlan: <802.11 Link Layer>\n");
   1226       1.1   dyoung 		return 0;
   1227       1.1   dyoung 	case MOD_UNLOAD:
   1228       1.1   dyoung 		return 0;
   1229       1.1   dyoung 	}
   1230       1.1   dyoung 	return EINVAL;
   1231       1.1   dyoung }
   1232       1.1   dyoung 
   1233       1.1   dyoung static moduledata_t ieee80211_mod = {
   1234       1.1   dyoung 	"wlan",
   1235       1.1   dyoung 	ieee80211_modevent,
   1236       1.1   dyoung 	0
   1237       1.1   dyoung };
   1238       1.1   dyoung DECLARE_MODULE(wlan, ieee80211_mod, SI_SUB_DRIVERS, SI_ORDER_FIRST);
   1239       1.1   dyoung MODULE_VERSION(wlan, 1);
   1240       1.1   dyoung MODULE_DEPEND(wlan, rc4, 1, 1, 1);
   1241      1.10   dyoung MODULE_DEPEND(wlan, ether, 1, 1, 1);
   1242       1.2   dyoung #endif
   1243