1 /*
2  * Copyright (c) 2001 Atsushi Onoe
3  * Copyright (c) 2002, 2003 Sam Leffler, Errno Consulting
4  * All rights reserved.
5  *
6  * Redistribution and use in source and binary forms, with or without
7  * modification, are permitted provided that the following conditions
8  * are met:
9  * 1. Redistributions of source code must retain the above copyright
10  *    notice, this list of conditions and the following disclaimer.
11  * 2. Redistributions in binary form must reproduce the above copyright
12  *    notice, this list of conditions and the following disclaimer in the
13  *    documentation and/or other materials provided with the distribution.
14  * 3. The name of the author may not be used to endorse or promote products
15  *    derived from this software without specific prior written permission.
16  *
17  * Alternatively, this software may be distributed under the terms of the
18  * GNU General Public License ("GPL") version 2 as published by the Free
19  * Software Foundation.
20  *
21  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
22  * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
23  * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
24  * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
25  * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
26  * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
27  * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
28  * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
29  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
30  * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
31  *
32  * $FreeBSD: src/sys/net80211/ieee80211_input.c,v 1.21 2004/06/13 17:29:09 mlaier Exp $
33  * $DragonFly: src/sys/netproto/802_11/wlan/ieee80211_input.c,v 1.1 2004/07/26 16:30:17 joerg Exp $
34  */
35 
36 #include "opt_inet.h"
37 
38 #include <sys/param.h>
39 #include <sys/systm.h>
40 #include <sys/mbuf.h>
41 #include <sys/malloc.h>
42 #include <sys/kernel.h>
43 #include <sys/socket.h>
44 #include <sys/sockio.h>
45 #include <sys/endian.h>
46 #include <sys/errno.h>
47 #include <sys/bus.h>
48 #include <sys/proc.h>
49 #include <sys/sysctl.h>
50 
51 #include <machine/atomic.h>
52 
53 #include <net/if.h>
54 #include <net/if_dl.h>
55 #include <net/if_media.h>
56 #include <net/if_arp.h>
57 #include <net/ethernet.h>
58 #include <net/if_llc.h>
59 
60 #include <netproto/802_11/ieee80211_var.h>
61 
62 #include <net/bpf.h>
63 
64 #ifdef INET
65 #include <netinet/in.h>
66 #include <netinet/if_ether.h>
67 #endif
68 
69 /*
70  * Process a received frame.  The node associated with the sender
71  * should be supplied.  If nothing was found in the node table then
72  * the caller is assumed to supply a reference to ic_bss instead.
73  * The RSSI and a timestamp are also supplied.  The RSSI data is used
74  * during AP scanning to select a AP to associate with; it can have
75  * any units so long as values have consistent units and higher values
76  * mean ``better signal''.  The receive timestamp is currently not used
77  * by the 802.11 layer.
78  */
79 void
80 ieee80211_input(struct ifnet *ifp, struct mbuf *m, struct ieee80211_node *ni,
81 	int rssi, uint32_t rstamp)
82 {
83 	struct ieee80211com *ic = (void *)ifp;
84 	struct ieee80211_frame *wh;
85 	struct ether_header *eh;
86 	struct mbuf *m1;
87 	int len;
88 	uint8_t dir, type, subtype;
89 	uint8_t *bssid;
90 	uint16_t rxseq;
91 
92 	KASSERT(ni != NULL, ("null node"));
93 
94 #ifdef M_HASFCS
95 	/* trim CRC here so WEP can find its own CRC at the end of packet. */
96 	if (m->m_flags & M_HASFCS) {
97 		m_adj(m, -IEEE80211_CRC_LEN);
98 		m->m_flags &= ~M_HASFCS;
99 	}
100 #endif
101 	KASSERT(m->m_pkthdr.len >= sizeof(struct ieee80211_frame_min),
102 		("frame length too short: %u", m->m_pkthdr.len));
103 
104 	/*
105 	 * In monitor mode, send everything directly to bpf.
106 	 * XXX may want to include the CRC
107 	 */
108 	if (ic->ic_opmode == IEEE80211_M_MONITOR)
109 		goto out;
110 
111 	wh = mtod(m, struct ieee80211_frame *);
112 	if ((wh->i_fc[0] & IEEE80211_FC0_VERSION_MASK) !=
113 	    IEEE80211_FC0_VERSION_0) {
114 		if (ifp->if_flags & IFF_DEBUG)
115 			if_printf(ifp, "receive packet with wrong version: %x\n",
116 			    wh->i_fc[0]);
117 		ic->ic_stats.is_rx_badversion++;
118 		goto err;
119 	}
120 
121 	dir = wh->i_fc[1] & IEEE80211_FC1_DIR_MASK;
122 	type = wh->i_fc[0] & IEEE80211_FC0_TYPE_MASK;
123 	/*
124 	 * NB: We are not yet prepared to handle control frames,
125 	 *     but permitting drivers to send them to us allows
126 	 *     them to go through bpf tapping at the 802.11 layer.
127 	 */
128 	if (m->m_pkthdr.len < sizeof(struct ieee80211_frame)) {
129 		/* XXX statistic */
130 		IEEE80211_DPRINTF2(("%s: frame too short, len %u\n",
131 			__func__, m->m_pkthdr.len));
132 		ic->ic_stats.is_rx_tooshort++;
133 		goto out;		/* XXX */
134 	}
135 	if (ic->ic_state != IEEE80211_S_SCAN) {
136 		switch (ic->ic_opmode) {
137 		case IEEE80211_M_STA:
138 			if (!IEEE80211_ADDR_EQ(wh->i_addr2, ni->ni_bssid)) {
139 				/* not interested in */
140 				IEEE80211_DPRINTF2(("%s: discard frame from "
141 					"bss %6D\n", __func__,
142 					wh->i_addr2, ":"));
143 				ic->ic_stats.is_rx_wrongbss++;
144 				goto out;
145 			}
146 			break;
147 		case IEEE80211_M_IBSS:
148 		case IEEE80211_M_AHDEMO:
149 		case IEEE80211_M_HOSTAP:
150 			if (dir == IEEE80211_FC1_DIR_NODS)
151 				bssid = wh->i_addr3;
152 			else
153 				bssid = wh->i_addr1;
154 			if (!IEEE80211_ADDR_EQ(bssid, ic->ic_bss->ni_bssid) &&
155 			    !IEEE80211_ADDR_EQ(bssid, ifp->if_broadcastaddr)) {
156 				/* not interested in */
157 				IEEE80211_DPRINTF2(("%s: discard frame from "
158 					"bss %6D\n", __func__,
159 					bssid, ":"));
160 				ic->ic_stats.is_rx_wrongbss++;
161 				goto out;
162 			}
163 			break;
164 		case IEEE80211_M_MONITOR:
165 			goto out;
166 		default:
167 			/* XXX catch bad values */
168 			break;
169 		}
170 		ni->ni_rssi = rssi;
171 		ni->ni_rstamp = rstamp;
172 		rxseq = ni->ni_rxseq;
173 		ni->ni_rxseq =
174 		    le16toh(*(uint16_t *)wh->i_seq) >> IEEE80211_SEQ_SEQ_SHIFT;
175 		/* TODO: fragment */
176 		if ((wh->i_fc[1] & IEEE80211_FC1_RETRY) &&
177 		    rxseq == ni->ni_rxseq) {
178 			/* duplicate, silently discarded */
179 			ic->ic_stats.is_rx_dup++; /* XXX per-station stat */
180 			goto out;
181 		}
182 		ni->ni_inact = 0;
183 	}
184 
185 	switch (type) {
186 	case IEEE80211_FC0_TYPE_DATA:
187 		switch (ic->ic_opmode) {
188 		case IEEE80211_M_STA:
189 			if (dir != IEEE80211_FC1_DIR_FROMDS) {
190 				ic->ic_stats.is_rx_wrongdir++;
191 				goto out;
192 			}
193 			if ((ifp->if_flags & IFF_SIMPLEX) &&
194 			    IEEE80211_IS_MULTICAST(wh->i_addr1) &&
195 			    IEEE80211_ADDR_EQ(wh->i_addr3, ic->ic_myaddr)) {
196 				/*
197 				 * In IEEE802.11 network, multicast packet
198 				 * sent from me is broadcasted from AP.
199 				 * It should be silently discarded for
200 				 * SIMPLEX interface.
201 				 */
202 				ic->ic_stats.is_rx_mcastecho++;
203 				goto out;
204 			}
205 			break;
206 		case IEEE80211_M_IBSS:
207 		case IEEE80211_M_AHDEMO:
208 			if (dir != IEEE80211_FC1_DIR_NODS) {
209 				ic->ic_stats.is_rx_wrongdir++;
210 				goto out;
211 			}
212 			break;
213 		case IEEE80211_M_HOSTAP:
214 			if (dir != IEEE80211_FC1_DIR_TODS) {
215 				ic->ic_stats.is_rx_wrongdir++;
216 				goto out;
217 			}
218 			/* check if source STA is associated */
219 			if (ni == ic->ic_bss) {
220 				IEEE80211_DPRINTF(("%s: data from unknown src "
221 					"%6D\n", __func__,
222 					wh->i_addr2, ":"));
223 				/* NB: caller deals with reference */
224 				ni = ieee80211_dup_bss(ic, wh->i_addr2);
225 				if (ni != NULL) {
226 					IEEE80211_SEND_MGMT(ic, ni,
227 					    IEEE80211_FC0_SUBTYPE_DEAUTH,
228 					    IEEE80211_REASON_NOT_AUTHED);
229 					ieee80211_free_node(ic, ni);
230 				}
231 				ic->ic_stats.is_rx_notassoc++;
232 				goto err;
233 			}
234 			if (ni->ni_associd == 0) {
235 				IEEE80211_DPRINTF(("ieee80211_input: "
236 				    "data from unassoc src %6D\n",
237 				    wh->i_addr2, ":"));
238 				IEEE80211_SEND_MGMT(ic, ni,
239 				    IEEE80211_FC0_SUBTYPE_DISASSOC,
240 				    IEEE80211_REASON_NOT_ASSOCED);
241 				ieee80211_unref_node(&ni);
242 				ic->ic_stats.is_rx_notassoc++;
243 				goto err;
244 			}
245 			break;
246 		case IEEE80211_M_MONITOR:
247 			break;
248 		}
249 		if (wh->i_fc[1] & IEEE80211_FC1_WEP) {
250 			if (ic->ic_flags & IEEE80211_F_WEPON) {
251 				m = ieee80211_wep_crypt(ifp, m, 0);
252 				if (m == NULL) {
253 					ic->ic_stats.is_rx_wepfail++;
254 					goto err;
255 				}
256 				wh = mtod(m, struct ieee80211_frame *);
257 			} else {
258 				ic->ic_stats.is_rx_nowep++;
259 				goto out;
260 			}
261 		}
262 		/* copy to listener after decrypt */
263 #ifdef IEEE80211_RAWBPF
264 		if (ic->ic_rawbpf)
265 			bpf_mtap(ic->ic_rawbpf, m);
266 #endif
267 		m = ieee80211_decap(ifp, m);
268 		if (m == NULL) {
269 			ic->ic_stats.is_rx_decap++;
270 			goto err;
271 		}
272 		ifp->if_ipackets++;
273 
274 		/* perform as a bridge within the AP */
275 		m1 = NULL;
276 		if (ic->ic_opmode == IEEE80211_M_HOSTAP) {
277 			eh = mtod(m, struct ether_header *);
278 			if (ETHER_IS_MULTICAST(eh->ether_dhost)) {
279 				m1 = m_copypacket(m, MB_DONTWAIT);
280 				if (m1 == NULL)
281 					ifp->if_oerrors++;
282 				else
283 					m1->m_flags |= M_MCAST;
284 			} else {
285 				ni = ieee80211_find_node(ic, eh->ether_dhost);
286 				if (ni != NULL) {
287 					if (ni->ni_associd != 0) {
288 						m1 = m;
289 						m = NULL;
290 					}
291 					ieee80211_free_node(ic, ni);
292 				}
293 			}
294 			if (m1 != NULL) {
295 				len = m1->m_pkthdr.len;
296 				IF_ENQUEUE(&ifp->if_snd, m1);
297 				if (m != NULL)
298 					ifp->if_omcasts++;
299 				ifp->if_obytes += len;
300 			}
301 		}
302 		if (m != NULL)
303 			(*ifp->if_input)(ifp, m);
304 		return;
305 
306 	case IEEE80211_FC0_TYPE_MGT:
307 		if (dir != IEEE80211_FC1_DIR_NODS) {
308 			ic->ic_stats.is_rx_wrongdir++;
309 			goto err;
310 		}
311 		if (ic->ic_opmode == IEEE80211_M_AHDEMO) {
312 			ic->ic_stats.is_rx_ahdemo_mgt++;
313 			goto out;
314 		}
315 		subtype = wh->i_fc[0] & IEEE80211_FC0_SUBTYPE_MASK;
316 
317 		/* drop frames without interest */
318 		if (ic->ic_state == IEEE80211_S_SCAN) {
319 			if (subtype != IEEE80211_FC0_SUBTYPE_BEACON &&
320 			    subtype != IEEE80211_FC0_SUBTYPE_PROBE_RESP) {
321 				ic->ic_stats.is_rx_mgtdiscard++;
322 				goto out;
323 			}
324 		} else {
325 			if (ic->ic_opmode != IEEE80211_M_IBSS &&
326 			    subtype == IEEE80211_FC0_SUBTYPE_BEACON) {
327 				ic->ic_stats.is_rx_mgtdiscard++;
328 				goto out;
329 			}
330 		}
331 
332 		if (ifp->if_flags & IFF_DEBUG) {
333 			/* avoid to print too many frames */
334 			int doprint = 0;
335 
336 			switch (subtype) {
337 			case IEEE80211_FC0_SUBTYPE_BEACON:
338 				if (ic->ic_state == IEEE80211_S_SCAN)
339 					doprint = 1;
340 				break;
341 			case IEEE80211_FC0_SUBTYPE_PROBE_REQ:
342 				if (ic->ic_opmode == IEEE80211_M_IBSS)
343 					doprint = 1;
344 				break;
345 			default:
346 				doprint = 1;
347 				break;
348 			}
349 #ifdef IEEE80211_DEBUG
350 			doprint += ieee80211_debug;
351 #endif
352 			if (doprint)
353 				if_printf(ifp, "received %s from %6D rssi %d\n",
354 				    ieee80211_mgt_subtype_name[subtype
355 				    >> IEEE80211_FC0_SUBTYPE_SHIFT],
356 				    wh->i_addr2, ":", rssi);
357 		}
358 #ifdef IEEE80211_RAWBPF
359 		if (ic->ic_rawbpf)
360 			bpf_mtap(ic->ic_rawbpf, m);
361 #endif
362 		(*ic->ic_recv_mgmt)(ic, m, ni, subtype, rssi, rstamp);
363 		m_freem(m);
364 		return;
365 
366 	case IEEE80211_FC0_TYPE_CTL:
367 		ic->ic_stats.is_rx_ctl++;
368 		goto out;
369 	default:
370 		IEEE80211_DPRINTF(("%s: bad type %x\n", __func__, type));
371 		/* should not come here */
372 		break;
373 	}
374   err:
375 	ifp->if_ierrors++;
376   out:
377 	if (m != NULL) {
378 #ifdef IEEE80211_RAWBPF
379 		if (ic->ic_rawbpf)
380 			bpf_mtap(ic->ic_rawbpf, m);
381 #endif
382 		m_freem(m);
383 	}
384 }
385 
386 struct mbuf *
387 ieee80211_decap(struct ifnet *ifp, struct mbuf *m)
388 {
389 	struct ether_header *eh;
390 	struct ieee80211_frame wh;
391 	struct llc *llc;
392 
393 	if (m->m_len < sizeof(wh) + sizeof(*llc)) {
394 		m = m_pullup(m, sizeof(wh) + sizeof(*llc));
395 		if (m == NULL)
396 			return NULL;
397 	}
398 	memcpy(&wh, mtod(m, caddr_t), sizeof(wh));
399 	llc = (struct llc *)(mtod(m, caddr_t) + sizeof(wh));
400 	if (llc->llc_dsap == LLC_SNAP_LSAP && llc->llc_ssap == LLC_SNAP_LSAP &&
401 	    llc->llc_control == LLC_UI && llc->llc_snap.org_code[0] == 0 &&
402 	    llc->llc_snap.org_code[1] == 0 && llc->llc_snap.org_code[2] == 0) {
403 		m_adj(m, sizeof(wh) + sizeof(struct llc) - sizeof(*eh));
404 		llc = NULL;
405 	} else {
406 		m_adj(m, sizeof(wh) - sizeof(*eh));
407 	}
408 	eh = mtod(m, struct ether_header *);
409 	switch (wh.i_fc[1] & IEEE80211_FC1_DIR_MASK) {
410 	case IEEE80211_FC1_DIR_NODS:
411 		IEEE80211_ADDR_COPY(eh->ether_dhost, wh.i_addr1);
412 		IEEE80211_ADDR_COPY(eh->ether_shost, wh.i_addr2);
413 		break;
414 	case IEEE80211_FC1_DIR_TODS:
415 		IEEE80211_ADDR_COPY(eh->ether_dhost, wh.i_addr3);
416 		IEEE80211_ADDR_COPY(eh->ether_shost, wh.i_addr2);
417 		break;
418 	case IEEE80211_FC1_DIR_FROMDS:
419 		IEEE80211_ADDR_COPY(eh->ether_dhost, wh.i_addr1);
420 		IEEE80211_ADDR_COPY(eh->ether_shost, wh.i_addr3);
421 		break;
422 	case IEEE80211_FC1_DIR_DSTODS:
423 		/* not yet supported */
424 		IEEE80211_DPRINTF(("%s: DS to DS\n", __func__));
425 		m_freem(m);
426 		return NULL;
427 	}
428 #ifdef ALIGNED_POINTER
429 	if (!ALIGNED_POINTER(mtod(m, caddr_t) + sizeof(*eh), uint32_t)) {
430 		struct mbuf *n, *n0, **np;
431 		caddr_t newdata;
432 		int off, pktlen;
433 
434 		n0 = NULL;
435 		np = &n0;
436 		off = 0;
437 		pktlen = m->m_pkthdr.len;
438 		while (pktlen > off) {
439 			if (n0 == NULL) {
440 				MGETHDR(n, MB_DONTWAIT, MT_DATA);
441 				if (n == NULL) {
442 					m_freem(m);
443 					return NULL;
444 				}
445 				M_MOVE_PKTHDR(n, m);
446 				n->m_len = MHLEN;
447 			} else {
448 				MGET(n, MB_DONTWAIT, MT_DATA);
449 				if (n == NULL) {
450 					m_freem(m);
451 					m_freem(n0);
452 					return NULL;
453 				}
454 				n->m_len = MLEN;
455 			}
456 			if (pktlen - off >= MINCLSIZE) {
457 				MCLGET(n, MB_DONTWAIT);
458 				if (n->m_flags & M_EXT)
459 					n->m_len = n->m_ext.ext_size;
460 			}
461 			if (n0 == NULL) {
462 				newdata =
463 				    (caddr_t)ALIGN(n->m_data + sizeof(*eh)) -
464 				    sizeof(*eh);
465 				n->m_len -= newdata - n->m_data;
466 				n->m_data = newdata;
467 			}
468 			if (n->m_len > pktlen - off)
469 				n->m_len = pktlen - off;
470 			m_copydata(m, off, n->m_len, mtod(n, caddr_t));
471 			off += n->m_len;
472 			*np = n;
473 			np = &n->m_next;
474 		}
475 		m_freem(m);
476 		m = n0;
477 	}
478 #endif /* ALIGNED_POINTER */
479 	if (llc != NULL) {
480 		eh = mtod(m, struct ether_header *);
481 		eh->ether_type = htons(m->m_pkthdr.len - sizeof(*eh));
482 	}
483 	return m;
484 }
485 
486 /*
487  * Install received rate set information in the node's state block.
488  */
489 static int
490 ieee80211_setup_rates(struct ieee80211com *ic, struct ieee80211_node *ni,
491 	uint8_t *rates, uint8_t *xrates, int flags)
492 {
493 	struct ieee80211_rateset *rs = &ni->ni_rates;
494 
495 	memset(rs, 0, sizeof(*rs));
496 	rs->rs_nrates = rates[1];
497 	memcpy(rs->rs_rates, rates + 2, rs->rs_nrates);
498 	if (xrates != NULL) {
499 		uint8_t nxrates;
500 		/*
501 		 * Tack on 11g extended supported rate element.
502 		 */
503 		nxrates = xrates[1];
504 		if (rs->rs_nrates + nxrates > IEEE80211_RATE_MAXSIZE) {
505 			nxrates = IEEE80211_RATE_MAXSIZE - rs->rs_nrates;
506 			IEEE80211_DPRINTF(("%s: extended rate set too large;"
507 				" only using %u of %u rates\n",
508 				__func__, nxrates, xrates[1]));
509 			ic->ic_stats.is_rx_rstoobig++;
510 		}
511 		memcpy(rs->rs_rates + rs->rs_nrates, xrates+2, nxrates);
512 		rs->rs_nrates += nxrates;
513 	}
514 	return ieee80211_fix_rate(ic, ni, flags);
515 }
516 
517 /* Verify the existence and length of __elem or get out. */
518 #define	IEEE80211_VERIFY_ELEMENT(__elem, __maxlen) do {			\
519 	if ((__elem) == NULL) {						\
520 		IEEE80211_DPRINTF(("%s: no " #__elem "in %s frame\n",	\
521 			__func__, ieee80211_mgt_subtype_name[subtype >>	\
522 				IEEE80211_FC0_SUBTYPE_SHIFT]));		\
523 		ic->ic_stats.is_rx_elem_missing++;			\
524 		return;							\
525 	}								\
526 	if ((__elem)[1] > (__maxlen)) {					\
527 		IEEE80211_DPRINTF(("%s: bad " #__elem " len %d in %s "	\
528 			"frame from %6D\n", __func__, (__elem)[1],	\
529 			ieee80211_mgt_subtype_name[subtype >>		\
530 				IEEE80211_FC0_SUBTYPE_SHIFT],		\
531 			wh->i_addr2, ":"));				\
532 		ic->ic_stats.is_rx_elem_toobig++;			\
533 		return;							\
534 	}								\
535 } while (0)
536 
537 #define	IEEE80211_VERIFY_LENGTH(_len, _minlen) do {			\
538 	if ((_len) < (_minlen)) {					\
539 		IEEE80211_DPRINTF(("%s: %s frame too short from %6D\n",	\
540 			__func__,					\
541 			ieee80211_mgt_subtype_name[subtype >>		\
542 				IEEE80211_FC0_SUBTYPE_SHIFT],		\
543 			wh->i_addr2, ":"));				\
544 		ic->ic_stats.is_rx_elem_toosmall++;			\
545 		return;							\
546 	}								\
547 } while (0)
548 
549 void
550 ieee80211_recv_mgmt(struct ieee80211com *ic, struct mbuf *m0,
551 	struct ieee80211_node *ni,
552 	int subtype, int rssi, uint32_t rstamp)
553 {
554 	struct ifnet *ifp = &ic->ic_if;
555 	struct ieee80211_frame *wh;
556 	uint8_t *frm, *efrm;
557 	uint8_t *ssid, *rates, *xrates;
558 	int reassoc, resp, newassoc, allocbs;
559 
560 	wh = mtod(m0, struct ieee80211_frame *);
561 	frm = (uint8_t *)&wh[1];
562 	efrm = mtod(m0, uint8_t *) + m0->m_len;
563 	switch (subtype) {
564 	case IEEE80211_FC0_SUBTYPE_PROBE_RESP:
565 	case IEEE80211_FC0_SUBTYPE_BEACON: {
566 		uint8_t *tstamp, *bintval, *capinfo, *country;
567 		uint8_t chan, bchan, fhindex, erp;
568 		uint16_t fhdwell;
569 		int isprobe;
570 
571 		if (ic->ic_opmode != IEEE80211_M_IBSS &&
572 		    ic->ic_state != IEEE80211_S_SCAN) {
573 			/* XXX: may be useful for background scan */
574 			return;
575 		}
576 		isprobe = (subtype == IEEE80211_FC0_SUBTYPE_PROBE_RESP);
577 
578 		/*
579 		 * beacon/probe response frame format
580 		 *	[8] time stamp
581 		 *	[2] beacon interval
582 		 *	[2] capability information
583 		 *	[tlv] ssid
584 		 *	[tlv] supported rates
585 		 *	[tlv] country information
586 		 *	[tlv] parameter set (FH/DS)
587 		 *	[tlv] erp information
588 		 *	[tlv] extended supported rates
589 		 */
590 		IEEE80211_VERIFY_LENGTH(efrm - frm, 12);
591 		tstamp  = frm;	frm += 8;
592 		bintval = frm;	frm += 2;
593 		capinfo = frm;	frm += 2;
594 		ssid = rates = xrates = country = NULL;
595 		bchan = ieee80211_chan2ieee(ic, ic->ic_bss->ni_chan);
596 		chan = bchan;
597 		fhdwell = 0;
598 		fhindex = 0;
599 		erp = 0;
600 		while (frm < efrm) {
601 			switch (*frm) {
602 			case IEEE80211_ELEMID_SSID:
603 				ssid = frm;
604 				break;
605 			case IEEE80211_ELEMID_RATES:
606 				rates = frm;
607 				break;
608 			case IEEE80211_ELEMID_COUNTRY:
609 				country = frm;
610 				break;
611 			case IEEE80211_ELEMID_FHPARMS:
612 				if (ic->ic_phytype == IEEE80211_T_FH) {
613 					fhdwell = (frm[3] << 8) | frm[2];
614 					chan = IEEE80211_FH_CHAN(frm[4], frm[5]);
615 					fhindex = frm[6];
616 				}
617 				break;
618 			case IEEE80211_ELEMID_DSPARMS:
619 				/*
620 				 * XXX hack this since depending on phytype
621 				 * is problematic for multi-mode devices.
622 				 */
623 				if (ic->ic_phytype != IEEE80211_T_FH)
624 					chan = frm[2];
625 				break;
626 			case IEEE80211_ELEMID_TIM:
627 				break;
628 			case IEEE80211_ELEMID_IBSSPARMS:
629 				break;
630 			case IEEE80211_ELEMID_XRATES:
631 				xrates = frm;
632 				break;
633 			case IEEE80211_ELEMID_ERP:
634 				if (frm[1] != 1) {
635 					IEEE80211_DPRINTF(("%s: invalid ERP "
636 						"element; length %u, expecting "
637 						"1\n", __func__, frm[1]));
638 					ic->ic_stats.is_rx_elem_toobig++;
639 					break;
640 				}
641 				erp = frm[2];
642 				break;
643 			default:
644 				IEEE80211_DPRINTF2(("%s: element id %u/len %u "
645 					"ignored\n", __func__, *frm, frm[1]));
646 				ic->ic_stats.is_rx_elem_unknown++;
647 				break;
648 			}
649 			frm += frm[1] + 2;
650 		}
651 		IEEE80211_VERIFY_ELEMENT(rates, IEEE80211_RATE_MAXSIZE);
652 		IEEE80211_VERIFY_ELEMENT(ssid, IEEE80211_NWID_LEN);
653 		if (
654 #if IEEE80211_CHAN_MAX < 255
655 		    chan > IEEE80211_CHAN_MAX ||
656 #endif
657 		    isclr(ic->ic_chan_active, chan)) {
658 			IEEE80211_DPRINTF(("%s: ignore %s with invalid channel "
659 				"%u\n", __func__,
660 				isprobe ? "probe response" : "beacon",
661 				chan));
662 			ic->ic_stats.is_rx_badchan++;
663 			return;
664 		}
665 		if (chan != bchan && ic->ic_phytype != IEEE80211_T_FH) {
666 			/*
667 			 * Frame was received on a channel different from the
668 			 * one indicated in the DS params element id;
669 			 * silently discard it.
670 			 *
671 			 * NB: this can happen due to signal leakage.
672 			 *     But we should take it for FH phy because
673 			 *     the rssi value should be correct even for
674 			 *     different hop pattern in FH.
675 			 */
676 			IEEE80211_DPRINTF(("%s: ignore %s on channel %u marked "
677 				"for channel %u\n", __func__,
678 				isprobe ? "probe response" : "beacon",
679 				bchan, chan));
680 			ic->ic_stats.is_rx_chanmismatch++;
681 			return;
682 		}
683 
684 		/*
685 		 * Use mac and channel for lookup so we collect all
686 		 * potential AP's when scanning.  Otherwise we may
687 		 * see the same AP on multiple channels and will only
688 		 * record the last one.  We could filter APs here based
689 		 * on rssi, etc. but leave that to the end of the scan
690 		 * so we can keep the selection criteria in one spot.
691 		 * This may result in a bloat of the scanned AP list but
692 		 * it shouldn't be too much.
693 		 */
694 		ni = ieee80211_lookup_node(ic, wh->i_addr2,
695 				&ic->ic_channels[chan]);
696 #ifdef IEEE80211_DEBUG
697 		if (ieee80211_debug &&
698 		    (ni == NULL || ic->ic_state == IEEE80211_S_SCAN)) {
699 			printf("%s: %s%s on chan %u (bss chan %u) ",
700 			    __func__, (ni == NULL ? "new " : ""),
701 			    isprobe ? "probe response" : "beacon",
702 			    chan, bchan);
703 			ieee80211_print_essid(ssid + 2, ssid[1]);
704 			printf(" from %6D\n", wh->i_addr2, ":");
705 			printf("%s: caps 0x%x bintval %u erp 0x%x\n",
706 				__func__, le16toh(*(uint16_t *)capinfo),
707 				le16toh(*(uint16_t *)bintval), erp);
708 			if (country)
709 				printf("%s: country info %*D\n",
710 					__func__, country[1], country+2, " ");
711 		}
712 #endif
713 		if (ni == NULL) {
714 			ni = ieee80211_alloc_node(ic, wh->i_addr2);
715 			if (ni == NULL)
716 				return;
717 			ni->ni_esslen = ssid[1];
718 			memset(ni->ni_essid, 0, sizeof(ni->ni_essid));
719 			memcpy(ni->ni_essid, ssid + 2, ssid[1]);
720 			allocbs = 1;
721 		} else if (ssid[1] != 0 && isprobe) {
722 			/*
723 			 * Update ESSID at probe response to adopt hidden AP by
724 			 * Lucent/Cisco, which announces null ESSID in beacon.
725 			 */
726 			ni->ni_esslen = ssid[1];
727 			memset(ni->ni_essid, 0, sizeof(ni->ni_essid));
728 			memcpy(ni->ni_essid, ssid + 2, ssid[1]);
729 			allocbs = 0;
730 		} else
731 			allocbs = 0;
732 		IEEE80211_ADDR_COPY(ni->ni_bssid, wh->i_addr3);
733 		ni->ni_rssi = rssi;
734 		ni->ni_rstamp = rstamp;
735 		memcpy(ni->ni_tstamp, tstamp, sizeof(ni->ni_tstamp));
736 		ni->ni_intval = le16toh(*(uint16_t *)bintval);
737 		ni->ni_capinfo = le16toh(*(uint16_t *)capinfo);
738 		/* XXX validate channel # */
739 		ni->ni_chan = &ic->ic_channels[chan];
740 		ni->ni_fhdwell = fhdwell;
741 		ni->ni_fhindex = fhindex;
742 		ni->ni_erp = erp;
743 		/* NB: must be after ni_chan is setup */
744 		ieee80211_setup_rates(ic, ni, rates, xrates, IEEE80211_F_DOSORT);
745 		/*
746 		 * When scanning we record results (nodes) with a zero
747 		 * refcnt.  Otherwise we want to hold the reference for
748 		 * ibss neighbors so the nodes don't get released prematurely.
749 		 * Anything else can be discarded (XXX and should be handled
750 		 * above so we don't do so much work).
751 		 */
752 		if (ic->ic_state == IEEE80211_S_SCAN)
753 			ieee80211_unref_node(&ni);	/* NB: do not free */
754 		else if (ic->ic_opmode == IEEE80211_M_IBSS &&
755 		    allocbs && isprobe) {
756 			/*
757 			 * Fake an association so the driver can setup it's
758 			 * private state.  The rate set has been setup above;
759 			 * there is no handshake as in ap/station operation.
760 			 */
761 			if (ic->ic_newassoc)
762 				(*ic->ic_newassoc)(ic, ni, 1);
763 			/* NB: hold reference */
764 		} else {
765 			/* XXX optimize to avoid work done above */
766 			ieee80211_free_node(ic, ni);
767 		}
768 		break;
769 	}
770 
771 	case IEEE80211_FC0_SUBTYPE_PROBE_REQ: {
772 		uint8_t rate;
773 
774 		if (ic->ic_opmode == IEEE80211_M_STA)
775 			return;
776 		if (ic->ic_state != IEEE80211_S_RUN)
777 			return;
778 
779 		/*
780 		 * prreq frame format
781 		 *	[tlv] ssid
782 		 *	[tlv] supported rates
783 		 *	[tlv] extended supported rates
784 		 */
785 		ssid = rates = xrates = NULL;
786 		while (frm < efrm) {
787 			switch (*frm) {
788 			case IEEE80211_ELEMID_SSID:
789 				ssid = frm;
790 				break;
791 			case IEEE80211_ELEMID_RATES:
792 				rates = frm;
793 				break;
794 			case IEEE80211_ELEMID_XRATES:
795 				xrates = frm;
796 				break;
797 			}
798 			frm += frm[1] + 2;
799 		}
800 		IEEE80211_VERIFY_ELEMENT(rates, IEEE80211_RATE_MAXSIZE);
801 		IEEE80211_VERIFY_ELEMENT(ssid, IEEE80211_NWID_LEN);
802 		if (ssid[1] != 0 &&
803 		    (ssid[1] != ic->ic_bss->ni_esslen ||
804 		    memcmp(ssid + 2, ic->ic_bss->ni_essid, ic->ic_bss->ni_esslen) != 0)) {
805 #ifdef IEEE80211_DEBUG
806 			if (ieee80211_debug) {
807 				printf("%s: ssid unmatch ", __func__);
808 				ieee80211_print_essid(ssid + 2, ssid[1]);
809 				printf(" from %6D\n", wh->i_addr2, ":");
810 			}
811 #endif
812 			ic->ic_stats.is_rx_ssidmismatch++;
813 			return;
814 		}
815 
816 		if (ni == ic->ic_bss) {
817 			ni = ieee80211_dup_bss(ic, wh->i_addr2);
818 			if (ni == NULL)
819 				return;
820 			IEEE80211_DPRINTF(("%s: new req from %6D\n",
821 				__func__, wh->i_addr2, ":"));
822 			allocbs = 1;
823 		} else
824 			allocbs = 0;
825 		ni->ni_rssi = rssi;
826 		ni->ni_rstamp = rstamp;
827 		rate = ieee80211_setup_rates(ic, ni, rates, xrates,
828 				IEEE80211_F_DOSORT | IEEE80211_F_DOFRATE
829 				| IEEE80211_F_DONEGO | IEEE80211_F_DODEL);
830 		if (rate & IEEE80211_RATE_BASIC) {
831 			IEEE80211_DPRINTF(("%s: rate negotiation failed: %6D\n",
832 				__func__, wh->i_addr2, ":"));
833 		} else {
834 			IEEE80211_SEND_MGMT(ic, ni,
835 				IEEE80211_FC0_SUBTYPE_PROBE_RESP, 0);
836 		}
837 		if (allocbs)
838 			ieee80211_free_node(ic, ni);
839 		break;
840 	}
841 
842 	case IEEE80211_FC0_SUBTYPE_AUTH: {
843 		uint16_t algo, seq, status;
844 		/*
845 		 * auth frame format
846 		 *	[2] algorithm
847 		 *	[2] sequence
848 		 *	[2] status
849 		 *	[tlv*] challenge
850 		 */
851 		IEEE80211_VERIFY_LENGTH(efrm - frm, 6);
852 		algo   = le16toh(*(uint16_t *)frm);
853 		seq    = le16toh(*(uint16_t *)(frm + 2));
854 		status = le16toh(*(uint16_t *)(frm + 4));
855 		if (algo != IEEE80211_AUTH_ALG_OPEN) {
856 			/* TODO: shared key auth */
857 			IEEE80211_DPRINTF(("%s: unsupported auth %d from %6D\n",
858 				__func__, algo, wh->i_addr2, ":"));
859 			ic->ic_stats.is_rx_auth_unsupported++;
860 			return;
861 		}
862 		switch (ic->ic_opmode) {
863 		case IEEE80211_M_IBSS:
864 			if (ic->ic_state != IEEE80211_S_RUN || seq != 1) {
865 				IEEE80211_DPRINTF(("%s: discard auth from %6D; "
866 					"state %u, seq %u\n", __func__,
867 					wh->i_addr2, ":",
868 					ic->ic_state, seq));
869 				ic->ic_stats.is_rx_bad_auth++;
870 				break;
871 			}
872 			ieee80211_new_state(ic, IEEE80211_S_AUTH,
873 			    wh->i_fc[0] & IEEE80211_FC0_SUBTYPE_MASK);
874 			break;
875 
876 		case IEEE80211_M_AHDEMO:
877 			/* should not come here */
878 			break;
879 
880 		case IEEE80211_M_HOSTAP:
881 			if (ic->ic_state != IEEE80211_S_RUN || seq != 1) {
882 				IEEE80211_DPRINTF(("%s: discard auth from %6D; "
883 					"state %u, seq %u\n", __func__,
884 					wh->i_addr2, ":",
885 					ic->ic_state, seq));
886 				ic->ic_stats.is_rx_bad_auth++;
887 				break;
888 			}
889 			if (ni == ic->ic_bss) {
890 				ni = ieee80211_alloc_node(ic, wh->i_addr2);
891 				if (ni == NULL)
892 					return;
893 				IEEE80211_ADDR_COPY(ni->ni_bssid, ic->ic_bss->ni_bssid);
894 				ni->ni_rssi = rssi;
895 				ni->ni_rstamp = rstamp;
896 				ni->ni_chan = ic->ic_bss->ni_chan;
897 				allocbs = 1;
898 			} else
899 				allocbs = 0;
900 			IEEE80211_SEND_MGMT(ic, ni,
901 				IEEE80211_FC0_SUBTYPE_AUTH, 2);
902 			if (ifp->if_flags & IFF_DEBUG)
903 				if_printf(ifp, "station %6D %s authenticated\n",
904 				    ni->ni_macaddr, ":",
905 				    (allocbs ? "newly" : "already"));
906 			break;
907 
908 		case IEEE80211_M_STA:
909 			if (ic->ic_state != IEEE80211_S_AUTH || seq != 2) {
910 				IEEE80211_DPRINTF(("%s: discard auth from %6D; "
911 					"state %u, seq %u\n", __func__,
912 					wh->i_addr2, ":",
913 					ic->ic_state, seq));
914 				ic->ic_stats.is_rx_bad_auth++;
915 				break;
916 			}
917 			if (status != 0) {
918 				if_printf(&ic->ic_if,
919 				    "authentication failed (reason %d) for %6D\n",
920 				    status,
921 				    wh->i_addr3, ":");
922 				if (ni != ic->ic_bss)
923 					ni->ni_fails++;
924 				ic->ic_stats.is_rx_auth_fail++;
925 				return;
926 			}
927 			ieee80211_new_state(ic, IEEE80211_S_ASSOC,
928 			    wh->i_fc[0] & IEEE80211_FC0_SUBTYPE_MASK);
929 			break;
930 		case IEEE80211_M_MONITOR:
931 			break;
932 		}
933 		break;
934 	}
935 
936 	case IEEE80211_FC0_SUBTYPE_ASSOC_REQ:
937 	case IEEE80211_FC0_SUBTYPE_REASSOC_REQ: {
938 		uint16_t capinfo, bintval;
939 
940 		if (ic->ic_opmode != IEEE80211_M_HOSTAP ||
941 		    (ic->ic_state != IEEE80211_S_RUN))
942 			return;
943 
944 		if (subtype == IEEE80211_FC0_SUBTYPE_REASSOC_REQ) {
945 			reassoc = 1;
946 			resp = IEEE80211_FC0_SUBTYPE_REASSOC_RESP;
947 		} else {
948 			reassoc = 0;
949 			resp = IEEE80211_FC0_SUBTYPE_ASSOC_RESP;
950 		}
951 		/*
952 		 * asreq frame format
953 		 *	[2] capability information
954 		 *	[2] listen interval
955 		 *	[6*] current AP address (reassoc only)
956 		 *	[tlv] ssid
957 		 *	[tlv] supported rates
958 		 *	[tlv] extended supported rates
959 		 */
960 		IEEE80211_VERIFY_LENGTH(efrm - frm, (reassoc ? 10 : 4));
961 		if (!IEEE80211_ADDR_EQ(wh->i_addr3, ic->ic_bss->ni_bssid)) {
962 			IEEE80211_DPRINTF(("%s: ignore other bss from %6D\n",
963 				__func__, wh->i_addr2, ":"));
964 			ic->ic_stats.is_rx_assoc_bss++;
965 			return;
966 		}
967 		capinfo = le16toh(*(uint16_t *)frm);	frm += 2;
968 		bintval = le16toh(*(uint16_t *)frm);	frm += 2;
969 		if (reassoc)
970 			frm += 6;	/* ignore current AP info */
971 		ssid = rates = xrates = NULL;
972 		while (frm < efrm) {
973 			switch (*frm) {
974 			case IEEE80211_ELEMID_SSID:
975 				ssid = frm;
976 				break;
977 			case IEEE80211_ELEMID_RATES:
978 				rates = frm;
979 				break;
980 			case IEEE80211_ELEMID_XRATES:
981 				xrates = frm;
982 				break;
983 			}
984 			frm += frm[1] + 2;
985 		}
986 		IEEE80211_VERIFY_ELEMENT(rates, IEEE80211_RATE_MAXSIZE);
987 		IEEE80211_VERIFY_ELEMENT(ssid, IEEE80211_NWID_LEN);
988 		if (ssid[1] != ic->ic_bss->ni_esslen ||
989 		    memcmp(ssid + 2, ic->ic_bss->ni_essid, ssid[1]) != 0) {
990 #ifdef IEEE80211_DEBUG
991 			if (ieee80211_debug) {
992 				printf("%s: ssid unmatch ", __func__);
993 				ieee80211_print_essid(ssid + 2, ssid[1]);
994 				printf(" from %6D\n", wh->i_addr2, ":");
995 			}
996 #endif
997 			ic->ic_stats.is_rx_ssidmismatch++;
998 			return;
999 		}
1000 		if (ni == ic->ic_bss) {
1001 			IEEE80211_DPRINTF(("%s: not authenticated for %6D\n",
1002 				__func__, wh->i_addr2, ":"));
1003 			ni = ieee80211_dup_bss(ic, wh->i_addr2);
1004 			if (ni != NULL) {
1005 				IEEE80211_SEND_MGMT(ic, ni,
1006 				    IEEE80211_FC0_SUBTYPE_DEAUTH,
1007 				    IEEE80211_REASON_ASSOC_NOT_AUTHED);
1008 				ieee80211_free_node(ic, ni);
1009 			}
1010 			ic->ic_stats.is_rx_assoc_notauth++;
1011 			return;
1012 		}
1013 		/* XXX per-node cipher suite */
1014 		/* XXX some stations use the privacy bit for handling APs
1015 		       that suport both encrypted and unencrypted traffic */
1016 		if ((capinfo & IEEE80211_CAPINFO_ESS) == 0 ||
1017 		    (capinfo & IEEE80211_CAPINFO_PRIVACY) !=
1018 		    ((ic->ic_flags & IEEE80211_F_WEPON) ?
1019 		     IEEE80211_CAPINFO_PRIVACY : 0)) {
1020 			IEEE80211_DPRINTF(("%s: capability mismatch %x for %6D\n",
1021 				__func__, capinfo, wh->i_addr2, ":"));
1022 			ni->ni_associd = 0;
1023 			IEEE80211_SEND_MGMT(ic, ni, resp,
1024 				IEEE80211_STATUS_CAPINFO);
1025 			ic->ic_stats.is_rx_assoc_capmismatch++;
1026 			return;
1027 		}
1028 		ieee80211_setup_rates(ic, ni, rates, xrates,
1029 				IEEE80211_F_DOSORT | IEEE80211_F_DOFRATE |
1030 				IEEE80211_F_DONEGO | IEEE80211_F_DODEL);
1031 		if (ni->ni_rates.rs_nrates == 0) {
1032 			IEEE80211_DPRINTF(("%s: rate unmatch for %6D\n",
1033 				__func__, wh->i_addr2, ":"));
1034 			ni->ni_associd = 0;
1035 			IEEE80211_SEND_MGMT(ic, ni, resp,
1036 				IEEE80211_STATUS_BASIC_RATE);
1037 			ic->ic_stats.is_rx_assoc_norate++;
1038 			return;
1039 		}
1040 		ni->ni_rssi = rssi;
1041 		ni->ni_rstamp = rstamp;
1042 		ni->ni_intval = bintval;
1043 		ni->ni_capinfo = capinfo;
1044 		ni->ni_chan = ic->ic_bss->ni_chan;
1045 		ni->ni_fhdwell = ic->ic_bss->ni_fhdwell;
1046 		ni->ni_fhindex = ic->ic_bss->ni_fhindex;
1047 		if (ni->ni_associd == 0) {
1048 			/* XXX handle rollover at 2007 */
1049 			/* XXX guarantee uniqueness */
1050 			ni->ni_associd = 0xc000 | ic->ic_bss->ni_associd++;
1051 			newassoc = 1;
1052 		} else
1053 			newassoc = 0;
1054 		/* XXX for 11g must turn off short slot time if long
1055 	           slot time sta associates */
1056 		IEEE80211_SEND_MGMT(ic, ni, resp, IEEE80211_STATUS_SUCCESS);
1057 		if (ifp->if_flags & IFF_DEBUG)
1058 			if_printf(ifp, "station %6D %s associated\n",
1059 			    ni->ni_macaddr, ":",
1060 			    (newassoc ? "newly" : "already"));
1061 		/* give driver a chance to setup state like ni_txrate */
1062 		if (ic->ic_newassoc)
1063 			(*ic->ic_newassoc)(ic, ni, newassoc);
1064 		break;
1065 	}
1066 
1067 	case IEEE80211_FC0_SUBTYPE_ASSOC_RESP:
1068 	case IEEE80211_FC0_SUBTYPE_REASSOC_RESP: {
1069 		uint16_t status;
1070 
1071 		if (ic->ic_opmode != IEEE80211_M_STA ||
1072 		    ic->ic_state != IEEE80211_S_ASSOC)
1073 			return;
1074 
1075 		/*
1076 		 * asresp frame format
1077 		 *	[2] capability information
1078 		 *	[2] status
1079 		 *	[2] association ID
1080 		 *	[tlv] supported rates
1081 		 *	[tlv] extended supported rates
1082 		 */
1083 		IEEE80211_VERIFY_LENGTH(efrm - frm, 6);
1084 		ni = ic->ic_bss;
1085 		ni->ni_capinfo = le16toh(*(uint16_t *)frm);
1086 		frm += 2;
1087 
1088 		status = le16toh(*(uint16_t *)frm);
1089 		frm += 2;
1090 		if (status != 0) {
1091 			if_printf(ifp, "association failed (reason %d) for %6D\n",
1092 			    status, wh->i_addr3, ":");
1093 			if (ni != ic->ic_bss)
1094 				ni->ni_fails++;
1095 			ic->ic_stats.is_rx_auth_fail++;
1096 			return;
1097 		}
1098 		ni->ni_associd = le16toh(*(uint16_t *)frm);
1099 		frm += 2;
1100 
1101 		rates = xrates = NULL;
1102 		while (frm < efrm) {
1103 			switch (*frm) {
1104 			case IEEE80211_ELEMID_RATES:
1105 				rates = frm;
1106 				break;
1107 			case IEEE80211_ELEMID_XRATES:
1108 				xrates = frm;
1109 				break;
1110 			}
1111 			frm += frm[1] + 2;
1112 		}
1113 
1114 		IEEE80211_VERIFY_ELEMENT(rates, IEEE80211_RATE_MAXSIZE);
1115 		ieee80211_setup_rates(ic, ni, rates, xrates,
1116 				IEEE80211_F_DOSORT | IEEE80211_F_DOFRATE |
1117 				IEEE80211_F_DONEGO | IEEE80211_F_DODEL);
1118 		if (ni->ni_rates.rs_nrates != 0)
1119 			ieee80211_new_state(ic, IEEE80211_S_RUN,
1120 				wh->i_fc[0] & IEEE80211_FC0_SUBTYPE_MASK);
1121 		break;
1122 	}
1123 
1124 	case IEEE80211_FC0_SUBTYPE_DEAUTH: {
1125 		uint16_t reason;
1126 		/*
1127 		 * deauth frame format
1128 		 *	[2] reason
1129 		 */
1130 		IEEE80211_VERIFY_LENGTH(efrm - frm, 2);
1131 		reason = le16toh(*(uint16_t *)frm);
1132 		ic->ic_stats.is_rx_deauth++;
1133 		switch (ic->ic_opmode) {
1134 		case IEEE80211_M_STA:
1135 			ieee80211_new_state(ic, IEEE80211_S_AUTH,
1136 			    wh->i_fc[0] & IEEE80211_FC0_SUBTYPE_MASK);
1137 			break;
1138 		case IEEE80211_M_HOSTAP:
1139 			if (ni != ic->ic_bss) {
1140 				if (ifp->if_flags & IFF_DEBUG)
1141 					if_printf(ifp, "station %6D deauthenticated"
1142 					    " by peer (reason %d)\n",
1143 					    ni->ni_macaddr, ":", reason);
1144 				/* node will be free'd on return */
1145 				ieee80211_unref_node(&ni);
1146 			}
1147 			break;
1148 		default:
1149 			break;
1150 		}
1151 		break;
1152 	}
1153 
1154 	case IEEE80211_FC0_SUBTYPE_DISASSOC: {
1155 		uint16_t reason;
1156 		/*
1157 		 * disassoc frame format
1158 		 *	[2] reason
1159 		 */
1160 		IEEE80211_VERIFY_LENGTH(efrm - frm, 2);
1161 		reason = le16toh(*(uint16_t *)frm);
1162 		ic->ic_stats.is_rx_disassoc++;
1163 		switch (ic->ic_opmode) {
1164 		case IEEE80211_M_STA:
1165 			ieee80211_new_state(ic, IEEE80211_S_ASSOC,
1166 			    wh->i_fc[0] & IEEE80211_FC0_SUBTYPE_MASK);
1167 			break;
1168 		case IEEE80211_M_HOSTAP:
1169 			if (ni != ic->ic_bss) {
1170 				if (ifp->if_flags & IFF_DEBUG)
1171 					if_printf(ifp, "station %6D disassociated"
1172 					    " by peer (reason %d)\n",
1173 					    ni->ni_macaddr, ":", reason);
1174 				ni->ni_associd = 0;
1175 				/* XXX node reclaimed how? */
1176 			}
1177 			break;
1178 		default:
1179 			break;
1180 		}
1181 		break;
1182 	}
1183 	default:
1184 		IEEE80211_DPRINTF(("%s: mgmt frame with subtype 0x%x not "
1185 			"handled\n", __func__, subtype));
1186 		ic->ic_stats.is_rx_badsubtype++;
1187 		break;
1188 	}
1189 }
1190 #undef IEEE80211_VERIFY_LENGTH
1191 #undef IEEE80211_VERIFY_ELEMENT
1192