summaryrefslogtreecommitdiffstats
path: root/sys/net80211/ieee80211_node.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_node.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_node.c')
-rw-r--r--sys/net80211/ieee80211_node.c73
1 files changed, 67 insertions, 6 deletions
diff --git a/sys/net80211/ieee80211_node.c b/sys/net80211/ieee80211_node.c
index 7fae394..30508d9 100644
--- a/sys/net80211/ieee80211_node.c
+++ b/sys/net80211/ieee80211_node.c
@@ -50,10 +50,16 @@ __FBSDID("$FreeBSD$");
#include <net80211/ieee80211_tdma.h>
#endif
#include <net80211/ieee80211_wds.h>
+#include <net80211/ieee80211_mesh.h>
#include <net/bpf.h>
/*
+ * IEEE80211_NODE_HASHSIZE must be a power of 2.
+ */
+CTASSERT((IEEE80211_NODE_HASHSIZE & (IEEE80211_NODE_HASHSIZE-1)) == 0);
+
+/*
* Association id's are managed with a bit vector.
*/
#define IEEE80211_AID_SET(_vap, b) \
@@ -322,7 +328,8 @@ ieee80211_create_ibss(struct ieee80211vap* vap, struct ieee80211_channel *chan)
struct ieee80211_node *ni;
IEEE80211_DPRINTF(vap, IEEE80211_MSG_SCAN,
- "%s: creating ibss on channel %u\n", __func__,
+ "%s: creating %s on channel %u\n", __func__,
+ ieee80211_opmode_name[vap->iv_opmode],
ieee80211_chan2ieee(ic, chan));
ni = ieee80211_alloc_node(&ic->ic_sta, vap, vap->iv_myaddr);
@@ -360,6 +367,11 @@ ieee80211_create_ibss(struct ieee80211vap* vap, struct ieee80211_channel *chan)
if ((vap->iv_caps & IEEE80211_C_TDMA) == 0)
#endif
memset(ni->ni_bssid, 0, IEEE80211_ADDR_LEN);
+#ifdef IEEE80211_SUPPORT_MESH
+ } else if (vap->iv_opmode == IEEE80211_M_MBSS) {
+ ni->ni_meshidlen = vap->iv_mesh->ms_idlen;
+ memcpy(ni->ni_meshid, vap->iv_mesh->ms_id, ni->ni_meshidlen);
+#endif
}
/*
* Fix the channel and related attributes.
@@ -609,6 +621,7 @@ gethtadjustflags(struct ieee80211com *ic)
case IEEE80211_M_AHDEMO:
case IEEE80211_M_HOSTAP:
case IEEE80211_M_IBSS:
+ case IEEE80211_M_MBSS:
flags |= ieee80211_htchanflags(vap->iv_bss->ni_chan);
break;
default:
@@ -784,6 +797,10 @@ ieee80211_sta_join(struct ieee80211vap *vap, struct ieee80211_channel *chan,
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);
+#ifdef IEEE80211_SUPPORT_MESH
+ if (ni->ni_ies.meshid_ie != NULL)
+ ieee80211_parse_meshid(ni, ni->ni_ies.meshid_ie);
+#endif
#ifdef IEEE80211_SUPPORT_TDMA
if (ni->ni_ies.tdma_ie != NULL)
ieee80211_parse_tdma(ni, ni->ni_ies.tdma_ie);
@@ -914,6 +931,11 @@ ieee80211_ies_expand(struct ieee80211_ies *ies)
case IEEE80211_ELEMID_HTCAP:
ies->htcap_ie = ie;
break;
+#ifdef IEEE80211_SUPPORT_MESH
+ case IEEE80211_ELEMID_MESHID:
+ ies->meshid_ie = ie;
+ break;
+#endif
}
ielen -= 2 + ie[1];
ie += 2 + ie[1];
@@ -951,6 +973,13 @@ node_cleanup(struct ieee80211_node *ni)
else if (ni->ni_ath_flags & IEEE80211_NODE_ATH)
ieee80211_ff_node_cleanup(ni);
#endif
+#ifdef IEEE80211_SUPPORT_MESH
+ /*
+ * Cleanup any mesh-related state.
+ */
+ if (vap->iv_opmode == IEEE80211_M_MBSS)
+ ieee80211_mesh_node_cleanup(ni);
+#endif
/*
* Clear any staging queue entries.
*/
@@ -1078,7 +1107,7 @@ 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(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;
@@ -1090,7 +1119,10 @@ ieee80211_alloc_node(struct ieee80211_node_table *nt,
ni->ni_inact = ni->ni_inact_reload;
ni->ni_ath_defkeyix = 0x7fff;
ieee80211_psq_init(&ni->ni_psq, "unknown");
-
+#ifdef IEEE80211_SUPPORT_MESH
+ if (vap->iv_opmode == IEEE80211_M_MBSS)
+ 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);
@@ -1242,7 +1274,7 @@ ieee80211_find_node_locked(struct ieee80211_node_table *nt,
IEEE80211_NODE_LOCK_ASSERT(nt);
- hash = IEEE80211_NODE_HASH(macaddr);
+ hash = IEEE80211_NODE_HASH(nt->nt_ic, macaddr);
LIST_FOREACH(ni, &nt->nt_hash[hash], ni_hash) {
if (IEEE80211_ADDR_EQ(ni->ni_macaddr, macaddr)) {
ieee80211_ref_node(ni); /* mark referenced */
@@ -1292,7 +1324,7 @@ ieee80211_find_vap_node_locked(struct ieee80211_node_table *nt,
IEEE80211_NODE_LOCK_ASSERT(nt);
- hash = IEEE80211_NODE_HASH(macaddr);
+ hash = IEEE80211_NODE_HASH(nt->nt_ic, macaddr);
LIST_FOREACH(ni, &nt->nt_hash[hash], ni_hash) {
if (ni->ni_vap == vap &&
IEEE80211_ADDR_EQ(ni->ni_macaddr, macaddr)) {
@@ -1391,7 +1423,10 @@ ieee80211_init_neighbor(struct ieee80211_node *ni,
ni->ni_fhindex = sp->fhindex;
ni->ni_erp = sp->erp;
ni->ni_timoff = sp->timoff;
-
+#ifdef IEEE80211_SUPPORT_MESH
+ if (ni->ni_vap->iv_opmode == IEEE80211_M_MBSS)
+ ieee80211_mesh_init_neighbor(ni, wh, sp);
+#endif
if (ieee80211_ies_init(&ni->ni_ies, sp->ies, sp->ies_len)) {
ieee80211_ies_expand(&ni->ni_ies);
if (ni->ni_ies.wme_ie != NULL)
@@ -2525,6 +2560,27 @@ get_adhoc_rssi(void *arg, struct ieee80211_node *ni)
}
}
+#ifdef IEEE80211_SUPPORT_MESH
+static void
+get_mesh_rssi(void *arg, struct ieee80211_node *ni)
+{
+ struct rssiinfo *info = arg;
+ 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;
+ rssi = vap->iv_ic->ic_node_getrssi(ni);
+ if (rssi != 0) {
+ info->rssi_samples++;
+ info->rssi_total += rssi;
+ }
+}
+#endif /* IEEE80211_SUPPORT_MESH */
+
int8_t
ieee80211_getrssi(struct ieee80211vap *vap)
{
@@ -2543,6 +2599,11 @@ ieee80211_getrssi(struct ieee80211vap *vap)
case IEEE80211_M_HOSTAP: /* average of all associated stations */
ieee80211_iterate_nodes(&ic->ic_sta, 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);
+ break;
+#endif
case IEEE80211_M_MONITOR: /* XXX */
case IEEE80211_M_STA: /* use stats from associated ap */
default:
OpenPOWER on IntegriCloud