Module Name: src Committed By: maxv Date: Tue Jan 16 15:42:52 UTC 2018
Modified Files: src/sys/net80211: ieee80211_input.c Log Message: Start splitting ieee80211_recv_mgmt. To generate a diff of this commit: cvs rdiff -u -r1.97 -r1.98 src/sys/net80211/ieee80211_input.c Please note that diffs are not public domain; they are subject to the copyright notices on the relevant files.
Modified files: Index: src/sys/net80211/ieee80211_input.c diff -u src/sys/net80211/ieee80211_input.c:1.97 src/sys/net80211/ieee80211_input.c:1.98 --- src/sys/net80211/ieee80211_input.c:1.97 Tue Jan 16 15:18:37 2018 +++ src/sys/net80211/ieee80211_input.c Tue Jan 16 15:42:52 2018 @@ -1,4 +1,4 @@ -/* $NetBSD: ieee80211_input.c,v 1.97 2018/01/16 15:18:37 maxv Exp $ */ +/* $NetBSD: ieee80211_input.c,v 1.98 2018/01/16 15:42:52 maxv Exp $ */ /* * Copyright (c) 2001 Atsushi Onoe @@ -37,7 +37,7 @@ __FBSDID("$FreeBSD: src/sys/net80211/ieee80211_input.c,v 1.81 2005/08/10 16:22:29 sam Exp $"); #endif #ifdef __NetBSD__ -__KERNEL_RCSID(0, "$NetBSD: ieee80211_input.c,v 1.97 2018/01/16 15:18:37 maxv Exp $"); +__KERNEL_RCSID(0, "$NetBSD: ieee80211_input.c,v 1.98 2018/01/16 15:42:52 maxv Exp $"); #endif #ifdef _KERNEL_OPT @@ -2001,369 +2001,403 @@ ieee80211_update_adhoc_node(struct ieee8 } } -void -ieee80211_recv_mgmt(struct ieee80211com *ic, struct mbuf *m0, +/* -------------------------------------------------------------------------- */ + +static void +ieee80211_recv_mgmt_beacon(struct ieee80211com *ic, struct mbuf *m0, struct ieee80211_node *ni, int subtype, int rssi, u_int32_t rstamp) { -#define ISPROBE(_st) ((_st) == IEEE80211_FC0_SUBTYPE_PROBE_RESP) -#define ISREASSOC(_st) ((_st) == IEEE80211_FC0_SUBTYPE_REASSOC_RESP) struct ieee80211_frame *wh; u_int8_t *frm, *efrm; - u_int8_t *ssid, *rates, *xrates, *wpa, *wme; - int reassoc, resp, allocbs; - u_int8_t rate; IEEE80211_DEBUGVAR(char ebuf[3 * ETHER_ADDR_LEN]); + struct ieee80211_scanparams scan; wh = mtod(m0, struct ieee80211_frame *); frm = (u_int8_t *)(wh + 1); efrm = mtod(m0, u_int8_t *) + m0->m_len; - switch (subtype) { - case IEEE80211_FC0_SUBTYPE_PROBE_RESP: - case IEEE80211_FC0_SUBTYPE_BEACON: { - struct ieee80211_scanparams scan; - - /* - * We process beacon/probe response frames: - * o when scanning, or - * o station mode when associated (to collect state - * updates such as 802.11g slot time), or - * o adhoc mode (to discover neighbors) - * Frames otherwise received are discarded. - */ - if (!((ic->ic_flags & IEEE80211_F_SCAN) || - (ic->ic_opmode == IEEE80211_M_STA && ni->ni_associd) || - ic->ic_opmode == IEEE80211_M_IBSS)) { - ic->ic_stats.is_rx_mgtdiscard++; - return; - } - - /* - * beacon/probe response frame format - * [8] time stamp - * [2] beacon interval - * [2] capability information - * [tlv] ssid - * [tlv] supported rates - * [tlv] country information - * [tlv] parameter set (FH/DS) - * [tlv] erp information - * [tlv] extended supported rates - * [tlv] WME - * [tlv] WPA or RSN - */ - IEEE80211_VERIFY_LENGTH(efrm - frm, 12); - memset(&scan, 0, sizeof(scan)); - scan.tstamp = frm; frm += 8; - scan.bintval = le16toh(*(u_int16_t *)frm); frm += 2; - scan.capinfo = le16toh(*(u_int16_t *)frm); frm += 2; - scan.bchan = ieee80211_chan2ieee(ic, ic->ic_curchan); - scan.chan = scan.bchan; - - while (frm + 1 < efrm) { - IEEE80211_VERIFY_LENGTH(efrm - frm, frm[1] + 2); + /* + * We process beacon/probe response frames: + * o when scanning, or + * o station mode when associated (to collect state + * updates such as 802.11g slot time), or + * o adhoc mode (to discover neighbors) + * Frames otherwise received are discarded. + */ + if (!((ic->ic_flags & IEEE80211_F_SCAN) || + (ic->ic_opmode == IEEE80211_M_STA && ni->ni_associd) || + ic->ic_opmode == IEEE80211_M_IBSS)) { + ic->ic_stats.is_rx_mgtdiscard++; + return; + } - switch (*frm) { - case IEEE80211_ELEMID_SSID: - scan.ssid = frm; - break; - case IEEE80211_ELEMID_RATES: - scan.rates = frm; - break; - case IEEE80211_ELEMID_COUNTRY: - scan.country = frm; - break; - case IEEE80211_ELEMID_FHPARMS: - IEEE80211_VERIFY_LENGTH(frm[1], 5); - if (ic->ic_phytype == IEEE80211_T_FH) { - scan.fhdwell = LE_READ_2(&frm[2]); - scan.chan = IEEE80211_FH_CHAN(frm[4], frm[5]); - scan.fhindex = frm[6]; - } - break; - case IEEE80211_ELEMID_DSPARMS: - /* - * XXX hack this since depending on phytype - * is problematic for multi-mode devices. - */ - IEEE80211_VERIFY_LENGTH(frm[1], 1); - if (ic->ic_phytype != IEEE80211_T_FH) - scan.chan = frm[2]; - break; - case IEEE80211_ELEMID_TIM: - /* XXX ATIM? */ - IEEE80211_VERIFY_LENGTH(frm[1], 5); - scan.tim = frm; - scan.timoff = frm - mtod(m0, u_int8_t *); - break; - case IEEE80211_ELEMID_IBSSPARMS: - break; - case IEEE80211_ELEMID_XRATES: - scan.xrates = frm; - break; - case IEEE80211_ELEMID_ERP: - if (frm[1] != 1) { - IEEE80211_DISCARD_IE(ic, - IEEE80211_MSG_ELEMID, wh, "ERP", - "bad len %u", frm[1]); - ic->ic_stats.is_rx_elem_toobig++; - break; - } - scan.erp = frm[2]; - break; - case IEEE80211_ELEMID_RSN: - scan.wpa = frm; - break; - case IEEE80211_ELEMID_VENDOR: - if (iswpaoui(frm)) - scan.wpa = frm; - else if (iswmeparam(frm) || iswmeinfo(frm)) - scan.wme = frm; - /* XXX Atheros OUI support */ - break; - default: - IEEE80211_DISCARD_IE(ic, IEEE80211_MSG_ELEMID, - wh, "unhandled", - "id %u, len %u", *frm, frm[1]); - ic->ic_stats.is_rx_elem_unknown++; + /* + * beacon/probe response frame format + * [8] time stamp + * [2] beacon interval + * [2] capability information + * [tlv] ssid + * [tlv] supported rates + * [tlv] country information + * [tlv] parameter set (FH/DS) + * [tlv] erp information + * [tlv] extended supported rates + * [tlv] WME + * [tlv] WPA or RSN + */ + IEEE80211_VERIFY_LENGTH(efrm - frm, 12); + memset(&scan, 0, sizeof(scan)); + scan.tstamp = frm; frm += 8; + scan.bintval = le16toh(*(u_int16_t *)frm); frm += 2; + scan.capinfo = le16toh(*(u_int16_t *)frm); frm += 2; + scan.bchan = ieee80211_chan2ieee(ic, ic->ic_curchan); + scan.chan = scan.bchan; + + while (frm + 1 < efrm) { + IEEE80211_VERIFY_LENGTH(efrm - frm, frm[1] + 2); + + switch (*frm) { + case IEEE80211_ELEMID_SSID: + scan.ssid = frm; + break; + case IEEE80211_ELEMID_RATES: + scan.rates = frm; + break; + case IEEE80211_ELEMID_COUNTRY: + scan.country = frm; + break; + case IEEE80211_ELEMID_FHPARMS: + IEEE80211_VERIFY_LENGTH(frm[1], 5); + if (ic->ic_phytype == IEEE80211_T_FH) { + scan.fhdwell = LE_READ_2(&frm[2]); + scan.chan = IEEE80211_FH_CHAN(frm[4], frm[5]); + scan.fhindex = frm[6]; + } + break; + case IEEE80211_ELEMID_DSPARMS: + /* + * XXX hack this since depending on phytype + * is problematic for multi-mode devices. + */ + IEEE80211_VERIFY_LENGTH(frm[1], 1); + if (ic->ic_phytype != IEEE80211_T_FH) + scan.chan = frm[2]; + break; + case IEEE80211_ELEMID_TIM: + /* XXX ATIM? */ + IEEE80211_VERIFY_LENGTH(frm[1], 5); + scan.tim = frm; + scan.timoff = frm - mtod(m0, u_int8_t *); + break; + case IEEE80211_ELEMID_IBSSPARMS: + break; + case IEEE80211_ELEMID_XRATES: + scan.xrates = frm; + break; + case IEEE80211_ELEMID_ERP: + if (frm[1] != 1) { + IEEE80211_DISCARD_IE(ic, + IEEE80211_MSG_ELEMID, wh, "ERP", + "bad len %u", frm[1]); + ic->ic_stats.is_rx_elem_toobig++; break; } - - frm += frm[1] + 2; + scan.erp = frm[2]; + break; + case IEEE80211_ELEMID_RSN: + scan.wpa = frm; + break; + case IEEE80211_ELEMID_VENDOR: + if (iswpaoui(frm)) + scan.wpa = frm; + else if (iswmeparam(frm) || iswmeinfo(frm)) + scan.wme = frm; + /* XXX Atheros OUI support */ + break; + default: + IEEE80211_DISCARD_IE(ic, IEEE80211_MSG_ELEMID, + wh, "unhandled", + "id %u, len %u", *frm, frm[1]); + ic->ic_stats.is_rx_elem_unknown++; + break; } - IEEE80211_VERIFY_ELEMENT(scan.rates, IEEE80211_RATE_MAXSIZE); - IEEE80211_VERIFY_ELEMENT(scan.ssid, IEEE80211_NWID_LEN); + frm += frm[1] + 2; + } - if ( + IEEE80211_VERIFY_ELEMENT(scan.rates, IEEE80211_RATE_MAXSIZE); + IEEE80211_VERIFY_ELEMENT(scan.ssid, IEEE80211_NWID_LEN); + + if ( #if IEEE80211_CHAN_MAX < 255 - scan.chan > IEEE80211_CHAN_MAX || + scan.chan > IEEE80211_CHAN_MAX || #endif - isclr(ic->ic_chan_active, scan.chan)) { - IEEE80211_DISCARD(ic, - IEEE80211_MSG_ELEMID | IEEE80211_MSG_INPUT, - wh, ieee80211_mgt_subtype_name[subtype >> - IEEE80211_FC0_SUBTYPE_SHIFT], - "invalid channel %u", scan.chan); - ic->ic_stats.is_rx_badchan++; - return; + isclr(ic->ic_chan_active, scan.chan)) { + IEEE80211_DISCARD(ic, + IEEE80211_MSG_ELEMID | IEEE80211_MSG_INPUT, + wh, ieee80211_mgt_subtype_name[subtype >> + IEEE80211_FC0_SUBTYPE_SHIFT], + "invalid channel %u", scan.chan); + ic->ic_stats.is_rx_badchan++; + return; + } + if (scan.chan != scan.bchan && + ic->ic_phytype != IEEE80211_T_FH) { + /* + * Frame was received on a channel different from the + * one indicated in the DS params element id; + * silently discard it. + * + * NB: this can happen due to signal leakage. + * But we should take it for FH phy because + * the rssi value should be correct even for + * different hop pattern in FH. + */ + IEEE80211_DISCARD(ic, + IEEE80211_MSG_ELEMID | IEEE80211_MSG_INPUT, + wh, ieee80211_mgt_subtype_name[subtype >> + IEEE80211_FC0_SUBTYPE_SHIFT], + "for off-channel %u", scan.chan); + ic->ic_stats.is_rx_chanmismatch++; + return; + } + if (!(IEEE80211_BINTVAL_MIN <= scan.bintval && + scan.bintval <= IEEE80211_BINTVAL_MAX)) { + IEEE80211_DISCARD(ic, + IEEE80211_MSG_ELEMID | IEEE80211_MSG_INPUT, + wh, ieee80211_mgt_subtype_name[subtype >> + IEEE80211_FC0_SUBTYPE_SHIFT], + "bogus beacon interval", scan.bintval); + ic->ic_stats.is_rx_badbintval++; + return; + } + + if (ni != ic->ic_bss) { + ni = ieee80211_refine_node_for_beacon(ic, ni, + &ic->ic_channels[scan.chan], scan.ssid); + } + /* + * Count frame now that we know it's to be processed. + */ + if (subtype == IEEE80211_FC0_SUBTYPE_BEACON) { + ic->ic_stats.is_rx_beacon++; /* XXX remove */ + IEEE80211_NODE_STAT(ni, rx_beacons); + } else + IEEE80211_NODE_STAT(ni, rx_proberesp); + + /* + * When operating in station mode, check for state updates. + * Be careful to ignore beacons received while doing a + * background scan. We consider only 11g/WMM stuff right now. + */ + if (ic->ic_opmode == IEEE80211_M_STA && + ni->ni_associd != 0 && + ((ic->ic_flags & IEEE80211_F_SCAN) == 0 || + IEEE80211_ADDR_EQ(wh->i_addr2, ni->ni_bssid))) { + /* record tsf of last beacon */ + memcpy(ni->ni_tstamp.data, scan.tstamp, + sizeof(ni->ni_tstamp)); + if (ni->ni_erp != scan.erp) { + IEEE80211_DPRINTF(ic, IEEE80211_MSG_ASSOC, + "[%s] erp change: was 0x%x, now 0x%x\n", + ether_snprintf(ebuf, sizeof(ebuf), + wh->i_addr2), ni->ni_erp, scan.erp); + if (ic->ic_curmode == IEEE80211_MODE_11G && + (ni->ni_erp & IEEE80211_ERP_USE_PROTECTION)) + ic->ic_flags |= IEEE80211_F_USEPROT; + else + ic->ic_flags &= ~IEEE80211_F_USEPROT; + ni->ni_erp = scan.erp; + /* XXX statistic */ } - if (scan.chan != scan.bchan && - ic->ic_phytype != IEEE80211_T_FH) { + if ((ni->ni_capinfo ^ scan.capinfo) & IEEE80211_CAPINFO_SHORT_SLOTTIME) { + IEEE80211_DPRINTF(ic, IEEE80211_MSG_ASSOC, + "[%s] capabilities change: before 0x%x," + " now 0x%x\n", + ether_snprintf(ebuf, sizeof(ebuf), + wh->i_addr2), + ni->ni_capinfo, scan.capinfo); /* - * Frame was received on a channel different from the - * one indicated in the DS params element id; - * silently discard it. - * - * NB: this can happen due to signal leakage. - * But we should take it for FH phy because - * the rssi value should be correct even for - * different hop pattern in FH. + * NB: we assume short preamble doesn't + * change dynamically */ - IEEE80211_DISCARD(ic, - IEEE80211_MSG_ELEMID | IEEE80211_MSG_INPUT, - wh, ieee80211_mgt_subtype_name[subtype >> - IEEE80211_FC0_SUBTYPE_SHIFT], - "for off-channel %u", scan.chan); - ic->ic_stats.is_rx_chanmismatch++; - return; - } - if (!(IEEE80211_BINTVAL_MIN <= scan.bintval && - scan.bintval <= IEEE80211_BINTVAL_MAX)) { - IEEE80211_DISCARD(ic, - IEEE80211_MSG_ELEMID | IEEE80211_MSG_INPUT, - wh, ieee80211_mgt_subtype_name[subtype >> - IEEE80211_FC0_SUBTYPE_SHIFT], - "bogus beacon interval", scan.bintval); - ic->ic_stats.is_rx_badbintval++; - return; - } - - if (ni != ic->ic_bss) { - ni = ieee80211_refine_node_for_beacon(ic, ni, - &ic->ic_channels[scan.chan], scan.ssid); - } - /* - * Count frame now that we know it's to be processed. - */ - if (subtype == IEEE80211_FC0_SUBTYPE_BEACON) { - ic->ic_stats.is_rx_beacon++; /* XXX remove */ - IEEE80211_NODE_STAT(ni, rx_beacons); - } else - IEEE80211_NODE_STAT(ni, rx_proberesp); + ieee80211_set_shortslottime(ic, + ic->ic_curmode == IEEE80211_MODE_11A || + (ni->ni_capinfo & IEEE80211_CAPINFO_SHORT_SLOTTIME)); + ni->ni_capinfo = scan.capinfo; + /* XXX statistic */ + } + if (scan.wme != NULL && + (ni->ni_flags & IEEE80211_NODE_QOS) && + ieee80211_parse_wmeparams(ic, scan.wme, wh) > 0) + ieee80211_wme_updateparams(ic); + if (scan.tim != NULL) { + struct ieee80211_tim_ie *ie = + (struct ieee80211_tim_ie *) scan.tim; - /* - * When operating in station mode, check for state updates. - * Be careful to ignore beacons received while doing a - * background scan. We consider only 11g/WMM stuff right now. - */ - if (ic->ic_opmode == IEEE80211_M_STA && - ni->ni_associd != 0 && - ((ic->ic_flags & IEEE80211_F_SCAN) == 0 || - IEEE80211_ADDR_EQ(wh->i_addr2, ni->ni_bssid))) { - /* record tsf of last beacon */ - memcpy(ni->ni_tstamp.data, scan.tstamp, - sizeof(ni->ni_tstamp)); - if (ni->ni_erp != scan.erp) { - IEEE80211_DPRINTF(ic, IEEE80211_MSG_ASSOC, - "[%s] erp change: was 0x%x, now 0x%x\n", - ether_snprintf(ebuf, sizeof(ebuf), - wh->i_addr2), ni->ni_erp, scan.erp); - if (ic->ic_curmode == IEEE80211_MODE_11G && - (ni->ni_erp & IEEE80211_ERP_USE_PROTECTION)) - ic->ic_flags |= IEEE80211_F_USEPROT; - else - ic->ic_flags &= ~IEEE80211_F_USEPROT; - ni->ni_erp = scan.erp; - /* XXX statistic */ - } - if ((ni->ni_capinfo ^ scan.capinfo) & IEEE80211_CAPINFO_SHORT_SLOTTIME) { - IEEE80211_DPRINTF(ic, IEEE80211_MSG_ASSOC, - "[%s] capabilities change: before 0x%x," - " now 0x%x\n", - ether_snprintf(ebuf, sizeof(ebuf), - wh->i_addr2), - ni->ni_capinfo, scan.capinfo); - /* - * NB: we assume short preamble doesn't - * change dynamically - */ - ieee80211_set_shortslottime(ic, - ic->ic_curmode == IEEE80211_MODE_11A || - (ni->ni_capinfo & IEEE80211_CAPINFO_SHORT_SLOTTIME)); - ni->ni_capinfo = scan.capinfo; - /* XXX statistic */ - } - if (scan.wme != NULL && - (ni->ni_flags & IEEE80211_NODE_QOS) && - ieee80211_parse_wmeparams(ic, scan.wme, wh) > 0) - ieee80211_wme_updateparams(ic); - if (scan.tim != NULL) { - struct ieee80211_tim_ie *ie = - (struct ieee80211_tim_ie *) scan.tim; - - ni->ni_dtim_count = ie->tim_count; - ni->ni_dtim_period = ie->tim_period; - } - if (ic->ic_flags & IEEE80211_F_SCAN) - ieee80211_add_scan(ic, &scan, wh, - subtype, rssi, rstamp); - ic->ic_bmiss_count = 0; - return; + ni->ni_dtim_count = ie->tim_count; + ni->ni_dtim_period = ie->tim_period; } - /* - * If scanning, just pass information to the scan module. - */ - if (ic->ic_flags & IEEE80211_F_SCAN) { - if (ic->ic_flags_ext & IEEE80211_FEXT_PROBECHAN) { - /* - * Actively scanning a channel marked passive; - * send a probe request now that we know there - * is 802.11 traffic present. - * - * XXX check if the beacon we recv'd gives - * us what we need and suppress the probe req - */ - ieee80211_probe_curchan(ic, 1); - ic->ic_flags_ext &= ~IEEE80211_FEXT_PROBECHAN; - } + if (ic->ic_flags & IEEE80211_F_SCAN) ieee80211_add_scan(ic, &scan, wh, subtype, rssi, rstamp); - return; - } - if (scan.capinfo & IEEE80211_CAPINFO_IBSS) - ieee80211_update_adhoc_node(ic, ni, wh, &scan, rssi, - rstamp); - break; + ic->ic_bmiss_count = 0; + return; } - case IEEE80211_FC0_SUBTYPE_PROBE_REQ: - if (ic->ic_opmode == IEEE80211_M_STA || - ic->ic_state != IEEE80211_S_RUN) { - ic->ic_stats.is_rx_mgtdiscard++; - return; + /* + * If scanning, just pass information to the scan module. + */ + if (ic->ic_flags & IEEE80211_F_SCAN) { + if (ic->ic_flags_ext & IEEE80211_FEXT_PROBECHAN) { + /* + * Actively scanning a channel marked passive; + * send a probe request now that we know there + * is 802.11 traffic present. + * + * XXX check if the beacon we recv'd gives + * us what we need and suppress the probe req + */ + ieee80211_probe_curchan(ic, 1); + ic->ic_flags_ext &= ~IEEE80211_FEXT_PROBECHAN; } - if (IEEE80211_IS_MULTICAST(wh->i_addr2)) { - /* frame must be directed */ - ic->ic_stats.is_rx_mgtdiscard++; /* XXX stat */ - return; + ieee80211_add_scan(ic, &scan, wh, + subtype, rssi, rstamp); + return; + } + if (scan.capinfo & IEEE80211_CAPINFO_IBSS) + ieee80211_update_adhoc_node(ic, ni, wh, &scan, rssi, rstamp); +} + +static void +ieee80211_recv_mgmt_probe_req(struct ieee80211com *ic, struct mbuf *m0, + struct ieee80211_node *ni, int subtype, int rssi, u_int32_t rstamp) +{ + struct ieee80211_frame *wh; + u_int8_t *frm, *efrm; + u_int8_t *ssid, *rates, *xrates; + int allocbs; + u_int8_t rate; + IEEE80211_DEBUGVAR(char ebuf[3 * ETHER_ADDR_LEN]); + + wh = mtod(m0, struct ieee80211_frame *); + frm = (u_int8_t *)(wh + 1); + efrm = mtod(m0, u_int8_t *) + m0->m_len; + + if (ic->ic_opmode == IEEE80211_M_STA || + ic->ic_state != IEEE80211_S_RUN) { + ic->ic_stats.is_rx_mgtdiscard++; + return; + } + if (IEEE80211_IS_MULTICAST(wh->i_addr2)) { + /* frame must be directed */ + ic->ic_stats.is_rx_mgtdiscard++; /* XXX stat */ + return; + } + + /* + * prreq frame format + * [tlv] ssid + * [tlv] supported rates + * [tlv] extended supported rates + */ + ssid = rates = xrates = NULL; + while (frm < efrm) { + switch (*frm) { + case IEEE80211_ELEMID_SSID: + ssid = frm; + break; + case IEEE80211_ELEMID_RATES: + rates = frm; + break; + case IEEE80211_ELEMID_XRATES: + xrates = frm; + break; } + frm += frm[1] + 2; + } + IEEE80211_VERIFY_ELEMENT(rates, IEEE80211_RATE_MAXSIZE); + IEEE80211_VERIFY_ELEMENT(ssid, IEEE80211_NWID_LEN); + IEEE80211_VERIFY_SSID(ic->ic_bss, ssid); + if ((ic->ic_flags & IEEE80211_F_HIDESSID) && ssid[1] == 0) { + IEEE80211_DISCARD(ic, IEEE80211_MSG_INPUT, + wh, ieee80211_mgt_subtype_name[subtype >> + IEEE80211_FC0_SUBTYPE_SHIFT], + "%s", "no ssid with ssid suppression enabled"); + ic->ic_stats.is_rx_ssidmismatch++; /*XXX*/ + return; + } - /* - * prreq frame format - * [tlv] ssid - * [tlv] supported rates - * [tlv] extended supported rates - */ - ssid = rates = xrates = NULL; - while (frm < efrm) { - switch (*frm) { - case IEEE80211_ELEMID_SSID: - ssid = frm; - break; - case IEEE80211_ELEMID_RATES: - rates = frm; - break; - case IEEE80211_ELEMID_XRATES: - xrates = frm; - break; - } - frm += frm[1] + 2; + if (ni == ic->ic_bss) { + if (ic->ic_opmode != IEEE80211_M_IBSS) + ni = ieee80211_tmp_node(ic, wh->i_addr2); + else if (IEEE80211_ADDR_EQ(wh->i_addr2, ni->ni_macaddr)) + ; + else { + /* + * XXX Cannot tell if the sender is operating + * in ibss mode. But we need a new node to + * send the response so blindly add them to the + * neighbor table. + */ + ni = ieee80211_fakeup_adhoc_node(&ic->ic_sta, + wh->i_addr2); } - IEEE80211_VERIFY_ELEMENT(rates, IEEE80211_RATE_MAXSIZE); - IEEE80211_VERIFY_ELEMENT(ssid, IEEE80211_NWID_LEN); - IEEE80211_VERIFY_SSID(ic->ic_bss, ssid); - if ((ic->ic_flags & IEEE80211_F_HIDESSID) && ssid[1] == 0) { - IEEE80211_DISCARD(ic, IEEE80211_MSG_INPUT, - wh, ieee80211_mgt_subtype_name[subtype >> - IEEE80211_FC0_SUBTYPE_SHIFT], - "%s", "no ssid with ssid suppression enabled"); - ic->ic_stats.is_rx_ssidmismatch++; /*XXX*/ + if (ni == NULL) return; - } + allocbs = 1; + } else + allocbs = 0; + IEEE80211_DPRINTF(ic, IEEE80211_MSG_ASSOC, + "[%s] recv probe req\n", ether_snprintf( + ebuf, sizeof(ebuf), wh->i_addr2)); + ni->ni_rssi = rssi; + ni->ni_rstamp = rstamp; + rate = ieee80211_setup_rates(ni, rates, xrates, + IEEE80211_R_DOSORT | IEEE80211_R_DOFRATE + | IEEE80211_R_DONEGO | IEEE80211_R_DODEL); + if (rate & IEEE80211_RATE_BASIC) { + IEEE80211_DISCARD(ic, IEEE80211_MSG_XRATE, + wh, ieee80211_mgt_subtype_name[subtype >> + IEEE80211_FC0_SUBTYPE_SHIFT], + "%s", "recv'd rate set invalid"); + } else { + IEEE80211_SEND_MGMT(ic, ni, + IEEE80211_FC0_SUBTYPE_PROBE_RESP, 0); + } + if (allocbs && ic->ic_opmode != IEEE80211_M_IBSS) { + /* reclaim immediately */ + ieee80211_free_node(ni); + } +} - if (ni == ic->ic_bss) { - if (ic->ic_opmode != IEEE80211_M_IBSS) - ni = ieee80211_tmp_node(ic, wh->i_addr2); - else if (IEEE80211_ADDR_EQ(wh->i_addr2, ni->ni_macaddr)) - ; - else { - /* - * XXX Cannot tell if the sender is operating - * in ibss mode. But we need a new node to - * send the response so blindly add them to the - * neighbor table. - */ - ni = ieee80211_fakeup_adhoc_node(&ic->ic_sta, - wh->i_addr2); - } - if (ni == NULL) - return; - allocbs = 1; - } else - allocbs = 0; - IEEE80211_DPRINTF(ic, IEEE80211_MSG_ASSOC, - "[%s] recv probe req\n", ether_snprintf( - ebuf, sizeof(ebuf), wh->i_addr2)); - ni->ni_rssi = rssi; - ni->ni_rstamp = rstamp; - rate = ieee80211_setup_rates(ni, rates, xrates, - IEEE80211_R_DOSORT | IEEE80211_R_DOFRATE - | IEEE80211_R_DONEGO | IEEE80211_R_DODEL); - if (rate & IEEE80211_RATE_BASIC) { - IEEE80211_DISCARD(ic, IEEE80211_MSG_XRATE, - wh, ieee80211_mgt_subtype_name[subtype >> - IEEE80211_FC0_SUBTYPE_SHIFT], - "%s", "recv'd rate set invalid"); - } else { - IEEE80211_SEND_MGMT(ic, ni, - IEEE80211_FC0_SUBTYPE_PROBE_RESP, 0); - } - if (allocbs && ic->ic_opmode != IEEE80211_M_IBSS) { - /* reclaim immediately */ - ieee80211_free_node(ni); - } - break; +/* -------------------------------------------------------------------------- */ + +void +ieee80211_recv_mgmt(struct ieee80211com *ic, struct mbuf *m0, + struct ieee80211_node *ni, int subtype, int rssi, u_int32_t rstamp) +{ +#define ISREASSOC(_st) ((_st) == IEEE80211_FC0_SUBTYPE_REASSOC_RESP) + struct ieee80211_frame *wh; + u_int8_t *frm, *efrm; + u_int8_t *ssid, *rates, *xrates, *wpa, *wme; + int reassoc, resp; + u_int8_t rate; + IEEE80211_DEBUGVAR(char ebuf[3 * ETHER_ADDR_LEN]); + + wh = mtod(m0, struct ieee80211_frame *); + frm = (u_int8_t *)(wh + 1); + efrm = mtod(m0, u_int8_t *) + m0->m_len; + + switch (subtype) { + case IEEE80211_FC0_SUBTYPE_PROBE_RESP: + case IEEE80211_FC0_SUBTYPE_BEACON: + ieee80211_recv_mgmt_beacon(ic, m0, ni, subtype, rssi, rstamp); + return; + + case IEEE80211_FC0_SUBTYPE_PROBE_REQ: + ieee80211_recv_mgmt_probe_req(ic, m0, ni, subtype, rssi, rstamp); + return; case IEEE80211_FC0_SUBTYPE_AUTH: { u_int16_t algo, seq, status; @@ -2855,7 +2889,6 @@ ieee80211_recv_mgmt(struct ieee80211com break; } #undef ISREASSOC -#undef ISPROBE } #undef IEEE80211_VERIFY_LENGTH #undef IEEE80211_VERIFY_ELEMENT