summaryrefslogtreecommitdiffstats
path: root/sys/net80211/ieee80211_scan_sta.c
diff options
context:
space:
mode:
Diffstat (limited to 'sys/net80211/ieee80211_scan_sta.c')
-rw-r--r--sys/net80211/ieee80211_scan_sta.c184
1 files changed, 159 insertions, 25 deletions
diff --git a/sys/net80211/ieee80211_scan_sta.c b/sys/net80211/ieee80211_scan_sta.c
index 367ecce..a76dd3c 100644
--- a/sys/net80211/ieee80211_scan_sta.c
+++ b/sys/net80211/ieee80211_scan_sta.c
@@ -48,6 +48,9 @@ __FBSDID("$FreeBSD$");
#ifdef IEEE80211_SUPPORT_TDMA
#include <net80211/ieee80211_tdma.h>
#endif
+#ifdef IEEE80211_SUPPORT_MESH
+#include <net80211/ieee80211_mesh.h>
+#endif
#include <net/bpf.h>
@@ -112,21 +115,23 @@ static void sta_flush_table(struct sta_table *);
* contents explains why. The following flags are or'd to to this
* mask and can be used to figure out why the entry was rejected.
*/
-#define MATCH_CHANNEL 0x0001 /* channel mismatch */
-#define MATCH_CAPINFO 0x0002 /* capabilities mismatch, e.g. no ess */
-#define MATCH_PRIVACY 0x0004 /* privacy mismatch */
-#define MATCH_RATE 0x0008 /* rate set mismatch */
-#define MATCH_SSID 0x0010 /* ssid mismatch */
-#define MATCH_BSSID 0x0020 /* bssid mismatch */
-#define MATCH_FAILS 0x0040 /* too many failed auth attempts */
-#define MATCH_NOTSEEN 0x0080 /* not seen in recent scans */
-#define MATCH_RSSI 0x0100 /* rssi deemed too low to use */
-#define MATCH_CC 0x0200 /* country code mismatch */
-#define MATCH_TDMA_NOIE 0x0400 /* no TDMA ie */
-#define MATCH_TDMA_NOTMASTER 0x0800 /* not TDMA master */
-#define MATCH_TDMA_NOSLOT 0x1000 /* all TDMA slots occupied */
-#define MATCH_TDMA_LOCAL 0x2000 /* local address */
-#define MATCH_TDMA_VERSION 0x4000 /* protocol version mismatch */
+#define MATCH_CHANNEL 0x00001 /* channel mismatch */
+#define MATCH_CAPINFO 0x00002 /* capabilities mismatch, e.g. no ess */
+#define MATCH_PRIVACY 0x00004 /* privacy mismatch */
+#define MATCH_RATE 0x00008 /* rate set mismatch */
+#define MATCH_SSID 0x00010 /* ssid mismatch */
+#define MATCH_BSSID 0x00020 /* bssid mismatch */
+#define MATCH_FAILS 0x00040 /* too many failed auth attempts */
+#define MATCH_NOTSEEN 0x00080 /* not seen in recent scans */
+#define MATCH_RSSI 0x00100 /* rssi deemed too low to use */
+#define MATCH_CC 0x00200 /* country code mismatch */
+#define MATCH_TDMA_NOIE 0x00400 /* no TDMA ie */
+#define MATCH_TDMA_NOTMASTER 0x00800 /* not TDMA master */
+#define MATCH_TDMA_NOSLOT 0x01000 /* all TDMA slots occupied */
+#define MATCH_TDMA_LOCAL 0x02000 /* local address */
+#define MATCH_TDMA_VERSION 0x04000 /* protocol version mismatch */
+#define MATCH_MESH_NOID 0x10000 /* no MESHID ie */
+#define MATCH_MESHID 0x20000 /* meshid mismatch */
static int match_bss(struct ieee80211vap *,
const struct ieee80211_scan_state *, struct sta_entry *, int);
static void adhoc_age(struct ieee80211_scan_state *);
@@ -139,6 +144,10 @@ isocmp(const uint8_t cc1[], const uint8_t cc2[])
/* number of references from net80211 layer */
static int nrefs = 0;
+/*
+ * Module glue.
+ */
+IEEE80211_SCANNER_MODULE(sta, 1);
/*
* Attach prior to any scanning work.
@@ -281,6 +290,10 @@ found:
memcpy(ise->se_tstamp.data, sp->tstamp, sizeof(ise->se_tstamp));
ise->se_intval = sp->bintval;
ise->se_capinfo = sp->capinfo;
+#ifdef IEEE80211_SUPPORT_MESH
+ if (sp->meshid != NULL && sp->meshid[1] != 0)
+ memcpy(ise->se_meshid, sp->meshid, 2+sp->meshid[1]);
+#endif
/*
* Beware of overriding se_chan for frames seen
* off-channel; this can cause us to attempt an
@@ -895,6 +908,12 @@ back:
#undef RV
}
+static __inline int
+match_id(const uint8_t *ie, const uint8_t *val, int len)
+{
+ return (ie[1] == len && memcmp(ie+2, val, len) == 0);
+}
+
static int
match_ssid(const uint8_t *ie,
int nssid, const struct ieee80211_scan_ssid ssids[])
@@ -902,8 +921,7 @@ match_ssid(const uint8_t *ie,
int i;
for (i = 0; i < nssid; i++) {
- if (ie[1] == ssids[i].len &&
- memcmp(ie+2, ssids[i].ssid, ie[1]) == 0)
+ if (match_id(ie, ssids[i].ssid, ssids[i].len))
return 1;
}
return 0;
@@ -986,7 +1004,22 @@ match_bss(struct ieee80211vap *vap,
#endif
}
#endif /* IEEE80211_SUPPORT_TDMA */
+#ifdef IEEE80211_SUPPORT_MESH
+ } else if (vap->iv_opmode == IEEE80211_M_MBSS) {
+ const struct ieee80211_mesh_state *ms = vap->iv_mesh;
+ /*
+ * Mesh nodes have IBSS & ESS bits in capinfo turned off
+ * and two special ie's that must be present.
+ */
+ if (se->se_capinfo & (IEEE80211_CAPINFO_IBSS|IEEE80211_CAPINFO_ESS))
+ fail |= MATCH_CAPINFO;
+ else if (se->se_meshid == NULL)
+ fail |= MATCH_MESH_NOID;
+ else if (ms->ms_idlen != 0 &&
+ match_id(se->se_meshid, ms->ms_id, ms->ms_idlen))
+ fail |= MATCH_MESHID;
} else {
+#endif
if ((se->se_capinfo & IEEE80211_CAPINFO_ESS) == 0)
fail |= MATCH_CAPINFO;
/*
@@ -1070,6 +1103,7 @@ match_bss(struct ieee80211vap *vap,
fail & MATCH_TDMA_NOSLOT ? 'f' :
fail & MATCH_TDMA_LOCAL ? 'l' :
#endif
+ fail & MATCH_MESH_NOID ? 'm' :
fail ? '-' : '+', ether_sprintf(se->se_macaddr));
printf(" %s%c", ether_sprintf(se->se_bssid),
fail & MATCH_BSSID ? '!' : ' ');
@@ -1087,7 +1121,7 @@ match_bss(struct ieee80211vap *vap,
"wep" : "no",
fail & MATCH_PRIVACY ? '!' : ' ');
ieee80211_print_essid(se->se_ssid+2, se->se_ssid[1]);
- printf("%s\n", fail & MATCH_SSID ? "!" : "");
+ printf("%s\n", fail & (MATCH_SSID | MATCH_MESHID) ? "!" : "");
}
#endif
return fail;
@@ -1415,6 +1449,7 @@ static const struct ieee80211_scanner sta_default = {
.scan_assoc_fail = sta_assoc_fail,
.scan_assoc_success = sta_assoc_success,
};
+IEEE80211_SCANNER_ALG(sta, IEEE80211_M_STA, sta_default);
/*
* Adhoc mode-specific support.
@@ -1514,7 +1549,8 @@ adhoc_pick_bss(struct ieee80211_scan_state *ss, struct ieee80211vap *vap)
struct ieee80211_channel *chan;
KASSERT(vap->iv_opmode == IEEE80211_M_IBSS ||
- vap->iv_opmode == IEEE80211_M_AHDEMO,
+ vap->iv_opmode == IEEE80211_M_AHDEMO ||
+ vap->iv_opmode == IEEE80211_M_MBSS,
("wrong opmode %u", vap->iv_opmode));
if (st->st_newscan) {
@@ -1630,6 +1666,8 @@ static const struct ieee80211_scanner adhoc_default = {
.scan_assoc_fail = sta_assoc_fail,
.scan_assoc_success = sta_assoc_success,
};
+IEEE80211_SCANNER_ALG(ibss, IEEE80211_M_IBSS, adhoc_default);
+IEEE80211_SCANNER_ALG(ahdemo, IEEE80211_M_AHDEMO, adhoc_default);
static void
ap_force_promisc(struct ieee80211com *ic)
@@ -1781,12 +1819,108 @@ static const struct ieee80211_scanner ap_default = {
.scan_assoc_success = sta_assoc_success,
.scan_assoc_fail = sta_assoc_fail,
};
+IEEE80211_SCANNER_ALG(ap, IEEE80211_M_HOSTAP, ap_default);
+#ifdef IEEE80211_SUPPORT_MESH
/*
- * Module glue.
+ * Pick an mbss network to join or find a channel
+ * to use to start an mbss network.
*/
-IEEE80211_SCANNER_MODULE(sta, 1);
-IEEE80211_SCANNER_ALG(sta, IEEE80211_M_STA, sta_default);
-IEEE80211_SCANNER_ALG(ibss, IEEE80211_M_IBSS, adhoc_default);
-IEEE80211_SCANNER_ALG(ahdemo, IEEE80211_M_AHDEMO, adhoc_default);
-IEEE80211_SCANNER_ALG(ap, IEEE80211_M_HOSTAP, ap_default);
+static int
+mesh_pick_bss(struct ieee80211_scan_state *ss, struct ieee80211vap *vap)
+{
+ struct sta_table *st = ss->ss_priv;
+ struct ieee80211_mesh_state *ms = vap->iv_mesh;
+ struct sta_entry *selbs;
+ struct ieee80211_channel *chan;
+
+ KASSERT(vap->iv_opmode == IEEE80211_M_MBSS,
+ ("wrong opmode %u", vap->iv_opmode));
+
+ if (st->st_newscan) {
+ sta_update_notseen(st);
+ st->st_newscan = 0;
+ }
+ if (ss->ss_flags & IEEE80211_SCAN_NOPICK) {
+ /*
+ * Manual/background scan, don't select+join the
+ * bss, just return. The scanning framework will
+ * handle notification that this has completed.
+ */
+ ss->ss_flags &= ~IEEE80211_SCAN_NOPICK;
+ return 1;
+ }
+ /*
+ * Automatic sequencing; look for a candidate and
+ * if found join the network.
+ */
+ /* NB: unlocked read should be ok */
+ if (TAILQ_FIRST(&st->st_entry) == NULL) {
+ IEEE80211_DPRINTF(vap, IEEE80211_MSG_SCAN,
+ "%s: no scan candidate\n", __func__);
+ if (ss->ss_flags & IEEE80211_SCAN_NOJOIN)
+ return 0;
+notfound:
+ if (ms->ms_idlen != 0) {
+ /*
+ * No existing mbss network to join and we have
+ * a meshid; start one up. If no channel was
+ * specified, try to select a channel.
+ */
+ if (vap->iv_des_chan == IEEE80211_CHAN_ANYC ||
+ IEEE80211_IS_CHAN_RADAR(vap->iv_des_chan)) {
+ struct ieee80211com *ic = vap->iv_ic;
+
+ chan = adhoc_pick_channel(ss, 0);
+ if (chan != NULL)
+ chan = ieee80211_ht_adjust_channel(ic,
+ chan, vap->iv_flags_ht);
+ } else
+ chan = vap->iv_des_chan;
+ if (chan != NULL) {
+ ieee80211_create_ibss(vap, chan);
+ return 1;
+ }
+ }
+ /*
+ * If nothing suitable was found decrement
+ * the failure counts so entries will be
+ * reconsidered the next time around. We
+ * really want to do this only for sta's
+ * where we've previously had some success.
+ */
+ sta_dec_fails(st);
+ st->st_newscan = 1;
+ return 0; /* restart scan */
+ }
+ selbs = select_bss(ss, vap, IEEE80211_MSG_SCAN);
+ if (ss->ss_flags & IEEE80211_SCAN_NOJOIN)
+ return (selbs != NULL);
+ if (selbs == NULL)
+ goto notfound;
+ chan = selbs->base.se_chan;
+ if (selbs->se_flags & STA_DEMOTE11B)
+ chan = demote11b(vap, chan);
+ if (!ieee80211_sta_join(vap, chan, &selbs->base))
+ goto notfound;
+ return 1; /* terminate scan */
+}
+
+static const struct ieee80211_scanner mesh_default = {
+ .scan_name = "default",
+ .scan_attach = sta_attach,
+ .scan_detach = sta_detach,
+ .scan_start = adhoc_start,
+ .scan_restart = sta_restart,
+ .scan_cancel = sta_cancel,
+ .scan_end = mesh_pick_bss,
+ .scan_flush = sta_flush,
+ .scan_pickchan = adhoc_pick_channel,
+ .scan_add = sta_add,
+ .scan_age = adhoc_age,
+ .scan_iterate = sta_iterate,
+ .scan_assoc_fail = sta_assoc_fail,
+ .scan_assoc_success = sta_assoc_success,
+};
+IEEE80211_SCANNER_ALG(mesh, IEEE80211_M_MBSS, mesh_default);
+#endif /* IEEE80211_SUPPORT_MESH */
OpenPOWER on IntegriCloud