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