xref: /titanic_41/usr/src/uts/common/io/net80211/net80211_input.c (revision ff0e937b36dcde1a47ff7b00aa76a491c0dc07a8)
1 /*
2  * Copyright 2009 Sun Microsystems, Inc.  All rights reserved.
3  * Use is subject to license terms.
4  */
5 
6 /*
7  * Copyright (c) 2001 Atsushi Onoe
8  * Copyright (c) 2002-2008 Sam Leffler, Errno Consulting
9  * All rights reserved.
10  *
11  * Redistribution and use in source and binary forms, with or without
12  * modification, are permitted provided that the following conditions
13  * are met:
14  * 1. Redistributions of source code must retain the above copyright
15  *    notice, this list of conditions and the following disclaimer.
16  * 2. Redistributions in binary form must reproduce the above copyright
17  *    notice, this list of conditions and the following disclaimer in the
18  *    documentation and/or other materials provided with the distribution.
19  * 3. The name of the author may not be used to endorse or promote products
20  *    derived from this software without specific prior written permission.
21  *
22  * Alternatively, this software may be distributed under the terms of the
23  * GNU General Public License ("GPL") version 2 as published by the Free
24  * Software Foundation.
25  *
26  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
27  * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
28  * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
29  * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
30  * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
31  * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
32  * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
33  * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
34  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
35  * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
36  */
37 
38 /*
39  * Process received frame
40  */
41 
42 #include <sys/mac_provider.h>
43 #include <sys/byteorder.h>
44 #include <sys/strsun.h>
45 #include "net80211_impl.h"
46 
47 static mblk_t *ieee80211_defrag(ieee80211com_t *, ieee80211_node_t *,
48     mblk_t *, int);
49 
50 /*
51  * Process a received frame.  The node associated with the sender
52  * should be supplied.  If nothing was found in the node table then
53  * the caller is assumed to supply a reference to ic_bss instead.
54  * The RSSI and a timestamp are also supplied.  The RSSI data is used
55  * during AP scanning to select a AP to associate with; it can have
56  * any units so long as values have consistent units and higher values
57  * mean ``better signal''.  The receive timestamp is currently not used
58  * by the 802.11 layer.
59  */
60 int
61 ieee80211_input(ieee80211com_t *ic, mblk_t *mp, struct ieee80211_node *in,
62     int32_t rssi, uint32_t rstamp)
63 {
64 	struct ieee80211_frame *wh;
65 	struct ieee80211_key *key;
66 	uint8_t *bssid;
67 	int hdrspace;
68 	int len;
69 	uint16_t rxseq;
70 	uint8_t dir;
71 	uint8_t type;
72 	uint8_t subtype;
73 	uint8_t tid;
74 
75 	ASSERT(in != NULL);
76 	in->in_inact = in->in_inact_reload;
77 	type = (uint8_t)-1;		/* undefined */
78 	len = MBLKL(mp);
79 	if (len < sizeof (struct ieee80211_frame_min)) {
80 		ieee80211_dbg(IEEE80211_MSG_ANY, "ieee80211_input: "
81 		    "too short (1): len %u", len);
82 		goto out;
83 	}
84 	/*
85 	 * Bit of a cheat here, we use a pointer for a 3-address
86 	 * frame format but don't reference fields past outside
87 	 * ieee80211_frame_min w/o first validating the data is
88 	 * present.
89 	 */
90 	wh = (struct ieee80211_frame *)mp->b_rptr;
91 	if ((wh->i_fc[0] & IEEE80211_FC0_VERSION_MASK) !=
92 	    IEEE80211_FC0_VERSION_0) {
93 		ieee80211_dbg(IEEE80211_MSG_ANY, "ieee80211_input: "
94 		    "discard pkt with wrong version %x", wh->i_fc[0]);
95 		goto out;
96 	}
97 
98 	dir = wh->i_fc[1] & IEEE80211_FC1_DIR_MASK;
99 	type = wh->i_fc[0] & IEEE80211_FC0_TYPE_MASK;
100 	subtype = wh->i_fc[0] & IEEE80211_FC0_SUBTYPE_MASK;
101 
102 	IEEE80211_LOCK(ic);
103 	if (!(ic->ic_flags & IEEE80211_F_SCAN)) {
104 		switch (ic->ic_opmode) {
105 		case IEEE80211_M_STA:
106 			bssid = wh->i_addr2;
107 			if (!IEEE80211_ADDR_EQ(bssid, in->in_bssid))
108 				goto out_exit_mutex;
109 			break;
110 		case IEEE80211_M_IBSS:
111 		case IEEE80211_M_AHDEMO:
112 			if (dir != IEEE80211_FC1_DIR_NODS) {
113 				bssid = wh->i_addr1;
114 			} else if (type == IEEE80211_FC0_TYPE_CTL) {
115 				bssid = wh->i_addr1;
116 			} else {
117 				if (len < sizeof (struct ieee80211_frame)) {
118 					ieee80211_dbg(IEEE80211_MSG_ANY,
119 					    "ieee80211_input: too short(2):"
120 					    "len %u\n", len);
121 					goto out_exit_mutex;
122 				}
123 				bssid = wh->i_addr3;
124 			}
125 			if (type != IEEE80211_FC0_TYPE_DATA)
126 				break;
127 			/*
128 			 * Data frame, validate the bssid.
129 			 */
130 			if (!IEEE80211_ADDR_EQ(bssid, ic->ic_bss->in_bssid) &&
131 			    !IEEE80211_ADDR_EQ(bssid, wifi_bcastaddr)) {
132 				/* not interested in */
133 				ieee80211_dbg(IEEE80211_MSG_INPUT,
134 				    "ieee80211_input: not to bss %s\n",
135 				    ieee80211_macaddr_sprintf(bssid));
136 				goto out_exit_mutex;
137 			}
138 			/*
139 			 * For adhoc mode we cons up a node when it doesn't
140 			 * exist. This should probably done after an ACL check.
141 			 */
142 			if (in == ic->ic_bss &&
143 			    ic->ic_opmode != IEEE80211_M_HOSTAP &&
144 			    !IEEE80211_ADDR_EQ(wh->i_addr2, in->in_macaddr)) {
145 				/*
146 				 * Fake up a node for this newly
147 				 * discovered member of the IBSS.
148 				 */
149 				in = ieee80211_fakeup_adhoc_node(&ic->ic_sta,
150 				    wh->i_addr2);
151 				if (in == NULL) {
152 					/* NB: stat kept for alloc failure */
153 					goto out_exit_mutex;
154 				}
155 			}
156 			break;
157 		default:
158 			goto out_exit_mutex;
159 		}
160 		in->in_rssi = (uint8_t)rssi;
161 		in->in_rstamp = rstamp;
162 		if (!(type & IEEE80211_FC0_TYPE_CTL)) {
163 			tid = 0;
164 			rxseq = LE_16(*(uint16_t *)wh->i_seq);
165 			if ((wh->i_fc[1] & IEEE80211_FC1_RETRY) &&
166 			    (rxseq - in->in_rxseqs[tid]) <= 0) {
167 				/* duplicate, discard */
168 				ieee80211_dbg(IEEE80211_MSG_INPUT,
169 				    "ieee80211_input: duplicate",
170 				    "seqno <%u,%u> fragno <%u,%u> tid %u",
171 				    rxseq >> IEEE80211_SEQ_SEQ_SHIFT,
172 				    in->in_rxseqs[tid] >>
173 				    IEEE80211_SEQ_SEQ_SHIFT,
174 				    rxseq & IEEE80211_SEQ_FRAG_MASK,
175 				    in->in_rxseqs[tid] &
176 				    IEEE80211_SEQ_FRAG_MASK,
177 				    tid);
178 				ic->ic_stats.is_rx_dups++;
179 				goto out_exit_mutex;
180 			}
181 			in->in_rxseqs[tid] = rxseq;
182 		}
183 	}
184 
185 	switch (type) {
186 	case IEEE80211_FC0_TYPE_DATA:
187 		hdrspace = ieee80211_hdrspace(wh);
188 		if (len < hdrspace) {
189 			ieee80211_dbg(IEEE80211_MSG_ANY, "ieee80211_input: "
190 			    "data too short: expecting %u", hdrspace);
191 			goto out_exit_mutex;
192 		}
193 		switch (ic->ic_opmode) {
194 		case IEEE80211_M_STA:
195 			if (dir != IEEE80211_FC1_DIR_FROMDS) {
196 				ieee80211_dbg(IEEE80211_MSG_INPUT,
197 				    "ieee80211_input: data ",
198 				    "unknown dir 0x%x", dir);
199 				goto out_exit_mutex;
200 			}
201 			if (IEEE80211_IS_MULTICAST(wh->i_addr1) &&
202 			    IEEE80211_ADDR_EQ(wh->i_addr3, ic->ic_macaddr)) {
203 				/*
204 				 * In IEEE802.11 network, multicast packet
205 				 * sent from me is broadcasted from AP.
206 				 * It should be silently discarded for
207 				 * SIMPLEX interface.
208 				 */
209 				ieee80211_dbg(IEEE80211_MSG_INPUT,
210 				    "ieee80211_input: multicast echo\n");
211 				goto out_exit_mutex;
212 			}
213 			break;
214 		case IEEE80211_M_IBSS:
215 		case IEEE80211_M_AHDEMO:
216 			if (dir != IEEE80211_FC1_DIR_NODS) {
217 				ieee80211_dbg(IEEE80211_MSG_INPUT,
218 				    "ieee80211_input: unknown dir 0x%x",
219 				    dir);
220 				goto out_exit_mutex;
221 			}
222 			break;
223 		default:
224 			ieee80211_err("ieee80211_input: "
225 			    "receive data, unknown opmode %u, skip\n",
226 			    ic->ic_opmode);
227 			goto out_exit_mutex;
228 		}
229 
230 		/*
231 		 * Handle privacy requirements.
232 		 */
233 		if (wh->i_fc[1] & IEEE80211_FC1_WEP) {
234 			if ((ic->ic_flags & IEEE80211_F_PRIVACY) == 0) {
235 				/*
236 				 * Discard encrypted frames when privacy off.
237 				 */
238 				ieee80211_dbg(IEEE80211_MSG_INPUT,
239 				    "ieee80211_input: ""WEP PRIVACY off");
240 				ic->ic_stats.is_wep_errors++;
241 				goto out_exit_mutex;
242 			}
243 			key = ieee80211_crypto_decap(ic, mp, hdrspace);
244 			if (key == NULL) {
245 				/* NB: stats+msgs handled in crypto_decap */
246 				ic->ic_stats.is_wep_errors++;
247 				goto out_exit_mutex;
248 			}
249 			wh = (struct ieee80211_frame *)mp->b_rptr;
250 			wh->i_fc[1] &= ~IEEE80211_FC1_WEP;
251 		} else {
252 			key = NULL;
253 		}
254 
255 		/*
256 		 * Next up, any fragmentation
257 		 */
258 		if (!IEEE80211_IS_MULTICAST(wh->i_addr1)) {
259 			mp = ieee80211_defrag(ic, in, mp, hdrspace);
260 			if (mp == NULL) {
261 				/* Fragment dropped or frame not complete yet */
262 				goto out_exit_mutex;
263 			}
264 		}
265 		wh = NULL;	/* no longer valid, catch any uses */
266 
267 		/*
268 		 * Next strip any MSDU crypto bits.
269 		 */
270 		if (key != NULL && !ieee80211_crypto_demic(ic, key, mp, 0)) {
271 			ieee80211_dbg(IEEE80211_MSG_INPUT, "ieee80211_input: "
272 			    "data demic error\n");
273 			goto out_exit_mutex;
274 		}
275 
276 		ic->ic_stats.is_rx_frags++;
277 		ic->ic_stats.is_rx_bytes += len;
278 		IEEE80211_UNLOCK(ic);
279 		mac_rx(ic->ic_mach, NULL, mp);
280 		return (IEEE80211_FC0_TYPE_DATA);
281 
282 	case IEEE80211_FC0_TYPE_MGT:
283 		if (dir != IEEE80211_FC1_DIR_NODS)
284 			goto out_exit_mutex;
285 		if (len < sizeof (struct ieee80211_frame))
286 			goto out_exit_mutex;
287 		if (wh->i_fc[1] & IEEE80211_FC1_WEP) {
288 			if (subtype != IEEE80211_FC0_SUBTYPE_AUTH) {
289 				/*
290 				 * Only shared key auth frames with a challenge
291 				 * should be encrypted, discard all others.
292 				 */
293 				ieee80211_dbg(IEEE80211_MSG_INPUT,
294 				    "ieee80211_input: "
295 				    "%s WEP set but not permitted",
296 				    IEEE80211_SUBTYPE_NAME(subtype));
297 				ic->ic_stats.is_wep_errors++;
298 				goto out_exit_mutex;
299 			}
300 			if ((ic->ic_flags & IEEE80211_F_PRIVACY) == 0) {
301 				/*
302 				 * Discard encrypted frames when privacy off.
303 				 */
304 				ieee80211_dbg(IEEE80211_MSG_INPUT,
305 				    "ieee80211_input: "
306 				    "mgt WEP set but PRIVACY off");
307 				ic->ic_stats.is_wep_errors++;
308 				goto out_exit_mutex;
309 			}
310 			hdrspace = ieee80211_hdrspace(wh);
311 			key = ieee80211_crypto_decap(ic, mp, hdrspace);
312 			if (key == NULL) {
313 				/* NB: stats+msgs handled in crypto_decap */
314 				goto out_exit_mutex;
315 			}
316 			wh = (struct ieee80211_frame *)mp->b_rptr;
317 			wh->i_fc[1] &= ~IEEE80211_FC1_WEP;
318 		}
319 		IEEE80211_UNLOCK(ic);
320 		ic->ic_recv_mgmt(ic, mp, in, subtype, rssi, rstamp);
321 		goto out;
322 
323 	case IEEE80211_FC0_TYPE_CTL:
324 	default:
325 		ieee80211_dbg(IEEE80211_MSG_ANY, "ieee80211_input: "
326 		    "bad frame type 0x%x", type);
327 		/* should not come here */
328 		break;
329 	}
330 out_exit_mutex:
331 	IEEE80211_UNLOCK(ic);
332 out:
333 	if (mp != NULL)
334 		freemsg(mp);
335 
336 	return (type);
337 }
338 
339 /*
340  * This function reassemble fragments.
341  * More fragments bit in the frame control means the packet is fragmented.
342  * While the sequence control field consists of 4-bit fragment number
343  * field and a 12-bit sequence number field.
344  */
345 /* ARGSUSED */
346 static mblk_t *
347 ieee80211_defrag(ieee80211com_t *ic, struct ieee80211_node *in, mblk_t *mp,
348     int hdrspace)
349 {
350 	struct ieee80211_frame *wh = (struct ieee80211_frame *)mp->b_rptr;
351 	struct ieee80211_frame *lwh;
352 	mblk_t *mfrag;
353 	uint16_t rxseq;
354 	uint8_t fragno;
355 	uint8_t more_frag;
356 
357 	ASSERT(!IEEE80211_IS_MULTICAST(wh->i_addr1));
358 	more_frag = wh->i_fc[1] & IEEE80211_FC1_MORE_FRAG;
359 	rxseq = LE_16(*(uint16_t *)wh->i_seq);
360 	fragno = rxseq & IEEE80211_SEQ_FRAG_MASK;
361 
362 	/* Quick way out, if there's nothing to defragment */
363 	if (!more_frag && fragno == 0 && in->in_rxfrag == NULL)
364 		return (mp);
365 
366 	/*
367 	 * Remove frag to insure it doesn't get reaped by timer.
368 	 */
369 	if (in->in_table == NULL) {
370 		/*
371 		 * Should never happen.  If the node is orphaned (not in
372 		 * the table) then input packets should not reach here.
373 		 * Otherwise, a concurrent request that yanks the table
374 		 * should be blocked by other interlocking and/or by first
375 		 * shutting the driver down.  Regardless, be defensive
376 		 * here and just bail
377 		 */
378 		freemsg(mp);
379 		return (NULL);
380 	}
381 	IEEE80211_NODE_LOCK(in->in_table);
382 	mfrag = in->in_rxfrag;
383 	in->in_rxfrag = NULL;
384 	IEEE80211_NODE_UNLOCK(in->in_table);
385 
386 	/*
387 	 * Validate new fragment is in order and
388 	 * related to the previous ones.
389 	 */
390 	if (mfrag != NULL) {
391 		uint16_t last_rxseq;
392 
393 		lwh = (struct ieee80211_frame *)mfrag->b_rptr;
394 		last_rxseq = LE_16(*(uint16_t *)lwh->i_seq);
395 		/*
396 		 * Sequence control field contains 12-bit sequence no
397 		 * and 4-bit fragment number. For fragemnts, the
398 		 * sequence no is not changed.
399 		 * NB: check seq # and frag together
400 		 */
401 		if (rxseq != last_rxseq + 1 ||
402 		    !IEEE80211_ADDR_EQ(wh->i_addr1, lwh->i_addr1) ||
403 		    !IEEE80211_ADDR_EQ(wh->i_addr2, lwh->i_addr2)) {
404 			/*
405 			 * Unrelated fragment or no space for it,
406 			 * clear current fragments.
407 			 */
408 			freemsg(mfrag);
409 			mfrag = NULL;
410 		}
411 	}
412 
413 	if (mfrag == NULL) {
414 		if (fragno != 0) {	/* !first fragment, discard */
415 			freemsg(mp);
416 			return (NULL);
417 		}
418 		mfrag = mp;
419 	} else {			/* concatenate */
420 		(void) adjmsg(mp, hdrspace);
421 		linkb(mfrag, mp);
422 		/* track last seqnum and fragno */
423 		lwh = (struct ieee80211_frame *)mfrag->b_rptr;
424 		*(uint16_t *)lwh->i_seq = *(uint16_t *)wh->i_seq;
425 	}
426 	if (more_frag != 0) {		/* more to come, save */
427 		in->in_rxfragstamp = ddi_get_lbolt();
428 		in->in_rxfrag = mfrag;
429 		mfrag = NULL;
430 	}
431 
432 	return (mfrag);
433 }
434 
435 /*
436  * Install received rate set information in the node's state block.
437  */
438 int
439 ieee80211_setup_rates(struct ieee80211_node *in, const uint8_t *rates,
440     const uint8_t *xrates, int flags)
441 {
442 	struct ieee80211_rateset *rs = &in->in_rates;
443 
444 	bzero(rs, sizeof (*rs));
445 	rs->ir_nrates = rates[1];
446 	/* skip 1 byte element ID and 1 byte length */
447 	bcopy(rates + 2, rs->ir_rates, rs->ir_nrates);
448 	if (xrates != NULL) {
449 		uint8_t nxrates;
450 
451 		/*
452 		 * Tack on 11g extended supported rate element.
453 		 */
454 		nxrates = xrates[1];
455 		if (rs->ir_nrates + nxrates > IEEE80211_RATE_MAXSIZE) {
456 			nxrates = IEEE80211_RATE_MAXSIZE - rs->ir_nrates;
457 			ieee80211_dbg(IEEE80211_MSG_XRATE,
458 			    "ieee80211_setup_rates: %s",
459 			    "[%s] extended rate set too large;"
460 			    " only using %u of %u rates\n",
461 			    ieee80211_macaddr_sprintf(in->in_macaddr),
462 			    nxrates, xrates[1]);
463 		}
464 		bcopy(xrates + 2, rs->ir_rates + rs->ir_nrates, nxrates);
465 		rs->ir_nrates += nxrates;
466 	}
467 	return (ieee80211_fix_rate(in, flags));
468 }
469 
470 /*
471  * Process open-system authentication response frame and start
472  * association if the authentication request is accepted.
473  */
474 static void
475 ieee80211_auth_open(ieee80211com_t *ic, struct ieee80211_frame *wh,
476     struct ieee80211_node *in, uint16_t seq, uint16_t status)
477 {
478 	IEEE80211_LOCK_ASSERT(ic);
479 	if (in->in_authmode == IEEE80211_AUTH_SHARED) {
480 		ieee80211_dbg(IEEE80211_MSG_AUTH,
481 		    "open auth: bad sta auth mode %u", in->in_authmode);
482 		return;
483 	}
484 	if (ic->ic_opmode == IEEE80211_M_STA) {
485 		if (ic->ic_state != IEEE80211_S_AUTH ||
486 		    seq != IEEE80211_AUTH_OPEN_RESPONSE) {
487 			return;
488 		}
489 		IEEE80211_UNLOCK(ic);
490 		if (status != 0) {
491 			ieee80211_dbg(IEEE80211_MSG_DEBUG | IEEE80211_MSG_AUTH,
492 			    "open auth failed (reason %d)\n", status);
493 			if (in != ic->ic_bss)
494 				in->in_fails++;
495 			ieee80211_new_state(ic, IEEE80211_S_SCAN, 0);
496 		} else {
497 			/* i_fc[0] - frame control's type & subtype field */
498 			ieee80211_new_state(ic, IEEE80211_S_ASSOC,
499 			    wh->i_fc[0] & IEEE80211_FC0_SUBTYPE_MASK);
500 		}
501 		IEEE80211_LOCK(ic);
502 	} else {
503 		ieee80211_dbg(IEEE80211_MSG_AUTH, "ieee80211_auth_open: "
504 		    "bad operating mode %u", ic->ic_opmode);
505 	}
506 }
507 
508 /*
509  * Allocate challenge text for use by shared-key authentication
510  * Return B_TRUE on success, B_FALST otherwise.
511  */
512 static boolean_t
513 ieee80211_alloc_challenge(struct ieee80211_node *in)
514 {
515 	if (in->in_challenge == NULL) {
516 		in->in_challenge = kmem_alloc(IEEE80211_CHALLENGE_LEN,
517 		    KM_NOSLEEP);
518 	}
519 	if (in->in_challenge == NULL) {
520 		ieee80211_dbg(IEEE80211_MSG_DEBUG | IEEE80211_MSG_AUTH,
521 		    "[%s] shared key challenge alloc failed\n",
522 		    ieee80211_macaddr_sprintf(in->in_macaddr));
523 	}
524 	return (in->in_challenge != NULL);
525 }
526 
527 /*
528  * Process shared-key authentication response frames. If authentication
529  * succeeds, start association; otherwise, restart scan.
530  */
531 static void
532 ieee80211_auth_shared(ieee80211com_t *ic, struct ieee80211_frame *wh,
533     uint8_t *frm, uint8_t *efrm, struct ieee80211_node *in, uint16_t seq,
534     uint16_t status)
535 {
536 	uint8_t *challenge;
537 
538 	/*
539 	 * Pre-shared key authentication is evil; accept
540 	 * it only if explicitly configured (it is supported
541 	 * mainly for compatibility with clients like OS X).
542 	 */
543 	IEEE80211_LOCK_ASSERT(ic);
544 	if (in->in_authmode != IEEE80211_AUTH_AUTO &&
545 	    in->in_authmode != IEEE80211_AUTH_SHARED) {
546 		ieee80211_dbg(IEEE80211_MSG_AUTH, "ieee80211_auth_shared: "
547 		    "bad sta auth mode %u", in->in_authmode);
548 		goto bad;
549 	}
550 
551 	challenge = NULL;
552 	if (frm + 1 < efrm) {
553 		/*
554 		 * Challenge text information element
555 		 * frm[0] - element ID
556 		 * frm[1] - length
557 		 * frm[2]... - challenge text
558 		 */
559 		if ((frm[1] + 2) > (_PTRDIFF(efrm, frm))) {
560 			ieee80211_dbg(IEEE80211_MSG_AUTH,
561 			    "ieee80211_auth_shared: ie %d%d too long\n",
562 			    frm[0], (frm[1] + 2) - (_PTRDIFF(efrm, frm)));
563 			goto bad;
564 		}
565 		if (*frm == IEEE80211_ELEMID_CHALLENGE)
566 			challenge = frm;
567 		frm += frm[1] + 2;
568 	}
569 	switch (seq) {
570 	case IEEE80211_AUTH_SHARED_CHALLENGE:
571 	case IEEE80211_AUTH_SHARED_RESPONSE:
572 		if (challenge == NULL) {
573 			ieee80211_dbg(IEEE80211_MSG_AUTH,
574 			    "ieee80211_auth_shared: no challenge\n");
575 			goto bad;
576 		}
577 		if (challenge[1] != IEEE80211_CHALLENGE_LEN) {
578 			ieee80211_dbg(IEEE80211_MSG_AUTH,
579 			    "ieee80211_auth_shared: bad challenge len %d\n",
580 			    challenge[1]);
581 			goto bad;
582 		}
583 	default:
584 		break;
585 	}
586 	switch (ic->ic_opmode) {
587 	case IEEE80211_M_STA:
588 		if (ic->ic_state != IEEE80211_S_AUTH)
589 			return;
590 		switch (seq) {
591 		case IEEE80211_AUTH_SHARED_PASS:
592 			if (in->in_challenge != NULL) {
593 				kmem_free(in->in_challenge,
594 				    IEEE80211_CHALLENGE_LEN);
595 				in->in_challenge = NULL;
596 			}
597 			if (status != 0) {
598 				ieee80211_dbg(IEEE80211_MSG_DEBUG |
599 				    IEEE80211_MSG_AUTH,
600 				    "shared key auth failed (reason %d)\n",
601 				    status);
602 				if (in != ic->ic_bss)
603 					in->in_fails++;
604 				return;
605 			}
606 			IEEE80211_UNLOCK(ic);
607 			ieee80211_new_state(ic, IEEE80211_S_ASSOC,
608 			    wh->i_fc[0] & IEEE80211_FC0_SUBTYPE_MASK);
609 			IEEE80211_LOCK(ic);
610 			break;
611 		case IEEE80211_AUTH_SHARED_CHALLENGE:
612 			if (!ieee80211_alloc_challenge(in))
613 				return;
614 			bcopy(&challenge[2], in->in_challenge, challenge[1]);
615 			IEEE80211_UNLOCK(ic);
616 			IEEE80211_SEND_MGMT(ic, in, IEEE80211_FC0_SUBTYPE_AUTH,
617 			    seq + 1);
618 			IEEE80211_LOCK(ic);
619 			break;
620 		default:
621 			ieee80211_dbg(IEEE80211_MSG_AUTH, "80211_auth_shared: "
622 			    "shared key auth: bad seq %d", seq);
623 			return;
624 		}
625 		break;
626 
627 	default:
628 		ieee80211_dbg(IEEE80211_MSG_AUTH,
629 		    "ieee80211_auth_shared: bad opmode %u\n",
630 		    ic->ic_opmode);
631 		break;
632 	}
633 	return;
634 bad:
635 	if (ic->ic_opmode == IEEE80211_M_STA) {
636 		/*
637 		 * Kick the state machine.  This short-circuits
638 		 * using the mgt frame timeout to trigger the
639 		 * state transition.
640 		 */
641 		if (ic->ic_state == IEEE80211_S_AUTH) {
642 			IEEE80211_UNLOCK(ic);
643 			ieee80211_new_state(ic, IEEE80211_S_SCAN, 0);
644 			IEEE80211_LOCK(ic);
645 		}
646 	}
647 }
648 
649 static int
650 iswpaoui(const uint8_t *frm)
651 {
652 	uint32_t c;
653 	bcopy(frm + 2, &c, 4);
654 	return (frm[1] > 3 && LE_32(c) == ((WPA_OUI_TYPE << 24) | WPA_OUI));
655 }
656 
657 /*
658  * Process a beacon/probe response frame.
659  * When the device is in station mode, create a node and add it
660  * to the node database for a new ESS or update node info if it's
661  * already there.
662  */
663 static void
664 ieee80211_recv_beacon(ieee80211com_t *ic, mblk_t *mp, struct ieee80211_node *in,
665     int subtype, int rssi, uint32_t rstamp)
666 {
667 	ieee80211_impl_t *im = ic->ic_private;
668 	struct ieee80211_frame *wh;
669 	uint8_t *frm;
670 	uint8_t *efrm;	/* end of frame body */
671 	struct ieee80211_scanparams scan;
672 
673 	wh = (struct ieee80211_frame *)mp->b_rptr;
674 	frm = (uint8_t *)&wh[1];
675 	efrm = (uint8_t *)mp->b_wptr;
676 
677 	/*
678 	 * We process beacon/probe response frames:
679 	 *    o when scanning, or
680 	 *    o station mode when associated (to collect state
681 	 *	updates such as 802.11g slot time), or
682 	 *    o adhoc mode (to discover neighbors)
683 	 * Frames otherwise received are discarded.
684 	 */
685 	if (!((ic->ic_flags & IEEE80211_F_SCAN) ||
686 	    (ic->ic_opmode == IEEE80211_M_STA && in->in_associd != 0) ||
687 	    ic->ic_opmode == IEEE80211_M_IBSS)) {
688 		return;
689 	}
690 
691 	/*
692 	 * beacon/probe response frame format
693 	 *	[8] time stamp
694 	 *	[2] beacon interval
695 	 *	[2] capability information
696 	 *	[tlv] ssid
697 	 *	[tlv] supported rates
698 	 *	[tlv] country information
699 	 *	[tlv] parameter set (FH/DS)
700 	 *	[tlv] erp information
701 	 *	[tlv] extended supported rates
702 	 *	[tlv] WME
703 	 *	[tlv] WPA or RSN
704 	 */
705 	IEEE80211_VERIFY_LENGTH(_PTRDIFF(efrm, frm),
706 	    IEEE80211_BEACON_ELEM_MIN, return);
707 	bzero(&scan, sizeof (scan));
708 	scan.tstamp  = frm;
709 	frm += 8;
710 	scan.bintval = LE_16(*(uint16_t *)frm);
711 	frm += 2;
712 	scan.capinfo = LE_16(*(uint16_t *)frm);
713 	frm += 2;
714 	scan.bchan = ieee80211_chan2ieee(ic, ic->ic_curchan);
715 	scan.chan = scan.bchan;
716 
717 	while (frm < efrm) {
718 		/* Agere element in beacon */
719 		if ((*frm == IEEE80211_ELEMID_AGERE1) ||
720 		    (*frm == IEEE80211_ELEMID_AGERE2)) {
721 			frm = efrm;
722 			break;
723 		}
724 
725 		IEEE80211_VERIFY_LENGTH(_PTRDIFF(efrm, frm), frm[1], return);
726 		switch (*frm) {
727 		case IEEE80211_ELEMID_SSID:
728 			scan.ssid = frm;
729 			break;
730 		case IEEE80211_ELEMID_RATES:
731 			scan.rates = frm;
732 			break;
733 		case IEEE80211_ELEMID_COUNTRY:
734 			scan.country = frm;
735 			break;
736 		case IEEE80211_ELEMID_FHPARMS:
737 			if (ic->ic_phytype == IEEE80211_T_FH) {
738 				scan.fhdwell = LE_16(*(uint16_t *)(frm + 2));
739 				scan.chan = IEEE80211_FH_CHAN(frm[4], frm[5]);
740 				scan.fhindex = frm[6];
741 				scan.phytype = IEEE80211_T_FH;
742 			}
743 			break;
744 		case IEEE80211_ELEMID_DSPARMS:
745 			if (ic->ic_phytype != IEEE80211_T_FH) {
746 				scan.chan = frm[2];
747 				scan.phytype = IEEE80211_T_DS;
748 			}
749 			break;
750 		case IEEE80211_ELEMID_TIM:
751 			scan.tim = frm;
752 			scan.timoff = _PTRDIFF(frm, mp->b_rptr);
753 			break;
754 		case IEEE80211_ELEMID_IBSSPARMS:
755 			break;
756 		case IEEE80211_ELEMID_XRATES:
757 			scan.xrates = frm;
758 			break;
759 		case IEEE80211_ELEMID_ERP:
760 			if (frm[1] != 1) {
761 				ieee80211_dbg(IEEE80211_MSG_ELEMID,
762 				    "ieee80211_recv_mgmt: ignore %s, "
763 				    "invalid ERP element; "
764 				    "length %u, expecting 1\n",
765 				    IEEE80211_SUBTYPE_NAME(subtype),
766 				    frm[1]);
767 				break;
768 			}
769 			scan.erp = frm[2];
770 			scan.phytype = IEEE80211_T_OFDM;
771 			break;
772 		case IEEE80211_ELEMID_RSN:
773 			scan.wpa = frm;
774 			break;
775 		case IEEE80211_ELEMID_VENDOR:
776 			if (iswpaoui(frm))
777 				scan.wpa = frm;		/* IEEE802.11i D3.0 */
778 			break;
779 		default:
780 			ieee80211_dbg(IEEE80211_MSG_ELEMID,
781 			    "ieee80211_recv_mgmt: ignore %s,"
782 			    "unhandled id %u, len %u, totallen %u",
783 			    IEEE80211_SUBTYPE_NAME(subtype),
784 			    *frm, frm[1],
785 			    MBLKL(mp));
786 			break;
787 		}
788 		/* frm[1] - component length */
789 		frm += IEEE80211_ELEM_LEN(frm[1]);
790 	}
791 	IEEE80211_VERIFY_ELEMENT(scan.rates, IEEE80211_RATE_MAXSIZE, return);
792 	IEEE80211_VERIFY_ELEMENT(scan.ssid, IEEE80211_NWID_LEN, return);
793 	if (ieee80211_isclr(ic->ic_chan_active, scan.chan)) {
794 		ieee80211_dbg(IEEE80211_MSG_ELEMID | IEEE80211_MSG_INPUT,
795 		    "ieee80211_recv_mgmt: ignore %s ,"
796 		    "invalid channel %u\n",
797 		    IEEE80211_SUBTYPE_NAME(subtype), scan.chan);
798 		return;
799 	}
800 	if (scan.chan != scan.bchan &&
801 	    ic->ic_phytype != IEEE80211_T_FH) {
802 		/*
803 		 * Frame was received on a channel different from the
804 		 * one indicated in the DS params element id;
805 		 * silently discard it.
806 		 *
807 		 * NB:	this can happen due to signal leakage.
808 		 *	But we should take it for FH phy because
809 		 *	the rssi value should be correct even for
810 		 *	different hop pattern in FH.
811 		 */
812 		ieee80211_dbg(IEEE80211_MSG_ELEMID,
813 		    "ieee80211_recv_mgmt: ignore %s ,"
814 		    "phytype %u channel %u marked for %u\n",
815 		    IEEE80211_SUBTYPE_NAME(subtype),
816 		    ic->ic_phytype, scan.bchan, scan.chan);
817 		return;
818 	}
819 	if (!(IEEE80211_BINTVAL_MIN <= scan.bintval &&
820 	    scan.bintval <= IEEE80211_BINTVAL_MAX)) {
821 		ieee80211_dbg(IEEE80211_MSG_ELEMID | IEEE80211_MSG_INPUT,
822 		    "ieee80211_recv_mgmt: ignore %s ,"
823 		    "bogus beacon interval %u\n",
824 		    IEEE80211_SUBTYPE_NAME(subtype), scan.bintval);
825 		return;
826 	}
827 
828 	/*
829 	 * When operating in station mode, check for state updates.
830 	 * Be careful to ignore beacons received while doing a
831 	 * background scan.  We consider only 11g/WMM stuff right now.
832 	 */
833 	if (ic->ic_opmode == IEEE80211_M_STA &&
834 	    in->in_associd != 0 &&
835 	    (!(ic->ic_flags & IEEE80211_F_SCAN) ||
836 	    IEEE80211_ADDR_EQ(wh->i_addr2, in->in_bssid))) {
837 		/* record tsf of last beacon */
838 		bcopy(scan.tstamp, in->in_tstamp.data,
839 		    sizeof (in->in_tstamp));
840 		/* count beacon frame for s/w bmiss handling */
841 		im->im_swbmiss_count++;
842 		im->im_bmiss_count = 0;
843 
844 		if ((in->in_capinfo ^ scan.capinfo) &
845 		    IEEE80211_CAPINFO_SHORT_SLOTTIME) {
846 			ieee80211_dbg(IEEE80211_MSG_ASSOC,
847 			    "ieee80211_recv_mgmt: "
848 			    "[%s] cap change: before 0x%x, now 0x%x\n",
849 			    ieee80211_macaddr_sprintf(wh->i_addr2),
850 			    in->in_capinfo, scan.capinfo);
851 			/*
852 			 * NB:	we assume short preamble doesn't
853 			 *	change dynamically
854 			 */
855 			ieee80211_set_shortslottime(ic,
856 			    ic->ic_curmode == IEEE80211_MODE_11A ||
857 			    (scan.capinfo &
858 			    IEEE80211_CAPINFO_SHORT_SLOTTIME));
859 			in->in_capinfo = scan.capinfo;
860 		}
861 
862 		if (scan.tim != NULL) {
863 			struct ieee80211_tim_ie *ie;
864 
865 			ie = (struct ieee80211_tim_ie *)scan.tim;
866 			in->in_dtim_count = ie->tim_count;
867 			in->in_dtim_period = ie->tim_period;
868 		}
869 		if (ic->ic_flags & IEEE80211_F_SCAN) {
870 			ieee80211_add_scan(ic, &scan, wh, subtype, rssi,
871 			    rstamp);
872 		}
873 		return;
874 	}
875 	/*
876 	 * If scanning, just pass information to the scan module.
877 	 */
878 	if (ic->ic_flags & IEEE80211_F_SCAN) {
879 		ieee80211_add_scan(ic, &scan, wh, subtype, rssi, rstamp);
880 		return;
881 	}
882 
883 	if (ic->ic_opmode == IEEE80211_M_IBSS &&
884 	    scan.capinfo & IEEE80211_CAPINFO_IBSS) {
885 		if (!IEEE80211_ADDR_EQ(wh->i_addr2, in->in_macaddr)) {
886 			/*
887 			 * Create a new entry in the neighbor table.
888 			 */
889 			in = ieee80211_add_neighbor(ic, wh, &scan);
890 		} else {
891 			/*
892 			 * Copy data from beacon to neighbor table.
893 			 * Some of this information might change after
894 			 * ieee80211_add_neighbor(), so we just copy
895 			 * everything over to be safe.
896 			 */
897 			ieee80211_init_neighbor(in, wh, &scan);
898 		}
899 		if (in != NULL) {
900 			in->in_rssi = (uint8_t)rssi;
901 			in->in_rstamp = rstamp;
902 		}
903 	}
904 }
905 
906 /*
907  * Perform input processing for 802.11 management frames.
908  * It's the default ic_recv_mgmt callback function for the interface
909  * softc, ic. Tipically ic_recv_mgmt is called within ieee80211_input()
910  */
911 void
912 ieee80211_recv_mgmt(ieee80211com_t *ic, mblk_t *mp, struct ieee80211_node *in,
913     int subtype, int rssi, uint32_t rstamp)
914 {
915 	struct ieee80211_frame *wh;
916 	uint8_t *frm;		/* pointer to start of the frame */
917 	uint8_t *efrm;		/* pointer to end of the frame */
918 	uint8_t *ssid;
919 	uint8_t *rates;
920 	uint8_t *xrates;	/* extended rates */
921 	boolean_t allocbs = B_FALSE;
922 	uint8_t rate;
923 	uint16_t algo;		/* authentication algorithm */
924 	uint16_t seq;		/* sequence no */
925 	uint16_t status;
926 	uint16_t capinfo;
927 	uint16_t associd;	/* association ID */
928 
929 	IEEE80211_LOCK(ic);
930 	wh = (struct ieee80211_frame *)mp->b_rptr;
931 	frm = (uint8_t *)&wh[1];
932 	efrm = (uint8_t *)mp->b_wptr;
933 	switch (subtype) {
934 	case IEEE80211_FC0_SUBTYPE_PROBE_RESP:
935 	case IEEE80211_FC0_SUBTYPE_BEACON:
936 		ieee80211_recv_beacon(ic, mp, in, subtype, rssi, rstamp);
937 		break;
938 
939 	case IEEE80211_FC0_SUBTYPE_PROBE_REQ:
940 		if (ic->ic_opmode == IEEE80211_M_STA ||
941 		    ic->ic_state != IEEE80211_S_RUN ||
942 		    IEEE80211_IS_MULTICAST(wh->i_addr2)) {
943 			break;
944 		}
945 
946 		/*
947 		 * prreq frame format
948 		 *	[tlv] ssid
949 		 *	[tlv] supported rates
950 		 *	[tlv] extended supported rates
951 		 */
952 		ssid = rates = xrates = NULL;
953 		while (frm < efrm) {
954 			IEEE80211_VERIFY_LENGTH(_PTRDIFF(efrm, frm),
955 			    frm[1], goto out);
956 			switch (*frm) {
957 			case IEEE80211_ELEMID_SSID:
958 				ssid = frm;
959 				break;
960 			case IEEE80211_ELEMID_RATES:
961 				rates = frm;
962 				break;
963 			case IEEE80211_ELEMID_XRATES:
964 				xrates = frm;
965 				break;
966 			}
967 			frm += frm[1] + 2;
968 		}
969 		IEEE80211_VERIFY_ELEMENT(rates, IEEE80211_RATE_MAXSIZE, break);
970 		if (xrates != NULL) {
971 			IEEE80211_VERIFY_ELEMENT(xrates,
972 			    IEEE80211_RATE_MAXSIZE - rates[1], break);
973 		}
974 		IEEE80211_VERIFY_ELEMENT(ssid, IEEE80211_NWID_LEN, break);
975 		IEEE80211_VERIFY_SSID(ic->ic_bss, ssid, break);
976 		if (ic->ic_flags & IEEE80211_F_HIDESSID) {
977 			if (ssid == NULL || ssid[1] == 0) {
978 				ieee80211_dbg(IEEE80211_MSG_INPUT,
979 				    "ieee80211_recv_mgmt: ignore %s, "
980 				    "no ssid with ssid suppression enabled",
981 				    IEEE80211_SUBTYPE_NAME(subtype));
982 				break;
983 			}
984 		}
985 
986 		if (in == ic->ic_bss) {
987 			if (ic->ic_opmode != IEEE80211_M_IBSS) {
988 				in = ieee80211_tmp_node(ic, wh->i_addr2);
989 				allocbs = B_TRUE;
990 			} else if (!IEEE80211_ADDR_EQ(wh->i_addr2,
991 			    in->in_macaddr)) {
992 				/*
993 				 * Cannot tell if the sender is operating
994 				 * in ibss mode.  But we need a new node to
995 				 * send the response so blindly add them to the
996 				 * neighbor table.
997 				 */
998 				in = ieee80211_fakeup_adhoc_node(&ic->ic_sta,
999 				    wh->i_addr2);
1000 			}
1001 			if (in == NULL)
1002 				break;
1003 		}
1004 		ieee80211_dbg(IEEE80211_MSG_ASSOC, "ieee80211_recv_mgmt: "
1005 		    "[%s] recv probe req\n",
1006 		    ieee80211_macaddr_sprintf(wh->i_addr2));
1007 		in->in_rssi = (uint8_t)rssi;
1008 		in->in_rstamp = rstamp;
1009 		/*
1010 		 * Adjust and check station's rate list with device's
1011 		 * supported rate.  Send back response if there is at
1012 		 * least one rate or the fixed rate(if being set) is
1013 		 * supported by both station and the device
1014 		 */
1015 		rate = ieee80211_setup_rates(in, rates, xrates,
1016 		    IEEE80211_F_DOSORT | IEEE80211_F_DOFRATE |
1017 		    IEEE80211_F_DONEGO | IEEE80211_F_DODEL);
1018 		if (rate & IEEE80211_RATE_BASIC) {
1019 			ieee80211_dbg(IEEE80211_MSG_XRATE, "ieee80211_recv_mgmt"
1020 			    "%s recv'd rate set invalid",
1021 			    IEEE80211_SUBTYPE_NAME(subtype));
1022 		} else {
1023 			IEEE80211_UNLOCK(ic);
1024 			IEEE80211_SEND_MGMT(ic, in,
1025 			    IEEE80211_FC0_SUBTYPE_PROBE_RESP, 0);
1026 			IEEE80211_LOCK(ic);
1027 		}
1028 		if (allocbs) {
1029 			/*
1030 			 * Temporary node created just to send a
1031 			 * response, reclaim immediately.
1032 			 */
1033 			ieee80211_free_node(in);
1034 		}
1035 		break;
1036 
1037 	case IEEE80211_FC0_SUBTYPE_AUTH:
1038 		/*
1039 		 * auth frame format
1040 		 *	[2] algorithm
1041 		 *	[2] sequence
1042 		 *	[2] status
1043 		 *	[tlv*] challenge
1044 		 */
1045 		IEEE80211_VERIFY_LENGTH(_PTRDIFF(efrm, frm),
1046 		    IEEE80211_AUTH_ELEM_MIN, break);
1047 		algo   = LE_16(*(uint16_t *)frm);
1048 		seq    = LE_16(*(uint16_t *)(frm + 2));
1049 		status = LE_16(*(uint16_t *)(frm + 4));
1050 		ieee80211_dbg(IEEE80211_MSG_AUTH, "ieee80211_recv_mgmt: "
1051 		    "[%s] recv auth frame with algorithm %d seq %d\n",
1052 		    ieee80211_macaddr_sprintf(wh->i_addr2), algo, seq);
1053 
1054 		if (ic->ic_flags & IEEE80211_F_COUNTERM) {
1055 			ieee80211_dbg(IEEE80211_MSG_AUTH | IEEE80211_MSG_CRYPTO,
1056 			    "ieee80211_recv_mgmt: ignore auth, %s\n",
1057 			    "TKIP countermeasures enabled");
1058 			break;
1059 		}
1060 		switch (algo) {
1061 		case IEEE80211_AUTH_ALG_SHARED:
1062 			ieee80211_auth_shared(ic, wh, frm + 6, efrm, in,
1063 			    seq, status);
1064 			break;
1065 		case IEEE80211_AUTH_ALG_OPEN:
1066 			ieee80211_auth_open(ic, wh, in, seq, status);
1067 			break;
1068 		default:
1069 			ieee80211_dbg(IEEE80211_MSG_ANY, "ieee80211_recv_mgmt: "
1070 			    "ignore auth, unsupported alg %d", algo);
1071 			break;
1072 		}
1073 		break;
1074 
1075 	case IEEE80211_FC0_SUBTYPE_ASSOC_RESP:
1076 	case IEEE80211_FC0_SUBTYPE_REASSOC_RESP:
1077 		if (ic->ic_opmode != IEEE80211_M_STA ||
1078 		    ic->ic_state != IEEE80211_S_ASSOC)
1079 			break;
1080 
1081 		/*
1082 		 * asresp frame format
1083 		 *	[2] capability information
1084 		 *	[2] status
1085 		 *	[2] association ID
1086 		 *	[tlv] supported rates
1087 		 *	[tlv] extended supported rates
1088 		 *	[tlv] WME
1089 		 */
1090 		IEEE80211_VERIFY_LENGTH(_PTRDIFF(efrm, frm),
1091 		    IEEE80211_ASSOC_RESP_ELEM_MIN, break);
1092 		in = ic->ic_bss;
1093 		capinfo = LE_16(*(uint16_t *)frm);
1094 		frm += 2;
1095 		status = LE_16(*(uint16_t *)frm);
1096 		frm += 2;
1097 		if (status != 0) {
1098 			ieee80211_dbg(IEEE80211_MSG_ASSOC,
1099 			    "assoc failed (reason %d)\n", status);
1100 			in = ieee80211_find_node(&ic->ic_scan, wh->i_addr2);
1101 			if (in != NULL) {
1102 				in->in_fails++;
1103 				ieee80211_free_node(in);
1104 			}
1105 			break;
1106 		}
1107 		associd = LE_16(*(uint16_t *)frm);
1108 		frm += 2;
1109 
1110 		rates = xrates = NULL;
1111 		while (frm < efrm) {
1112 			/*
1113 			 * Do not discard frames containing proprietary Agere
1114 			 * elements 128 and 129, as the reported element length
1115 			 * is often wrong. Skip rest of the frame, since we can
1116 			 * not rely on the given element length making it
1117 			 * impossible to know where the next element starts
1118 			 */
1119 			if ((*frm == IEEE80211_ELEMID_AGERE1) ||
1120 			    (*frm == IEEE80211_ELEMID_AGERE2)) {
1121 				frm = efrm;
1122 				break;
1123 			}
1124 
1125 			IEEE80211_VERIFY_LENGTH(_PTRDIFF(efrm, frm),
1126 			    frm[1], goto out);
1127 			switch (*frm) {
1128 			case IEEE80211_ELEMID_RATES:
1129 				rates = frm;
1130 				break;
1131 			case IEEE80211_ELEMID_XRATES:
1132 				xrates = frm;
1133 				break;
1134 			}
1135 			frm += frm[1] + 2;
1136 		}
1137 
1138 		IEEE80211_VERIFY_ELEMENT(rates, IEEE80211_RATE_MAXSIZE, break);
1139 		/*
1140 		 * Adjust and check AP's rate list with device's
1141 		 * supported rate. Re-start scan if no rate is or the
1142 		 * fixed rate(if being set) cannot be supported by
1143 		 * either AP or the device.
1144 		 */
1145 		rate = ieee80211_setup_rates(in, rates, xrates,
1146 		    IEEE80211_F_DOSORT | IEEE80211_F_DOFRATE |
1147 		    IEEE80211_F_DONEGO | IEEE80211_F_DODEL);
1148 		if (rate & IEEE80211_RATE_BASIC) {
1149 			ieee80211_dbg(IEEE80211_MSG_ASSOC,
1150 			    "assoc failed (rate set mismatch)\n");
1151 			if (in != ic->ic_bss)
1152 				in->in_fails++;
1153 			IEEE80211_UNLOCK(ic);
1154 			ieee80211_new_state(ic, IEEE80211_S_SCAN, 0);
1155 			return;
1156 		}
1157 
1158 		in->in_capinfo = capinfo;
1159 		in->in_associd = associd;
1160 		in->in_flags &= ~IEEE80211_NODE_QOS;
1161 		/*
1162 		 * Configure state now that we are associated.
1163 		 */
1164 		if (ic->ic_curmode == IEEE80211_MODE_11A ||
1165 		    (in->in_capinfo & IEEE80211_CAPINFO_SHORT_PREAMBLE)) {
1166 			ic->ic_flags |= IEEE80211_F_SHPREAMBLE;
1167 			ic->ic_flags &= ~IEEE80211_F_USEBARKER;
1168 		} else {
1169 			ic->ic_flags &= ~IEEE80211_F_SHPREAMBLE;
1170 			ic->ic_flags |= IEEE80211_F_USEBARKER;
1171 		}
1172 		ieee80211_set_shortslottime(ic,
1173 		    ic->ic_curmode == IEEE80211_MODE_11A ||
1174 		    (in->in_capinfo & IEEE80211_CAPINFO_SHORT_SLOTTIME));
1175 		/*
1176 		 * Honor ERP protection.
1177 		 *
1178 		 * NB:	in_erp should zero for non-11g operation.
1179 		 *	check ic_curmode anyway
1180 		 */
1181 		if (ic->ic_curmode == IEEE80211_MODE_11G &&
1182 		    (in->in_erp & IEEE80211_ERP_USE_PROTECTION))
1183 			ic->ic_flags |= IEEE80211_F_USEPROT;
1184 		else
1185 			ic->ic_flags &= ~IEEE80211_F_USEPROT;
1186 		ieee80211_dbg(IEEE80211_MSG_ASSOC,
1187 		    "assoc success: %s preamble, %s slot time%s%s\n",
1188 		    ic->ic_flags&IEEE80211_F_SHPREAMBLE ? "short" : "long",
1189 		    ic->ic_flags&IEEE80211_F_SHSLOT ? "short" : "long",
1190 		    ic->ic_flags&IEEE80211_F_USEPROT ? ", protection" : "",
1191 		    in->in_flags & IEEE80211_NODE_QOS ? ", QoS" : "");
1192 		IEEE80211_UNLOCK(ic);
1193 		ieee80211_new_state(ic, IEEE80211_S_RUN, subtype);
1194 		return;
1195 
1196 	case IEEE80211_FC0_SUBTYPE_DEAUTH:
1197 		if (ic->ic_state == IEEE80211_S_SCAN)
1198 			break;
1199 
1200 		/*
1201 		 * deauth frame format
1202 		 *	[2] reason
1203 		 */
1204 		IEEE80211_VERIFY_LENGTH(_PTRDIFF(efrm, frm), 2, break);
1205 		status = LE_16(*(uint16_t *)frm);
1206 
1207 		ieee80211_dbg(IEEE80211_MSG_AUTH,
1208 		    "recv deauthenticate (reason %d)\n", status);
1209 		switch (ic->ic_opmode) {
1210 		case IEEE80211_M_STA:
1211 			IEEE80211_UNLOCK(ic);
1212 			ieee80211_new_state(ic, IEEE80211_S_AUTH,
1213 			    wh->i_fc[0] & IEEE80211_FC0_SUBTYPE_MASK);
1214 			return;
1215 		default:
1216 			break;
1217 		}
1218 		break;
1219 
1220 	case IEEE80211_FC0_SUBTYPE_DISASSOC:
1221 		if (ic->ic_state != IEEE80211_S_RUN &&
1222 		    ic->ic_state != IEEE80211_S_ASSOC &&
1223 		    ic->ic_state != IEEE80211_S_AUTH)
1224 			break;
1225 		/*
1226 		 * disassoc frame format
1227 		 *	[2] reason
1228 		 */
1229 		IEEE80211_VERIFY_LENGTH(_PTRDIFF(efrm, frm), 2, break);
1230 		status = LE_16(*(uint16_t *)frm);
1231 
1232 		ieee80211_dbg(IEEE80211_MSG_ASSOC,
1233 		    "recv disassociate (reason %d)\n", status);
1234 		switch (ic->ic_opmode) {
1235 		case IEEE80211_M_STA:
1236 			IEEE80211_UNLOCK(ic);
1237 			ieee80211_new_state(ic, IEEE80211_S_ASSOC,
1238 			    wh->i_fc[0] & IEEE80211_FC0_SUBTYPE_MASK);
1239 			return;
1240 		default:
1241 			break;
1242 		}
1243 		break;
1244 
1245 	default:
1246 		ieee80211_dbg(IEEE80211_MSG_ANY, "ieee80211_recv_mgmt: "
1247 		    "subtype 0x%x not handled\n", subtype);
1248 		break;
1249 	} /* switch subtype */
1250 out:
1251 	IEEE80211_UNLOCK(ic);
1252 }
1253