Merge from vendor branch BIND:
[dragonfly.git] / sys / netproto / 802_11 / wlan / ieee80211_input.c
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