Clarify/fix handling of the current channel:

o add ic_curchan and use it uniformly for specifying the current
  channel instead of overloading ic->ic_bss->ni_chan (or in some
  drivers ic_ibss_chan)
o add ieee80211_scanparams structure to encapsulate scanning-related
  state captured for rx frames
o move rx beacon+probe response frame handling into separate routines
o change beacon+probe response handling to treat the scan table
  more like a scan cache--look for an existing entry before adding
  a new one; this combined with ic_curchan use corrects handling of
  stations that were previously found at a different channel
o move adhoc neighbor discovery by beacon+probe response frames to
  a new ieee80211_add_neighbor routine

Reviewed by:	avatar
Tested by:	avatar, Michal Mertl
MFC after:	2 weeks
This commit is contained in:
Sam Leffler 2005-08-10 16:22:30 +00:00
parent 44938dbf6d
commit b5c9941514
Notes: svn2git 2020-12-20 02:59:44 +00:00
svn path=/head/; revision=148936
14 changed files with 344 additions and 248 deletions

View file

@ -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:

View file

@ -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;
}

View file

@ -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;

View file

@ -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);

View file

@ -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 =

View file

@ -167,6 +167,10 @@ ieee80211_ifattach(struct ieee80211com *ic)
ic->ic_modecaps |= 1<<IEEE80211_MODE_TURBO_A;
if (IEEE80211_IS_CHAN_108G(c))
ic->ic_modecaps |= 1<<IEEE80211_MODE_TURBO_G;
if (ic->ic_curchan == NULL) {
/* arbitrarily pick the first channel */
ic->ic_curchan = &ic->ic_channels[i];
}
}
}
/* validate ic->ic_curmode */

View file

@ -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;
}

View file

@ -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;
}

View file

@ -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) \

View file

@ -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_ */

View file

@ -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;

View file

@ -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

View file

@ -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 *);

View file

@ -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;