Skip site navigation (1)Skip section navigation (2)
Date:      Thu, 7 May 2009 20:39:23 +0000 (UTC)
From:      Rui Paulo <rpaulo@FreeBSD.org>
To:        src-committers@freebsd.org, svn-src-projects@freebsd.org
Subject:   svn commit: r191901 - projects/mesh11s/sys/net80211
Message-ID:  <200905072039.n47KdNgr067584@svn.freebsd.org>

next in thread | raw e-mail | index | archive | help
Author: rpaulo
Date: Thu May  7 20:39:23 2009
New Revision: 191901
URL: http://svn.freebsd.org/changeset/base/191901

Log:
  Checkpoint mesh peer link handling.
  
  Sponsored by:	The FreeBSD Foundation

Modified:
  projects/mesh11s/sys/net80211/ieee80211_mesh.c
  projects/mesh11s/sys/net80211/ieee80211_node.c
  projects/mesh11s/sys/net80211/ieee80211_node.h
  projects/mesh11s/sys/net80211/ieee80211_output.c

Modified: projects/mesh11s/sys/net80211/ieee80211_mesh.c
==============================================================================
--- projects/mesh11s/sys/net80211/ieee80211_mesh.c	Thu May  7 20:28:06 2009	(r191900)
+++ projects/mesh11s/sys/net80211/ieee80211_mesh.c	Thu May  7 20:39:23 2009	(r191901)
@@ -69,6 +69,32 @@ static int	mesh_input(struct ieee80211_n
 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 *);
+static void	mesh_peer_timeout(void *);
+
+int	ieee80211_mesh_retrytimeout = 40;	/* 40 miliseconds */
+#define	RETRY_TIMEOUT	msecs_to_ticks(ieee80211_mesh_retrytimeout)
+int	ieee80211_mesh_maxretries = 60;
+#define MESH_SET_TIMEOUT(xni)							\
+do {										\
+	xni->ni_mtimerboff = RETRY_TIMEOUT;					\
+	callout_reset(&xni->ni_mtimer, RETRY_TIMEOUT, mesh_peer_timeout, xni);	\
+} while (0)
+/*
+ * Same as above but backoffs timer statisically 50%.
+ * XXX: wrong arc4random usage.
+ */
+#define MESH_SET_TIMEOUT_BACKOFF(xni)						\
+do {										\
+	xni->ni_mtimerboff = xni->ni_mtimerboff +				\
+	    ((arc4random() & 0xff) % xni->ni_mtimerboff);			\
+	callout_reset(&xni->ni_mtimer, RETRY_TIMEOUT, mesh_peer_timeout, xni);	\
+} while (0)
+
+/* unalligned little endian access */     
+#define LE_READ_2(p)					\
+	((uint16_t)					\
+	 ((((const uint8_t *)(p))[0]      ) |		\
+	  (((const uint8_t *)(p))[1] <<  8)))
 
 void
 ieee80211_mesh_attach(struct ieee80211com *ic)
