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