summaryrefslogtreecommitdiffstats
path: root/sys/net80211
diff options
context:
space:
mode:
authorsam <sam@FreeBSD.org>2005-08-10 16:22:30 +0000
committersam <sam@FreeBSD.org>2005-08-10 16:22:30 +0000
commit7d1366bf6d72fe0b21b589eee177dccbdccc5dc5 (patch)
treeb9c0e277abb905c850c4e7b7e0d8615bf32983ff /sys/net80211
parentfcb7f09afa00151c86541bef3c214f25a101d786 (diff)
downloadFreeBSD-src-7d1366bf6d72fe0b21b589eee177dccbdccc5dc5.zip
FreeBSD-src-7d1366bf6d72fe0b21b589eee177dccbdccc5dc5.tar.gz
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
Diffstat (limited to 'sys/net80211')
-rw-r--r--sys/net80211/ieee80211.c4
-rw-r--r--sys/net80211/ieee80211_input.c243
-rw-r--r--sys/net80211/ieee80211_ioctl.c34
-rw-r--r--sys/net80211/ieee80211_node.c193
-rw-r--r--sys/net80211/ieee80211_node.h36
-rw-r--r--sys/net80211/ieee80211_output.c20
-rw-r--r--sys/net80211/ieee80211_proto.c4
-rw-r--r--sys/net80211/ieee80211_proto.h1
-rw-r--r--sys/net80211/ieee80211_var.h1
9 files changed, 316 insertions, 220 deletions
diff --git a/sys/net80211/ieee80211.c b/sys/net80211/ieee80211.c
index a34f875..74ee627 100644
--- a/sys/net80211/ieee80211.c
+++ b/sys/net80211/ieee80211.c
@@ -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 */
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;
}
diff --git a/sys/net80211/ieee80211_ioctl.c b/sys/net80211/ieee80211_ioctl.c
index db9439f..e8cf5c4 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 @@ found:
;
}
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 af7c1fc..dc098a0 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 6b3934e..e2bfc2c 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 85e610d..b6c1586 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 b76d576..5537b33 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 18a4211..45fe164 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 2ef0e54..c552d36 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;
OpenPOWER on IntegriCloud