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