diff --git a/sys/dev/ath/if_ath.c b/sys/dev/ath/if_ath.c index afd9d615935a..05cad26e28a8 100644 --- a/sys/dev/ath/if_ath.c +++ b/sys/dev/ath/if_ath.c @@ -844,7 +844,6 @@ ath_init(void *arg) struct ath_softc *sc = (struct ath_softc *) arg; struct ieee80211com *ic = &sc->sc_ic; struct ifnet *ifp = sc->sc_ifp; - struct ieee80211_node *ni; struct ath_hal *ah = sc->sc_ah; HAL_STATUS status; @@ -865,8 +864,8 @@ ath_init(void *arg) * be followed by initialization of the appropriate bits * and then setup of the interrupt mask. */ - sc->sc_curchan.channel = ic->ic_ibss_chan->ic_freq; - sc->sc_curchan.channelFlags = ath_chan2flags(ic, ic->ic_ibss_chan); + sc->sc_curchan.channel = ic->ic_curchan->ic_freq; + sc->sc_curchan.channelFlags = ath_chan2flags(ic, ic->ic_curchan); if (!ath_hal_reset(ah, ic->ic_opmode, &sc->sc_curchan, AH_FALSE, &status)) { if_printf(ifp, "unable to reset hardware; hal status %u\n", status); @@ -918,9 +917,7 @@ ath_init(void *arg) * to kick the 802.11 state machine as it's likely to * immediately call back to us to send mgmt frames. */ - ni = ic->ic_bss; - ni->ni_chan = ic->ic_ibss_chan; - ath_chan_change(sc, ni->ni_chan); + ath_chan_change(sc, ic->ic_curchan); if (ic->ic_opmode != IEEE80211_M_MONITOR) { if (ic->ic_roaming != IEEE80211_ROAMING_MANUAL) ieee80211_new_state(ic, IEEE80211_S_SCAN, -1); @@ -1022,7 +1019,7 @@ ath_reset(struct ifnet *ifp) * Convert to a HAL channel description with the flags * constrained to reflect the current operating mode. */ - c = ic->ic_ibss_chan; + c = ic->ic_curchan; sc->sc_curchan.channel = c->ic_freq; sc->sc_curchan.channelFlags = ath_chan2flags(ic, c); @@ -4114,7 +4111,7 @@ ath_newstate(struct ieee80211com *ic, enum ieee80211_state nstate, int arg) goto done; } ni = ic->ic_bss; - error = ath_chan_set(sc, ni->ni_chan); + error = ath_chan_set(sc, ic->ic_curchan); if (error != 0) goto bad; rfilt = ath_calcrxfilter(sc, nstate); @@ -4153,7 +4150,7 @@ ath_newstate(struct ieee80211com *ic, enum ieee80211_state nstate, int arg) , ni->ni_intval , ether_sprintf(ni->ni_bssid) , ni->ni_capinfo - , ieee80211_chan2ieee(ic, ni->ni_chan)); + , ieee80211_chan2ieee(ic, ic->ic_curchan)); switch (ic->ic_opmode) { case IEEE80211_M_HOSTAP: diff --git a/sys/dev/ipw/if_ipw.c b/sys/dev/ipw/if_ipw.c index 88afe1ca7af3..2d850a9cedd9 100644 --- a/sys/dev/ipw/if_ipw.c +++ b/sys/dev/ipw/if_ipw.c @@ -1002,7 +1002,7 @@ ipw_fix_channel(struct ieee80211com *ic, struct mbuf *m) #if IEEE80211_CHAN_MAX < 255 if (frm[2] <= IEEE80211_CHAN_MAX) #endif - ic->ic_bss->ni_chan = &ic->ic_channels[frm[2]]; + ic->ic_curchan = &ic->ic_channels[frm[2]]; frm += frm[1] + 2; } diff --git a/sys/dev/ral/if_ral.c b/sys/dev/ral/if_ral.c index 716bde490f93..1b275e97fa55 100644 --- a/sys/dev/ral/if_ral.c +++ b/sys/dev/ral/if_ral.c @@ -990,21 +990,21 @@ ral_newstate(struct ieee80211com *ic, enum ieee80211_state nstate, int arg) break; case IEEE80211_S_SCAN: - ral_set_chan(sc, ic->ic_bss->ni_chan); + ral_set_chan(sc, ic->ic_curchan); callout_reset(&sc->scan_ch, (sc->dwelltime * hz) / 1000, ral_next_scan, sc); break; case IEEE80211_S_AUTH: - ral_set_chan(sc, ic->ic_bss->ni_chan); + ral_set_chan(sc, ic->ic_curchan); break; case IEEE80211_S_ASSOC: - ral_set_chan(sc, ic->ic_bss->ni_chan); + ral_set_chan(sc, ic->ic_curchan); break; case IEEE80211_S_RUN: - ral_set_chan(sc, ic->ic_bss->ni_chan); + ral_set_chan(sc, ic->ic_curchan); if (ic->ic_opmode != IEEE80211_M_MONITOR) ral_set_bssid(sc, ic->ic_bss->ni_bssid); @@ -1768,7 +1768,7 @@ ral_tx_mgt(struct ral_softc *sc, struct mbuf *m0, struct ieee80211_node *ni) desc = &sc->prioq.desc[sc->prioq.cur]; data = &sc->prioq.data[sc->prioq.cur]; - rate = IEEE80211_IS_CHAN_5GHZ(ni->ni_chan) ? 12 : 4; + rate = IEEE80211_IS_CHAN_5GHZ(ic->ic_curchan) ? 12 : 4; error = bus_dmamap_load_mbuf_sg(sc->prioq.data_dmat, data->map, m0, segs, &nsegs, 0); @@ -1910,7 +1910,7 @@ ral_tx_data(struct ral_softc *sc, struct mbuf *m0, struct ieee80211_node *ni) uint16_t dur; int rtsrate, ackrate; - rtsrate = IEEE80211_IS_CHAN_5GHZ(ni->ni_chan) ? 12 : 4; + rtsrate = IEEE80211_IS_CHAN_5GHZ(ic->ic_curchan) ? 12 : 4; ackrate = ral_ack_rate(rate); dur = ral_txtime(m0->m_pkthdr.len + 4, rate, ic->ic_flags) + @@ -2739,7 +2739,8 @@ ral_init(void *priv) /* set default BSS channel */ ic->ic_bss->ni_chan = ic->ic_ibss_chan; - ral_set_chan(sc, ic->ic_bss->ni_chan); + ic->ic_curchan = ic->ic_ibss_chan; + ral_set_chan(sc, ic->ic_curchan); /* kick Rx */ tmp = RAL_DROP_PHY_ERROR | RAL_DROP_CRC_ERROR; diff --git a/sys/dev/usb/if_ural.c b/sys/dev/usb/if_ural.c index 00836523592d..7deb1bc8d368 100644 --- a/sys/dev/usb/if_ural.c +++ b/sys/dev/usb/if_ural.c @@ -722,20 +722,20 @@ ural_task(void *arg) break; case IEEE80211_S_SCAN: - ural_set_chan(sc, ic->ic_bss->ni_chan); + ural_set_chan(sc, ic->ic_curchan); callout_reset(&sc->scan_ch, hz / 5, ural_next_scan, sc); break; case IEEE80211_S_AUTH: - ural_set_chan(sc, ic->ic_bss->ni_chan); + ural_set_chan(sc, ic->ic_curchan); break; case IEEE80211_S_ASSOC: - ural_set_chan(sc, ic->ic_bss->ni_chan); + ural_set_chan(sc, ic->ic_curchan); break; case IEEE80211_S_RUN: - ural_set_chan(sc, ic->ic_bss->ni_chan); + ural_set_chan(sc, ic->ic_curchan); if (ic->ic_opmode != IEEE80211_M_MONITOR) ural_set_bssid(sc, ic->ic_bss->ni_bssid); @@ -1125,7 +1125,7 @@ ural_tx_mgt(struct ural_softc *sc, struct mbuf *m0, struct ieee80211_node *ni) data = &sc->tx_data[0]; desc = (struct ural_tx_desc *)data->buf; - rate = IEEE80211_IS_CHAN_5GHZ(ni->ni_chan) ? 12 : 4; + rate = IEEE80211_IS_CHAN_5GHZ(ic->ic_curchan) ? 12 : 4; if (sc->sc_drvbpf != NULL) { struct ural_tx_radiotap_header *tap = &sc->sc_txtap; @@ -1956,7 +1956,8 @@ ural_init(void *priv) /* set default BSS channel */ ic->ic_bss->ni_chan = ic->ic_ibss_chan; - ural_set_chan(sc, ic->ic_bss->ni_chan); + ic->ic_curchan = ic->ic_ibss_chan; + ural_set_chan(sc, ic->ic_curchan); /* clear statistic registers (STA_CSR0 to STA_CSR10) */ ural_read_multi(sc, RAL_STA_CSR0, sta, sizeof sta); diff --git a/sys/dev/wi/if_wi.c b/sys/dev/wi/if_wi.c index 4de137ce52fd..fc9ab4d06527 100644 --- a/sys/dev/wi/if_wi.c +++ b/sys/dev/wi/if_wi.c @@ -2736,6 +2736,7 @@ wi_newstate(struct ieee80211com *ic, enum ieee80211_state nstate, int arg) wi_read_rid(sc, WI_RID_CURRENT_CHAN, &val, &buflen); /* XXX validate channel */ ni->ni_chan = &ic->ic_channels[le16toh(val)]; + ic->ic_curchan = ni->ni_chan; ic->ic_ibss_chan = ni->ni_chan; #if NBPFILTER > 0 sc->sc_tx_th.wt_chan_freq = sc->sc_rx_th.wr_chan_freq = diff --git a/sys/net80211/ieee80211.c b/sys/net80211/ieee80211.c index a34f8751068b..74ee6276d919 100644 --- a/sys/net80211/ieee80211.c +++ b/sys/net80211/ieee80211.c @@ -167,6 +167,10 @@ ieee80211_ifattach(struct ieee80211com *ic) ic->ic_modecaps |= 1<ic_modecaps |= 1<ic_curchan == NULL) { + /* arbitrarily pick the first channel */ + ic->ic_curchan = &ic->ic_channels[i]; + } } } /* validate ic->ic_curmode */ diff --git a/sys/net80211/ieee80211_input.c b/sys/net80211/ieee80211_input.c index 8a6a49930b67..74b147e21660 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, - wh, ieee80211_mgt_subtype_name[subtype >> - IEEE80211_FC0_SUBTYPE_SHIFT], - "for off-channel %u", chan); - ic->ic_stats.is_rx_chanmismatch++; - return; - } - if (!(IEEE80211_BINTVAL_MIN <= bintval && - 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); + "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; } @@ -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. + * If scanning, just pass information to the scan module. */ - ni->ni_timoff = timoff; - /* - * Record optional information elements that might be - * used by applications or drivers. - */ - 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; } diff --git a/sys/net80211/ieee80211_ioctl.c b/sys/net80211/ieee80211_ioctl.c index db9439f47d9c..e8cf5c4e4f17 100644 --- a/sys/net80211/ieee80211_ioctl.c +++ b/sys/net80211/ieee80211_ioctl.c @@ -252,7 +252,7 @@ ieee80211_cfgget(struct ieee80211com *ic, u_long cmd, caddr_t data) break; case WI_RID_CURRENT_CHAN: wreq.wi_val[0] = htole16( - ieee80211_chan2ieee(ic, ic->ic_bss->ni_chan)); + ieee80211_chan2ieee(ic, ic->ic_curchan)); wreq.wi_len = 1; break; case WI_RID_COMMS_QUALITY: @@ -448,7 +448,6 @@ findrate(struct ieee80211com *ic, enum ieee80211_phymode mode, int rate) static int ieee80211_setupscan(struct ieee80211com *ic, const u_int8_t chanlist[]) { - int i; /* * XXX don't permit a scan to be started unless we @@ -460,20 +459,6 @@ ieee80211_setupscan(struct ieee80211com *ic, const u_int8_t chanlist[]) */ if (!IS_UP(ic)) return EINVAL; - if (ic->ic_ibss_chan == NULL || - isclr(chanlist, ieee80211_chan2ieee(ic, ic->ic_ibss_chan))) { - for (i = 0; i <= IEEE80211_CHAN_MAX; i++) - if (isset(chanlist, i)) { - ic->ic_ibss_chan = &ic->ic_channels[i]; - goto found; - } - return EINVAL; /* no active channels */ -found: - ; - } - if (ic->ic_bss->ni_chan == IEEE80211_CHAN_ANYC || - isclr(chanlist, ieee80211_chan2ieee(ic, ic->ic_bss->ni_chan))) - ic->ic_bss->ni_chan = ic->ic_ibss_chan; memcpy(ic->ic_chan_active, chanlist, sizeof(ic->ic_chan_active)); /* * We force the state to INIT before calling ieee80211_new_state @@ -827,18 +812,6 @@ ieee80211_cfgset(struct ieee80211com *ic, u_long cmd, caddr_t data) return error; } -static struct ieee80211_channel * -getcurchan(struct ieee80211com *ic) -{ - switch (ic->ic_state) { - case IEEE80211_S_INIT: - case IEEE80211_S_SCAN: - return ic->ic_des_chan; - default: - return ic->ic_ibss_chan; - } -} - static int cap2cipher(int flag) { @@ -1351,7 +1324,7 @@ ieee80211_ioctl_get80211(struct ieee80211com *ic, u_long cmd, struct ieee80211re ireq->i_val = ic->ic_bss->ni_authmode; break; case IEEE80211_IOC_CHANNEL: - ireq->i_val = ieee80211_chan2ieee(ic, getcurchan(ic)); + ireq->i_val = ieee80211_chan2ieee(ic, ic->ic_curchan); break; case IEEE80211_IOC_POWERSAVE: if (ic->ic_flags & IEEE80211_F_PMGTON) @@ -1841,9 +1814,6 @@ ieee80211_ioctl_setchanlist(struct ieee80211com *ic, struct ieee80211req *ireq) ; } memcpy(ic->ic_chan_active, chanlist, sizeof(ic->ic_chan_active)); - if (ic->ic_bss->ni_chan == IEEE80211_CHAN_ANYC || - isclr(chanlist, ieee80211_chan2ieee(ic, ic->ic_bss->ni_chan))) - ic->ic_bss->ni_chan = ic->ic_ibss_chan; return IS_UP_AUTO(ic) ? ENETRESET : 0; } diff --git a/sys/net80211/ieee80211_node.c b/sys/net80211/ieee80211_node.c index af7c1fcd19f4..dc098a03bccc 100644 --- a/sys/net80211/ieee80211_node.c +++ b/sys/net80211/ieee80211_node.c @@ -261,16 +261,12 @@ ieee80211_reset_scan(struct ieee80211com *ic) } else memcpy(ic->ic_chan_scan, ic->ic_chan_active, sizeof(ic->ic_chan_active)); - /* NB: hack, setup so next_scan starts with the first channel */ - if (ic->ic_bss->ni_chan == IEEE80211_CHAN_ANYC) - ieee80211_set_chan(ic, ic->ic_bss, - &ic->ic_channels[IEEE80211_CHAN_MAX]); #ifdef IEEE80211_DEBUG if (ieee80211_msg_scan(ic)) { printf("%s: scan set:", __func__); dump_chanlist(ic->ic_chan_scan); printf(" start chan %u\n", - ieee80211_chan2ieee(ic, ic->ic_bss->ni_chan)); + ieee80211_chan2ieee(ic, ic->ic_curchan)); } #endif /* IEEE80211_DEBUG */ } @@ -324,7 +320,7 @@ ieee80211_next_scan(struct ieee80211com *ic) */ ic->ic_mgt_timer = 0; - chan = ic->ic_bss->ni_chan; + chan = ic->ic_curchan; do { if (++chan > &ic->ic_channels[IEEE80211_CHAN_MAX]) chan = &ic->ic_channels[0]; @@ -332,13 +328,19 @@ ieee80211_next_scan(struct ieee80211com *ic) clrbit(ic->ic_chan_scan, ieee80211_chan2ieee(ic, chan)); IEEE80211_DPRINTF(ic, IEEE80211_MSG_SCAN, "%s: chan %d->%d\n", __func__, - ieee80211_chan2ieee(ic, ic->ic_bss->ni_chan), + ieee80211_chan2ieee(ic, ic->ic_curchan), ieee80211_chan2ieee(ic, chan)); - ieee80211_set_chan(ic, ic->ic_bss, chan); + ic->ic_curchan = chan; + /* + * XXX drivers should do this as needed, + * XXX for now maintain compatibility + */ + ic->ic_bss->ni_rates = + ic->ic_sup_rates[ieee80211_chan2mode(ic, chan)]; ieee80211_new_state(ic, IEEE80211_S_SCAN, -1); return 1; } - } while (chan != ic->ic_bss->ni_chan); + } while (chan != ic->ic_curchan); ieee80211_end_scan(ic); return 0; } @@ -408,6 +410,7 @@ ieee80211_create_ibss(struct ieee80211com* ic, struct ieee80211_channel *chan) * Fix the channel and related attributes. */ ieee80211_set_chan(ic, ni, chan); + ic->ic_curchan = chan; ic->ic_curmode = ieee80211_chan2mode(ic, chan); /* * Do mode-specific rate setup. @@ -790,6 +793,7 @@ ieee80211_sta_join(struct ieee80211com *ic, struct ieee80211_node *selbs) * mode is locked. */ ic->ic_curmode = ieee80211_chan2mode(ic, selbs->ni_chan); + ic->ic_curchan = selbs->ni_chan; ieee80211_reset_erp(ic); ieee80211_wme_initparams(ic); @@ -1085,6 +1089,177 @@ ieee80211_fakeup_adhoc_node(struct ieee80211_node_table *nt, return ni; } +#ifdef IEEE80211_DEBUG +static void +dump_probe_beacon(u_int8_t subtype, int isnew, + const u_int8_t mac[IEEE80211_ADDR_LEN], + const struct ieee80211_scanparams *sp) +{ + + printf("[%s] %s%s on chan %u (bss chan %u) ", + ether_sprintf(mac), isnew ? "new " : "", + ieee80211_mgt_subtype_name[subtype >> IEEE80211_FC0_SUBTYPE_SHIFT], + sp->chan, sp->bchan); + ieee80211_print_essid(sp->ssid + 2, sp->ssid[1]); + printf("\n"); + + if (isnew) { + printf("[%s] caps 0x%x bintval %u erp 0x%x", + ether_sprintf(mac), sp->capinfo, sp->bintval, sp->erp); + if (sp->country != NULL) { +#ifdef __FreeBSD__ + printf(" country info %*D", + sp->country[1], sp->country+2, " "); +#else + int i; + printf(" country info"); + for (i = 0; i < sp->country[1]; i++) + printf(" %02x", sp->country[i+2]); +#endif + } + printf("\n"); + } +} +#endif /* IEEE80211_DEBUG */ + +static void +saveie(u_int8_t **iep, const u_int8_t *ie) +{ + + if (ie == NULL) + *iep = NULL; + else + ieee80211_saveie(iep, ie); +} + +/* + * Process a beacon or probe response frame. + */ +void +ieee80211_add_scan(struct ieee80211com *ic, + const struct ieee80211_scanparams *sp, + const struct ieee80211_frame *wh, + int subtype, int rssi, int rstamp) +{ +#define ISPROBE(_st) ((_st) == IEEE80211_FC0_SUBTYPE_PROBE_RESP) + struct ieee80211_node_table *nt = &ic->ic_scan; + struct ieee80211_node *ni; + int newnode = 0; + + ni = ieee80211_find_node(nt, wh->i_addr2); + if (ni == NULL) { + /* + * Create a new entry. + */ + ni = ic->ic_node_alloc(nt); + if (ni == NULL) { + ic->ic_stats.is_rx_nodealloc++; + return; + } + ieee80211_setup_node(nt, ni, wh->i_addr2); + /* + * XXX inherit from ic_bss. + */ + ni->ni_authmode = ic->ic_bss->ni_authmode; + ni->ni_txpower = ic->ic_bss->ni_txpower; + ni->ni_vlan = ic->ic_bss->ni_vlan; /* XXX?? */ + ieee80211_set_chan(ic, ni, ic->ic_curchan); + ni->ni_rsn = ic->ic_bss->ni_rsn; + newnode = 1; + } +#ifdef IEEE80211_DEBUG + if (ieee80211_msg_scan(ic) && (ic->ic_flags & IEEE80211_F_SCAN)) + dump_probe_beacon(subtype, newnode, wh->i_addr2, sp); +#endif + /* XXX ap beaconing multiple ssid w/ same bssid */ + if (sp->ssid[1] != 0 && + (ISPROBE(subtype) || ni->ni_esslen == 0)) { + ni->ni_esslen = sp->ssid[1]; + memset(ni->ni_essid, 0, sizeof(ni->ni_essid)); + memcpy(ni->ni_essid, sp->ssid + 2, sp->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, sp->tstamp, sizeof(ni->ni_tstamp)); + ni->ni_intval = sp->bintval; + ni->ni_capinfo = sp->capinfo; + ni->ni_chan = &ic->ic_channels[sp->chan]; + ni->ni_fhdwell = sp->fhdwell; + ni->ni_fhindex = sp->fhindex; + ni->ni_erp = sp->erp; + if (sp->tim != NULL) { + struct ieee80211_tim_ie *ie = + (struct ieee80211_tim_ie *) sp->tim; + + ni->ni_dtim_count = ie->tim_count; + ni->ni_dtim_period = ie->tim_period; + } + /* + * 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 = sp->timoff; + /* + * Record optional information elements that might be + * used by applications or drivers. + */ + saveie(&ni->ni_wme_ie, sp->wme); + saveie(&ni->ni_wpa_ie, sp->wpa); + + /* NB: must be after ni_chan is setup */ + ieee80211_setup_rates(ni, sp->rates, sp->xrates, IEEE80211_F_DOSORT); + + if (!newnode) + ieee80211_free_node(ni); +#undef ISPROBE +} + +/* + * Do node discovery in adhoc mode on receipt of a beacon + * or probe response frame. Note that for the driver's + * benefit we we treat this like an association so the + * driver has an opportunity to setup it's private state. + */ +struct ieee80211_node * +ieee80211_add_neighbor(struct ieee80211com *ic, + const struct ieee80211_frame *wh, + const struct ieee80211_scanparams *sp) +{ + struct ieee80211_node *ni; + + ni = ieee80211_dup_bss(&ic->ic_sta, wh->i_addr2);/* XXX alloc_node? */ + if (ni != NULL) { + ni->ni_esslen = sp->ssid[1]; + memcpy(ni->ni_essid, sp->ssid + 2, sp->ssid[1]); + IEEE80211_ADDR_COPY(ni->ni_bssid, wh->i_addr3); + memcpy(ni->ni_tstamp.data, sp->tstamp, sizeof(ni->ni_tstamp)); + ni->ni_intval = sp->bintval; + ni->ni_capinfo = sp->capinfo; + ni->ni_chan = ic->ic_bss->ni_chan; + ni->ni_fhdwell = sp->fhdwell; + ni->ni_fhindex = sp->fhindex; + ni->ni_erp = sp->erp; + ni->ni_timoff = sp->timoff; + if (sp->wme != NULL) + ieee80211_saveie(&ni->ni_wme_ie, sp->wme); + if (sp->wpa != NULL) + ieee80211_saveie(&ni->ni_wpa_ie, sp->wpa); + + /* NB: must be after ni_chan is setup */ + ieee80211_setup_rates(ni, sp->rates, sp->xrates, IEEE80211_F_DOSORT); + + if (ic->ic_newassoc != NULL) + ic->ic_newassoc(ni, 1); + /* XXX not right for 802.1x/WPA */ + ieee80211_node_authorize(ni); + } + return ni; +} + #define IS_CTL(wh) \ ((wh->i_fc[0] & IEEE80211_FC0_TYPE_MASK) == IEEE80211_FC0_TYPE_CTL) #define IS_PSPOLL(wh) \ diff --git a/sys/net80211/ieee80211_node.h b/sys/net80211/ieee80211_node.h index 6b3934e4b51f..e2bfc2c87398 100644 --- a/sys/net80211/ieee80211_node.h +++ b/sys/net80211/ieee80211_node.h @@ -132,7 +132,7 @@ struct ieee80211_node { u_int8_t ni_esslen; u_int8_t ni_essid[IEEE80211_NWID_LEN]; struct ieee80211_rateset ni_rates; /* negotiated rate set */ - struct ieee80211_channel *ni_chan; + struct ieee80211_channel *ni_chan; /* XXX multiple uses */ u_int16_t ni_fhdwell; /* FH only */ u_int8_t ni_fhindex; /* FH only */ u_int8_t ni_erp; /* ERP from beacon/probe resp */ @@ -293,4 +293,38 @@ struct ieee80211_node *ieee80211_fakeup_adhoc_node( void ieee80211_node_join(struct ieee80211com *, struct ieee80211_node *,int); void ieee80211_node_leave(struct ieee80211com *, struct ieee80211_node *); u_int8_t ieee80211_getrssi(struct ieee80211com *ic); + +/* + * Parameters supplied when adding/updating an entry in a + * scan cache. Pointer variables should be set to NULL + * if no data is available. Pointer references can be to + * local data; any information that is saved will be copied. + * All multi-byte values must be in host byte order. + */ +struct ieee80211_scanparams { + u_int16_t capinfo; /* 802.11 capabilities */ + u_int16_t fhdwell; /* FHSS dwell interval */ + u_int8_t chan; /* */ + u_int8_t bchan; + u_int8_t fhindex; + u_int8_t erp; + u_int16_t bintval; + u_int8_t timoff; + u_int8_t *tim; + u_int8_t *tstamp; + u_int8_t *country; + u_int8_t *ssid; + u_int8_t *rates; + u_int8_t *xrates; + u_int8_t *wpa; + u_int8_t *wme; +}; + +void ieee80211_add_scan(struct ieee80211com *, + const struct ieee80211_scanparams *, + const struct ieee80211_frame *, + int subtype, int rssi, int rstamp); +struct ieee80211_node *ieee80211_add_neighbor(struct ieee80211com *, + const struct ieee80211_frame *, + const struct ieee80211_scanparams *); #endif /* _NET80211_IEEE80211_NODE_H_ */ diff --git a/sys/net80211/ieee80211_output.c b/sys/net80211/ieee80211_output.c index 85e610d389aa..b6c15867e7ca 100644 --- a/sys/net80211/ieee80211_output.c +++ b/sys/net80211/ieee80211_output.c @@ -187,7 +187,7 @@ ieee80211_mgmt_output(struct ieee80211com *ic, struct ieee80211_node *ni, ieee80211_mgt_subtype_name[ (type & IEEE80211_FC0_SUBTYPE_MASK) >> IEEE80211_FC0_SUBTYPE_SHIFT], - ieee80211_chan2ieee(ic, ni->ni_chan)); + ieee80211_chan2ieee(ic, ic->ic_curchan)); } #endif IEEE80211_NODE_STAT(ni, tx_mgmt); @@ -236,7 +236,7 @@ ieee80211_send_nulldata(struct ieee80211_node *ni) IEEE80211_DPRINTF(ic, IEEE80211_MSG_DEBUG | IEEE80211_MSG_DUMPPKTS, "[%s] send null data frame on channel %u, pwr mgt %s\n", ether_sprintf(ni->ni_macaddr), - ieee80211_chan2ieee(ic, ni->ni_chan), + ieee80211_chan2ieee(ic, ic->ic_curchan), wh->i_fc[1] & IEEE80211_FC1_PWR_MGT ? "ena" : "dis"); IF_ENQUEUE(&ic->ic_mgtq, m); /* cheat */ @@ -999,7 +999,7 @@ ieee80211_send_probereq(struct ieee80211_node *ni, } frm = ieee80211_add_ssid(frm, ssid, ssidlen); - mode = ieee80211_chan2mode(ic, ni->ni_chan); + mode = ieee80211_chan2mode(ic, ic->ic_curchan); frm = ieee80211_add_rates(frm, &ic->ic_sup_rates[mode]); frm = ieee80211_add_xrates(frm, &ic->ic_sup_rates[mode]); @@ -1027,7 +1027,7 @@ ieee80211_send_probereq(struct ieee80211_node *ni, IEEE80211_DPRINTF(ic, IEEE80211_MSG_DEBUG | IEEE80211_MSG_DUMPPKTS, "[%s] send probe req on channel %u\n", ether_sprintf(wh->i_addr1), - ieee80211_chan2ieee(ic, ni->ni_chan)); + ieee80211_chan2ieee(ic, ic->ic_curchan)); IF_ENQUEUE(&ic->ic_mgtq, m); if_start(ic->ic_ifp); @@ -1109,7 +1109,7 @@ ieee80211_send_mgmt(struct ieee80211com *ic, struct ieee80211_node *ni, if (ic->ic_flags & IEEE80211_F_PRIVACY) capinfo |= IEEE80211_CAPINFO_PRIVACY; if ((ic->ic_flags & IEEE80211_F_SHPREAMBLE) && - IEEE80211_IS_CHAN_2GHZ(ni->ni_chan)) + IEEE80211_IS_CHAN_2GHZ(ic->ic_curchan)) capinfo |= IEEE80211_CAPINFO_SHORT_PREAMBLE; if (ic->ic_flags & IEEE80211_F_SHSLOT) capinfo |= IEEE80211_CAPINFO_SHORT_SLOTTIME; @@ -1126,14 +1126,14 @@ ieee80211_send_mgmt(struct ieee80211com *ic, struct ieee80211_node *ni, *frm++ = ni->ni_fhdwell & 0x00ff; *frm++ = (ni->ni_fhdwell >> 8) & 0x00ff; *frm++ = IEEE80211_FH_CHANSET( - ieee80211_chan2ieee(ic, ni->ni_chan)); + ieee80211_chan2ieee(ic, ic->ic_curchan)); *frm++ = IEEE80211_FH_CHANPAT( - ieee80211_chan2ieee(ic, ni->ni_chan)); + ieee80211_chan2ieee(ic, ic->ic_curchan)); *frm++ = ni->ni_fhindex; } else { *frm++ = IEEE80211_ELEMID_DSPARMS; *frm++ = 1; - *frm++ = ieee80211_chan2ieee(ic, ni->ni_chan); + *frm++ = ieee80211_chan2ieee(ic, ic->ic_curchan); } if (ic->ic_opmode == IEEE80211_M_IBSS) { @@ -1265,7 +1265,7 @@ ieee80211_send_mgmt(struct ieee80211com *ic, struct ieee80211_node *ni, * short premable is set. */ if ((ic->ic_flags & IEEE80211_F_SHPREAMBLE) && - IEEE80211_IS_CHAN_2GHZ(ni->ni_chan)) + IEEE80211_IS_CHAN_2GHZ(ic->ic_curchan)) capinfo |= IEEE80211_CAPINFO_SHORT_PREAMBLE; if ((ni->ni_capinfo & IEEE80211_CAPINFO_SHORT_SLOTTIME) && (ic->ic_caps & IEEE80211_C_SHSLOT)) @@ -1321,7 +1321,7 @@ ieee80211_send_mgmt(struct ieee80211com *ic, struct ieee80211_node *ni, if (ic->ic_flags & IEEE80211_F_PRIVACY) capinfo |= IEEE80211_CAPINFO_PRIVACY; if ((ic->ic_flags & IEEE80211_F_SHPREAMBLE) && - IEEE80211_IS_CHAN_2GHZ(ni->ni_chan)) + IEEE80211_IS_CHAN_2GHZ(ic->ic_curchan)) capinfo |= IEEE80211_CAPINFO_SHORT_PREAMBLE; if (ic->ic_flags & IEEE80211_F_SHSLOT) capinfo |= IEEE80211_CAPINFO_SHORT_SLOTTIME; diff --git a/sys/net80211/ieee80211_proto.c b/sys/net80211/ieee80211_proto.c index b76d57625b37..5537b336fa49 100644 --- a/sys/net80211/ieee80211_proto.c +++ b/sys/net80211/ieee80211_proto.c @@ -922,7 +922,7 @@ ieee80211_newstate(struct ieee80211com *ic, enum ieee80211_state nstate, int arg * beacons on the channel. */ if ((ic->ic_flags & IEEE80211_F_ASCAN) && - (ni->ni_chan->ic_flags & IEEE80211_CHAN_PASSIVE) == 0) { + (ic->ic_curchan->ic_flags & IEEE80211_CHAN_PASSIVE) == 0) { ieee80211_send_probereq(ni, ic->ic_myaddr, ifp->if_broadcastaddr, ifp->if_broadcastaddr, @@ -1043,7 +1043,7 @@ ieee80211_newstate(struct ieee80211com *ic, enum ieee80211_state nstate, int arg ieee80211_print_essid(ic->ic_bss->ni_essid, ni->ni_esslen); printf(" channel %d start %uMb\n", - ieee80211_chan2ieee(ic, ni->ni_chan), + ieee80211_chan2ieee(ic, ic->ic_curchan), IEEE80211_RATE2MBS(ni->ni_rates.rs_rates[ni->ni_txrate])); } #endif diff --git a/sys/net80211/ieee80211_proto.h b/sys/net80211/ieee80211_proto.h index 18a4211aa270..45fe1641e715 100644 --- a/sys/net80211/ieee80211_proto.h +++ b/sys/net80211/ieee80211_proto.h @@ -61,6 +61,7 @@ int ieee80211_input(struct ieee80211com *, struct mbuf *, struct ieee80211_node *, int, u_int32_t); int ieee80211_setup_rates(struct ieee80211_node *ni, const u_int8_t *rates, const u_int8_t *xrates, int flags); +void ieee80211_saveie(u_int8_t **, const u_int8_t *); void ieee80211_recv_mgmt(struct ieee80211com *, struct mbuf *, struct ieee80211_node *, int, int, u_int32_t); int ieee80211_send_nulldata(struct ieee80211_node *); diff --git a/sys/net80211/ieee80211_var.h b/sys/net80211/ieee80211_var.h index 2ef0e54a6211..c552d36a8aa1 100644 --- a/sys/net80211/ieee80211_var.h +++ b/sys/net80211/ieee80211_var.h @@ -136,6 +136,7 @@ struct ieee80211com { struct bpf_if *ic_rawbpf; /* packet filter structure */ struct ieee80211_node *ic_bss; /* information for this node */ struct ieee80211_channel *ic_ibss_chan; + struct ieee80211_channel *ic_curchan; /* current channel */ int ic_fixed_rate; /* index to ic_sup_rates[] */ u_int16_t ic_rtsthreshold; u_int16_t ic_fragthreshold;