xref: /dflybsd-src/sys/netproto/802_11/wlan/ieee80211_proto.c (revision f186073c4a388d0ef5a2d0b9f111db8a500d3523)
1*f186073cSJoerg Sonnenberger /*
2*f186073cSJoerg Sonnenberger  * Copyright (c) 2001 Atsushi Onoe
3*f186073cSJoerg Sonnenberger  * Copyright (c) 2002, 2003 Sam Leffler, Errno Consulting
4*f186073cSJoerg Sonnenberger  * All rights reserved.
5*f186073cSJoerg Sonnenberger  *
6*f186073cSJoerg Sonnenberger  * Redistribution and use in source and binary forms, with or without
7*f186073cSJoerg Sonnenberger  * modification, are permitted provided that the following conditions
8*f186073cSJoerg Sonnenberger  * are met:
9*f186073cSJoerg Sonnenberger  * 1. Redistributions of source code must retain the above copyright
10*f186073cSJoerg Sonnenberger  *    notice, this list of conditions and the following disclaimer.
11*f186073cSJoerg Sonnenberger  * 2. Redistributions in binary form must reproduce the above copyright
12*f186073cSJoerg Sonnenberger  *    notice, this list of conditions and the following disclaimer in the
13*f186073cSJoerg Sonnenberger  *    documentation and/or other materials provided with the distribution.
14*f186073cSJoerg Sonnenberger  * 3. The name of the author may not be used to endorse or promote products
15*f186073cSJoerg Sonnenberger  *    derived from this software without specific prior written permission.
16*f186073cSJoerg Sonnenberger  *
17*f186073cSJoerg Sonnenberger  * Alternatively, this software may be distributed under the terms of the
18*f186073cSJoerg Sonnenberger  * GNU General Public License ("GPL") version 2 as published by the Free
19*f186073cSJoerg Sonnenberger  * Software Foundation.
20*f186073cSJoerg Sonnenberger  *
21*f186073cSJoerg Sonnenberger  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
22*f186073cSJoerg Sonnenberger  * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
23*f186073cSJoerg Sonnenberger  * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
24*f186073cSJoerg Sonnenberger  * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
25*f186073cSJoerg Sonnenberger  * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
26*f186073cSJoerg Sonnenberger  * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
27*f186073cSJoerg Sonnenberger  * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
28*f186073cSJoerg Sonnenberger  * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
29*f186073cSJoerg Sonnenberger  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
30*f186073cSJoerg Sonnenberger  * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
31*f186073cSJoerg Sonnenberger  *
32*f186073cSJoerg Sonnenberger  * $FreeBSD: src/sys/net80211/ieee80211_proto.c,v 1.8 2004/04/02 20:22:25 sam Exp $
33*f186073cSJoerg Sonnenberger  * $DragonFly: src/sys/netproto/802_11/wlan/ieee80211_proto.c,v 1.1 2004/07/26 16:30:17 joerg Exp $
34*f186073cSJoerg Sonnenberger  */
35*f186073cSJoerg Sonnenberger 
36*f186073cSJoerg Sonnenberger /*
37*f186073cSJoerg Sonnenberger  * IEEE 802.11 protocol support.
38*f186073cSJoerg Sonnenberger  */
39*f186073cSJoerg Sonnenberger 
40*f186073cSJoerg Sonnenberger #include "opt_inet.h"
41*f186073cSJoerg Sonnenberger 
42*f186073cSJoerg Sonnenberger #include <sys/param.h>
43*f186073cSJoerg Sonnenberger #include <sys/systm.h>
44*f186073cSJoerg Sonnenberger #include <sys/mbuf.h>
45*f186073cSJoerg Sonnenberger #include <sys/malloc.h>
46*f186073cSJoerg Sonnenberger #include <sys/kernel.h>
47*f186073cSJoerg Sonnenberger #include <sys/socket.h>
48*f186073cSJoerg Sonnenberger #include <sys/sockio.h>
49*f186073cSJoerg Sonnenberger #include <sys/endian.h>
50*f186073cSJoerg Sonnenberger #include <sys/errno.h>
51*f186073cSJoerg Sonnenberger #include <sys/bus.h>
52*f186073cSJoerg Sonnenberger #include <sys/proc.h>
53*f186073cSJoerg Sonnenberger #include <sys/sysctl.h>
54*f186073cSJoerg Sonnenberger 
55*f186073cSJoerg Sonnenberger #include <machine/atomic.h>
56*f186073cSJoerg Sonnenberger 
57*f186073cSJoerg Sonnenberger #include <net/if.h>
58*f186073cSJoerg Sonnenberger #include <net/if_dl.h>
59*f186073cSJoerg Sonnenberger #include <net/if_media.h>
60*f186073cSJoerg Sonnenberger #include <net/if_arp.h>
61*f186073cSJoerg Sonnenberger #include <net/ethernet.h>
62*f186073cSJoerg Sonnenberger #include <net/if_llc.h>
63*f186073cSJoerg Sonnenberger 
64*f186073cSJoerg Sonnenberger #include <netproto/802_11/ieee80211_var.h>
65*f186073cSJoerg Sonnenberger 
66*f186073cSJoerg Sonnenberger #include <net/bpf.h>
67*f186073cSJoerg Sonnenberger 
68*f186073cSJoerg Sonnenberger #ifdef INET
69*f186073cSJoerg Sonnenberger #include <netinet/in.h>
70*f186073cSJoerg Sonnenberger #include <netinet/if_ether.h>
71*f186073cSJoerg Sonnenberger #endif
72*f186073cSJoerg Sonnenberger 
73*f186073cSJoerg Sonnenberger #define	IEEE80211_RATE2MBS(r)	(((r) & IEEE80211_RATE_VAL) / 2)
74*f186073cSJoerg Sonnenberger 
75*f186073cSJoerg Sonnenberger const char *ieee80211_mgt_subtype_name[] = {
76*f186073cSJoerg Sonnenberger 	"assoc_req",	"assoc_resp",	"reassoc_req",	"reassoc_resp",
77*f186073cSJoerg Sonnenberger 	"probe_req",	"probe_resp",	"reserved#6",	"reserved#7",
78*f186073cSJoerg Sonnenberger 	"beacon",	"atim",		"disassoc",	"auth",
79*f186073cSJoerg Sonnenberger 	"deauth",	"reserved#13",	"reserved#14",	"reserved#15"
80*f186073cSJoerg Sonnenberger };
81*f186073cSJoerg Sonnenberger const char *ieee80211_state_name[IEEE80211_S_MAX] = {
82*f186073cSJoerg Sonnenberger 	"INIT",		/* IEEE80211_S_INIT */
83*f186073cSJoerg Sonnenberger 	"SCAN",		/* IEEE80211_S_SCAN */
84*f186073cSJoerg Sonnenberger 	"AUTH",		/* IEEE80211_S_AUTH */
85*f186073cSJoerg Sonnenberger 	"ASSOC",	/* IEEE80211_S_ASSOC */
86*f186073cSJoerg Sonnenberger 	"RUN"		/* IEEE80211_S_RUN */
87*f186073cSJoerg Sonnenberger };
88*f186073cSJoerg Sonnenberger 
89*f186073cSJoerg Sonnenberger static int ieee80211_newstate(struct ieee80211com *, enum ieee80211_state, int);
90*f186073cSJoerg Sonnenberger 
91*f186073cSJoerg Sonnenberger void
92*f186073cSJoerg Sonnenberger ieee80211_proto_attach(struct ifnet *ifp)
93*f186073cSJoerg Sonnenberger {
94*f186073cSJoerg Sonnenberger 	struct ieee80211com *ic = (void *)ifp;
95*f186073cSJoerg Sonnenberger 
96*f186073cSJoerg Sonnenberger 	ifp->if_hdrlen = sizeof(struct ieee80211_frame);
97*f186073cSJoerg Sonnenberger 
98*f186073cSJoerg Sonnenberger #ifdef notdef
99*f186073cSJoerg Sonnenberger 	ic->ic_rtsthreshold = IEEE80211_RTS_DEFAULT;
100*f186073cSJoerg Sonnenberger #else
101*f186073cSJoerg Sonnenberger 	ic->ic_rtsthreshold = IEEE80211_RTS_MAX;
102*f186073cSJoerg Sonnenberger #endif
103*f186073cSJoerg Sonnenberger 	ic->ic_fragthreshold = 2346;		/* XXX not used yet */
104*f186073cSJoerg Sonnenberger 	ic->ic_fixed_rate = -1;			/* no fixed rate */
105*f186073cSJoerg Sonnenberger 	ic->ic_protmode = IEEE80211_PROT_CTSONLY;
106*f186073cSJoerg Sonnenberger 
107*f186073cSJoerg Sonnenberger 	/* protocol state change handler */
108*f186073cSJoerg Sonnenberger 	ic->ic_newstate = ieee80211_newstate;
109*f186073cSJoerg Sonnenberger 
110*f186073cSJoerg Sonnenberger 	/* initialize management frame handlers */
111*f186073cSJoerg Sonnenberger 	ic->ic_recv_mgmt = ieee80211_recv_mgmt;
112*f186073cSJoerg Sonnenberger 	ic->ic_send_mgmt = ieee80211_send_mgmt;
113*f186073cSJoerg Sonnenberger }
114*f186073cSJoerg Sonnenberger 
115*f186073cSJoerg Sonnenberger void
116*f186073cSJoerg Sonnenberger ieee80211_proto_detach(struct ifnet *ifp)
117*f186073cSJoerg Sonnenberger {
118*f186073cSJoerg Sonnenberger 	struct ieee80211com *ic = (void *)ifp;
119*f186073cSJoerg Sonnenberger 
120*f186073cSJoerg Sonnenberger 	IF_DRAIN(&ic->ic_mgtq);
121*f186073cSJoerg Sonnenberger }
122*f186073cSJoerg Sonnenberger 
123*f186073cSJoerg Sonnenberger void
124*f186073cSJoerg Sonnenberger ieee80211_print_essid(uint8_t *essid, int len)
125*f186073cSJoerg Sonnenberger {
126*f186073cSJoerg Sonnenberger 	int i;
127*f186073cSJoerg Sonnenberger 	uint8_t *p;
128*f186073cSJoerg Sonnenberger 
129*f186073cSJoerg Sonnenberger 	if (len > IEEE80211_NWID_LEN)
130*f186073cSJoerg Sonnenberger 		len = IEEE80211_NWID_LEN;
131*f186073cSJoerg Sonnenberger 	/* determine printable or not */
132*f186073cSJoerg Sonnenberger 	for (i = 0, p = essid; i < len; i++, p++) {
133*f186073cSJoerg Sonnenberger 		if (*p < ' ' || *p > 0x7e)
134*f186073cSJoerg Sonnenberger 			break;
135*f186073cSJoerg Sonnenberger 	}
136*f186073cSJoerg Sonnenberger 	if (i == len) {
137*f186073cSJoerg Sonnenberger 		printf("\"");
138*f186073cSJoerg Sonnenberger 		for (i = 0, p = essid; i < len; i++, p++)
139*f186073cSJoerg Sonnenberger 			printf("%c", *p);
140*f186073cSJoerg Sonnenberger 		printf("\"");
141*f186073cSJoerg Sonnenberger 	} else {
142*f186073cSJoerg Sonnenberger 		printf("0x");
143*f186073cSJoerg Sonnenberger 		for (i = 0, p = essid; i < len; i++, p++)
144*f186073cSJoerg Sonnenberger 			printf("%02x", *p);
145*f186073cSJoerg Sonnenberger 	}
146*f186073cSJoerg Sonnenberger }
147*f186073cSJoerg Sonnenberger 
148*f186073cSJoerg Sonnenberger void
149*f186073cSJoerg Sonnenberger ieee80211_dump_pkt(uint8_t *buf, int len, int rate, int rssi)
150*f186073cSJoerg Sonnenberger {
151*f186073cSJoerg Sonnenberger 	struct ieee80211_frame *wh;
152*f186073cSJoerg Sonnenberger 	int i;
153*f186073cSJoerg Sonnenberger 
154*f186073cSJoerg Sonnenberger 	wh = (struct ieee80211_frame *)buf;
155*f186073cSJoerg Sonnenberger 	switch (wh->i_fc[1] & IEEE80211_FC1_DIR_MASK) {
156*f186073cSJoerg Sonnenberger 	case IEEE80211_FC1_DIR_NODS:
157*f186073cSJoerg Sonnenberger 		printf("NODS %6D->%6D(%6D)", wh->i_addr2, ":",
158*f186073cSJoerg Sonnenberger 		       wh->i_addr1, ":", wh->i_addr3, ":");
159*f186073cSJoerg Sonnenberger 		break;
160*f186073cSJoerg Sonnenberger 	case IEEE80211_FC1_DIR_TODS:
161*f186073cSJoerg Sonnenberger 		printf("TODS %6D->%6D(%6D)", wh->i_addr2, ":",
162*f186073cSJoerg Sonnenberger 		       wh->i_addr3, ":", wh->i_addr1, ":");
163*f186073cSJoerg Sonnenberger 		break;
164*f186073cSJoerg Sonnenberger 	case IEEE80211_FC1_DIR_FROMDS:
165*f186073cSJoerg Sonnenberger 		printf("FRDS %6D->%6D(%6D)", wh->i_addr3, ":",
166*f186073cSJoerg Sonnenberger 		       wh->i_addr1, ":", wh->i_addr2, ":");
167*f186073cSJoerg Sonnenberger 		break;
168*f186073cSJoerg Sonnenberger 	case IEEE80211_FC1_DIR_DSTODS:
169*f186073cSJoerg Sonnenberger 		printf("DSDS %6D->%6D(%6D->%6D)", (uint8_t *)&wh[1], ":",
170*f186073cSJoerg Sonnenberger 		       wh->i_addr3, ":", wh->i_addr2, ":", wh->i_addr1, ":");
171*f186073cSJoerg Sonnenberger 		break;
172*f186073cSJoerg Sonnenberger 	}
173*f186073cSJoerg Sonnenberger 	switch (wh->i_fc[0] & IEEE80211_FC0_TYPE_MASK) {
174*f186073cSJoerg Sonnenberger 	case IEEE80211_FC0_TYPE_DATA:
175*f186073cSJoerg Sonnenberger 		printf(" data");
176*f186073cSJoerg Sonnenberger 		break;
177*f186073cSJoerg Sonnenberger 	case IEEE80211_FC0_TYPE_MGT:
178*f186073cSJoerg Sonnenberger 		printf(" %s", ieee80211_mgt_subtype_name[
179*f186073cSJoerg Sonnenberger 		    (wh->i_fc[0] & IEEE80211_FC0_SUBTYPE_MASK)
180*f186073cSJoerg Sonnenberger 		    >> IEEE80211_FC0_SUBTYPE_SHIFT]);
181*f186073cSJoerg Sonnenberger 		break;
182*f186073cSJoerg Sonnenberger 	default:
183*f186073cSJoerg Sonnenberger 		printf(" type#%d", wh->i_fc[0] & IEEE80211_FC0_TYPE_MASK);
184*f186073cSJoerg Sonnenberger 		break;
185*f186073cSJoerg Sonnenberger 	}
186*f186073cSJoerg Sonnenberger 	if (wh->i_fc[1] & IEEE80211_FC1_WEP)
187*f186073cSJoerg Sonnenberger 		printf(" WEP");
188*f186073cSJoerg Sonnenberger 	if (rate >= 0)
189*f186073cSJoerg Sonnenberger 		printf(" %dM", rate / 2);
190*f186073cSJoerg Sonnenberger 	if (rssi >= 0)
191*f186073cSJoerg Sonnenberger 		printf(" +%d", rssi);
192*f186073cSJoerg Sonnenberger 	printf("\n");
193*f186073cSJoerg Sonnenberger 	if (len > 0) {
194*f186073cSJoerg Sonnenberger 		for (i = 0; i < len; i++) {
195*f186073cSJoerg Sonnenberger 			if ((i & 1) == 0)
196*f186073cSJoerg Sonnenberger 				printf(" ");
197*f186073cSJoerg Sonnenberger 			printf("%02x", buf[i]);
198*f186073cSJoerg Sonnenberger 		}
199*f186073cSJoerg Sonnenberger 		printf("\n");
200*f186073cSJoerg Sonnenberger 	}
201*f186073cSJoerg Sonnenberger }
202*f186073cSJoerg Sonnenberger 
203*f186073cSJoerg Sonnenberger int
204*f186073cSJoerg Sonnenberger ieee80211_fix_rate(struct ieee80211com *ic, struct ieee80211_node *ni, int flags)
205*f186073cSJoerg Sonnenberger {
206*f186073cSJoerg Sonnenberger #define	RV(v)	((v) & IEEE80211_RATE_VAL)
207*f186073cSJoerg Sonnenberger 	int i, j, ignore, error;
208*f186073cSJoerg Sonnenberger 	int okrate, badrate;
209*f186073cSJoerg Sonnenberger 	struct ieee80211_rateset *srs, *nrs;
210*f186073cSJoerg Sonnenberger 	uint8_t r;
211*f186073cSJoerg Sonnenberger 
212*f186073cSJoerg Sonnenberger 	error = 0;
213*f186073cSJoerg Sonnenberger 	okrate = badrate = 0;
214*f186073cSJoerg Sonnenberger 	srs = &ic->ic_sup_rates[ieee80211_chan2mode(ic, ni->ni_chan)];
215*f186073cSJoerg Sonnenberger 	nrs = &ni->ni_rates;
216*f186073cSJoerg Sonnenberger 	for (i = 0; i < nrs->rs_nrates; ) {
217*f186073cSJoerg Sonnenberger 		ignore = 0;
218*f186073cSJoerg Sonnenberger 		if (flags & IEEE80211_F_DOSORT) {
219*f186073cSJoerg Sonnenberger 			/*
220*f186073cSJoerg Sonnenberger 			 * Sort rates.
221*f186073cSJoerg Sonnenberger 			 */
222*f186073cSJoerg Sonnenberger 			for (j = i + 1; j < nrs->rs_nrates; j++) {
223*f186073cSJoerg Sonnenberger 				if (RV(nrs->rs_rates[i]) > RV(nrs->rs_rates[j])) {
224*f186073cSJoerg Sonnenberger 					r = nrs->rs_rates[i];
225*f186073cSJoerg Sonnenberger 					nrs->rs_rates[i] = nrs->rs_rates[j];
226*f186073cSJoerg Sonnenberger 					nrs->rs_rates[j] = r;
227*f186073cSJoerg Sonnenberger 				}
228*f186073cSJoerg Sonnenberger 			}
229*f186073cSJoerg Sonnenberger 		}
230*f186073cSJoerg Sonnenberger 		r = nrs->rs_rates[i] & IEEE80211_RATE_VAL;
231*f186073cSJoerg Sonnenberger 		badrate = r;
232*f186073cSJoerg Sonnenberger 		if (flags & IEEE80211_F_DOFRATE) {
233*f186073cSJoerg Sonnenberger 			/*
234*f186073cSJoerg Sonnenberger 			 * Apply fixed rate constraint.  Note that we do
235*f186073cSJoerg Sonnenberger 			 * not apply the constraint to basic rates as
236*f186073cSJoerg Sonnenberger 			 * otherwise we may not be able to associate if
237*f186073cSJoerg Sonnenberger 			 * the rate set we submit to the AP is invalid
238*f186073cSJoerg Sonnenberger 			 * (e.g. fix rate at 36Mb/s which is not a basic
239*f186073cSJoerg Sonnenberger 			 * rate for 11a operation).
240*f186073cSJoerg Sonnenberger 			 */
241*f186073cSJoerg Sonnenberger 			if ((nrs->rs_rates[i] & IEEE80211_RATE_BASIC) == 0 &&
242*f186073cSJoerg Sonnenberger 			    ic->ic_fixed_rate >= 0 &&
243*f186073cSJoerg Sonnenberger 			    r != RV(srs->rs_rates[ic->ic_fixed_rate]))
244*f186073cSJoerg Sonnenberger 				ignore++;
245*f186073cSJoerg Sonnenberger 		}
246*f186073cSJoerg Sonnenberger 		if (flags & IEEE80211_F_DONEGO) {
247*f186073cSJoerg Sonnenberger 			/*
248*f186073cSJoerg Sonnenberger 			 * Check against supported rates.
249*f186073cSJoerg Sonnenberger 			 */
250*f186073cSJoerg Sonnenberger 			for (j = 0; j < srs->rs_nrates; j++) {
251*f186073cSJoerg Sonnenberger 				if (r == RV(srs->rs_rates[j])) {
252*f186073cSJoerg Sonnenberger 					/*
253*f186073cSJoerg Sonnenberger 					 * Overwrite with the supported rate
254*f186073cSJoerg Sonnenberger 					 * value so any basic rate bit is set.
255*f186073cSJoerg Sonnenberger 					 * This insures that response we send
256*f186073cSJoerg Sonnenberger 					 * to stations have the necessary basic
257*f186073cSJoerg Sonnenberger 					 * rate bit set.
258*f186073cSJoerg Sonnenberger 					 */
259*f186073cSJoerg Sonnenberger 					nrs->rs_rates[i] = srs->rs_rates[j];
260*f186073cSJoerg Sonnenberger 					break;
261*f186073cSJoerg Sonnenberger 				}
262*f186073cSJoerg Sonnenberger 			}
263*f186073cSJoerg Sonnenberger 			if (j == srs->rs_nrates) {
264*f186073cSJoerg Sonnenberger 				/*
265*f186073cSJoerg Sonnenberger 				 * A rate in the node's rate set is not
266*f186073cSJoerg Sonnenberger 				 * supported.  If this is a basic rate and we
267*f186073cSJoerg Sonnenberger 				 * are operating as an AP then this is an error.
268*f186073cSJoerg Sonnenberger 				 * Otherwise we just discard/ignore the rate.
269*f186073cSJoerg Sonnenberger 				 * Note that this is important for 11b stations
270*f186073cSJoerg Sonnenberger 				 * when they want to associate with an 11g AP.
271*f186073cSJoerg Sonnenberger 				 */
272*f186073cSJoerg Sonnenberger 				if (ic->ic_opmode == IEEE80211_M_HOSTAP &&
273*f186073cSJoerg Sonnenberger 				    (nrs->rs_rates[i] & IEEE80211_RATE_BASIC))
274*f186073cSJoerg Sonnenberger 					error++;
275*f186073cSJoerg Sonnenberger 				ignore++;
276*f186073cSJoerg Sonnenberger 			}
277*f186073cSJoerg Sonnenberger 		}
278*f186073cSJoerg Sonnenberger 		if (flags & IEEE80211_F_DODEL) {
279*f186073cSJoerg Sonnenberger 			/*
280*f186073cSJoerg Sonnenberger 			 * Delete unacceptable rates.
281*f186073cSJoerg Sonnenberger 			 */
282*f186073cSJoerg Sonnenberger 			if (ignore) {
283*f186073cSJoerg Sonnenberger 				nrs->rs_nrates--;
284*f186073cSJoerg Sonnenberger 				for (j = i; j < nrs->rs_nrates; j++)
285*f186073cSJoerg Sonnenberger 					nrs->rs_rates[j] = nrs->rs_rates[j + 1];
286*f186073cSJoerg Sonnenberger 				nrs->rs_rates[j] = 0;
287*f186073cSJoerg Sonnenberger 				continue;
288*f186073cSJoerg Sonnenberger 			}
289*f186073cSJoerg Sonnenberger 		}
290*f186073cSJoerg Sonnenberger 		if (!ignore)
291*f186073cSJoerg Sonnenberger 			okrate = nrs->rs_rates[i];
292*f186073cSJoerg Sonnenberger 		i++;
293*f186073cSJoerg Sonnenberger 	}
294*f186073cSJoerg Sonnenberger 	if (okrate == 0 || error != 0)
295*f186073cSJoerg Sonnenberger 		return badrate | IEEE80211_RATE_BASIC;
296*f186073cSJoerg Sonnenberger 	else
297*f186073cSJoerg Sonnenberger 		return RV(okrate);
298*f186073cSJoerg Sonnenberger #undef RV
299*f186073cSJoerg Sonnenberger }
300*f186073cSJoerg Sonnenberger 
301*f186073cSJoerg Sonnenberger static int
302*f186073cSJoerg Sonnenberger ieee80211_newstate(struct ieee80211com *ic, enum ieee80211_state nstate, int mgt)
303*f186073cSJoerg Sonnenberger {
304*f186073cSJoerg Sonnenberger 	struct ifnet *ifp = &ic->ic_if;
305*f186073cSJoerg Sonnenberger 	struct ieee80211_node *ni;
306*f186073cSJoerg Sonnenberger 	enum ieee80211_state ostate;
307*f186073cSJoerg Sonnenberger 	struct lwkt_tokref ilock;
308*f186073cSJoerg Sonnenberger 
309*f186073cSJoerg Sonnenberger 	ostate = ic->ic_state;
310*f186073cSJoerg Sonnenberger 	IEEE80211_DPRINTF(("%s: %s -> %s\n", __func__,
311*f186073cSJoerg Sonnenberger 		ieee80211_state_name[ostate], ieee80211_state_name[nstate]));
312*f186073cSJoerg Sonnenberger 	ic->ic_state = nstate;			/* state transition */
313*f186073cSJoerg Sonnenberger 	ni = ic->ic_bss;			/* NB: no reference held */
314*f186073cSJoerg Sonnenberger 	switch (nstate) {
315*f186073cSJoerg Sonnenberger 	case IEEE80211_S_INIT:
316*f186073cSJoerg Sonnenberger 		switch (ostate) {
317*f186073cSJoerg Sonnenberger 		case IEEE80211_S_INIT:
318*f186073cSJoerg Sonnenberger 			break;
319*f186073cSJoerg Sonnenberger 		case IEEE80211_S_RUN:
320*f186073cSJoerg Sonnenberger 			switch (ic->ic_opmode) {
321*f186073cSJoerg Sonnenberger 			case IEEE80211_M_STA:
322*f186073cSJoerg Sonnenberger 				IEEE80211_SEND_MGMT(ic, ni,
323*f186073cSJoerg Sonnenberger 				    IEEE80211_FC0_SUBTYPE_DISASSOC,
324*f186073cSJoerg Sonnenberger 				    IEEE80211_REASON_ASSOC_LEAVE);
325*f186073cSJoerg Sonnenberger 				break;
326*f186073cSJoerg Sonnenberger 			case IEEE80211_M_HOSTAP:
327*f186073cSJoerg Sonnenberger 				lwkt_gettoken(&ilock, &ic->ic_nodetoken);
328*f186073cSJoerg Sonnenberger 				TAILQ_FOREACH(ni, &ic->ic_node, ni_list) {
329*f186073cSJoerg Sonnenberger 					if (ni->ni_associd == 0)
330*f186073cSJoerg Sonnenberger 						continue;
331*f186073cSJoerg Sonnenberger 					IEEE80211_SEND_MGMT(ic, ni,
332*f186073cSJoerg Sonnenberger 					    IEEE80211_FC0_SUBTYPE_DISASSOC,
333*f186073cSJoerg Sonnenberger 					    IEEE80211_REASON_ASSOC_LEAVE);
334*f186073cSJoerg Sonnenberger 				}
335*f186073cSJoerg Sonnenberger 				lwkt_reltoken(&ilock);
336*f186073cSJoerg Sonnenberger 				break;
337*f186073cSJoerg Sonnenberger 			default:
338*f186073cSJoerg Sonnenberger 				break;
339*f186073cSJoerg Sonnenberger 			}
340*f186073cSJoerg Sonnenberger 			/* FALLTHRU */
341*f186073cSJoerg Sonnenberger 		case IEEE80211_S_ASSOC:
342*f186073cSJoerg Sonnenberger 			switch (ic->ic_opmode) {
343*f186073cSJoerg Sonnenberger 			case IEEE80211_M_STA:
344*f186073cSJoerg Sonnenberger 				IEEE80211_SEND_MGMT(ic, ni,
345*f186073cSJoerg Sonnenberger 				    IEEE80211_FC0_SUBTYPE_DEAUTH,
346*f186073cSJoerg Sonnenberger 				    IEEE80211_REASON_AUTH_LEAVE);
347*f186073cSJoerg Sonnenberger 				break;
348*f186073cSJoerg Sonnenberger 			case IEEE80211_M_HOSTAP:
349*f186073cSJoerg Sonnenberger 				lwkt_gettoken(&ilock, &ic->ic_nodetoken);
350*f186073cSJoerg Sonnenberger 				TAILQ_FOREACH(ni, &ic->ic_node, ni_list) {
351*f186073cSJoerg Sonnenberger 					IEEE80211_SEND_MGMT(ic, ni,
352*f186073cSJoerg Sonnenberger 					    IEEE80211_FC0_SUBTYPE_DEAUTH,
353*f186073cSJoerg Sonnenberger 					    IEEE80211_REASON_AUTH_LEAVE);
354*f186073cSJoerg Sonnenberger 				}
355*f186073cSJoerg Sonnenberger 				lwkt_reltoken(&ilock);
356*f186073cSJoerg Sonnenberger 				break;
357*f186073cSJoerg Sonnenberger 			default:
358*f186073cSJoerg Sonnenberger 				break;
359*f186073cSJoerg Sonnenberger 			}
360*f186073cSJoerg Sonnenberger 			/* FALLTHRU */
361*f186073cSJoerg Sonnenberger 		case IEEE80211_S_AUTH:
362*f186073cSJoerg Sonnenberger 		case IEEE80211_S_SCAN:
363*f186073cSJoerg Sonnenberger 			ic->ic_mgt_timer = 0;
364*f186073cSJoerg Sonnenberger 			IF_DRAIN(&ic->ic_mgtq);
365*f186073cSJoerg Sonnenberger 			if (ic->ic_wep_ctx != NULL) {
366*f186073cSJoerg Sonnenberger 				free(ic->ic_wep_ctx, M_DEVBUF);
367*f186073cSJoerg Sonnenberger 				ic->ic_wep_ctx = NULL;
368*f186073cSJoerg Sonnenberger 			}
369*f186073cSJoerg Sonnenberger 			ieee80211_free_allnodes(ic);
370*f186073cSJoerg Sonnenberger 			break;
371*f186073cSJoerg Sonnenberger 		}
372*f186073cSJoerg Sonnenberger 		break;
373*f186073cSJoerg Sonnenberger 	case IEEE80211_S_SCAN:
374*f186073cSJoerg Sonnenberger 		ic->ic_flags &= ~IEEE80211_F_SIBSS;
375*f186073cSJoerg Sonnenberger 		/* initialize bss for probe request */
376*f186073cSJoerg Sonnenberger 		IEEE80211_ADDR_COPY(ni->ni_macaddr, ifp->if_broadcastaddr);
377*f186073cSJoerg Sonnenberger 		IEEE80211_ADDR_COPY(ni->ni_bssid, ifp->if_broadcastaddr);
378*f186073cSJoerg Sonnenberger 		ni->ni_rates = ic->ic_sup_rates[
379*f186073cSJoerg Sonnenberger 			ieee80211_chan2mode(ic, ni->ni_chan)];
380*f186073cSJoerg Sonnenberger 		ni->ni_associd = 0;
381*f186073cSJoerg Sonnenberger 		ni->ni_rstamp = 0;
382*f186073cSJoerg Sonnenberger 		switch (ostate) {
383*f186073cSJoerg Sonnenberger 		case IEEE80211_S_INIT:
384*f186073cSJoerg Sonnenberger 			if (ic->ic_opmode == IEEE80211_M_HOSTAP &&
385*f186073cSJoerg Sonnenberger 			    ic->ic_des_chan != IEEE80211_CHAN_ANYC) {
386*f186073cSJoerg Sonnenberger 				/*
387*f186073cSJoerg Sonnenberger 				 * AP operation and we already have a channel;
388*f186073cSJoerg Sonnenberger 				 * bypass the scan and startup immediately.
389*f186073cSJoerg Sonnenberger 				 */
390*f186073cSJoerg Sonnenberger 				ieee80211_create_ibss(ic, ic->ic_des_chan);
391*f186073cSJoerg Sonnenberger 			} else {
392*f186073cSJoerg Sonnenberger 				ieee80211_begin_scan(ifp);
393*f186073cSJoerg Sonnenberger 			}
394*f186073cSJoerg Sonnenberger 			break;
395*f186073cSJoerg Sonnenberger 		case IEEE80211_S_SCAN:
396*f186073cSJoerg Sonnenberger 			/* scan next */
397*f186073cSJoerg Sonnenberger 			if (ic->ic_flags & IEEE80211_F_ASCAN) {
398*f186073cSJoerg Sonnenberger 				IEEE80211_SEND_MGMT(ic, ni,
399*f186073cSJoerg Sonnenberger 				    IEEE80211_FC0_SUBTYPE_PROBE_REQ, 0);
400*f186073cSJoerg Sonnenberger 			}
401*f186073cSJoerg Sonnenberger 			break;
402*f186073cSJoerg Sonnenberger 		case IEEE80211_S_RUN:
403*f186073cSJoerg Sonnenberger 			/* beacon miss */
404*f186073cSJoerg Sonnenberger 			if (ifp->if_flags & IFF_DEBUG) {
405*f186073cSJoerg Sonnenberger 				/* XXX bssid clobbered above */
406*f186073cSJoerg Sonnenberger 				if_printf(ifp, "no recent beacons from %6D;"
407*f186073cSJoerg Sonnenberger 				    " rescanning\n",
408*f186073cSJoerg Sonnenberger 				    ic->ic_bss->ni_bssid, ":");
409*f186073cSJoerg Sonnenberger 			}
410*f186073cSJoerg Sonnenberger 			ieee80211_free_allnodes(ic);
411*f186073cSJoerg Sonnenberger 			/* FALLTHRU */
412*f186073cSJoerg Sonnenberger 		case IEEE80211_S_AUTH:
413*f186073cSJoerg Sonnenberger 		case IEEE80211_S_ASSOC:
414*f186073cSJoerg Sonnenberger 			/* timeout restart scan */
415*f186073cSJoerg Sonnenberger 			ni = ieee80211_find_node(ic, ic->ic_bss->ni_macaddr);
416*f186073cSJoerg Sonnenberger 			if (ni != NULL) {
417*f186073cSJoerg Sonnenberger 				ni->ni_fails++;
418*f186073cSJoerg Sonnenberger 				ieee80211_unref_node(&ni);
419*f186073cSJoerg Sonnenberger 			}
420*f186073cSJoerg Sonnenberger 			ieee80211_begin_scan(ifp);
421*f186073cSJoerg Sonnenberger 			break;
422*f186073cSJoerg Sonnenberger 		}
423*f186073cSJoerg Sonnenberger 		break;
424*f186073cSJoerg Sonnenberger 	case IEEE80211_S_AUTH:
425*f186073cSJoerg Sonnenberger 		switch (ostate) {
426*f186073cSJoerg Sonnenberger 		case IEEE80211_S_INIT:
427*f186073cSJoerg Sonnenberger 			IEEE80211_DPRINTF(("%s: invalid transition\n",
428*f186073cSJoerg Sonnenberger 				__func__));
429*f186073cSJoerg Sonnenberger 			break;
430*f186073cSJoerg Sonnenberger 		case IEEE80211_S_SCAN:
431*f186073cSJoerg Sonnenberger 			IEEE80211_SEND_MGMT(ic, ni,
432*f186073cSJoerg Sonnenberger 			    IEEE80211_FC0_SUBTYPE_AUTH, 1);
433*f186073cSJoerg Sonnenberger 			break;
434*f186073cSJoerg Sonnenberger 		case IEEE80211_S_AUTH:
435*f186073cSJoerg Sonnenberger 		case IEEE80211_S_ASSOC:
436*f186073cSJoerg Sonnenberger 			switch (mgt) {
437*f186073cSJoerg Sonnenberger 			case IEEE80211_FC0_SUBTYPE_AUTH:
438*f186073cSJoerg Sonnenberger 				/* ??? */
439*f186073cSJoerg Sonnenberger 				IEEE80211_SEND_MGMT(ic, ni,
440*f186073cSJoerg Sonnenberger 				    IEEE80211_FC0_SUBTYPE_AUTH, 2);
441*f186073cSJoerg Sonnenberger 				break;
442*f186073cSJoerg Sonnenberger 			case IEEE80211_FC0_SUBTYPE_DEAUTH:
443*f186073cSJoerg Sonnenberger 				/* ignore and retry scan on timeout */
444*f186073cSJoerg Sonnenberger 				break;
445*f186073cSJoerg Sonnenberger 			}
446*f186073cSJoerg Sonnenberger 			break;
447*f186073cSJoerg Sonnenberger 		case IEEE80211_S_RUN:
448*f186073cSJoerg Sonnenberger 			switch (mgt) {
449*f186073cSJoerg Sonnenberger 			case IEEE80211_FC0_SUBTYPE_AUTH:
450*f186073cSJoerg Sonnenberger 				IEEE80211_SEND_MGMT(ic, ni,
451*f186073cSJoerg Sonnenberger 				    IEEE80211_FC0_SUBTYPE_AUTH, 2);
452*f186073cSJoerg Sonnenberger 				ic->ic_state = ostate;	/* stay RUN */
453*f186073cSJoerg Sonnenberger 				break;
454*f186073cSJoerg Sonnenberger 			case IEEE80211_FC0_SUBTYPE_DEAUTH:
455*f186073cSJoerg Sonnenberger 				/* try to reauth */
456*f186073cSJoerg Sonnenberger 				IEEE80211_SEND_MGMT(ic, ni,
457*f186073cSJoerg Sonnenberger 				    IEEE80211_FC0_SUBTYPE_AUTH, 1);
458*f186073cSJoerg Sonnenberger 				break;
459*f186073cSJoerg Sonnenberger 			}
460*f186073cSJoerg Sonnenberger 			break;
461*f186073cSJoerg Sonnenberger 		}
462*f186073cSJoerg Sonnenberger 		break;
463*f186073cSJoerg Sonnenberger 	case IEEE80211_S_ASSOC:
464*f186073cSJoerg Sonnenberger 		switch (ostate) {
465*f186073cSJoerg Sonnenberger 		case IEEE80211_S_INIT:
466*f186073cSJoerg Sonnenberger 		case IEEE80211_S_SCAN:
467*f186073cSJoerg Sonnenberger 		case IEEE80211_S_ASSOC:
468*f186073cSJoerg Sonnenberger 			IEEE80211_DPRINTF(("%s: invalid transition\n",
469*f186073cSJoerg Sonnenberger 				__func__));
470*f186073cSJoerg Sonnenberger 			break;
471*f186073cSJoerg Sonnenberger 		case IEEE80211_S_AUTH:
472*f186073cSJoerg Sonnenberger 			IEEE80211_SEND_MGMT(ic, ni,
473*f186073cSJoerg Sonnenberger 			    IEEE80211_FC0_SUBTYPE_ASSOC_REQ, 0);
474*f186073cSJoerg Sonnenberger 			break;
475*f186073cSJoerg Sonnenberger 		case IEEE80211_S_RUN:
476*f186073cSJoerg Sonnenberger 			IEEE80211_SEND_MGMT(ic, ni,
477*f186073cSJoerg Sonnenberger 			    IEEE80211_FC0_SUBTYPE_ASSOC_REQ, 1);
478*f186073cSJoerg Sonnenberger 			break;
479*f186073cSJoerg Sonnenberger 		}
480*f186073cSJoerg Sonnenberger 		break;
481*f186073cSJoerg Sonnenberger 	case IEEE80211_S_RUN:
482*f186073cSJoerg Sonnenberger 		switch (ostate) {
483*f186073cSJoerg Sonnenberger 		case IEEE80211_S_INIT:
484*f186073cSJoerg Sonnenberger 		case IEEE80211_S_AUTH:
485*f186073cSJoerg Sonnenberger 		case IEEE80211_S_RUN:
486*f186073cSJoerg Sonnenberger 			IEEE80211_DPRINTF(("%s: invalid transition\n",
487*f186073cSJoerg Sonnenberger 				__func__));
488*f186073cSJoerg Sonnenberger 			break;
489*f186073cSJoerg Sonnenberger 		case IEEE80211_S_SCAN:		/* adhoc/hostap mode */
490*f186073cSJoerg Sonnenberger 		case IEEE80211_S_ASSOC:		/* infra mode */
491*f186073cSJoerg Sonnenberger 			KASSERT(ni->ni_txrate < ni->ni_rates.rs_nrates,
492*f186073cSJoerg Sonnenberger 				("%s: bogus xmit rate %u setup\n", __func__,
493*f186073cSJoerg Sonnenberger 					ni->ni_txrate));
494*f186073cSJoerg Sonnenberger 			if (ifp->if_flags & IFF_DEBUG) {
495*f186073cSJoerg Sonnenberger 				if_printf(ifp, " ");
496*f186073cSJoerg Sonnenberger 				if (ic->ic_opmode == IEEE80211_M_STA)
497*f186073cSJoerg Sonnenberger 					printf("associated ");
498*f186073cSJoerg Sonnenberger 				else
499*f186073cSJoerg Sonnenberger 					printf("synchronized ");
500*f186073cSJoerg Sonnenberger 				printf("with %6D ssid ", ni->ni_bssid, ":");
501*f186073cSJoerg Sonnenberger 				ieee80211_print_essid(ic->ic_bss->ni_essid,
502*f186073cSJoerg Sonnenberger 				    ni->ni_esslen);
503*f186073cSJoerg Sonnenberger 				printf(" channel %d start %uMb\n",
504*f186073cSJoerg Sonnenberger 					ieee80211_chan2ieee(ic, ni->ni_chan),
505*f186073cSJoerg Sonnenberger 					IEEE80211_RATE2MBS(ni->ni_rates.rs_rates[ni->ni_txrate]));
506*f186073cSJoerg Sonnenberger 			}
507*f186073cSJoerg Sonnenberger 			ic->ic_mgt_timer = 0;
508*f186073cSJoerg Sonnenberger 			(*ifp->if_start)(ifp);
509*f186073cSJoerg Sonnenberger 			break;
510*f186073cSJoerg Sonnenberger 		}
511*f186073cSJoerg Sonnenberger 		break;
512*f186073cSJoerg Sonnenberger 	}
513*f186073cSJoerg Sonnenberger 	return 0;
514*f186073cSJoerg Sonnenberger }
515