summaryrefslogtreecommitdiffstats
path: root/sys/net80211/ieee80211_node.c
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/ieee80211_node.c
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/ieee80211_node.c')
-rw-r--r--sys/net80211/ieee80211_node.c193
1 files changed, 184 insertions, 9 deletions
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) \
OpenPOWER on IntegriCloud