summaryrefslogtreecommitdiffstats
path: root/freebsd/sys/net80211/ieee80211_node.c
diff options
context:
space:
mode:
authorChristian Mauderer <Christian.Mauderer@embedded-brains.de>2016-11-14 13:46:13 +0100
committerChristian Mauderer <Christian.Mauderer@embedded-brains.de>2017-01-17 12:50:57 +0100
commita241ea8e924154a217768b6e4910a62e0d25cfe2 (patch)
tree404fef7dab5f6dd06c0c3889dbc96214a5e226d4 /freebsd/sys/net80211/ieee80211_node.c
parentUse thread name support (diff)
downloadrtems-libbsd-a241ea8e924154a217768b6e4910a62e0d25cfe2.tar.bz2
Import IEEE 802.11 from FreeBSD.
Diffstat (limited to 'freebsd/sys/net80211/ieee80211_node.c')
-rw-r--r--freebsd/sys/net80211/ieee80211_node.c776
1 files changed, 516 insertions, 260 deletions
diff --git a/freebsd/sys/net80211/ieee80211_node.c b/freebsd/sys/net80211/ieee80211_node.c
index 5bf33549..c9c6df96 100644
--- a/freebsd/sys/net80211/ieee80211_node.c
+++ b/freebsd/sys/net80211/ieee80211_node.c
@@ -40,6 +40,7 @@ __FBSDID("$FreeBSD$");
#include <sys/socket.h>
#include <net/if.h>
+#include <net/if_var.h>
#include <net/if_media.h>
#include <net/ethernet.h>
@@ -74,12 +75,6 @@ CTASSERT((IEEE80211_NODE_HASHSIZE & (IEEE80211_NODE_HASHSIZE-1)) == 0);
#define IEEE80211_AID_ISSET(_vap, b) \
((_vap)->iv_aid_bitmap[IEEE80211_AID(b) / 32] & (1 << (IEEE80211_AID(b) % 32)))
-#ifdef IEEE80211_DEBUG_REFCNT
-#define REFCNT_LOC "%s (%s:%u) %p<%s> refcnt %d\n", __func__, func, line
-#else
-#define REFCNT_LOC "%s %p<%s> refcnt %d\n", __func__
-#endif
-
static int ieee80211_sta_join1(struct ieee80211_node *);
static struct ieee80211_node *node_alloc(struct ieee80211vap *,
@@ -94,6 +89,8 @@ static void node_getmimoinfo(const struct ieee80211_node *,
static void _ieee80211_free_node(struct ieee80211_node *);
+static void node_reclaim(struct ieee80211_node_table *nt,
+ struct ieee80211_node *ni);
static void ieee80211_node_table_init(struct ieee80211com *ic,
struct ieee80211_node_table *nt, const char *name,
int inact, int keymaxix);
@@ -113,7 +110,7 @@ ieee80211_node_attach(struct ieee80211com *ic)
"802.11 staging q");
ieee80211_node_table_init(ic, &ic->ic_sta, "station",
IEEE80211_INACT_INIT, ic->ic_max_keyix);
- callout_init(&ic->ic_inact, CALLOUT_MPSAFE);
+ callout_init(&ic->ic_inact, 1);
callout_reset(&ic->ic_inact, IEEE80211_INACT_WAIT*hz,
ieee80211_node_timeout, ic);
@@ -171,9 +168,10 @@ ieee80211_node_latevattach(struct ieee80211vap *vap)
"WARNING: max aid too small, changed to %d\n",
vap->iv_max_aid);
}
- vap->iv_aid_bitmap = (uint32_t *) malloc(
+ vap->iv_aid_bitmap = (uint32_t *) IEEE80211_MALLOC(
howmany(vap->iv_max_aid, 32) * sizeof(uint32_t),
- M_80211_NODE, M_NOWAIT | M_ZERO);
+ M_80211_NODE,
+ IEEE80211_M_NOWAIT | IEEE80211_M_ZERO);
if (vap->iv_aid_bitmap == NULL) {
/* XXX no way to recover */
printf("%s: no memory for AID bitmap, max aid %d!\n",
@@ -198,7 +196,7 @@ ieee80211_node_vdetach(struct ieee80211vap *vap)
vap->iv_bss = NULL;
}
if (vap->iv_aid_bitmap != NULL) {
- free(vap->iv_aid_bitmap, M_80211_NODE);
+ IEEE80211_FREE(vap->iv_aid_bitmap, M_80211_NODE);
vap->iv_aid_bitmap = NULL;
}
}
@@ -328,9 +326,11 @@ ieee80211_create_ibss(struct ieee80211vap* vap, struct ieee80211_channel *chan)
struct ieee80211_node *ni;
IEEE80211_DPRINTF(vap, IEEE80211_MSG_SCAN,
- "%s: creating %s on channel %u\n", __func__,
+ "%s: creating %s on channel %u%c flags 0x%08x\n", __func__,
ieee80211_opmode_name[vap->iv_opmode],
- ieee80211_chan2ieee(ic, chan));
+ ieee80211_chan2ieee(ic, chan),
+ ieee80211_channel_type_char(chan),
+ chan->ic_flags);
ni = ieee80211_alloc_node(&ic->ic_sta, vap, vap->iv_myaddr);
if (ni == NULL) {
@@ -411,6 +411,14 @@ ieee80211_create_ibss(struct ieee80211vap* vap, struct ieee80211_channel *chan)
}
}
+ /* XXX TODO: other bits and pieces - eg fast-frames? */
+
+ /* If we're an 11n channel then initialise the 11n bits */
+ if (IEEE80211_IS_CHAN_HT(ni->ni_chan)) {
+ /* XXX what else? */
+ ieee80211_ht_node_init(ni);
+ }
+
(void) ieee80211_sta_join1(ieee80211_ref_node(ni));
}
@@ -554,31 +562,18 @@ check_bss_debug(struct ieee80211vap *vap, struct ieee80211_node *ni)
}
#endif /* IEEE80211_DEBUG */
-/*
- * Handle 802.11 ad hoc network merge. The
- * convention, set by the Wireless Ethernet Compatibility Alliance
- * (WECA), is that an 802.11 station will change its BSSID to match
- * the "oldest" 802.11 ad hoc network, on the same channel, that
- * has the station's desired SSID. The "oldest" 802.11 network
- * sends beacons with the greatest TSF timestamp.
- *
- * The caller is assumed to validate TSF's before attempting a merge.
- *
- * Return !0 if the BSSID changed, 0 otherwise.
- */
+
int
-ieee80211_ibss_merge(struct ieee80211_node *ni)
+ieee80211_ibss_merge_check(struct ieee80211_node *ni)
{
struct ieee80211vap *vap = ni->ni_vap;
-#ifdef IEEE80211_DEBUG
- struct ieee80211com *ic = ni->ni_ic;
-#endif
if (ni == vap->iv_bss ||
IEEE80211_ADDR_EQ(ni->ni_bssid, vap->iv_bss->ni_bssid)) {
/* unchanged, nothing to do */
return 0;
}
+
if (!check_bss(vap, ni)) {
/* capabilities mismatch */
IEEE80211_DPRINTF(vap, IEEE80211_MSG_ASSOC,
@@ -590,6 +585,89 @@ ieee80211_ibss_merge(struct ieee80211_node *ni)
vap->iv_stats.is_ibss_capmismatch++;
return 0;
}
+
+ return 1;
+}
+
+/*
+ * Check if the given node should populate the node table.
+ *
+ * We need to be in "see all beacons for all ssids" mode in order
+ * to do IBSS merges, however this means we will populate nodes for
+ * /all/ IBSS SSIDs, versus just the one we care about.
+ *
+ * So this check ensures the node can actually belong to our IBSS
+ * configuration. For now it simply checks the SSID.
+ */
+int
+ieee80211_ibss_node_check_new(struct ieee80211_node *ni,
+ const struct ieee80211_scanparams *scan)
+{
+ struct ieee80211vap *vap = ni->ni_vap;
+ int i;
+
+ /*
+ * If we have no SSID and no scan SSID, return OK.
+ */
+ if (vap->iv_des_nssid == 0 && scan->ssid == NULL)
+ goto ok;
+
+ /*
+ * If we have one of (SSID, scan SSID) then return error.
+ */
+ if (!! (vap->iv_des_nssid == 0) != !! (scan->ssid == NULL))
+ goto mismatch;
+
+ /*
+ * Double-check - we need scan SSID.
+ */
+ if (scan->ssid == NULL)
+ goto mismatch;
+
+ /*
+ * Check if the scan SSID matches the SSID list for the VAP.
+ */
+ for (i = 0; i < vap->iv_des_nssid; i++) {
+
+ /* Sanity length check */
+ if (vap->iv_des_ssid[i].len != scan->ssid[1])
+ continue;
+
+ /* Note: SSID in the scan entry is the IE format */
+ if (memcmp(vap->iv_des_ssid[i].ssid, scan->ssid + 2,
+ vap->iv_des_ssid[i].len) == 0)
+ goto ok;
+ }
+
+mismatch:
+ return (0);
+ok:
+ return (1);
+}
+
+/*
+ * Handle 802.11 ad hoc network merge. The
+ * convention, set by the Wireless Ethernet Compatibility Alliance
+ * (WECA), is that an 802.11 station will change its BSSID to match
+ * the "oldest" 802.11 ad hoc network, on the same channel, that
+ * has the station's desired SSID. The "oldest" 802.11 network
+ * sends beacons with the greatest TSF timestamp.
+ *
+ * The caller is assumed to validate TSF's before attempting a merge.
+ *
+ * Return !0 if the BSSID changed, 0 otherwise.
+ */
+int
+ieee80211_ibss_merge(struct ieee80211_node *ni)
+{
+#ifdef IEEE80211_DEBUG
+ struct ieee80211vap *vap = ni->ni_vap;
+ struct ieee80211com *ic = ni->ni_ic;
+#endif
+
+ if (! ieee80211_ibss_merge_check(ni))
+ return 0;
+
IEEE80211_DPRINTF(vap, IEEE80211_MSG_ASSOC,
"%s: new bssid %s: %s preamble, %s slot time%s\n", __func__,
ether_sprintf(ni->ni_bssid),
@@ -687,6 +765,14 @@ ieee80211_setcurchan(struct ieee80211com *ic, struct ieee80211_channel *c)
ieee80211_runtask(ic, &ic->ic_chan_task);
}
+void
+ieee80211_update_chw(struct ieee80211com *ic)
+{
+
+ ieee80211_setupcurchan(ic, ic->ic_curchan);
+ ieee80211_runtask(ic, &ic->ic_chw_task);
+}
+
/*
* Join the specified IBSS/BSS network. The node is assumed to
* be passed in with a held reference.
@@ -712,9 +798,15 @@ ieee80211_sta_join1(struct ieee80211_node *selbs)
IEEE80211_ADDR_EQ(obss->ni_macaddr, selbs->ni_macaddr));
vap->iv_bss = selbs; /* NB: caller assumed to bump refcnt */
if (obss != NULL) {
+ struct ieee80211_node_table *nt = obss->ni_table;
+
copy_bss(selbs, obss);
ieee80211_node_decref(obss); /* iv_bss reference */
- ieee80211_free_node(obss); /* station table reference */
+
+ IEEE80211_NODE_LOCK(nt);
+ node_reclaim(nt, obss); /* station table reference */
+ IEEE80211_NODE_UNLOCK(nt);
+
obss = NULL; /* NB: guard against later use */
}
@@ -765,6 +857,7 @@ ieee80211_sta_join(struct ieee80211vap *vap, struct ieee80211_channel *chan,
/* XXX msg */
return 0;
}
+
/*
* Expand scan state into node's format.
* XXX may not need all this stuff
@@ -805,6 +898,10 @@ ieee80211_sta_join(struct ieee80211vap *vap, struct ieee80211_channel *chan,
if (ni->ni_ies.tdma_ie != NULL)
ieee80211_parse_tdma(ni, ni->ni_ies.tdma_ie);
#endif
+
+ /* XXX parse VHT IEs */
+ /* XXX parse BSSLOAD IE */
+ /* XXX parse APCHANREP IE */
}
vap->iv_dtim_period = se->se_dtimperiod;
@@ -815,6 +912,29 @@ ieee80211_sta_join(struct ieee80211vap *vap, struct ieee80211_channel *chan,
IEEE80211_F_DOSORT);
if (ieee80211_iserp_rateset(&ni->ni_rates))
ni->ni_flags |= IEEE80211_NODE_ERP;
+
+ /*
+ * Setup HT state for this node if it's available, otherwise
+ * non-STA modes won't pick this state up.
+ *
+ * For IBSS and related modes that don't go through an
+ * association request/response, the only appropriate place
+ * to setup the HT state is here.
+ */
+ if (ni->ni_ies.htinfo_ie != NULL &&
+ ni->ni_ies.htcap_ie != NULL &&
+ vap->iv_flags_ht & IEEE80211_FHT_HT) {
+ ieee80211_ht_node_init(ni);
+ ieee80211_ht_updateparams(ni,
+ ni->ni_ies.htcap_ie,
+ ni->ni_ies.htinfo_ie);
+ ieee80211_setup_htrates(ni, ni->ni_ies.htcap_ie,
+ IEEE80211_F_JOIN | IEEE80211_F_DOBRS);
+ ieee80211_setup_basic_htrates(ni, ni->ni_ies.htinfo_ie);
+ }
+ /* XXX else check for ath FF? */
+ /* XXX QoS? Difficult given that WME config is specific to a master */
+
ieee80211_node_setuptxparms(ni);
ieee80211_ratectl_node_init(ni);
@@ -840,7 +960,7 @@ ieee80211_sta_leave(struct ieee80211_node *ni)
void
ieee80211_node_deauth(struct ieee80211_node *ni, int reason)
{
- /* NB: bump the refcnt to be sure temporay nodes are not reclaimed */
+ /* NB: bump the refcnt to be sure temporary nodes are not reclaimed */
ieee80211_ref_node(ni);
if (ni->ni_associd != 0)
IEEE80211_SEND_MGMT(ni, IEEE80211_FC0_SUBTYPE_DEAUTH, reason);
@@ -853,8 +973,8 @@ node_alloc(struct ieee80211vap *vap, const uint8_t macaddr[IEEE80211_ADDR_LEN])
{
struct ieee80211_node *ni;
- ni = (struct ieee80211_node *) malloc(sizeof(struct ieee80211_node),
- M_80211_NODE, M_NOWAIT | M_ZERO);
+ ni = (struct ieee80211_node *) IEEE80211_MALLOC(sizeof(struct ieee80211_node),
+ M_80211_NODE, IEEE80211_M_NOWAIT | IEEE80211_M_ZERO);
return ni;
}
@@ -871,11 +991,12 @@ ieee80211_ies_init(struct ieee80211_ies *ies, const uint8_t *data, int len)
memset(ies, 0, offsetof(struct ieee80211_ies, data));
if (ies->data != NULL && ies->len != len) {
/* data size changed */
- free(ies->data, M_80211_NODE_IE);
+ IEEE80211_FREE(ies->data, M_80211_NODE_IE);
ies->data = NULL;
}
if (ies->data == NULL) {
- ies->data = (uint8_t *) malloc(len, M_80211_NODE_IE, M_NOWAIT);
+ ies->data = (uint8_t *) IEEE80211_MALLOC(len, M_80211_NODE_IE,
+ IEEE80211_M_NOWAIT | IEEE80211_M_ZERO);
if (ies->data == NULL) {
ies->len = 0;
/* NB: pointers have already been zero'd above */
@@ -894,7 +1015,7 @@ void
ieee80211_ies_cleanup(struct ieee80211_ies *ies)
{
if (ies->data != NULL)
- free(ies->data, M_80211_NODE_IE);
+ IEEE80211_FREE(ies->data, M_80211_NODE_IE);
}
/*
@@ -932,11 +1053,29 @@ ieee80211_ies_expand(struct ieee80211_ies *ies)
case IEEE80211_ELEMID_HTCAP:
ies->htcap_ie = ie;
break;
+ case IEEE80211_ELEMID_HTINFO:
+ ies->htinfo_ie = ie;
+ break;
#ifdef IEEE80211_SUPPORT_MESH
case IEEE80211_ELEMID_MESHID:
ies->meshid_ie = ie;
break;
#endif
+ case IEEE80211_ELEMID_VHT_CAP:
+ ies->vhtcap_ie = ie;
+ break;
+ case IEEE80211_ELEMID_VHT_OPMODE:
+ ies->vhtopmode_ie = ie;
+ break;
+ case IEEE80211_ELEMID_VHT_PWR_ENV:
+ ies->vhtpwrenv_ie = ie;
+ break;
+ case IEEE80211_ELEMID_BSSLOAD:
+ ies->bssload_ie = ie;
+ break;
+ case IEEE80211_ELEMID_APCHANREP:
+ ies->apchanrep_ie = ie;
+ break;
}
ielen -= 2 + ie[1];
ie += 2 + ie[1];
@@ -952,7 +1091,6 @@ ieee80211_ies_expand(struct ieee80211_ies *ies)
static void
node_cleanup(struct ieee80211_node *ni)
{
-#define N(a) (sizeof(a)/sizeof(a[0]))
struct ieee80211vap *vap = ni->ni_vap;
struct ieee80211com *ic = ni->ni_ic;
int i;
@@ -971,8 +1109,8 @@ node_cleanup(struct ieee80211_node *ni)
if (ni->ni_flags & IEEE80211_NODE_HT)
ieee80211_ht_node_cleanup(ni);
#ifdef IEEE80211_SUPPORT_SUPERG
- else if (ni->ni_ath_flags & IEEE80211_NODE_ATH)
- ieee80211_ff_node_cleanup(ni);
+ /* Always do FF node cleanup; for A-MSDU */
+ ieee80211_ff_node_cleanup(ni);
#endif
#ifdef IEEE80211_SUPPORT_MESH
/*
@@ -1004,7 +1142,7 @@ node_cleanup(struct ieee80211_node *ni)
ni->ni_associd = 0;
if (ni->ni_challenge != NULL) {
- free(ni->ni_challenge, M_80211_NODE);
+ IEEE80211_FREE(ni->ni_challenge, M_80211_NODE);
ni->ni_challenge = NULL;
}
/*
@@ -1019,7 +1157,7 @@ node_cleanup(struct ieee80211_node *ni)
*
* XXX does this leave us open to inheriting old state?
*/
- for (i = 0; i < N(ni->ni_rxfrag); i++)
+ for (i = 0; i < nitems(ni->ni_rxfrag); i++)
if (ni->ni_rxfrag[i] != NULL) {
m_freem(ni->ni_rxfrag[i]);
ni->ni_rxfrag[i] = NULL;
@@ -1028,7 +1166,6 @@ node_cleanup(struct ieee80211_node *ni)
* Must be careful here to remove any key map entry w/o a LOR.
*/
ieee80211_node_delucastkey(ni);
-#undef N
}
static void
@@ -1040,7 +1177,7 @@ node_free(struct ieee80211_node *ni)
ic->ic_node_cleanup(ni);
ieee80211_ies_cleanup(&ni->ni_ies);
ieee80211_psq_cleanup(&ni->ni_psq);
- free(ni, M_80211_NODE);
+ IEEE80211_FREE(ni, M_80211_NODE);
}
static void
@@ -1048,8 +1185,6 @@ node_age(struct ieee80211_node *ni)
{
struct ieee80211vap *vap = ni->ni_vap;
- IEEE80211_NODE_LOCK_ASSERT(&vap->iv_ic->ic_sta);
-
/*
* Age frames on the power save queue.
*/
@@ -1109,13 +1244,44 @@ node_getmimoinfo(const struct ieee80211_node *ni,
/* XXX EVM? */
}
+static void
+ieee80211_add_node_nt(struct ieee80211_node_table *nt,
+ struct ieee80211_node *ni)
+{
+ struct ieee80211com *ic = nt->nt_ic;
+ int hash;
+
+ IEEE80211_NODE_LOCK_ASSERT(nt);
+
+ hash = IEEE80211_NODE_HASH(ic, ni->ni_macaddr);
+ (void) ic; /* XXX IEEE80211_NODE_HASH */
+ TAILQ_INSERT_TAIL(&nt->nt_node, ni, ni_list);
+ LIST_INSERT_HEAD(&nt->nt_hash[hash], ni, ni_hash);
+ nt->nt_count++;
+ ni->ni_table = nt;
+}
+
+static void
+ieee80211_del_node_nt(struct ieee80211_node_table *nt,
+ struct ieee80211_node *ni)
+{
+
+ IEEE80211_NODE_LOCK_ASSERT(nt);
+
+ TAILQ_REMOVE(&nt->nt_node, ni, ni_list);
+ LIST_REMOVE(ni, ni_hash);
+ nt->nt_count--;
+ KASSERT(nt->nt_count >= 0,
+ ("nt_count is negative (%d)!\n", nt->nt_count));
+ ni->ni_table = NULL;
+}
+
struct ieee80211_node *
ieee80211_alloc_node(struct ieee80211_node_table *nt,
struct ieee80211vap *vap, const uint8_t macaddr[IEEE80211_ADDR_LEN])
{
struct ieee80211com *ic = nt->nt_ic;
struct ieee80211_node *ni;
- int hash;
ni = ic->ic_node_alloc(vap, macaddr);
if (ni == NULL) {
@@ -1128,7 +1294,6 @@ ieee80211_alloc_node(struct ieee80211_node_table *nt,
ether_sprintf(macaddr), nt->nt_name);
IEEE80211_ADDR_COPY(ni->ni_macaddr, macaddr);
- hash = IEEE80211_NODE_HASH(ic, macaddr);
ieee80211_node_initref(ni); /* mark referenced */
ni->ni_chan = IEEE80211_CHAN_ANYC;
ni->ni_authmode = IEEE80211_AUTH_OPEN;
@@ -1145,9 +1310,7 @@ ieee80211_alloc_node(struct ieee80211_node_table *nt,
ieee80211_mesh_node_init(vap, ni);
#endif
IEEE80211_NODE_LOCK(nt);
- TAILQ_INSERT_TAIL(&nt->nt_node, ni, ni_list);
- LIST_INSERT_HEAD(&nt->nt_hash[hash], ni, ni_hash);
- ni->ni_table = nt;
+ ieee80211_add_node_nt(nt, ni);
ni->ni_vap = vap;
ni->ni_ic = ic;
IEEE80211_NODE_UNLOCK(nt);
@@ -1398,7 +1561,7 @@ ieee80211_fakeup_adhoc_node(struct ieee80211vap *vap,
{
struct ieee80211_node *ni;
- IEEE80211_DPRINTF(vap, IEEE80211_MSG_NODE,
+ IEEE80211_DPRINTF(vap, IEEE80211_MSG_NODE | IEEE80211_MSG_ASSOC,
"%s: mac<%s>\n", __func__, ether_sprintf(macaddr));
ni = ieee80211_dup_bss(vap, macaddr);
if (ni != NULL) {
@@ -1416,6 +1579,9 @@ ieee80211_fakeup_adhoc_node(struct ieee80211vap *vap,
* so we can do interesting things (e.g. use
* WME to disable ACK's).
*/
+ /*
+ * XXX TODO: 11n?
+ */
if (vap->iv_flags & IEEE80211_F_WME)
ni->ni_flags |= IEEE80211_NODE_QOS;
#ifdef IEEE80211_SUPPORT_SUPERG
@@ -1425,8 +1591,44 @@ ieee80211_fakeup_adhoc_node(struct ieee80211vap *vap,
}
ieee80211_node_setuptxparms(ni);
ieee80211_ratectl_node_init(ni);
+
+ /*
+ * XXX TODO: 11n? At least 20MHz, at least A-MPDU RX,
+ * not A-MPDU TX; not 11n rates, etc. We'll cycle
+ * that after we hear that we can indeed do 11n
+ * (either by a beacon frame or by a probe response.)
+ */
+
+ /*
+ * This is the first time we see the node.
+ */
if (ic->ic_newassoc != NULL)
ic->ic_newassoc(ni, 1);
+
+ /*
+ * Kick off a probe request to the given node;
+ * we will then use the probe response to update
+ * 11n/etc configuration state.
+ *
+ * XXX TODO: this isn't guaranteed, and until we get
+ * a probe response, we won't be able to actually
+ * do anything 802.11n related to the node.
+ * So if this does indeed work, maybe we should hold
+ * off on sending responses until we get the probe
+ * response, or just default to some sensible subset
+ * of 802.11n behaviour (eg always allow aggregation
+ * negotiation TO us, but not FROM us, etc) so we
+ * aren't entirely busted.
+ */
+ if (vap->iv_opmode == IEEE80211_M_IBSS) {
+ ieee80211_send_probereq(ni, /* node */
+ vap->iv_myaddr, /* SA */
+ ni->ni_macaddr, /* DA */
+ vap->iv_bss->ni_bssid, /* BSSID */
+ vap->iv_bss->ni_essid,
+ vap->iv_bss->ni_esslen); /* SSID */
+ }
+
/* XXX not right for 802.1x/WPA */
ieee80211_node_authorize(ni);
}
@@ -1438,6 +1640,8 @@ ieee80211_init_neighbor(struct ieee80211_node *ni,
const struct ieee80211_frame *wh,
const struct ieee80211_scanparams *sp)
{
+ int do_ht_setup = 0;
+
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);
@@ -1463,12 +1667,56 @@ ieee80211_init_neighbor(struct ieee80211_node *ni,
if (ni->ni_ies.ath_ie != NULL)
ieee80211_parse_ath(ni, ni->ni_ies.ath_ie);
#endif
+ if (ni->ni_ies.htcap_ie != NULL)
+ ieee80211_parse_htcap(ni, ni->ni_ies.htcap_ie);
+ if (ni->ni_ies.htinfo_ie != NULL)
+ ieee80211_parse_htinfo(ni, ni->ni_ies.htinfo_ie);
+
+ if ((ni->ni_ies.htcap_ie != NULL) &&
+ (ni->ni_ies.htinfo_ie != NULL) &&
+ (ni->ni_vap->iv_flags_ht & IEEE80211_FHT_HT)) {
+ do_ht_setup = 1;
+ }
}
/* NB: must be after ni_chan is setup */
ieee80211_setup_rates(ni, sp->rates, sp->xrates,
IEEE80211_F_DOSORT | IEEE80211_F_DOFRATE |
IEEE80211_F_DONEGO | IEEE80211_F_DODEL);
+
+ /*
+ * If the neighbor is HT compatible, flip that on.
+ */
+ if (do_ht_setup) {
+ IEEE80211_DPRINTF(ni->ni_vap, IEEE80211_MSG_ASSOC,
+ "%s: doing HT setup\n", __func__);
+ ieee80211_ht_node_init(ni);
+ ieee80211_ht_updateparams(ni,
+ ni->ni_ies.htcap_ie,
+ ni->ni_ies.htinfo_ie);
+ ieee80211_setup_htrates(ni,
+ ni->ni_ies.htcap_ie,
+ IEEE80211_F_JOIN | IEEE80211_F_DOBRS);
+ ieee80211_setup_basic_htrates(ni,
+ ni->ni_ies.htinfo_ie);
+ ieee80211_node_setuptxparms(ni);
+ ieee80211_ratectl_node_init(ni);
+
+ /* Reassociate; we're now 11n */
+ /*
+ * XXX TODO: this is the wrong thing to do -
+ * we're calling it with isnew=1 so the ath(4)
+ * driver reinitialises the rate tables.
+ * This "mostly" works for ath(4), but it won't
+ * be right for firmware devices which allocate
+ * node states.
+ *
+ * So, do we just create a new node and delete
+ * the old one? Or?
+ */
+ if (ni->ni_ic->ic_newassoc)
+ ni->ni_ic->ic_newassoc(ni, 1);
+ }
}
/*
@@ -1484,7 +1732,7 @@ ieee80211_add_neighbor(struct ieee80211vap *vap,
{
struct ieee80211_node *ni;
- IEEE80211_DPRINTF(vap, IEEE80211_MSG_NODE,
+ IEEE80211_DPRINTF(vap, IEEE80211_MSG_ASSOC,
"%s: mac<%s>\n", __func__, ether_sprintf(wh->i_addr2));
ni = ieee80211_dup_bss(vap, wh->i_addr2);/* XXX alloc_node? */
if (ni != NULL) {
@@ -1645,6 +1893,10 @@ ieee80211_find_txnode(struct ieee80211vap *vap,
* caller to be consistent with
* ieee80211_find_node_locked.
*/
+ /*
+ * XXX TODO: this doesn't fake up 11n state; we need
+ * to find another way to get it upgraded.
+ */
ni = ieee80211_fakeup_adhoc_node(vap, macaddr);
if (ni != NULL)
(void) ieee80211_ref_node(ni);
@@ -1679,13 +1931,33 @@ _ieee80211_free_node(struct ieee80211_node *ni)
if (vap->iv_aid_bitmap != NULL)
IEEE80211_AID_CLR(vap, ni->ni_associd);
}
- if (nt != NULL) {
- TAILQ_REMOVE(&nt->nt_node, ni, ni_list);
- LIST_REMOVE(ni, ni_hash);
- }
+ if (nt != NULL)
+ ieee80211_del_node_nt(nt, ni);
ni->ni_ic->ic_node_free(ni);
}
+/*
+ * Clear any entry in the unicast key mapping table.
+ */
+static int
+node_clear_keyixmap(struct ieee80211_node_table *nt, struct ieee80211_node *ni)
+{
+ ieee80211_keyix keyix;
+
+ keyix = ni->ni_ucastkey.wk_rxkeyix;
+ if (nt->nt_keyixmap != NULL && keyix < nt->nt_keyixmax &&
+ nt->nt_keyixmap[keyix] == ni) {
+ IEEE80211_DPRINTF(ni->ni_vap, IEEE80211_MSG_NODE,
+ "%s: %p<%s> clear key map entry %u\n",
+ __func__, ni, ether_sprintf(ni->ni_macaddr), keyix);
+ nt->nt_keyixmap[keyix] = NULL;
+ ieee80211_node_decref(ni);
+ return 1;
+ }
+
+ return 0;
+}
+
void
#ifdef IEEE80211_DEBUG_REFCNT
ieee80211_free_node_debug(struct ieee80211_node *ni, const char *func, int line)
@@ -1707,24 +1979,9 @@ ieee80211_free_node(struct ieee80211_node *ni)
* Last reference, reclaim state.
*/
_ieee80211_free_node(ni);
- } else if (ieee80211_node_refcnt(ni) == 1 &&
- nt->nt_keyixmap != NULL) {
- ieee80211_keyix keyix;
- /*
- * Check for a last reference in the key mapping table.
- */
- keyix = ni->ni_ucastkey.wk_rxkeyix;
- if (keyix < nt->nt_keyixmax &&
- nt->nt_keyixmap[keyix] == ni) {
- IEEE80211_DPRINTF(ni->ni_vap,
- IEEE80211_MSG_NODE,
- "%s: %p<%s> clear key map entry", __func__,
- ni, ether_sprintf(ni->ni_macaddr));
- nt->nt_keyixmap[keyix] = NULL;
- ieee80211_node_decref(ni); /* XXX needed? */
+ } else if (ieee80211_node_refcnt(ni) == 1)
+ if (node_clear_keyixmap(nt, ni))
_ieee80211_free_node(ni);
- }
- }
IEEE80211_NODE_UNLOCK(nt);
} else {
if (ieee80211_node_dectestref(ni))
@@ -1792,7 +2049,6 @@ ieee80211_node_delucastkey(struct ieee80211_node *ni)
static void
node_reclaim(struct ieee80211_node_table *nt, struct ieee80211_node *ni)
{
- ieee80211_keyix keyix;
IEEE80211_NODE_LOCK_ASSERT(nt);
@@ -1807,15 +2063,7 @@ node_reclaim(struct ieee80211_node_table *nt, struct ieee80211_node *ni)
* table. We cannot depend on the mapping table entry
* being cleared because the node may not be free'd.
*/
- keyix = ni->ni_ucastkey.wk_rxkeyix;
- if (nt->nt_keyixmap != NULL && keyix < nt->nt_keyixmax &&
- nt->nt_keyixmap[keyix] == ni) {
- IEEE80211_DPRINTF(ni->ni_vap, IEEE80211_MSG_NODE,
- "%s: %p<%s> clear key map entry %u\n",
- __func__, ni, ether_sprintf(ni->ni_macaddr), keyix);
- nt->nt_keyixmap[keyix] = NULL;
- ieee80211_node_decref(ni); /* NB: don't need free */
- }
+ (void)node_clear_keyixmap(nt, ni);
if (!ieee80211_node_dectestref(ni)) {
/*
* Other references are present, just remove the
@@ -1823,9 +2071,7 @@ node_reclaim(struct ieee80211_node_table *nt, struct ieee80211_node *ni)
* the references are dropped storage will be
* reclaimed.
*/
- TAILQ_REMOVE(&nt->nt_node, ni, ni_list);
- LIST_REMOVE(ni, ni_hash);
- ni->ni_table = NULL; /* clear reference */
+ ieee80211_del_node_nt(nt, ni);
} else
_ieee80211_free_node(ni);
}
@@ -1839,22 +2085,21 @@ ieee80211_node_table_init(struct ieee80211com *ic,
struct ieee80211_node_table *nt,
const char *name, int inact, int keyixmax)
{
- struct ifnet *ifp = ic->ic_ifp;
nt->nt_ic = ic;
- IEEE80211_NODE_LOCK_INIT(nt, ifp->if_xname);
- IEEE80211_NODE_ITERATE_LOCK_INIT(nt, ifp->if_xname);
+ IEEE80211_NODE_LOCK_INIT(nt, ic->ic_name);
TAILQ_INIT(&nt->nt_node);
+ nt->nt_count = 0;
nt->nt_name = name;
- nt->nt_scangen = 1;
nt->nt_inact_init = inact;
nt->nt_keyixmax = keyixmax;
if (nt->nt_keyixmax > 0) {
- nt->nt_keyixmap = (struct ieee80211_node **) malloc(
+ nt->nt_keyixmap = (struct ieee80211_node **) IEEE80211_MALLOC(
keyixmax * sizeof(struct ieee80211_node *),
- M_80211_NODE, M_NOWAIT | M_ZERO);
+ M_80211_NODE,
+ IEEE80211_M_NOWAIT | IEEE80211_M_ZERO);
if (nt->nt_keyixmap == NULL)
- if_printf(ic->ic_ifp,
+ ic_printf(ic,
"Cannot allocate key index map with %u entries\n",
keyixmax);
} else
@@ -1911,162 +2156,140 @@ ieee80211_node_table_cleanup(struct ieee80211_node_table *nt)
printf("%s: %s[%u] still active\n", __func__,
nt->nt_name, i);
#endif
- free(nt->nt_keyixmap, M_80211_NODE);
+ IEEE80211_FREE(nt->nt_keyixmap, M_80211_NODE);
nt->nt_keyixmap = NULL;
}
- IEEE80211_NODE_ITERATE_LOCK_DESTROY(nt);
IEEE80211_NODE_LOCK_DESTROY(nt);
}
-/*
- * Timeout inactive stations and do related housekeeping.
- * Note that we cannot hold the node lock while sending a
- * frame as this would lead to a LOR. Instead we use a
- * generation number to mark nodes that we've scanned and
- * drop the lock and restart a scan if we have to time out
- * a node. Since we are single-threaded by virtue of
- * controlling the inactivity timer we can be sure this will
- * process each node only once.
- */
static void
-ieee80211_timeout_stations(struct ieee80211com *ic)
+timeout_stations(void *arg __unused, struct ieee80211_node *ni)
{
- struct ieee80211_node_table *nt = &ic->ic_sta;
- struct ieee80211vap *vap;
- struct ieee80211_node *ni;
- int gen = 0;
+ struct ieee80211com *ic = ni->ni_ic;
+ struct ieee80211vap *vap = ni->ni_vap;
- IEEE80211_NODE_ITERATE_LOCK(nt);
- gen = ++nt->nt_scangen;
-restart:
- IEEE80211_NODE_LOCK(nt);
- TAILQ_FOREACH(ni, &nt->nt_node, ni_list) {
- if (ni->ni_scangen == gen) /* previously handled */
- continue;
- ni->ni_scangen = gen;
- /*
- * Ignore entries for which have yet to receive an
- * authentication frame. These are transient and
- * will be reclaimed when the last reference to them
- * goes away (when frame xmits complete).
- */
- vap = ni->ni_vap;
- /*
- * Only process stations when in RUN state. This
- * insures, for example, that we don't timeout an
- * inactive station during CAC. Note that CSA state
- * is actually handled in ieee80211_node_timeout as
- * it applies to more than timeout processing.
- */
- if (vap->iv_state != IEEE80211_S_RUN)
- continue;
- /* XXX can vap be NULL? */
- if ((vap->iv_opmode == IEEE80211_M_HOSTAP ||
- vap->iv_opmode == IEEE80211_M_STA) &&
- (ni->ni_flags & IEEE80211_NODE_AREF) == 0)
- continue;
+ /*
+ * Only process stations when in RUN state. This
+ * insures, for example, that we don't timeout an
+ * inactive station during CAC. Note that CSA state
+ * is actually handled in ieee80211_node_timeout as
+ * it applies to more than timeout processing.
+ */
+ if (vap->iv_state != IEEE80211_S_RUN)
+ return;
+ /*
+ * Ignore entries for which have yet to receive an
+ * authentication frame. These are transient and
+ * will be reclaimed when the last reference to them
+ * goes away (when frame xmits complete).
+ */
+ if ((vap->iv_opmode == IEEE80211_M_HOSTAP ||
+ vap->iv_opmode == IEEE80211_M_STA) &&
+ (ni->ni_flags & IEEE80211_NODE_AREF) == 0)
+ return;
+ /*
+ * Free fragment if not needed anymore
+ * (last fragment older than 1s).
+ * XXX doesn't belong here, move to node_age
+ */
+ if (ni->ni_rxfrag[0] != NULL &&
+ ticks > ni->ni_rxfragstamp + hz) {
+ m_freem(ni->ni_rxfrag[0]);
+ ni->ni_rxfrag[0] = NULL;
+ }
+ if (ni->ni_inact > 0) {
+ ni->ni_inact--;
+ IEEE80211_NOTE(vap, IEEE80211_MSG_INACT, ni,
+ "%s: inact %u inact_reload %u nrates %u",
+ __func__, ni->ni_inact, ni->ni_inact_reload,
+ ni->ni_rates.rs_nrates);
+ }
+ /*
+ * Special case ourself; we may be idle for extended periods
+ * of time and regardless reclaiming our state is wrong.
+ * XXX run ic_node_age
+ */
+ /* XXX before inact decrement? */
+ if (ni == vap->iv_bss)
+ return;
+ if (ni->ni_associd != 0 ||
+ (vap->iv_opmode == IEEE80211_M_IBSS ||
+ vap->iv_opmode == IEEE80211_M_AHDEMO)) {
/*
- * Free fragment if not needed anymore
- * (last fragment older than 1s).
- * XXX doesn't belong here, move to node_age
+ * Age/drain resources held by the station.
*/
- if (ni->ni_rxfrag[0] != NULL &&
- ticks > ni->ni_rxfragstamp + hz) {
- m_freem(ni->ni_rxfrag[0]);
- ni->ni_rxfrag[0] = NULL;
- }
- if (ni->ni_inact > 0) {
- ni->ni_inact--;
- IEEE80211_NOTE(vap, IEEE80211_MSG_INACT, ni,
- "%s: inact %u inact_reload %u nrates %u",
- __func__, ni->ni_inact, ni->ni_inact_reload,
- ni->ni_rates.rs_nrates);
- }
+ ic->ic_node_age(ni);
/*
- * Special case ourself; we may be idle for extended periods
- * of time and regardless reclaiming our state is wrong.
- * XXX run ic_node_age
+ * Probe the station before time it out. We
+ * send a null data frame which may not be
+ * universally supported by drivers (need it
+ * for ps-poll support so it should be...).
+ *
+ * XXX don't probe the station unless we've
+ * received a frame from them (and have
+ * some idea of the rates they are capable
+ * of); this will get fixed more properly
+ * soon with better handling of the rate set.
*/
- if (ni == vap->iv_bss)
- continue;
- if (ni->ni_associd != 0 ||
- (vap->iv_opmode == IEEE80211_M_IBSS ||
- vap->iv_opmode == IEEE80211_M_AHDEMO)) {
- /*
- * Age/drain resources held by the station.
- */
- ic->ic_node_age(ni);
- /*
- * Probe the station before time it out. We
- * send a null data frame which may not be
- * universally supported by drivers (need it
- * for ps-poll support so it should be...).
- *
- * XXX don't probe the station unless we've
- * received a frame from them (and have
- * some idea of the rates they are capable
- * of); this will get fixed more properly
- * soon with better handling of the rate set.
- */
- if ((vap->iv_flags_ext & IEEE80211_FEXT_INACT) &&
- (0 < ni->ni_inact &&
- ni->ni_inact <= vap->iv_inact_probe) &&
- ni->ni_rates.rs_nrates != 0) {
- IEEE80211_NOTE(vap,
- IEEE80211_MSG_INACT | IEEE80211_MSG_NODE,
- ni, "%s",
- "probe station due to inactivity");
- /*
- * Grab a reference before unlocking the table
- * so the node cannot be reclaimed before we
- * send the frame. ieee80211_send_nulldata
- * understands we've done this and reclaims the
- * ref for us as needed.
- */
- ieee80211_ref_node(ni);
- IEEE80211_NODE_UNLOCK(nt);
- ieee80211_send_nulldata(ni);
- /* XXX stat? */
- goto restart;
- }
- }
if ((vap->iv_flags_ext & IEEE80211_FEXT_INACT) &&
- ni->ni_inact <= 0) {
+ (0 < ni->ni_inact &&
+ ni->ni_inact <= vap->iv_inact_probe) &&
+ ni->ni_rates.rs_nrates != 0) {
IEEE80211_NOTE(vap,
- IEEE80211_MSG_INACT | IEEE80211_MSG_NODE, ni,
- "station timed out due to inactivity "
- "(refcnt %u)", ieee80211_node_refcnt(ni));
+ IEEE80211_MSG_INACT | IEEE80211_MSG_NODE,
+ ni, "%s",
+ "probe station due to inactivity");
/*
- * Send a deauthenticate frame and drop the station.
- * This is somewhat complicated due to reference counts
- * and locking. At this point a station will typically
- * have a reference count of 1. ieee80211_node_leave
- * will do a "free" of the node which will drop the
- * reference count. But in the meantime a reference
- * wil be held by the deauth frame. The actual reclaim
- * of the node will happen either after the tx is
- * completed or by ieee80211_node_leave.
- *
- * Separately we must drop the node lock before sending
- * in case the driver takes a lock, as this can result
- * in a LOR between the node lock and the driver lock.
+ * Grab a reference so the node cannot
+ * be reclaimed before we send the frame.
+ * ieee80211_send_nulldata understands
+ * we've done this and reclaims the
+ * ref for us as needed.
*/
+ /* XXX fix this (not required anymore). */
ieee80211_ref_node(ni);
- IEEE80211_NODE_UNLOCK(nt);
- if (ni->ni_associd != 0) {
- IEEE80211_SEND_MGMT(ni,
- IEEE80211_FC0_SUBTYPE_DEAUTH,
- IEEE80211_REASON_AUTH_EXPIRE);
- }
- ieee80211_node_leave(ni);
- ieee80211_free_node(ni);
- vap->iv_stats.is_node_timeout++;
- goto restart;
+ /* XXX useless */
+ ieee80211_send_nulldata(ni);
+ /* XXX stat? */
+ return;
}
}
- IEEE80211_NODE_UNLOCK(nt);
+ if ((vap->iv_flags_ext & IEEE80211_FEXT_INACT) &&
+ ni->ni_inact <= 0) {
+ IEEE80211_NOTE(vap,
+ IEEE80211_MSG_INACT | IEEE80211_MSG_NODE, ni,
+ "station timed out due to inactivity "
+ "(refcnt %u)", ieee80211_node_refcnt(ni));
+ /*
+ * Send a deauthenticate frame and drop the station.
+ * This is somewhat complicated due to reference counts
+ * and locking. At this point a station will typically
+ * have a reference count of 2. ieee80211_node_leave
+ * will do a "free" of the node which will drop the
+ * reference count. But in the meantime a reference
+ * wil be held by the deauth frame. The actual reclaim
+ * of the node will happen either after the tx is
+ * completed or by ieee80211_node_leave.
+ */
+ if (ni->ni_associd != 0) {
+ IEEE80211_SEND_MGMT(ni,
+ IEEE80211_FC0_SUBTYPE_DEAUTH,
+ IEEE80211_REASON_AUTH_EXPIRE);
+ }
+ ieee80211_node_leave(ni);
+ vap->iv_stats.is_node_timeout++;
+ }
+}
+
+/*
+ * Timeout inactive stations and do related housekeeping.
+ */
+static void
+ieee80211_timeout_stations(struct ieee80211com *ic)
+{
+ struct ieee80211_node_table *nt = &ic->ic_sta;
- IEEE80211_NODE_ITERATE_UNLOCK(nt);
+ ieee80211_iterate_nodes(nt, timeout_stations, NULL);
}
/*
@@ -2131,7 +2354,7 @@ ieee80211_node_timeout(void *arg)
* Defer timeout processing if a channel switch is pending.
* We typically need to be mute so not doing things that
* might generate frames is good to handle in one place.
- * Supressing the station timeout processing may extend the
+ * Suppressing the station timeout processing may extend the
* lifetime of inactive stations (by not decrementing their
* idle counters) but this should be ok unless the CSA is
* active for an unusually long time.
@@ -2150,30 +2373,69 @@ ieee80211_node_timeout(void *arg)
ieee80211_node_timeout, ic);
}
-void
-ieee80211_iterate_nodes(struct ieee80211_node_table *nt,
- ieee80211_iter_func *f, void *arg)
+/*
+ * The same as ieee80211_iterate_nodes(), but for one vap only.
+ */
+int
+ieee80211_iterate_nodes_vap(struct ieee80211_node_table *nt,
+ struct ieee80211vap *vap, ieee80211_iter_func *f, void *arg)
{
+ struct ieee80211_node **ni_arr;
struct ieee80211_node *ni;
- u_int gen;
+ size_t size;
+ int count, i;
- IEEE80211_NODE_ITERATE_LOCK(nt);
- gen = ++nt->nt_scangen;
-restart:
+ /*
+ * Iterate over the node table and save an array of ref'ed nodes.
+ *
+ * This is separated out from calling the actual node function so that
+ * no LORs will occur.
+ */
IEEE80211_NODE_LOCK(nt);
+ count = nt->nt_count;
+ size = count * sizeof(struct ieee80211_node *);
+ ni_arr = (struct ieee80211_node **) IEEE80211_MALLOC(size, M_80211_NODE,
+ IEEE80211_M_NOWAIT | IEEE80211_M_ZERO);
+ if (ni_arr == NULL) {
+ IEEE80211_NODE_UNLOCK(nt);
+ return (ENOMEM);
+ }
+
+ i = 0;
TAILQ_FOREACH(ni, &nt->nt_node, ni_list) {
- if (ni->ni_scangen != gen) {
- ni->ni_scangen = gen;
- (void) ieee80211_ref_node(ni);
- IEEE80211_NODE_UNLOCK(nt);
- (*f)(arg, ni);
- ieee80211_free_node(ni);
- goto restart;
- }
+ if (vap != NULL && ni->ni_vap != vap)
+ continue;
+ KASSERT(i < count,
+ ("node array overflow (vap %p, i %d, count %d)\n",
+ vap, i, count));
+ ni_arr[i] = ieee80211_ref_node(ni);
+ i++;
}
IEEE80211_NODE_UNLOCK(nt);
- IEEE80211_NODE_ITERATE_UNLOCK(nt);
+ for (i = 0; i < count; i++) {
+ if (ni_arr[i] == NULL) /* end of the list */
+ break;
+ (*f)(arg, ni_arr[i]);
+ /* ieee80211_free_node() locks by itself */
+ ieee80211_free_node(ni_arr[i]);
+ }
+
+ IEEE80211_FREE(ni_arr, M_80211_NODE);
+
+ return (0);
+}
+
+/*
+ * Just a wrapper, so we don't have to change every ieee80211_iterate_nodes()
+ * reference in the source.
+ */
+void
+ieee80211_iterate_nodes(struct ieee80211_node_table *nt,
+ ieee80211_iter_func *f, void *arg)
+{
+ /* XXX no way to pass error to the caller. */
+ (void) ieee80211_iterate_nodes_vap(nt, NULL, f, arg);
}
void
@@ -2181,8 +2443,8 @@ ieee80211_dump_node(struct ieee80211_node_table *nt, struct ieee80211_node *ni)
{
printf("0x%p: mac %s refcnt %d\n", ni,
ether_sprintf(ni->ni_macaddr), ieee80211_node_refcnt(ni));
- printf("\tscangen %u authmode %u flags 0x%x\n",
- ni->ni_scangen, ni->ni_authmode, ni->ni_flags);
+ printf("\tauthmode %u flags 0x%x\n",
+ ni->ni_authmode, ni->ni_flags);
printf("\tassocid 0x%x txpower %u vlan %u\n",
ni->ni_associd, ni->ni_txpower, ni->ni_vlan);
printf("\ttxseq %u rxseq %u fragno %u rxfragstamp %u\n",
@@ -2466,7 +2728,7 @@ ieee80211_erp_timeout(struct ieee80211com *ic)
IEEE80211_LOCK_ASSERT(ic);
if ((ic->ic_flags_ext & IEEE80211_FEXT_NONERP_PR) &&
- time_after(ticks, ic->ic_lastnonerp + IEEE80211_NONERP_PRESENT_AGE)) {
+ ieee80211_time_after(ticks, ic->ic_lastnonerp + IEEE80211_NONERP_PRESENT_AGE)) {
#if 0
IEEE80211_NOTE(vap, IEEE80211_MSG_ASSOC, ni,
"%s", "age out non-ERP sta present on channel");
@@ -2511,7 +2773,6 @@ ieee80211_node_leave(struct ieee80211_node *ni)
IEEE80211_LOCK(ic);
IEEE80211_AID_CLR(vap, ni->ni_associd);
- ni->ni_associd = 0;
vap->iv_sta_assoc--;
ic->ic_sta_assoc--;
@@ -2544,7 +2805,6 @@ done:
}
struct rssiinfo {
- struct ieee80211vap *vap;
int rssi_samples;
uint32_t rssi_total;
};
@@ -2556,8 +2816,6 @@ get_hostap_rssi(void *arg, struct ieee80211_node *ni)
struct ieee80211vap *vap = ni->ni_vap;
int8_t rssi;
- if (info->vap != vap)
- return;
/* only associated stations */
if (ni->ni_associd == 0)
return;
@@ -2575,8 +2833,6 @@ get_adhoc_rssi(void *arg, struct ieee80211_node *ni)
struct ieee80211vap *vap = ni->ni_vap;
int8_t rssi;
- if (info->vap != vap)
- return;
/* only neighbors */
/* XXX check bssid */
if ((ni->ni_capinfo & IEEE80211_CAPINFO_IBSS) == 0)
@@ -2596,8 +2852,6 @@ get_mesh_rssi(void *arg, struct ieee80211_node *ni)
struct ieee80211vap *vap = ni->ni_vap;
int8_t rssi;
- if (info->vap != vap)
- return;
/* only neighbors that peered successfully */
if (ni->ni_mlstate != IEEE80211_NODE_MESH_ESTABLISHED)
return;
@@ -2618,18 +2872,20 @@ ieee80211_getrssi(struct ieee80211vap *vap)
info.rssi_total = 0;
info.rssi_samples = 0;
- info.vap = vap;
switch (vap->iv_opmode) {
case IEEE80211_M_IBSS: /* average of all ibss neighbors */
case IEEE80211_M_AHDEMO: /* average of all neighbors */
- ieee80211_iterate_nodes(&ic->ic_sta, get_adhoc_rssi, &info);
+ ieee80211_iterate_nodes_vap(&ic->ic_sta, vap, get_adhoc_rssi,
+ &info);
break;
case IEEE80211_M_HOSTAP: /* average of all associated stations */
- ieee80211_iterate_nodes(&ic->ic_sta, get_hostap_rssi, &info);
+ ieee80211_iterate_nodes_vap(&ic->ic_sta, vap, get_hostap_rssi,
+ &info);
break;
#ifdef IEEE80211_SUPPORT_MESH
case IEEE80211_M_MBSS: /* average of all mesh neighbors */
- ieee80211_iterate_nodes(&ic->ic_sta, get_mesh_rssi, &info);
+ ieee80211_iterate_nodes_vap(&ic->ic_sta, vap, get_mesh_rssi,
+ &info);
break;
#endif
case IEEE80211_M_MONITOR: /* XXX */