Skip site navigation (1)Skip section navigation (2)
Date:      Wed, 11 Jan 2012 05:40:58 +0100
From:      Monthadar Al Jaberi <monthadar@gmail.com>
To:        freebsd-wireless@freebsd.org
Subject:   11s mesh path setup problem
Message-ID:  <CA%2BsBSoJWXD5S-zvxHR_=iwh26G0bd00trR=E-jCUBD03uMrU%2BQ@mail.gmail.com>

next in thread | raw e-mail | index | archive | help

[-- Attachment #1 --]
Hi,

Current hwmp cant handle to setup a path between 4 nodes in a line
topology (among other things it cant handle)

Below you will find a small patch to correct this with some debug
output cleanup and comments.

After the patch, you should be able to e.g. ping from node 4 to node 1
and get a ping reply back, he is what the output from ifconfig list
mesh should look like on all 4 nodes after one ping packet.

Node1# ifconfig wlan1 list mesh
DEST    NEXT HOP  HOPS METRIC LIFETIME   MSEQ FLAGS
Node2    Node2         1         17018     5000          0         V
Node3    Node2         2         34036     5000          0         V
Node4    Node2         3         34036     5000          3         V

Node2# ifconfig wlan1 list mesh
DEST    NEXT HOP  HOPS METRIC LIFETIME   MSEQ FLAGS
Node1    Node1         1   17018     5000      3    V
Node3    Node3         1   17018     5000      0    V
Node4    Node3         2   17018     5000      3    V

Node3# ifconfig wlan1 list mesh
DEST    NEXT HOP  HOPS METRIC LIFETIME   MSEQ FLAGS
Node2    Node2         1         0            5000          0          V
Node4    Node4         1         0            5000          3          V
Node1    Node2         2         34036     5000          3          V

Node4# ifconfig wlan1 list mesh
DEST    NEXT HOP  HOPS METRIC LIFETIME   MSEQ FLAGS
Node3    Node3         1         0            5000          0          V
Node1    Node3         3         51054     5000          3          V

If anyone could try it that would be nice, either on real hardware as
I did above, or in a simulated environment
(https://github.com/monthadar/FreeBSD-IEEE80211s-simulator/wiki) :)

and please do test other scenarios :)

patch is attached.

-- 
Monthadar Al Jaberi

[-- Attachment #2 --]
diff --git a/sys/net/if_ethersubr.c b/sys/net/if_ethersubr.c
index 1d16ae6..fc86c94 100644
--- a/sys/net/if_ethersubr.c
+++ b/sys/net/if_ethersubr.c
@@ -968,9 +968,13 @@ discard:
 char *
 ether_sprintf(const u_char *ap)
 {
-	static char etherbuf[18];
-	snprintf(etherbuf, sizeof (etherbuf), "%6D", ap, ":");
-	return (etherbuf);
+	static char etherbuf[6][18];
+	static int i = 0;
+	char *buf;
+	snprintf(etherbuf[i], sizeof (etherbuf[0]), "%6D", ap, ":");
+	buf = etherbuf[i];
+	i = (i+1)%2;
+	return (buf);
 }
 
 /*
diff --git a/sys/net80211/ieee80211_hwmp.c b/sys/net80211/ieee80211_hwmp.c
index 78729fc..7c99351 100644
--- a/sys/net80211/ieee80211_hwmp.c
+++ b/sys/net80211/ieee80211_hwmp.c
@@ -139,9 +139,13 @@ static const uint8_t	broadcastaddr[IEEE80211_ADDR_LEN] =
 typedef uint32_t ieee80211_hwmp_seq;
 #define	HWMP_SEQ_LT(a, b)	((int32_t)((a)-(b)) < 0)
 #define	HWMP_SEQ_LEQ(a, b)	((int32_t)((a)-(b)) <= 0)
+#define	HWMP_SEQ_EQ(a, b)	((int32_t)((a)-(b)) == 0)
 #define	HWMP_SEQ_GT(a, b)	((int32_t)((a)-(b)) > 0)
 #define	HWMP_SEQ_GEQ(a, b)	((int32_t)((a)-(b)) >= 0)
 
+/* The longer one of the lifetime should be stored as new lifetime */
+#define MESH_ROUTE_LIFETIME_MAX(a, b)	(a > b ? a : b)
+
 /*
  * Private extension of ieee80211_mesh_route.
  */
@@ -676,8 +680,10 @@ hwmp_recv_preq(struct ieee80211vap *vap, struct ieee80211_node *ni,
 {
 	struct ieee80211_mesh_state *ms = vap->iv_mesh;
 	struct ieee80211_mesh_route *rt = NULL;
-	struct ieee80211_mesh_route *rtorig = NULL;
-	struct ieee80211_hwmp_route *hrorig;
+	struct ieee80211_mesh_route *rtorig = NULL; // Originator route
+	struct ieee80211_mesh_route *rttarg = NULL; // Target route
+	struct ieee80211_hwmp_route *hrorig = NULL;
+	struct ieee80211_hwmp_route *hrtarg = NULL;
 	struct ieee80211_hwmp_state *hs = vap->iv_hwmp;
 	struct ieee80211_meshprep_ie prep;
 
@@ -692,46 +698,83 @@ hwmp_recv_preq(struct ieee80211vap *vap, struct ieee80211_node *ni,
 		return;
 
 	IEEE80211_NOTE(vap, IEEE80211_MSG_HWMP, ni,
-	    "received PREQ, source %s", ether_sprintf(preq->preq_origaddr));
+	    "received PREQ, originator %s, target %s", ether_sprintf(preq->preq_origaddr), ether_sprintf(PREQ_TADDR(0)));
 
 	/*
-	 * Acceptance criteria: if the PREQ is not for us and
-	 * forwarding is disabled, discard this PREQ.
+	 * Acceptance criteria: if the PREQ is not for us or not broadcast
+	 * AND forwarding is disabled, discard this PREQ.
 	 */
-	if (!IEEE80211_ADDR_EQ(vap->iv_myaddr, PREQ_TADDR(0)) &&
+	if ((!IEEE80211_ADDR_EQ(vap->iv_myaddr, PREQ_TADDR(0)) || /* need to check PROXY */
+		!IEEE80211_IS_MULTICAST(PREQ_TADDR(0))) &&
 	    !(ms->ms_flags & IEEE80211_MESHFLAGS_FWD)) {
 		IEEE80211_DISCARD_MAC(vap, IEEE80211_MSG_HWMP,
 		    preq->preq_origaddr, NULL, "%s", "not accepting PREQ");
 		return;
 	}
+	/*
+	 * Acceptance criteria: if unicast addressed 
+	 * AND no valid forwarding for Target of PREQ, discard this PREQ.
+	 */
+	rttarg = ieee80211_mesh_rt_find(vap, PREQ_TADDR(0));
+	if(rttarg != NULL)
+		hrtarg = IEEE80211_MESH_ROUTE_PRIV(rttarg, struct ieee80211_hwmp_route);
+	if((preq->preq_flags & IEEE80211_MESHPREQ_FLAGS_AM) == 0 && /* address mode: ucast */
+		rttarg == NULL &&
+		!IEEE80211_ADDR_EQ(vap->iv_myaddr, PREQ_TADDR(0))) {
+		IEEE80211_DISCARD_MAC(vap, IEEE80211_MSG_HWMP,
+		    preq->preq_origaddr, NULL, "unicast addressed PREQ of unknown target %s",
+				      ether_sprintf(PREQ_TADDR(0)));
+		return;
+	}
+	
+	/* PREQ ACCEPTED */
+
 	rtorig = ieee80211_mesh_rt_find(vap, preq->preq_origaddr);
-	if (rtorig == NULL)
+	if (rtorig == NULL){
 		rtorig = ieee80211_mesh_rt_add(vap, preq->preq_origaddr);
+		IEEE80211_NOTE(vap, IEEE80211_MSG_HWMP, ni,
+			"adding originator %s", ether_sprintf(preq->preq_origaddr));
+	}
 	if (rtorig == NULL) {
 		/* XXX stat */
 		return;
 	}
 	hrorig = IEEE80211_MESH_ROUTE_PRIV(rtorig, struct ieee80211_hwmp_route);
-	/*
-	 * Sequence number validation.
+
+	/* Data creation and update of forwarding information
+	 * according to Table 11C-8 for originator mesh STA.
 	 */
-	if (HWMP_SEQ_LEQ(preq->preq_id, hrorig->hr_preqid) &&
-	    HWMP_SEQ_LEQ(preq->preq_origseq, hrorig->hr_seq)) {
+	if(HWMP_SEQ_GT(preq->preq_origseq, hrorig->hr_seq) ||
+		(HWMP_SEQ_EQ(preq->preq_origseq, hrorig->hr_seq) && preq->preq_metric < rtorig->rt_metric)){
+		hrorig->hr_seq = preq->preq_origseq;
+		IEEE80211_ADDR_COPY(rtorig->rt_nexthop, wh->i_addr2);
+		rtorig->rt_metric = preq->preq_metric +
+			ms->ms_pmetric->mpm_metric(ni);
+		rtorig->rt_nhops  = preq->preq_hopcount + 1;
+		rtorig->rt_lifetime  = MESH_ROUTE_LIFETIME_MAX(preq->preq_lifetime, rtorig->rt_lifetime);
+		rtorig->rt_flags |= IEEE80211_MESHRT_FLAGS_VALID; /* path to orig is valid now */
+	}else if(hrtarg != NULL && 
+		HWMP_SEQ_EQ(hrtarg->hr_seq, PREQ_TSEQ(0)) &&
+		(rtorig->rt_flags & IEEE80211_MESHRT_FLAGS_VALID) == 0){
 		IEEE80211_NOTE(vap, IEEE80211_MSG_HWMP, ni,
-		    "discard PREQ from %s, old seq no %u <= %u",
-		    ether_sprintf(preq->preq_origaddr),
-		    preq->preq_origseq, hrorig->hr_seq);
+			"received PREQ, originator %s", "unknown");
+	}else{
+		IEEE80211_DISCARD_MAC(vap, IEEE80211_MSG_HWMP,
+		    preq->preq_origaddr, NULL, "%s, last seen orig.seq %d, preq orig.seq %d", "discarding PREQ", hrorig->hr_seq, preq->preq_origseq);
 		return;
 	}
-	hrorig->hr_preqid = preq->preq_id;
-	hrorig->hr_seq = preq->preq_origseq;
+	
+	/* 
+	 * Forwarding information for transmitter mesh STA 
+	 * [OPTIONAL: if metric improved]
+	 */
 
 	/*
 	 * Check if the PREQ is addressed to us.
 	 */
 	if (IEEE80211_ADDR_EQ(vap->iv_myaddr, PREQ_TADDR(0))) {
 		IEEE80211_NOTE(vap, IEEE80211_MSG_HWMP, ni,
-		    "reply to %s", ether_sprintf(preq->preq_origaddr));
+		    "reply PREP, originator %s", ether_sprintf(preq->preq_origaddr));
 		/*
 		 * Build and send a PREP frame.
 		 */
@@ -819,11 +862,13 @@ hwmp_recv_preq(struct ieee80211vap *vap, struct ieee80211_node *ni,
 			if (preq->preq_ttl > 1 &&
 			    preq->preq_hopcount < hs->hs_maxhops) {
 				IEEE80211_NOTE(vap, IEEE80211_MSG_HWMP, ni,
-				    "forward PREQ from %s",
-				    ether_sprintf(preq->preq_origaddr));
+				    "forward PREQ, originator %s, to %s",
+				    ether_sprintf(preq->preq_origaddr), ether_sprintf(rt->rt_nexthop));
 				/*
 				 * Propagate the original PREQ.
+				 * PREQ is unicast now to rt->rt_nexthop
 				 */
+				ppreq.preq_flags &= ~IEEE80211_MESHPREQ_FLAGS_AM;
 				ppreq.preq_hopcount += 1;
 				ppreq.preq_ttl -= 1;
 				ppreq.preq_metric +=
@@ -837,7 +882,7 @@ hwmp_recv_preq(struct ieee80211vap *vap, struct ieee80211_node *ni,
 				ppreq.preq_targets[0].target_flags &=
 				    ~IEEE80211_MESHPREQ_TFLAGS_RF;
 				hwmp_send_preq(ni, vap->iv_myaddr,
-				    broadcastaddr, &ppreq);
+				    rt->rt_nexthop, &ppreq);
 			}
 			/*
 			 * Check if we can send an intermediate Path Reply,
@@ -870,26 +915,11 @@ hwmp_recv_preq(struct ieee80211vap *vap, struct ieee80211_node *ni,
 		 */
 		} else if (preq->preq_ttl > 1 &&
 		    preq->preq_hopcount < hs->hs_maxhops) {
-			if (rt == NULL) {
-				rt = ieee80211_mesh_rt_add(vap, PREQ_TADDR(0));
-				if (rt == NULL) {
-					IEEE80211_NOTE(vap, IEEE80211_MSG_HWMP,
-					    ni, "unable to add PREQ path to %s",
-					    ether_sprintf(PREQ_TADDR(0)));
-					vap->iv_stats.is_mesh_rtaddfailed++;
-					return;
-				}
-			}
-			rt->rt_metric = preq->preq_metric;
-			rt->rt_lifetime = preq->preq_lifetime;
-			hrorig = IEEE80211_MESH_ROUTE_PRIV(rt,
-			    struct ieee80211_hwmp_route);
-			hrorig->hr_seq = preq->preq_origseq;
-			hrorig->hr_preqid = preq->preq_id;
-
 			IEEE80211_NOTE(vap, IEEE80211_MSG_HWMP, ni,
-			    "forward PREQ from %s",
-			    ether_sprintf(preq->preq_origaddr));
+			    "broadcast PREQ, originator %s, target %s",
+			    ether_sprintf(preq->preq_origaddr),
+				       ether_sprintf(PREQ_TADDR(0)));
+			ppreq.preq_flags |= IEEE80211_MESHPREQ_FLAGS_AM;
 			ppreq.preq_hopcount += 1;
 			ppreq.preq_ttl -= 1;
 			ppreq.preq_metric += ms->ms_pmetric->mpm_metric(ni);
@@ -956,12 +986,14 @@ hwmp_recv_prep(struct ieee80211vap *vap, struct ieee80211_node *ni,
 		return;
 
 	IEEE80211_NOTE(vap, IEEE80211_MSG_HWMP, ni,
-	    "received PREP from %s", ether_sprintf(prep->prep_targetaddr));
+	    "received PREP, originator %s, target %s", ether_sprintf(prep->prep_origaddr), ether_sprintf(prep->prep_targetaddr));
 
 	rt = ieee80211_mesh_rt_find(vap, prep->prep_targetaddr);
 	if (rt == NULL) {
 		/*
-		 * If we have no entry this could be a reply to a root PREQ.
+		 * If we have no entry this could be a reply to a root PREQ. 
+		 * XXX: not true anymore cause we dont create entry for target when
+		 * propagating PREQs like the old code did.
 		 */
 		if (hs->hs_rootmode != IEEE80211_HWMP_ROOTMODE_DISABLED) {
 			rt = ieee80211_mesh_rt_add(vap, prep->prep_targetaddr);
@@ -989,13 +1021,23 @@ hwmp_recv_prep(struct ieee80211vap *vap, struct ieee80211_node *ni,
 	 * Sequence number validation.
 	 */
 	hr = IEEE80211_MESH_ROUTE_PRIV(rt, struct ieee80211_hwmp_route);
-	if (HWMP_SEQ_LEQ(prep->prep_targetseq, hr->hr_seq)) {
+	if((rt->rt_flags & IEEE80211_MESHRT_FLAGS_VALID)){ // Accept if route is not valid
+	  if (HWMP_SEQ_LT(prep->prep_targetseq, hr->hr_seq)) {
 		IEEE80211_NOTE(vap, IEEE80211_MSG_HWMP, ni,
-		    "discard PREP from %s, old seq no %u <= %u",
+		    "discard PREP from %s, old seq no %u < %u",
 		    ether_sprintf(prep->prep_targetaddr),
 		    prep->prep_targetseq, hr->hr_seq);
 		return;
+	  }else if(HWMP_SEQ_LEQ(prep->prep_targetseq, hr->hr_seq) && //If same seqno compare metric
+		prep->prep_metric > rt->rt_metric) {
+		IEEE80211_NOTE(vap, IEEE80211_MSG_HWMP, ni,
+		    "discard PREP from %s, new metric %u > %u",
+		    ether_sprintf(prep->prep_targetaddr),
+		    prep->prep_metric, rt->rt_metric);
+		return;
+	  }
 	}
+	
 	hr->hr_seq = prep->prep_targetseq;
 	/*
 	 * If it's NOT for us, propagate the PREP.
@@ -1012,7 +1054,6 @@ hwmp_recv_prep(struct ieee80211vap *vap, struct ieee80211_node *ni,
 		pprep.prep_hopcount += 1;
 		pprep.prep_ttl -= 1;
 		pprep.prep_metric += ms->ms_pmetric->mpm_metric(ni);
-		IEEE80211_ADDR_COPY(pprep.prep_targetaddr, vap->iv_myaddr);
 		hwmp_send_prep(ni, vap->iv_myaddr, broadcastaddr, &pprep);
 	}
 	hr = IEEE80211_MESH_ROUTE_PRIV(rt, struct ieee80211_hwmp_route);
@@ -1022,7 +1063,7 @@ hwmp_recv_prep(struct ieee80211vap *vap, struct ieee80211_node *ni,
 		    "discard PREP for %s, route is marked PROXY",
 		    ether_sprintf(prep->prep_targetaddr));
 		vap->iv_stats.is_hwmp_proxy++;
-	} else if (prep->prep_origseq == hr->hr_origseq) {
+	} else if (hr->hr_origseq == 0 || prep->prep_origseq == hr->hr_origseq) { //first path discovery always fail!
 		/*
 		 * Check if we already have a path to this node.
 		 * If we do, check if this path reply contains a
@@ -1031,15 +1072,16 @@ hwmp_recv_prep(struct ieee80211vap *vap, struct ieee80211_node *ni,
 		if ((rt->rt_flags & IEEE80211_MESHRT_FLAGS_VALID) == 0 ||
 		    (prep->prep_hopcount < rt->rt_nhops ||
 		     prep->prep_metric < rt->rt_metric)) {
+			hr->hr_origseq = prep->prep_origseq;
 			IEEE80211_NOTE(vap, IEEE80211_MSG_HWMP, ni,
 			    "%s path to %s, hopcount %d:%d metric %d:%d",
 			    rt->rt_flags & IEEE80211_MESHRT_FLAGS_VALID ?
 				"prefer" : "update",
-			    ether_sprintf(prep->prep_origaddr),
-			    rt->rt_nhops, prep->prep_hopcount,
+			    ether_sprintf(prep->prep_targetaddr),
+			    rt->rt_nhops, prep->prep_hopcount + 1,
 			    rt->rt_metric, prep->prep_metric);
 			IEEE80211_ADDR_COPY(rt->rt_nexthop, wh->i_addr2);
-			rt->rt_nhops = prep->prep_hopcount;
+			rt->rt_nhops = prep->prep_hopcount + 1;
 			rt->rt_lifetime = prep->prep_lifetime;
 			rt->rt_metric = prep->prep_metric;
 			rt->rt_flags |= IEEE80211_MESHRT_FLAGS_VALID;
@@ -1052,9 +1094,9 @@ hwmp_recv_prep(struct ieee80211vap *vap, struct ieee80211_node *ni,
 		}
 	} else {
 		IEEE80211_NOTE(vap, IEEE80211_MSG_HWMP, ni,
-		    "discard PREP for %s, wrong seqno %u != %u",
+		    "discard PREP for %s, wrong orig seqno %u != %u",
 		    ether_sprintf(prep->prep_targetaddr), prep->prep_origseq,
-		    hr->hr_seq);
+		    hr->hr_origseq);
 		vap->iv_stats.is_hwmp_wrongseq++;
 	} 
 	/*
@@ -1323,13 +1365,13 @@ hwmp_discover(struct ieee80211vap *vap,
 			/* XXX check preq retries */
 			sendpreq = 1;
 			IEEE80211_NOTE_MAC(vap, IEEE80211_MSG_HWMP, dest,
-			    "start path discovery (src %s)",
+			    "start path discovery (src %s), target seq %u",
 			    m == NULL ? "<none>" : ether_sprintf(
-				mtod(m, struct ether_header *)->ether_shost));
+				mtod(m, struct ether_header *)->ether_shost), hr->hr_seq);
 			/*
 			 * Try to discover the path for this node.
 			 */
-			preq.preq_flags = 0;
+			preq.preq_flags = IEEE80211_MESHPREQ_FLAGS_AM; /* Group addressed PREQ Case A */
 			preq.preq_hopcount = 0;
 			preq.preq_ttl = ms->ms_ttl;
 			preq.preq_id = ++hs->hs_preqid;
@@ -1345,7 +1387,7 @@ hwmp_discover(struct ieee80211vap *vap,
 			if (ieee80211_hwmp_replyforward)
 				PREQ_TFLAGS(0) |= IEEE80211_MESHPREQ_TFLAGS_RF;
 			PREQ_TFLAGS(0) |= IEEE80211_MESHPREQ_TFLAGS_USN;
-			PREQ_TSEQ(0) = 0;
+			PREQ_TSEQ(0) = hr->hr_seq;
 			/* XXX check return value */
 			hwmp_send_preq(vap->iv_bss, vap->iv_myaddr,
 			    broadcastaddr, &preq);

Want to link to this message? Use this URL: <https://mail-archive.FreeBSD.org/cgi/mid.cgi?CA%2BsBSoJWXD5S-zvxHR_=iwh26G0bd00trR=E-jCUBD03uMrU%2BQ>