summaryrefslogtreecommitdiffstats
path: root/sys/net80211/ieee80211_scan_sta.c
diff options
context:
space:
mode:
authorrpaulo <rpaulo@FreeBSD.org>2009-07-11 15:02:45 +0000
committerrpaulo <rpaulo@FreeBSD.org>2009-07-11 15:02:45 +0000
commit8424d740209fc6cee8a8bc4deba2a40cdc77d1fd (patch)
tree7dd4e6a8c026ec13b70ca0a34e625684d79ec055 /sys/net80211/ieee80211_scan_sta.c
parentba5583d31888cb78136b114790fce49c792c14d0 (diff)
downloadFreeBSD-src-8424d740209fc6cee8a8bc4deba2a40cdc77d1fd.zip
FreeBSD-src-8424d740209fc6cee8a8bc4deba2a40cdc77d1fd.tar.gz
Implementation of the upcoming Wireless Mesh standard, 802.11s, on the
net80211 wireless stack. This work is based on the March 2009 D3.0 draft standard. This standard is expected to become final next year. This includes two main net80211 modules, ieee80211_mesh.c which deals with peer link management, link metric calculation, routing table control and mesh configuration and ieee80211_hwmp.c which deals with the actually routing process on the mesh network. HWMP is the mandatory routing protocol on by the mesh standard, but others, such as RA-OLSR, can be implemented. Authentication and encryption are not implemented. There are several scripts under tools/tools/net80211/scripts that can be used to test different mesh network topologies and they also teach you how to setup a mesh vap (for the impatient: ifconfig wlan0 create wlandev ... wlanmode mesh). A new build option is available: IEEE80211_SUPPORT_MESH and it's enabled by default on GENERIC kernels for i386, amd64, sparc64 and pc98. Drivers that support mesh networks right now are: ath, ral and mwl. More information at: http://wiki.freebsd.org/WifiMesh Please note that this work is experimental. Also, please note that bridging a mesh vap with another network interface is not yet supported. Many thanks to the FreeBSD Foundation for sponsoring this project and to Sam Leffler for his support. Also, I would like to thank Gateworks Corporation for sending me a Cambria board which was used during the development of this project. Reviewed by: sam Approved by: re (kensmith) Obtained from: projects/mesh11s
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