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