diff options
Diffstat (limited to 'sys/net80211/ieee80211_input.c')
-rw-r--r-- | sys/net80211/ieee80211_input.c | 243 |
1 files changed, 77 insertions, 166 deletions
diff --git a/sys/net80211/ieee80211_input.c b/sys/net80211/ieee80211_input.c index 8a6a499..74b147e 100644 --- a/sys/net80211/ieee80211_input.c +++ b/sys/net80211/ieee80211_input.c @@ -1692,7 +1692,7 @@ ieee80211_parse_wmeparams(struct ieee80211com *ic, u_int8_t *frm, #undef MS } -static void +void ieee80211_saveie(u_int8_t **iep, const u_int8_t *ie) { u_int ielen = ie[1]+2; @@ -1709,38 +1709,6 @@ ieee80211_saveie(u_int8_t **iep, const u_int8_t *ie) /* XXX note failure */ } -#ifdef IEEE80211_DEBUG -static void -dump_probe_beacon(u_int8_t subtype, int isnew, - const u_int8_t mac[IEEE80211_ADDR_LEN], - u_int8_t chan, u_int8_t bchan, u_int16_t capinfo, u_int16_t bintval, - u_int8_t erp, u_int8_t *ssid, u_int8_t *country) -{ - printf("[%s] %s%s on chan %u (bss chan %u) ", - ether_sprintf(mac), isnew ? "new " : "", - ieee80211_mgt_subtype_name[subtype >> IEEE80211_FC0_SUBTYPE_SHIFT], - chan, bchan); - ieee80211_print_essid(ssid + 2, ssid[1]); - printf("\n"); - - if (isnew) { - printf("[%s] caps 0x%x bintval %u erp 0x%x", - ether_sprintf(mac), capinfo, bintval, erp); - if (country) { -#ifdef __FreeBSD__ - printf(" country info %*D", country[1], country+2, " "); -#else - int i; - printf(" country info"); - for (i = 0; i < country[1]; i++) - printf(" %02x", country[i+2]); -#endif - } - printf("\n"); - } -} -#endif /* IEEE80211_DEBUG */ - void ieee80211_recv_mgmt(struct ieee80211com *ic, struct mbuf *m0, struct ieee80211_node *ni, @@ -1760,10 +1728,7 @@ ieee80211_recv_mgmt(struct ieee80211com *ic, struct mbuf *m0, switch (subtype) { case IEEE80211_FC0_SUBTYPE_PROBE_RESP: case IEEE80211_FC0_SUBTYPE_BEACON: { - u_int8_t *tstamp, *country, *tim; - u_int8_t chan, bchan, fhindex, erp; - u_int16_t capinfo, bintval, timoff; - u_int16_t fhdwell; + struct ieee80211_scanparams scan; /* * We process beacon/probe response frames: @@ -1794,32 +1759,29 @@ ieee80211_recv_mgmt(struct ieee80211com *ic, struct mbuf *m0, * [tlv] WPA or RSN */ IEEE80211_VERIFY_LENGTH(efrm - frm, 12); - tstamp = frm; frm += 8; - bintval = le16toh(*(u_int16_t *)frm); frm += 2; - capinfo = le16toh(*(u_int16_t *)frm); frm += 2; - ssid = rates = xrates = country = wpa = wme = tim = NULL; - bchan = ieee80211_chan2ieee(ic, ic->ic_bss->ni_chan); - chan = bchan; - fhdwell = 0; - fhindex = 0; - erp = 0; - timoff = 0; + 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 < efrm) { switch (*frm) { case IEEE80211_ELEMID_SSID: - ssid = frm; + scan.ssid = frm; break; case IEEE80211_ELEMID_RATES: - rates = frm; + scan.rates = frm; break; case IEEE80211_ELEMID_COUNTRY: - country = frm; + scan.country = frm; break; case IEEE80211_ELEMID_FHPARMS: if (ic->ic_phytype == IEEE80211_T_FH) { - fhdwell = LE_READ_2(&frm[2]); - chan = IEEE80211_FH_CHAN(frm[4], frm[5]); - fhindex = frm[6]; + 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: @@ -1828,17 +1790,17 @@ ieee80211_recv_mgmt(struct ieee80211com *ic, struct mbuf *m0, * is problematic for multi-mode devices. */ if (ic->ic_phytype != IEEE80211_T_FH) - chan = frm[2]; + scan.chan = frm[2]; break; case IEEE80211_ELEMID_TIM: /* XXX ATIM? */ - tim = frm; - timoff = frm - mtod(m0, u_int8_t *); + scan.tim = frm; + scan.timoff = frm - mtod(m0, u_int8_t *); break; case IEEE80211_ELEMID_IBSSPARMS: break; case IEEE80211_ELEMID_XRATES: - xrates = frm; + scan.xrates = frm; break; case IEEE80211_ELEMID_ERP: if (frm[1] != 1) { @@ -1848,16 +1810,16 @@ ieee80211_recv_mgmt(struct ieee80211com *ic, struct mbuf *m0, ic->ic_stats.is_rx_elem_toobig++; break; } - erp = frm[2]; + scan.erp = frm[2]; break; case IEEE80211_ELEMID_RSN: - wpa = frm; + scan.wpa = frm; break; case IEEE80211_ELEMID_VENDOR: if (iswpaoui(frm)) - wpa = frm; + scan.wpa = frm; else if (iswmeparam(frm) || iswmeinfo(frm)) - wme = frm; + scan.wme = frm; /* XXX Atheros OUI support */ break; default: @@ -1869,21 +1831,23 @@ ieee80211_recv_mgmt(struct ieee80211com *ic, struct mbuf *m0, } frm += frm[1] + 2; } - IEEE80211_VERIFY_ELEMENT(rates, IEEE80211_RATE_MAXSIZE); - IEEE80211_VERIFY_ELEMENT(ssid, IEEE80211_NWID_LEN); + IEEE80211_VERIFY_ELEMENT(scan.rates, IEEE80211_RATE_MAXSIZE); + IEEE80211_VERIFY_ELEMENT(scan.ssid, IEEE80211_NWID_LEN); if ( #if IEEE80211_CHAN_MAX < 255 - chan > IEEE80211_CHAN_MAX || + scan.chan > IEEE80211_CHAN_MAX || #endif - isclr(ic->ic_chan_active, chan)) { - IEEE80211_DISCARD(ic, IEEE80211_MSG_ELEMID, + 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", chan); + "invalid channel %u", scan.chan); ic->ic_stats.is_rx_badchan++; return; } - if (chan != bchan && ic->ic_phytype != IEEE80211_T_FH) { + 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; @@ -1894,20 +1858,21 @@ ieee80211_recv_mgmt(struct ieee80211com *ic, struct mbuf *m0, * the rssi value should be correct even for * different hop pattern in FH. */ - IEEE80211_DISCARD(ic, IEEE80211_MSG_ELEMID, + IEEE80211_DISCARD(ic, + IEEE80211_MSG_ELEMID | IEEE80211_MSG_INPUT, wh, ieee80211_mgt_subtype_name[subtype >> IEEE80211_FC0_SUBTYPE_SHIFT], - "for off-channel %u", chan); + "for off-channel %u", scan.chan); ic->ic_stats.is_rx_chanmismatch++; return; } - if (!(IEEE80211_BINTVAL_MIN <= bintval && - bintval <= IEEE80211_BINTVAL_MAX)) { + 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", bintval); + "bogus beacon interval", scan.bintval); ic->ic_stats.is_rx_badbintval++; return; } @@ -1931,27 +1896,27 @@ ieee80211_recv_mgmt(struct ieee80211com *ic, struct mbuf *m0, ((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, tstamp, + memcpy(ni->ni_tstamp.data, scan.tstamp, sizeof(ni->ni_tstamp)); - if (ni->ni_erp != erp) { + if (ni->ni_erp != scan.erp) { IEEE80211_DPRINTF(ic, IEEE80211_MSG_ASSOC, "[%s] erp change: was 0x%x, now 0x%x\n", ether_sprintf(wh->i_addr2), - ni->ni_erp, erp); + 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 = erp; + ni->ni_erp = scan.erp; /* XXX statistic */ } - if ((ni->ni_capinfo ^ capinfo) & IEEE80211_CAPINFO_SHORT_SLOTTIME) { + 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_sprintf(wh->i_addr2), - ni->ni_capinfo, capinfo); + ni->ni_capinfo, scan.capinfo); /* * NB: we assume short preamble doesn't * change dynamically @@ -1959,105 +1924,51 @@ ieee80211_recv_mgmt(struct ieee80211com *ic, struct mbuf *m0, ieee80211_set_shortslottime(ic, ic->ic_curmode == IEEE80211_MODE_11A || (ni->ni_capinfo & IEEE80211_CAPINFO_SHORT_SLOTTIME)); - ni->ni_capinfo = capinfo; + ni->ni_capinfo = scan.capinfo; /* XXX statistic */ } - if (wme != NULL && + if (scan.wme != NULL && (ni->ni_flags & IEEE80211_NODE_QOS) && - ieee80211_parse_wmeparams(ic, wme, wh) > 0) + ieee80211_parse_wmeparams(ic, scan.wme, wh) > 0) ieee80211_wme_updateparams(ic); - if (tim != NULL) { + if (scan.tim != NULL) { struct ieee80211_tim_ie *ie = - (struct ieee80211_tim_ie *) tim; + (struct ieee80211_tim_ie *) scan.tim; ni->ni_dtim_count = ie->tim_count; ni->ni_dtim_period = ie->tim_period; } - /* NB: don't need the rest of this */ - if ((ic->ic_flags & IEEE80211_F_SCAN) == 0) - return; - } - - if (ni == ic->ic_bss && - !IEEE80211_ADDR_EQ(wh->i_addr2, ni->ni_bssid)) { -#ifdef IEEE80211_DEBUG - if (ieee80211_msg_scan(ic)) - dump_probe_beacon(subtype, 1, - wh->i_addr2, chan, bchan, capinfo, - bintval, erp, ssid, country); -#endif - /* - * Create a new entry. If scanning the entry goes - * in the scan cache. Otherwise, be particular when - * operating in adhoc mode--only take nodes marked - * as ibss participants so we don't populate our - * neighbor table with unintersting sta's. - */ - if ((ic->ic_flags & IEEE80211_F_SCAN) == 0) { - if ((capinfo & IEEE80211_CAPINFO_IBSS) == 0) - return; - ni = ieee80211_fakeup_adhoc_node(&ic->ic_sta, - wh->i_addr2); - } else - ni = ieee80211_dup_bss(&ic->ic_scan, wh->i_addr2); - if (ni == NULL) - return; - ni->ni_esslen = ssid[1]; - memset(ni->ni_essid, 0, sizeof(ni->ni_essid)); - memcpy(ni->ni_essid, ssid + 2, ssid[1]); - } else if (ssid[1] != 0 && - (ISPROBE(subtype) || ni->ni_esslen == 0)) { - /* - * Update ESSID at probe response to adopt - * hidden AP by Lucent/Cisco, which announces - * null ESSID in beacon. - */ -#ifdef IEEE80211_DEBUG - if (ieee80211_msg_scan(ic) || - ieee80211_msg_debug(ic)) - dump_probe_beacon(subtype, 0, - wh->i_addr2, chan, bchan, capinfo, - bintval, erp, ssid, country); -#endif - ni->ni_esslen = ssid[1]; - memset(ni->ni_essid, 0, sizeof(ni->ni_essid)); - memcpy(ni->ni_essid, ssid + 2, ssid[1]); - } - ni->ni_scangen = ic->ic_scan.nt_scangen; - IEEE80211_ADDR_COPY(ni->ni_bssid, wh->i_addr3); - ni->ni_rssi = rssi; - ni->ni_rstamp = rstamp; - memcpy(ni->ni_tstamp.data, tstamp, sizeof(ni->ni_tstamp)); - ni->ni_intval = bintval; - ni->ni_capinfo = capinfo; - ni->ni_chan = &ic->ic_channels[chan]; - ni->ni_fhdwell = fhdwell; - ni->ni_fhindex = fhindex; - ni->ni_erp = erp; - if (tim != NULL) { - struct ieee80211_tim_ie *ie = - (struct ieee80211_tim_ie *) 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); + return; } /* - * Record the byte offset from the mac header to - * the start of the TIM information element for - * use by hardware and/or to speedup software - * processing of beacon frames. - */ - ni->ni_timoff = timoff; - /* - * Record optional information elements that might be - * used by applications or drivers. + * If scanning, just pass information to the scan module. */ - if (wme != NULL) - ieee80211_saveie(&ni->ni_wme_ie, wme); - if (wpa != NULL) - ieee80211_saveie(&ni->ni_wpa_ie, wpa); - /* NB: must be after ni_chan is setup */ - ieee80211_setup_rates(ni, rates, xrates, IEEE80211_F_DOSORT); + if (ic->ic_flags & IEEE80211_F_SCAN) { + ieee80211_add_scan(ic, &scan, wh, + subtype, rssi, rstamp); + return; + } + if (scan.capinfo & IEEE80211_CAPINFO_IBSS) { + if (!IEEE80211_ADDR_EQ(wh->i_addr2, ni->ni_macaddr)) { + /* + * Create a new entry in the neighbor table. + */ + ni = ieee80211_add_neighbor(ic, wh, &scan); + } else { + /* + * Record tsf for potential resync. + */ + memcpy(ni->ni_tstamp.data, scan.tstamp, + sizeof(ni->ni_tstamp)); + } + if (ni != NULL) { + ni->ni_rssi = rssi; + ni->ni_rstamp = rstamp; + } + } break; } |