svn commit: r191685 - projects/mesh11s/sys/net80211
Rui Paulo
rpaulo at FreeBSD.org
Thu Apr 30 12:16:16 UTC 2009
Author: rpaulo
Date: Thu Apr 30 12:16:15 2009
New Revision: 191685
URL: http://svn.freebsd.org/changeset/base/191685
Log:
Initial implementation of Mesh Peering. This makes it possible to
establish a mesh link with a Linux mesh node, but the code is still
imature.
Sponsored by: The FreeBSD Foundation
Modified:
projects/mesh11s/sys/net80211/ieee80211_ht.c
projects/mesh11s/sys/net80211/ieee80211_mesh.c
projects/mesh11s/sys/net80211/ieee80211_mesh.h
projects/mesh11s/sys/net80211/ieee80211_node.h
Modified: projects/mesh11s/sys/net80211/ieee80211_ht.c
==============================================================================
--- projects/mesh11s/sys/net80211/ieee80211_ht.c Thu Apr 30 12:14:52 2009 (r191684)
+++ projects/mesh11s/sys/net80211/ieee80211_ht.c Thu Apr 30 12:16:15 2009 (r191685)
@@ -48,6 +48,7 @@ __FBSDID("$FreeBSD$");
#include <net80211/ieee80211_var.h>
#include <net80211/ieee80211_input.h>
+#include <net80211/ieee80211_mesh.h>
/* define here, used throughout file */
#define MS(_v, _f) (((_v) & _f) >> _f##_S)
@@ -2121,7 +2122,7 @@ ieee80211_send_action(struct ieee80211_n
struct mbuf *m;
uint8_t *frm;
uint16_t baparamset;
- int ret;
+ int ret, addsize;
KASSERT(ni != NULL, ("null node"));
@@ -2137,11 +2138,29 @@ ieee80211_send_action(struct ieee80211_n
ieee80211_node_refcnt(ni)+1);
ieee80211_ref_node(ni);
+ addsize = 0;
+ switch (category) {
+ case IEEE80211_ACTION_CAT_BA:
+ case IEEE80211_ACTION_CAT_HT:
+ addsize += sizeof(struct ieee80211_action_ba_addbaresponse);
+ break;
+ case IEEE80211_ACTION_CAT_MESHPEERING:
+ addsize += sizeof(uint16_t); /* capabilities */
+ addsize += 2 + vap->iv_meshidlen; /* Mesh ID */
+ addsize += sizeof(struct ieee80211_meshconf_ie);
+ /* On Open frames, the peer link ID is not sent */
+ if (action == IEEE80211_ACTION_MESHPEERING_OPEN)
+ addsize += sizeof(struct ieee80211_meshpeer_ie) - 2;
+ else
+ addsize += sizeof(struct ieee80211_meshpeer_ie);
+ break;
+ }
m = ieee80211_getmgtframe(&frm,
ic->ic_headroom + sizeof(struct ieee80211_frame),
sizeof(uint16_t) /* action+category */
/* XXX may action payload */
- + sizeof(struct ieee80211_action_ba_addbaresponse)
+ + addsize
+
);
if (m == NULL)
senderr(ENOMEM, is_tx_nobuf);
@@ -2210,6 +2229,43 @@ ieee80211_send_action(struct ieee80211_n
goto badaction;
}
break;
+ case IEEE80211_ACTION_CAT_MESHPEERING:
+
+ switch (action) {
+ case IEEE80211_ACTION_MESHPEERING_OPEN:
+ IEEE80211_NOTE(vap,
+ IEEE80211_MSG_ACTION | IEEE80211_MSG_MESH, ni,
+ "send PEER OPEN action: lid %x", args[0]);
+ *frm++ = 0; /* capabilites */
+ *frm++ = 0;
+ frm = ieee80211_add_meshid(frm, vap);
+ frm = ieee80211_add_meshconf(frm, vap);
+ *frm++ = IEEE80211_ELEMID_MESHPEER;
+ *frm++ = 3; /* len */
+ *frm++ = IEEE80211_MESH_PEER_LINK_OPEN; /* subtype */
+ ADDSHORT(frm, args[0]); /* local ID */
+ break;
+ case IEEE80211_ACTION_MESHPEERING_CONFIRM:
+ IEEE80211_NOTE(vap,
+ IEEE80211_MSG_ACTION | IEEE80211_MSG_MESH, ni,
+ "send PEER CONFIRM action: lid %x, pid %x",
+ args[0], args[1]);
+ *frm++ = 0; /* capabilites */
+ *frm++ = 0;
+ *frm++ = 0; /* status code */
+ *frm++ = 0;
+ *frm++ = 0; /* AID */
+ *frm++ = 0;
+ frm = ieee80211_add_meshid(frm, vap);
+ frm = ieee80211_add_meshconf(frm, vap);
+ *frm++ = IEEE80211_ELEMID_MESHPEER;
+ *frm++ = 5; /* len */
+ *frm++ = IEEE80211_MESH_PEER_LINK_CONFIRM; /* subtype */
+ ADDSHORT(frm, args[0]);
+ ADDSHORT(frm, args[1]);
+ break;
+ }
+ break;
default:
badaction:
IEEE80211_NOTE(vap,
Modified: projects/mesh11s/sys/net80211/ieee80211_mesh.c
==============================================================================
--- projects/mesh11s/sys/net80211/ieee80211_mesh.c Thu Apr 30 12:14:52 2009 (r191684)
+++ projects/mesh11s/sys/net80211/ieee80211_mesh.c Thu Apr 30 12:16:15 2009 (r191685)
@@ -68,6 +68,7 @@ static int mesh_input(struct ieee80211_n
uint32_t);
static void mesh_recv_mgmt(struct ieee80211_node *, struct mbuf *, int,
int, int, uint32_t);
+static void mesh_recv_action(struct ieee80211_node *, struct mbuf *);
void
ieee80211_mesh_attach(struct ieee80211com *ic)
@@ -314,6 +315,7 @@ static void
mesh_recv_mgmt(struct ieee80211_node *ni, struct mbuf *m0, int subtype,
int rssi, int noise, uint32_t rstamp)
{
+ static const uint8_t zerobssid[IEEE80211_ADDR_LEN];
struct ieee80211vap *vap = ni->ni_vap;
struct ieee80211com *ic = ni->ni_ic;
struct ieee80211_frame *wh;
@@ -327,7 +329,6 @@ mesh_recv_mgmt(struct ieee80211_node *ni
case IEEE80211_FC0_SUBTYPE_BEACON:
{
struct ieee80211_scanparams scan;
-
/*
* We process beacon/probe response
* frames to discover neighbors.
@@ -363,6 +364,42 @@ mesh_recv_mgmt(struct ieee80211_node *ni
return;
}
+ /* The rest of this code assumes we setup and running */
+ if (vap->iv_state != IEEE80211_S_RUN)
+ return;
+ /*
+ * Ignore non-mesh STAs and STAs for other mesh networks.
+ */
+ if (scan.meshid &&
+ memcmp(scan.meshid+2, vap->iv_meshid, vap->iv_meshidlen) != 0) {
+ IEEE80211_NOTE(vap, IEEE80211_MSG_MESH, ni,
+ "beacon not for our mesh (%s)", scan.meshid+2);
+ return;
+ }
+
+ /*
+ * More validation: make sure we are talking to a Mesh node.
+ */
+ if ((scan.capinfo & (IEEE80211_CAPINFO_ESS|IEEE80211_CAPINFO_IBSS)) == 0 &&
+ !IEEE80211_ADDR_EQ(wh->i_addr2, ni->ni_macaddr) &&
+ IEEE80211_ADDR_EQ(wh->i_addr3, zerobssid)) {
+ /*
+ * Create a new entry in the neighbor table.
+ */
+ ni = ieee80211_add_neighbor(vap, wh, &scan);
+ } else {
+ /*
+ * Record tsf for potential resync.
+ */
+ memcpy(ni->ni_tstamp.data, scan.tstamp,
+ sizeof(ni->ni_tstamp));
+ }
+ if (ni != NULL) {
+ IEEE80211_RSSI_LPF(ni->ni_avgrssi, rssi);
+ ni->ni_noise = noise;
+ ni->ni_rstamp = rstamp;
+ }
+
/*
* If it's a beacon for our mesh and we haven't already
* peered with this node, send him a mgmt frame with
@@ -443,11 +480,15 @@ mesh_recv_mgmt(struct ieee80211_node *ni
break;
}
case IEEE80211_FC0_SUBTYPE_ACTION:
- if (vap->iv_state == IEEE80211_S_RUN) {
- if (ieee80211_parse_action(ni, m0) == 0)
- ic->ic_recv_action(ni, frm, efrm);
- } else
+ if (vap->iv_state != IEEE80211_S_RUN) {
vap->iv_stats.is_rx_mgtdiscard++;
+ break;
+ }
+ /* XXX parse_action is a bit useless now */
+ if (ieee80211_parse_action(ni, m0) == 0) {
+ mesh_recv_action(ni, m0);
+ ic->ic_recv_action(ni, frm, efrm);
+ }
break;
case IEEE80211_FC0_SUBTYPE_AUTH:
case IEEE80211_FC0_SUBTYPE_ASSOC_REQ:
@@ -467,6 +508,97 @@ mesh_recv_mgmt(struct ieee80211_node *ni
break;
}
}
+static void
+mesh_recv_action(struct ieee80211_node *ni, struct mbuf *m0)
+{
+ struct ieee80211vap *vap = ni->ni_vap;
+ struct ieee80211_action *ia;
+ struct ieee80211_frame *wh;
+ struct ieee80211_meshid_ie *meshid;
+ struct ieee80211_meshconf_ie *meshconf;
+ struct ieee80211_meshpeer_ie *meshpeer;
+ uint8_t *frm, *efrm;
+ uint16_t args[4];
+
+ wh = mtod(m0, struct ieee80211_frame *);
+ ia = (struct ieee80211_action *) &wh[1];
+ frm = (uint8_t *)&wh[1];
+ frm += sizeof(ia);
+ efrm = mtod(m0, uint8_t *) + m0->m_len;
+
+ /* XXX explain frame format */
+ meshid = NULL;
+ meshpeer = NULL;
+ meshconf = NULL;
+ while (efrm - frm > 1) {
+ IEEE80211_VERIFY_LENGTH(efrm - frm, frm[1] + 2, return);
+ switch (*frm) {
+ case IEEE80211_ELEMID_MESHID:
+ meshid = (struct ieee80211_meshid_ie *) frm;
+ break;
+ case IEEE80211_ELEMID_MESHCONF:
+ meshconf = (struct ieee80211_meshconf_ie *) frm;
+ break;
+ case IEEE80211_ELEMID_MESHPEER:
+ meshpeer = (struct ieee80211_meshpeer_ie *) frm;
+ break;
+ }
+ frm += frm[1] + 2;
+ }
+ /*
+ * Check if we agree on Mesh ID and Configuration.
+ * XXX: TBD
+ */
+ if (!meshid || !meshconf || !meshpeer) {
+ IEEE80211_DISCARD(vap,
+ IEEE80211_MSG_ACTION | IEEE80211_MSG_MESH,
+ wh, NULL, "%s", "action frame not for our mesh");
+ vap->iv_stats.is_rx_mgtdiscard++;
+ return;
+ }
+ switch (ia->ia_category) {
+ case IEEE80211_ACTION_CAT_MESHPEERING:
+ switch (ia->ia_action) {
+ case IEEE80211_ACTION_MESHPEERING_OPEN:
+ IEEE80211_NOTE(vap,
+ IEEE80211_MSG_ACTION | IEEE80211_MSG_MESH, ni,
+ "%s", "recv peering open");
+ ni->ni_peerstate = IEEE80211_NODE_MESH_OPENRCV;
+ ni->ni_llid = meshpeer->peer_llinkid;
+ ni->ni_plid = 0xf4ef;
+ args[0] = ni->ni_plid;
+ ieee80211_send_action(ni,
+ IEEE80211_ACTION_CAT_MESHPEERING,
+ IEEE80211_ACTION_MESHPEERING_OPEN, args);
+ break;
+ case IEEE80211_ACTION_MESHPEERING_CONFIRM:
+ IEEE80211_NOTE(vap,
+ IEEE80211_MSG_ACTION | IEEE80211_MSG_MESH, ni,
+ "%s", "recv peering confirm");
+ if (ni->ni_peerstate != IEEE80211_NODE_MESH_OPNSENT &&
+ ni->ni_peerstate != IEEE80211_NODE_MESH_OPENRCV) {
+ IEEE80211_DISCARD(vap,
+ IEEE80211_MSG_ACTION | IEEE80211_MSG_MESH,
+ wh, NULL, "received confirm in invalid "
+ "state %d", ni->ni_peerstate);
+ vap->iv_stats.is_rx_mgtdiscard++;
+ return;
+ }
+ ni->ni_peerstate = IEEE80211_NODE_MESH_CONFIRMRECV;
+ args[0] = 0xf4ef;
+ args[1] = ni->ni_llid;
+ ieee80211_send_action(ni,
+ IEEE80211_ACTION_CAT_MESHPEERING,
+ IEEE80211_ACTION_MESHPEERING_CONFIRM, args);
+ }
+ break;
+ default:
+ IEEE80211_DISCARD(vap, IEEE80211_MSG_ACTION | IEEE80211_MSG_MESH,
+ wh, NULL, "%s", "not handled");
+ vap->iv_stats.is_rx_mgtdiscard++;
+ }
+}
+
/*
* Parse a MESH ID ie on station join.
*/
Modified: projects/mesh11s/sys/net80211/ieee80211_mesh.h
==============================================================================
--- projects/mesh11s/sys/net80211/ieee80211_mesh.h Thu Apr 30 12:14:52 2009 (r191684)
+++ projects/mesh11s/sys/net80211/ieee80211_mesh.h Thu Apr 30 12:16:15 2009 (r191685)
@@ -250,6 +250,20 @@ struct ieee80211_meshpuc_ie {
uint8_t puc_daddr[IEEE80211_ADDR_LEN];
} __packed;
+/*
+ * 802.11s Action Frames
+ */
+#define IEEE80211_ACTION_CAT_MESHPEERING 30 /* XXX Linux */
+#define IEEE80211_ACTION_CAT_MESHLINK 13
+#define IEEE80211_ACTION_CAT_PATHSEL 14
+#define IEEE80211_ACTION_CAT_INTERWORK 15
+#define IEEE80211_ACTION_CAT_RESOURCE 16
+#define IEEE80211_ACTION_CAT_PROXY 17
+
+#define IEEE80211_ACTION_MESHPEERING_OPEN 0
+#define IEEE80211_ACTION_MESHPEERING_CONFIRM 1
+#define IEEE80211_ACTION_MESHPEERING_CLOSE 2
+
void ieee80211_mesh_attach(struct ieee80211com *);
void ieee80211_mesh_detach(struct ieee80211com *);
void ieee80211_parse_meshid(struct ieee80211_node *, const uint8_t *);
Modified: projects/mesh11s/sys/net80211/ieee80211_node.h
==============================================================================
--- projects/mesh11s/sys/net80211/ieee80211_node.h Thu Apr 30 12:14:52 2009 (r191684)
+++ projects/mesh11s/sys/net80211/ieee80211_node.h Thu Apr 30 12:16:15 2009 (r191685)
@@ -36,7 +36,7 @@
* Each ieee80211com instance has a single timer that fires every
* IEEE80211_INACT_WAIT seconds to handle "inactivity processing".
* This is used to do node inactivity processing when operating
- * as an AP or in adhoc mode. For inactivity processing each node
+ * as an AP, adhoc or mesh mode. For inactivity processing each node
* has a timeout set in it's ni_inact field that is decremented
* on each timeout and the node is reclaimed when the counter goes
* to zero. We use different inactivity timeout values depending
@@ -175,6 +175,17 @@ struct ieee80211_node {
uint8_t ni_dtim_period; /* DTIM period */
uint8_t ni_dtim_count; /* DTIM count for last bcn */
+ /* mesh */
+#define IEEE80211_NODE_MESH_IDLE 0
+#define IEEE80211_NODE_MESH_OPNSENT 1 /* Peer Open Frame Received */
+#define IEEE80211_NODE_MESH_OPENRCV 2 /* Peer Open Frame Sent */
+#define IEEE80211_NODE_MESH_CONFIRMRECV 3 /* Peer Confirm Frame Recvived */
+#define IEEE80211_NODE_MESH_ESTABLISHED 4 /* Peer Link Established */
+#define IEEE80211_NODE_MESH_HOLDING 5 /* Peer Link Closing */
+ int8_t ni_peerstate; /* Mesh Peering state */
+ uint16_t ni_llid; /* local link ID */
+ uint16_t ni_plid; /* peer link ID */
+
/* 11n state */
uint16_t ni_htcap; /* HT capabilities */
uint8_t ni_htparam; /* HT params */
More information about the svn-src-projects
mailing list