@@ -383,31 +409,14 @@ mesh_recv_mgmt(struct ieee80211_node *ni
 		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)) {
+			uint16_t args[4];
 			/*
 			 * Create a new entry in the neighbor table.
 			 */
 			ni = ieee80211_add_neighbor(vap, wh, &scan);
-		} else {
 			/*
-			 * Record tsf for potential resync.
+			 * Try to peer with this node.
 			 */
-			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
-		 * peer link IE.
-		 */
-		if (ni->ni_peerstate == IEEE80211_NODE_MESH_IDLE) {
-			uint16_t args[4];
-			
 			get_random_bytes(&ni->ni_plid, 2);
 			ni->ni_peerstate = IEEE80211_NODE_MESH_OPENSNT;
 			IEEE80211_NOTE(vap,
@@ -418,8 +427,15 @@ mesh_recv_mgmt(struct ieee80211_node *ni
 			ieee80211_send_action(ni,
 			    IEEE80211_ACTION_CAT_MESHPEERING,
 			    IEEE80211_ACTION_MESHPEERING_OPEN, args);
-			/* XXX setup timeout1 */
+			ni->ni_mrcount = 0;
+			MESH_SET_TIMEOUT(ni);
 		}
+		if (ni != NULL) {
+			IEEE80211_RSSI_LPF(ni->ni_avgrssi, rssi);
+			ni->ni_noise = noise;
+			ni->ni_rstamp = rstamp;
+		}
+
 		break;
 	}
 	case IEEE80211_FC0_SUBTYPE_PROBE_REQ:
@@ -441,13 +457,12 @@ mesh_recv_mgmt(struct ieee80211_node *ni
 			vap->iv_stats.is_rx_mgtdiscard++;       /* XXX stat */
 			return;
 		}
-
 		/*
 		 * prreq frame format
 		 *      [tlv] ssid
 		 *      [tlv] supported rates
 		 *      [tlv] extended supported rates
-		 *	[tlv] Mesh ID
+		 *	[tlv] mesh id
                  */
 		ssid = meshid = rates = xrates = NULL;
 		sfrm = frm;
@@ -522,6 +537,7 @@ mesh_recv_mgmt(struct ieee80211_node *ni
 		break;
 	}
 }
+
 static void
 mesh_recv_action(struct ieee80211_node *ni, struct mbuf *m0)
 {
@@ -540,7 +556,15 @@ mesh_recv_action(struct ieee80211_node *
 	frm += sizeof(ia);
 	efrm = mtod(m0, uint8_t *) + m0->m_len;
 
-	/* XXX explain frame format */
+	/*
+	 * We received an action for an unknown neighbor.
+	 * XXX: wait for it to beacon or create ieee80211_node?
+	 */
+	if (ni == vap->iv_bss) {
+		return;
+	}
+		
+
 	meshid = NULL;
 	meshpeer = NULL;
 	meshconf = NULL;
@@ -555,6 +579,9 @@ mesh_recv_action(struct ieee80211_node *
 			break;
 		case IEEE80211_ELEMID_MESHPEER:
 			meshpeer = (struct ieee80211_meshpeer_ie *) frm;
+			meshpeer->peer_llinkid = LE_READ_2(&meshpeer->peer_llinkid);
+			meshpeer->peer_linkid = LE_READ_2(&meshpeer->peer_linkid);
+			meshpeer->peer_rcode = LE_READ_2(&meshpeer->peer_rcode);
 			break;
 		}
 		frm += frm[1] + 2;
@@ -570,15 +597,19 @@ mesh_recv_action(struct ieee80211_node *
 		vap->iv_stats.is_rx_mgtdiscard++;
 		return;
 	}
+
 	switch (ia->ia_category) {
+	/*
+	 * Mesh Peer Link Management Finite State Machine handling.
+	 */
 	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 PEER OPEN");
+			    "recv PEER OPEN, lid 0x%x", meshpeer->peer_llinkid);
 			switch (ni->ni_peerstate) {
-			case IEEE80211_NODE_MESH_IDLE:			
+			case IEEE80211_NODE_MESH_IDLE:
 				ni->ni_peerstate = IEEE80211_NODE_MESH_OPENRCV;
 				IEEE80211_NOTE(vap,
 				    IEEE80211_MSG_MESH,
@@ -591,7 +622,7 @@ mesh_recv_action(struct ieee80211_node *
 				ieee80211_send_action(ni,
 				    IEEE80211_ACTION_CAT_MESHPEERING,
 				    IEEE80211_ACTION_MESHPEERING_OPEN, args);
-				/* ... and confirm the link. */
+				/* ...and confirm the link. */
 				args[0] = ni->ni_plid;
 				args[1] = ni->ni_llid;
 				ieee80211_send_action(ni,
@@ -610,6 +641,7 @@ mesh_recv_action(struct ieee80211_node *
 				break;
 			case IEEE80211_NODE_MESH_OPENSNT:
 				ni->ni_peerstate = IEEE80211_NODE_MESH_OPENRCV;
+				ni->ni_llid = meshpeer->peer_llinkid;
 				IEEE80211_NOTE(vap,
 				    IEEE80211_MSG_MESH,
 				    ni, "peer link: switching to state %d",
@@ -635,12 +667,28 @@ mesh_recv_action(struct ieee80211_node *
 				    IEEE80211_ACTION_MESHPEERING_CONFIRM, args);
 				/* clear timeoutC */
 				break;
+			case IEEE80211_NODE_MESH_ESTABLISHED:
+				args[0] = ni->ni_plid;
+				args[1] = ni->ni_llid;
+				ieee80211_send_action(ni,
+				    IEEE80211_ACTION_CAT_MESHPEERING,
+				    IEEE80211_ACTION_MESHPEERING_CONFIRM, args);
+				break;
+			case IEEE80211_NODE_MESH_HOLDING:
+				args[0] = ni->ni_llid;
+				args[1] = ni->ni_plid;
+				args[2] = IEEE80211_REASON_MESH_MAX_RETRIES;
+				ieee80211_send_action(ni,
+				    IEEE80211_ACTION_CAT_MESHPEERING,
+				    IEEE80211_ACTION_MESHPEERING_CLOSE, args);
+				break;
 			}
 			break;
 		case IEEE80211_ACTION_MESHPEERING_CONFIRM:
 			IEEE80211_NOTE(vap,
 			    IEEE80211_MSG_ACTION | IEEE80211_MSG_MESH, ni,
-			    "%s", "recv PEER CONFIRM");
+			    "recv PEER CONFIRM, local id 0x%x, peer id 0x%x",
+			    meshpeer->peer_llinkid, meshpeer->peer_linkid);
 			switch (ni->ni_peerstate) {
 			case IEEE80211_NODE_MESH_OPENRCV:
 				ni->ni_peerstate = IEEE80211_NODE_MESH_ESTABLISHED;
@@ -648,7 +696,6 @@ mesh_recv_action(struct ieee80211_node *
 				    IEEE80211_MSG_MESH,
 				    ni, "peer link: switching to state %d",
 				    ni->ni_peerstate);
-				/* clear timeoutR */
 				break;
 			case IEEE80211_NODE_MESH_OPENSNT:
 				ni->ni_peerstate = IEEE80211_NODE_MESH_CONFIRMRECV;
@@ -657,14 +704,37 @@ mesh_recv_action(struct ieee80211_node *
 				    ni, "peer link: switching to state %d",
 				    ni->ni_peerstate);
 				break;
+			case IEEE80211_NODE_MESH_HOLDING:
+				args[0] = ni->ni_llid;
+				args[1] = ni->ni_plid;
+				args[2] = IEEE80211_REASON_MESH_MAX_RETRIES;
+				ieee80211_send_action(ni,
+				    IEEE80211_ACTION_CAT_MESHPEERING,
+				    IEEE80211_ACTION_MESHPEERING_CLOSE, args);
+				break;
 			default:
-
 				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++;
 			}
+			break;
+		case IEEE80211_ACTION_MESHPEERING_CLOSE:
+			IEEE80211_NOTE(vap,
+			    IEEE80211_MSG_ACTION | IEEE80211_MSG_MESH, ni,
+			    "%s", "recv PEER CLOSE");
+			switch (ni->ni_peerstate) {
+			case IEEE80211_NODE_MESH_OPENRCV:
+				ni->ni_peerstate = IEEE80211_NODE_MESH_HOLDING;
+				MESH_SET_TIMEOUT(ni);
+				break;
+			case IEEE80211_NODE_MESH_OPENSNT:
+				break;
+			case IEEE80211_NODE_MESH_HOLDING:
+				break;
+			}
+			break;
 		}
 		break;
 	default:
@@ -675,6 +745,50 @@ mesh_recv_action(struct ieee80211_node *
 }
 
 /*
+ * Mesh Peer Link Management FSM timeout handling.
+ */
+static void
+mesh_peer_timeout(void *arg)
+{
+	struct ieee80211_node *ni = (struct ieee80211_node *)arg;
+	struct ieee80211vap *vap = ni->ni_vap;
+	uint16_t args[4];
+
+	IEEE80211_NOTE(vap,
+	    IEEE80211_MSG_MESH,
+	    ni, "mesh link timeout, state %d, retry counter %d",
+	    ni->ni_peerstate, ni->ni_mrcount);
+	
+	switch (ni->ni_peerstate) {
+	case IEEE80211_NODE_MESH_OPENSNT:
+	case IEEE80211_NODE_MESH_OPENRCV:
+		if (ni->ni_mrcount == ieee80211_mesh_maxretries) {
+			args[0] = ni->ni_plid;
+			args[2] = IEEE80211_REASON_MESH_MAX_RETRIES;
+			ieee80211_send_action(ni,
+			    IEEE80211_ACTION_CAT_MESHPEERING,
+			    IEEE80211_ACTION_MESHPEERING_CLOSE, args);
+			ni->ni_mrcount = 0;
+			ni->ni_peerstate = IEEE80211_NODE_MESH_HOLDING;
+			MESH_SET_TIMEOUT(ni);
+		} else {
+			args[0] = ni->ni_plid;
+			ieee80211_send_action(ni,
+			    IEEE80211_ACTION_CAT_MESHPEERING,
+			    IEEE80211_ACTION_MESHPEERING_OPEN, args);
+			ni->ni_mrcount++;
+			MESH_SET_TIMEOUT_BACKOFF(ni);
+		}
+		break;
+	case IEEE80211_NODE_MESH_CONFIRMRECV:
+	
+		break;
+	case IEEE80211_NODE_MESH_HOLDING:
+		break;
+	}
+}
+
+/*
  * Parse a MESH ID ie on station join.
  */
 void

Modified: projects/mesh11s/sys/net80211/ieee80211_node.c
==============================================================================
--- projects/mesh11s/sys/net80211/ieee80211_node.c	Thu May  7 20:28:06 2009	(r191900)
+++ projects/mesh11s/sys/net80211/ieee80211_node.c	Thu May  7 20:39:23 2009	(r191901)
@@ -1384,6 +1384,8 @@ ieee80211_init_neighbor(struct ieee80211
 	const struct ieee80211_frame *wh,
 	const struct ieee80211_scanparams *sp)
 {
+	struct ieee80211vap *vap = ni->ni_vap;
+	
 	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);
@@ -1395,6 +1397,11 @@ ieee80211_init_neighbor(struct ieee80211
 	ni->ni_fhindex = sp->fhindex;
 	ni->ni_erp = sp->erp;
 	ni->ni_timoff = sp->timoff;
+	if (vap->iv_opmode == IEEE80211_M_MBSS) {	
+		ni->ni_meshidlen = sp->meshid[1];
+		memcpy(ni->ni_meshid, sp->meshid + 2, sp->meshid[1]);
+		callout_init(&ni->ni_mtimer, CALLOUT_MPSAFE);
+	}
 
 	if (ieee80211_ies_init(&ni->ni_ies, sp->ies, sp->ies_len)) {
 		ieee80211_ies_expand(&ni->ni_ies);

Modified: projects/mesh11s/sys/net80211/ieee80211_node.h
==============================================================================
--- projects/mesh11s/sys/net80211/ieee80211_node.h	Thu May  7 20:28:06 2009	(r191900)
+++ projects/mesh11s/sys/net80211/ieee80211_node.h	Thu May  7 20:39:23 2009	(r191901)
@@ -185,6 +185,9 @@ struct ieee80211_node {
 	int8_t			ni_peerstate;	/* Mesh Peering state */
 	uint16_t		ni_llid;	/* local link ID */
 	uint16_t		ni_plid;	/* peer link ID */
+	struct callout		ni_mtimer;	/* mesh timer */
+	uint8_t			ni_mrcount;	/* mesh retry counter */
+	uint8_t			ni_mtimerboff;	/* mesh timer backoff value */
 
 	/* 11n state */
 	uint16_t		ni_htcap;	/* HT capabilities */

Modified: projects/mesh11s/sys/net80211/ieee80211_output.c
==============================================================================
--- projects/mesh11s/sys/net80211/ieee80211_output.c	Thu May  7 20:28:06 2009	(r191900)
+++ projects/mesh11s/sys/net80211/ieee80211_output.c	Thu May  7 20:39:23 2009	(r191901)
@@ -663,6 +663,17 @@ ieee80211_send_action(struct ieee80211_n
 	case IEEE80211_ACTION_CAT_MESHPEERING:
 		rs = ieee80211_get_suprates(ic, ic->ic_curchan);
 		switch (action) {
+		/*
+		 * mesh peer open action frame format:
+		 *   [1] action
+		 *   [1] category
+		 *   [2] capabilities
+		 *   [tlv] rates
+		 *   [tlv] xrates
+		 *   [tlv] mesh id
+		 *   [tlv] mesh conf
+		 *   [tlv] mesh peer link mgmt
+		 */
 		case IEEE80211_ACTION_MESHPEERING_OPEN:
 			IEEE80211_NOTE(vap,
 			    IEEE80211_MSG_ACTION | IEEE80211_MSG_MESH, ni,
@@ -675,6 +686,19 @@ ieee80211_send_action(struct ieee80211_n
 			frm = ieee80211_add_meshpeer(frm,
 			    IEEE80211_MESH_PEER_LINK_OPEN, args[0], 0, 0);
 			break;
+		/*
+		 * mesh peer confirm action frame format:
+		 *   [1] action
+		 *   [1] category
+		 *   [2] capabilities
+		 *   [2] status code
+		 *   [2] association id (0)
+		 *   [tlv] rates
+		 *   [tlv] xrates
+		 *   [tlv] mesh id
+		 *   [tlv] mesh conf
+		 *   [tlv] mesh peer link mgmt
+		 */
 		case IEEE80211_ACTION_MESHPEERING_CONFIRM:
 			IEEE80211_NOTE(vap,
 			    IEEE80211_MSG_ACTION | IEEE80211_MSG_MESH, ni,
@@ -691,6 +715,14 @@ ieee80211_send_action(struct ieee80211_n
 			    IEEE80211_MESH_PEER_LINK_CONFIRM, args[0], args[1],
 			    0);
 			break;
+		/*
+		 * mesh peer close action frame format:
+		 *   [1] action
+		 *   [1] category
+		 *   [2] reason code
+		 *   [tlv] mesh id
+		 *   [tlv] mesh peer link mgmt
+		 */
 		case IEEE80211_ACTION_MESHPEERING_CLOSE:
 			IEEE80211_NOTE(vap,
 			    IEEE80211_MSG_ACTION | IEEE80211_MSG_MESH, ni,



Want to link to this message? Use this URL: <https://mail-archive.FreeBSD.org/cgi/mid.cgi?200905072039.n47KdNgr067584>