svn commit: r234878 - head/sys/net80211

Monthadar Al Jaberi monthadar at FreeBSD.org
Tue May 1 15:56:27 UTC 2012


Author: monthadar
Date: Tue May  1 15:56:26 2012
New Revision: 234878
URL: http://svn.freebsd.org/changeset/base/234878

Log:
  Mesh forwarding with proxy support.
  
  * Modified HWMP PREP/PREQ to contain a proxy entry and also changed PREP
  frame processing according to amendment as following:
          o Fixed PREP to always update/create if acceptance criteria is meet;
          o PREQ processing to reply if request is for a proxy entry that is
            proxied by us;
          o Removed hwmp_discover call from PREQ, because sending a PREP will
            build the forward path, and by receving and accepting a PREQ we
            have already built the reverse path (non-proactive code);
  * Disabled code for pro-active in PREP for now (will make a separate patch for
  pro-active HWMP routing later)
  * Added proxy information for a Mesh route, mesh gate to use and proxy seqno;
  * Modified ieee80211_encap according to amendment;
  * Introduced Mesh control address extension enum and removed unused struct,
  also rename some structure element names.
  * Modified mesh_input and added mesh_recv_* that should verify and process mesh
  data frames according to 9.32 Mesh forwarding framework in amendment;
  * Modified mesh_decap accordingly to changes done in mesh control AE struct;
  
  Approved by: adrian

Modified:
  head/sys/net80211/ieee80211_hwmp.c
  head/sys/net80211/ieee80211_mesh.c
  head/sys/net80211/ieee80211_mesh.h
  head/sys/net80211/ieee80211_output.c

Modified: head/sys/net80211/ieee80211_hwmp.c
==============================================================================
--- head/sys/net80211/ieee80211_hwmp.c	Tue May  1 15:47:30 2012	(r234877)
+++ head/sys/net80211/ieee80211_hwmp.c	Tue May  1 15:56:26 2012	(r234878)
@@ -143,6 +143,8 @@ typedef uint32_t ieee80211_hwmp_seq;
 #define	HWMP_SEQ_GT(a, b)	((int32_t)((a)-(b)) > 0)
 #define	HWMP_SEQ_GEQ(a, b)	((int32_t)((a)-(b)) >= 0)
 
+#define HWMP_SEQ_MAX(a, b)	(a > b ? a : b)
+
 /*
  * Private extension of ieee80211_mesh_route.
  */
@@ -866,7 +868,7 @@ hwmp_recv_preq(struct ieee80211vap *vap,
     const struct ieee80211_frame *wh, const struct ieee80211_meshpreq_ie *preq)
 {
 	struct ieee80211_mesh_state *ms = vap->iv_mesh;
-	struct ieee80211_mesh_route *rt = NULL;
+	struct ieee80211_mesh_route *rt = NULL; /* pro-active code */
 	struct ieee80211_mesh_route *rtorig = NULL;
 	struct ieee80211_mesh_route *rttarg = NULL;
 	struct ieee80211_hwmp_route *hrorig = NULL;
@@ -963,31 +965,44 @@ hwmp_recv_preq(struct ieee80211vap *vap,
 
 	/*
 	 * Check if the PREQ is addressed to us.
+	 * or a Proxy currently supplied by us.
 	 */
-	if (IEEE80211_ADDR_EQ(vap->iv_myaddr, PREQ_TADDR(0))) {
-		IEEE80211_NOTE(vap, IEEE80211_MSG_HWMP, ni,
-		    "reply to %6D", preq->preq_origaddr, ":");
+	if (IEEE80211_ADDR_EQ(vap->iv_myaddr, PREQ_TADDR(0)) ||
+	    (rttarg != NULL &&
+	    rttarg->rt_flags & IEEE80211_MESHRT_FLAGS_PROXY &&
+	    rttarg->rt_flags & IEEE80211_MESHRT_FLAGS_VALID)) {
 		/*
-		 * Build and send a PREP frame.
+		 * When we are the target we shall update our own HWMP seq
+		 * number with max of (current and preq->seq) + 1
 		 */
+		hs->hs_seq = HWMP_SEQ_MAX(hs->hs_seq, PREQ_TSEQ(0)) + 1;
+
 		prep.prep_flags = 0;
+		if (rttarg != NULL && /* if NULL it means we are the target */
+		    rttarg->rt_flags & IEEE80211_MESHRT_FLAGS_PROXY) {
+			IEEE80211_NOTE(vap, IEEE80211_MSG_HWMP, ni,
+			    "reply for proxy %6D", rttarg->rt_dest, ":");
+			prep.prep_flags |= IEEE80211_MESHPREP_FLAGS_AE;
+			IEEE80211_ADDR_COPY(prep.prep_target_ext_addr,
+			    rttarg->rt_dest);
+			/* update proxy seqno to HWMP seqno */
+			rttarg->rt_ext_seq = hs->hs_seq;
+		}
+		/*
+		 * Build and send a PREP frame.
+		 */
 		prep.prep_hopcount = 0;
 		prep.prep_ttl = ms->ms_ttl;
 		IEEE80211_ADDR_COPY(prep.prep_targetaddr, vap->iv_myaddr);
-		prep.prep_targetseq = ++hs->hs_seq;
+		prep.prep_targetseq = hs->hs_seq;
 		prep.prep_lifetime = preq->preq_lifetime;
 		prep.prep_metric = IEEE80211_MESHLMETRIC_INITIALVAL;
 		IEEE80211_ADDR_COPY(prep.prep_origaddr, preq->preq_origaddr);
 		prep.prep_origseq = preq->preq_origseq;
+
+		IEEE80211_NOTE(vap, IEEE80211_MSG_HWMP, ni,
+		    "reply to %6D", preq->preq_origaddr, ":");
 		hwmp_send_prep(ni, vap->iv_myaddr, wh->i_addr2, &prep);
-		/*
-		 * Build the reverse path, if we don't have it already.
-		 */
-		rt = ieee80211_mesh_rt_find(vap, preq->preq_origaddr);
-		if (rt == NULL)
-			hwmp_discover(vap, preq->preq_origaddr, NULL);
-		else if ((rt->rt_flags & IEEE80211_MESHRT_FLAGS_VALID) == 0)
-			hwmp_discover(vap, rt->rt_dest, NULL);
 		return;
 	}
 	/*
@@ -1179,15 +1194,19 @@ hwmp_recv_prep(struct ieee80211vap *vap,
 	struct ieee80211_mesh_state *ms = vap->iv_mesh;
 	struct ieee80211_hwmp_state *hs = vap->iv_hwmp;
 	struct ieee80211_mesh_route *rt = NULL;
+	struct ieee80211_mesh_route *rtorig = NULL;
+	struct ieee80211_mesh_route *rtext = NULL;
 	struct ieee80211_hwmp_route *hr;
 	struct ieee80211com *ic = vap->iv_ic;
 	struct ifnet *ifp = vap->iv_ifp;
 	struct mbuf *m, *next;
 	uint32_t metric = 0;
+	const uint8_t *addr;
 
 	/*
-	 * Acceptance criteria: if the corresponding PREQ was not generated
-	 * by us and forwarding is disabled, discard this PREP.
+	 * Acceptance criteria: If the corresponding PREP was not generated
+	 * by us or generated by an external mac that is proxied by us
+	 * and forwarding is disabled, discard this PREP.
 	 */
 	if (ni == vap->iv_bss ||
 	    ni->ni_mlstate != IEEE80211_NODE_MESH_ESTABLISHED)
@@ -1195,10 +1214,21 @@ hwmp_recv_prep(struct ieee80211vap *vap,
 	if (!IEEE80211_ADDR_EQ(vap->iv_myaddr, prep->prep_origaddr) &&
 	    !(ms->ms_flags & IEEE80211_MESHFLAGS_FWD))
 		return;
+	rtorig = ieee80211_mesh_rt_find(vap, prep->prep_origaddr);
+	if (rtorig != NULL &&
+	    !(rtorig->rt_flags & IEEE80211_MESHRT_FLAGS_PROXY)) {
+		IEEE80211_NOTE(vap, IEEE80211_MSG_HWMP, ni,
+		    "received PREP(%u) for an orig(%6D) not proxied by us",
+		    prep->prep_origseq, prep->prep_origaddr, ":");
+		return;
+	}
+
+	/* PREP ACCEPTED */
 
 	IEEE80211_NOTE(vap, IEEE80211_MSG_HWMP, ni,
 	    "received PREP from %6D", prep->prep_targetaddr, ":");
 
+#if 0
 	rt = ieee80211_mesh_rt_find(vap, prep->prep_targetaddr);
 	if (rt == NULL) {
 		/*
@@ -1228,10 +1258,30 @@ hwmp_recv_prep(struct ieee80211vap *vap,
 		}
 		return;
 	}
+#endif
+
 	/*
-	 * Sequence number validation.
+	 * If accepted shall create or update the active forwarding information
+	 * it maintains for the target mesh STA of the PREP (according to the
+	 * rules defined in 13.10.8.4). If the conditions for creating or
+	 * updating the forwarding information have not been met in those
+	 * rules, no further steps are applied to the PREP.
+	 * [OPTIONAL]: update forwarding information to TA if metric improves.
 	 */
+	rt = ieee80211_mesh_rt_find(vap, prep->prep_targetaddr);
+	if (rt == NULL) {
+		rt = ieee80211_mesh_rt_add(vap, prep->prep_targetaddr);
+		if (rt == NULL) {
+			IEEE80211_NOTE(vap, IEEE80211_MSG_HWMP, ni,
+			    "unable to add PREP path to %6D",
+			    prep->prep_targetaddr, ":");
+			vap->iv_stats.is_mesh_rtaddfailed++;
+			return;
+		}
+	}
 	hr = IEEE80211_MESH_ROUTE_PRIV(rt, struct ieee80211_hwmp_route);
+	/* update path metric */
+	metric = prep->prep_metric + ms->ms_pmetric->mpm_metric(ni);
 	if ((rt->rt_flags & IEEE80211_MESHRT_FLAGS_VALID)) {
 		if (HWMP_SEQ_LT(prep->prep_targetseq, hr->hr_seq)) {
 			IEEE80211_NOTE(vap, IEEE80211_MSG_HWMP, ni,
@@ -1240,7 +1290,7 @@ hwmp_recv_prep(struct ieee80211vap *vap,
 			    prep->prep_targetseq, hr->hr_seq);
 			return;
 		} else if (HWMP_SEQ_LEQ(prep->prep_targetseq, hr->hr_seq) &&
-		    prep->prep_metric > rt->rt_metric) {
+		    metric > rt->rt_metric) {
 			IEEE80211_NOTE(vap, IEEE80211_MSG_HWMP, ni,
 			    "discard PREP from %6D, new metric %u > %u",
 			    prep->prep_targetaddr, ":",
@@ -1249,7 +1299,21 @@ hwmp_recv_prep(struct ieee80211vap *vap,
 		}
 	}
 
+	IEEE80211_NOTE(vap, IEEE80211_MSG_HWMP, ni,
+	    "%s path to %6D, hopcount %d:%d metric %d:%d",
+	    rt->rt_flags & IEEE80211_MESHRT_FLAGS_VALID ?
+	    "prefer" : "update",
+	    prep->prep_targetaddr, ":",
+	    rt->rt_nhops, prep->prep_hopcount,
+	    rt->rt_metric, metric);
+
 	hr->hr_seq = prep->prep_targetseq;
+	IEEE80211_ADDR_COPY(rt->rt_nexthop, ni->ni_macaddr);
+	rt->rt_metric = metric;
+	rt->rt_nhops = prep->prep_hopcount + 1;
+	ieee80211_mesh_rt_update(rt, prep->prep_lifetime);
+	rt->rt_flags |= IEEE80211_MESHRT_FLAGS_VALID; /* mark valid */
+
 	/*
 	 * If it's NOT for us, propagate the PREP.
 	 */
@@ -1265,53 +1329,45 @@ hwmp_recv_prep(struct ieee80211vap *vap,
 		pprep.prep_ttl -= 1;
 		pprep.prep_metric += ms->ms_pmetric->mpm_metric(ni);
 		hwmp_send_prep(ni, vap->iv_myaddr, broadcastaddr, &pprep);
+
+		/* may store target external address if recevied PREP w/ AE */
+		/* precursor list for the Target Mesh STA Address is updated */
 	}
-	hr = IEEE80211_MESH_ROUTE_PRIV(rt, struct ieee80211_hwmp_route);
-	if (rt->rt_flags & IEEE80211_MESHRT_FLAGS_PROXY) {
-		/* NB: never clobber a proxy entry */;
-		IEEE80211_NOTE(vap, IEEE80211_MSG_HWMP, ni,
-		    "discard PREP for %6D, route is marked PROXY",
-		    prep->prep_targetaddr, ":");
-		vap->iv_stats.is_hwmp_proxy++;
-	/* NB: first path discovery always fails */
-	} else if (hr->hr_origseq == 0 ||
-	    prep->prep_origseq == hr->hr_origseq) {
-		/*
-		 * Check if we already have a path to this node.
-		 * If we do, check if this path reply contains a
-		 * better route.
-		 */
-		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;
-			metric = prep->prep_metric +
-			    ms->ms_pmetric->mpm_metric(ni);
-			IEEE80211_NOTE(vap, IEEE80211_MSG_HWMP, ni,
-			    "%s path to %6D, hopcount %d:%d metric %d:%d",
-			    rt->rt_flags & IEEE80211_MESHRT_FLAGS_VALID ?
-				"prefer" : "update",
-			    prep->prep_origaddr, ":",
-			    rt->rt_nhops, prep->prep_hopcount,
-			    rt->rt_metric, prep->prep_metric);
-			IEEE80211_ADDR_COPY(rt->rt_nexthop, wh->i_addr2);
-			rt->rt_nhops = prep->prep_hopcount + 1;
-			ieee80211_mesh_rt_update(rt, prep->prep_lifetime);
-			rt->rt_metric = metric;
-			rt->rt_flags |= IEEE80211_MESHRT_FLAGS_VALID;
-		} else {
-			IEEE80211_NOTE(vap, IEEE80211_MSG_HWMP, ni,
-			    "ignore PREP for %6D, hopcount %d:%d metric %d:%d",
-			    prep->prep_targetaddr, ":",
-			    rt->rt_nhops, prep->prep_hopcount,
-			    rt->rt_metric, prep->prep_metric);
+	/* check if we received a PREP for a proxy address */
+	else if (prep->prep_flags & IEEE80211_MESHPREP_FLAGS_AE) {
+		rtext = ieee80211_mesh_rt_find(vap,
+			prep->prep_target_ext_addr);
+		if (rtext == NULL) {
+			rtext = ieee80211_mesh_rt_add(vap,
+				prep->prep_target_ext_addr);
+			if (rtext == NULL) {
+				IEEE80211_NOTE(vap, IEEE80211_MSG_HWMP, ni,
+				    "unable to add PREP path to proxy %6D",
+				    prep->prep_targetaddr, ":");
+				vap->iv_stats.is_mesh_rtaddfailed++;
+				return;
+			}
 		}
-	} else {
 		IEEE80211_NOTE(vap, IEEE80211_MSG_HWMP, ni,
-		    "discard PREP for %6D, wrong orig seqno %u != %u",
-		    prep->prep_targetaddr, ":", prep->prep_origseq,
-		    hr->hr_origseq);
-		vap->iv_stats.is_hwmp_wrongseq++;
+		    "%s path to %6D, hopcount %d:%d metric %d:%d",
+		    rtext->rt_flags & IEEE80211_MESHRT_FLAGS_VALID ?
+		    "prefer" : "update",
+		    prep->prep_target_ext_addr, ":",
+		    rtext->rt_nhops, prep->prep_hopcount,
+		    rtext->rt_metric, metric);
+
+		rtext->rt_flags = IEEE80211_MESHRT_FLAGS_PROXY |
+			IEEE80211_MESHRT_FLAGS_VALID;
+		IEEE80211_ADDR_COPY(rtext->rt_dest,
+		    prep->prep_target_ext_addr);
+		IEEE80211_ADDR_COPY(rtext->rt_mesh_gate,
+		    prep->prep_targetaddr);
+		IEEE80211_ADDR_COPY(rtext->rt_nexthop, wh->i_addr2);
+		rtext->rt_metric = metric;
+		rtext->rt_lifetime = prep->prep_lifetime;
+		rtext->rt_nhops = prep->prep_hopcount + 1;
+		rtext->rt_ext_seq = prep->prep_origseq; /* proxy seq */
+		/* proxy entries have no HWMP priv data, nullify them to be sure? */
 	}
 	/*
 	 * Check for frames queued awaiting path discovery.
@@ -1320,9 +1376,11 @@ hwmp_recv_prep(struct ieee80211vap *vap,
 	 *     stuck back on the stageq because there won't be
 	 *     a path.
 	 */
+	addr = prep->prep_flags & IEEE80211_MESHPREP_FLAGS_AE ?
+	    prep->prep_target_ext_addr : prep->prep_targetaddr;
 	m = ieee80211_ageq_remove(&ic->ic_stageq,
 	    (struct ieee80211_node *)(uintptr_t)
-	    ieee80211_mac_hash(ic, rt->rt_dest));
+	    ieee80211_mac_hash(ic, addr)); /* either dest or ext_dest */
 	for (; m != NULL; m = next) {
 		next = m->m_nextpkt;
 		m->m_nextpkt = NULL;

Modified: head/sys/net80211/ieee80211_mesh.c
==============================================================================
--- head/sys/net80211/ieee80211_mesh.c	Tue May  1 15:47:30 2012	(r234877)
+++ head/sys/net80211/ieee80211_mesh.c	Tue May  1 15:56:26 2012	(r234878)
@@ -284,12 +284,14 @@ ieee80211_mesh_proxy_check(struct ieee80
 		} else {
 			IEEE80211_NOTE_MAC(vap, IEEE80211_MSG_MESH, dest,
 			    "%s", "add proxy entry");
+			IEEE80211_ADDR_COPY(rt->rt_mesh_gate, vap->iv_myaddr);
 			IEEE80211_ADDR_COPY(rt->rt_nexthop, vap->iv_myaddr);
 			rt->rt_flags |= IEEE80211_MESHRT_FLAGS_VALID
 				     |  IEEE80211_MESHRT_FLAGS_PROXY;
 		}
-	/* XXX assert PROXY? */
 	} else if ((rt->rt_flags & IEEE80211_MESHRT_FLAGS_VALID) == 0) {
+		KASSERT(rt->rt_flags & IEEE80211_MESHRT_FLAGS_PROXY,
+		    ("no proxy flag for poxy entry"));
 		struct ieee80211com *ic = vap->iv_ic;
 		/*
 		 * Fix existing entry created by received frames from
@@ -910,9 +912,14 @@ mesh_forward(struct ieee80211vap *vap, s
 	struct ieee80211_node *ni;
 	int err;
 
-	if (mc->mc_ttl == 0) {
+	/*
+	 * mesh ttl of 1 means we are the last one receving it,
+	 * according to amendment we decrement and then check if
+	 * 0, if so we dont forward.
+	 */
+	if (mc->mc_ttl < 1) {
 		IEEE80211_NOTE_FRAME(vap, IEEE80211_MSG_MESH, wh,
-		    "%s", "frame not fwd'd, ttl 0");
+		    "%s", "frame not fwd'd, ttl 1");
 		vap->iv_stats.is_mesh_fwd_ttl++;
 		return;
 	}
@@ -952,6 +959,12 @@ mesh_forward(struct ieee80211vap *vap, s
 	} else {
 		ni = mesh_find_txnode(vap, whcopy->i_addr3);
 		if (ni == NULL) {
+			/*
+			 * [Optional] any of the following three actions:
+			 * o silently discard
+			 * o trigger a path discovery
+			 * o inform TA that meshDA is unreachable.
+			 */
 			IEEE80211_NOTE_FRAME(vap, IEEE80211_MSG_MESH, wh,
 			    "%s", "frame not fwd'd, no path");
 			vap->iv_stats.is_mesh_fwd_nopath++;
@@ -980,9 +993,10 @@ mesh_forward(struct ieee80211vap *vap, s
 static struct mbuf *
 mesh_decap(struct ieee80211vap *vap, struct mbuf *m, int hdrlen, int meshdrlen)
 {
-#define	WHDIR(wh) ((wh)->i_fc[1] & IEEE80211_FC1_DIR_MASK)
+#define	WHDIR(wh)	((wh)->i_fc[1] & IEEE80211_FC1_DIR_MASK)
+#define	MC01(mc)	((const struct ieee80211_meshcntl_ae01 *)mc)
 	uint8_t b[sizeof(struct ieee80211_qosframe_addr4) +
-		  sizeof(struct ieee80211_meshcntl_ae11)];
+		  sizeof(struct ieee80211_meshcntl_ae10)];
 	const struct ieee80211_qosframe_addr4 *wh;
 	const struct ieee80211_meshcntl_ae10 *mc;
 	struct ether_header *eh;
@@ -1016,13 +1030,14 @@ mesh_decap(struct ieee80211vap *vap, str
 		m_adj(m, hdrlen - sizeof(*eh));
 	}
 	eh = mtod(m, struct ether_header *);
-	ae = mc->mc_flags & 3;
+	ae = mc->mc_flags & IEEE80211_MESH_AE_MASK;
 	if (WHDIR(wh) == IEEE80211_FC1_DIR_FROMDS) {
 		IEEE80211_ADDR_COPY(eh->ether_dhost, wh->i_addr1);
-		if (ae == 0) {
+		if (ae == IEEE80211_MESH_AE_00) {
 			IEEE80211_ADDR_COPY(eh->ether_shost, wh->i_addr3);
-		} else if (ae == 1) {
-			IEEE80211_ADDR_COPY(eh->ether_shost, mc->mc_addr4);
+		} else if (ae == IEEE80211_MESH_AE_01) {
+			IEEE80211_ADDR_COPY(eh->ether_shost,
+			    MC01(mc)->mc_addr4);
 		} else {
 			IEEE80211_DISCARD(vap, IEEE80211_MSG_ANY,
 			    (const struct ieee80211_frame *)wh, NULL,
@@ -1032,12 +1047,12 @@ mesh_decap(struct ieee80211vap *vap, str
 			return NULL;
 		}
 	} else {
-		if (ae == 0) {
+		if (ae == IEEE80211_MESH_AE_00) {
 			IEEE80211_ADDR_COPY(eh->ether_dhost, wh->i_addr3);
 			IEEE80211_ADDR_COPY(eh->ether_shost, wh->i_addr4);
-		} else if (ae == 2) {
-			IEEE80211_ADDR_COPY(eh->ether_dhost, mc->mc_addr4);
-			IEEE80211_ADDR_COPY(eh->ether_shost, mc->mc_addr5);
+		} else if (ae == IEEE80211_MESH_AE_10) {
+			IEEE80211_ADDR_COPY(eh->ether_dhost, mc->mc_addr5);
+			IEEE80211_ADDR_COPY(eh->ether_shost, mc->mc_addr6);
 		} else {
 			IEEE80211_DISCARD(vap, IEEE80211_MSG_ANY,
 			    (const struct ieee80211_frame *)wh, NULL,
@@ -1059,7 +1074,8 @@ mesh_decap(struct ieee80211vap *vap, str
 		eh->ether_type = htons(m->m_pkthdr.len - sizeof(*eh));
 	}
 	return m;
-#undef WDIR
+#undef	WDIR
+#undef	MC01
 }
 
 /*
@@ -1075,12 +1091,13 @@ mesh_isucastforme(struct ieee80211vap *v
 
 	KASSERT((wh->i_fc[1] & IEEE80211_FC1_DIR_MASK) == IEEE80211_FC1_DIR_DSTODS,
 	    ("bad dir 0x%x:0x%x", wh->i_fc[0], wh->i_fc[1]));
-	KASSERT(ae == 0 || ae == 2, ("bad AE %d", ae));
-	if (ae == 2) {				/* ucast w/ proxy */
+	KASSERT(ae == IEEE80211_MESH_AE_00 || ae == IEEE80211_MESH_AE_10,
+	    ("bad AE %d", ae));
+	if (ae == IEEE80211_MESH_AE_10) {	/* ucast w/ proxy */
 		const struct ieee80211_meshcntl_ae10 *mc10 =
 		    (const struct ieee80211_meshcntl_ae10 *) mc;
 		struct ieee80211_mesh_route *rt =
-		    ieee80211_mesh_rt_find(vap, mc10->mc_addr4);
+		    ieee80211_mesh_rt_find(vap, mc10->mc_addr5);
 		/* check for proxy route to ourself */
 		return (rt != NULL &&
 		    (rt->rt_flags & IEEE80211_MESHRT_FLAGS_PROXY));
@@ -1088,19 +1105,139 @@ mesh_isucastforme(struct ieee80211vap *v
 		return IEEE80211_ADDR_EQ(wh->i_addr3, vap->iv_myaddr);
 }
 
+/*
+ * Verifies transmitter, updates lifetime, precursor list and forwards data.
+ * > 0 means we have forwarded data and no need to process locally
+ * == 0 means we want to process locally (and we may have forwarded data
+ * < 0 means there was an error and data should be discarded
+ */
+static int
+mesh_recv_indiv_data_to_fwrd(struct ieee80211vap *vap, struct mbuf *m,
+    struct ieee80211_frame *wh, const struct ieee80211_meshcntl *mc)
+{
+
+	/*
+	 * TODO:
+	 * o verify addr2 is  a legitimate transmitter
+	 * o set lifetime of addr3 to initial value
+	 * o set lifetime of addr4 to initial value
+	 * o lifetime of precursor of addr3 (addr2) is max(init, curr)
+	 * o lifetime of precursor of addr4 (nexthop) is max(init, curr)
+	 */
+
+	mesh_forward(vap, m, mc);
+	return (1); /* dont process locally */
+}
+
+/*
+ * Verifies transmitter, updates lifetime, precursor list and process data
+ * locally, if data is is proxy with AE = 10 it could mean data should go
+ * on another mesh path or data should be forwarded to the DS.
+ *
+ * > 0 means we have forwarded data and no need to process locally
+ * == 0 means we want to process locally (and we may have forwarded data
+ * < 0 means there was an error and data should be discarded
+ */
+static int
+mesh_recv_indiv_data_to_me(struct ieee80211vap *vap, struct mbuf *m,
+    struct ieee80211_frame *wh, const struct ieee80211_meshcntl *mc)
+{
+	struct ieee80211_qosframe_addr4 *qwh;
+	const struct ieee80211_meshcntl_ae10 *mc10;
+	struct ieee80211_mesh_route *rt;
+	int ae;
+
+	qwh = (struct ieee80211_qosframe_addr4 *)wh;
+	mc10 = (const struct ieee80211_meshcntl_ae10 *)mc;
+
+	/*
+	 * TODO:
+	 * o verify addr2 is  a legitimate transmitter
+	 * o set lifetime of addr4 to initial value
+	 * o lifetime of precursor entry is max(init, curr)
+	 */
+
+	ae = mc10->mc_flags & IEEE80211_MESH_AE_MASK;
+	KASSERT(ae == IEEE80211_MESH_AE_00 ||
+	    ae == IEEE80211_MESH_AE_10, ("bad AE %d", ae));
+	if (ae == IEEE80211_MESH_AE_10) {
+		if (IEEE80211_ADDR_EQ(mc10->mc_addr5, qwh->i_addr3)) {
+			return (0); /* process locally */
+		}
+
+		rt =  ieee80211_mesh_rt_find(vap, mc10->mc_addr5);
+		if (rt != NULL &&
+		    (rt->rt_flags & IEEE80211_MESHRT_FLAGS_VALID) &&
+		    (rt->rt_flags & IEEE80211_MESHRT_FLAGS_PROXY) == 0) {
+			/*
+			 * Forward on another mesh-path, according to
+			 * amendment as specified in 9.32.4.1
+			 */
+			IEEE80211_ADDR_COPY(qwh->i_addr3, mc10->mc_addr5);
+			mesh_forward(vap, m,
+			    (const struct ieee80211_meshcntl *)mc10);
+			return (1); /* dont process locally */
+		}
+		/*
+		 * All other cases: forward of MSDUs from the MBSS to DS indiv.
+		 * addressed according to 13.11.3.2.
+		 */
+	}
+	return (0); /* process locally */
+}
+
+/*
+ * Try to forward the group addressed data on to other mesh STAs, and
+ * also to the DS.
+ *
+ * > 0 means we have forwarded data and no need to process locally
+ * == 0 means we want to process locally (and we may have forwarded data
+ * < 0 means there was an error and data should be discarded
+ */
+static int
+mesh_recv_group_data(struct ieee80211vap *vap, struct mbuf *m,
+    struct ieee80211_frame *wh, const struct ieee80211_meshcntl *mc)
+{
+#define	MC01(mc)	((const struct ieee80211_meshcntl_ae01 *)mc)
+	struct ieee80211_mesh_state *ms = vap->iv_mesh;
+
+	mesh_forward(vap, m, mc);
+
+	if(mc->mc_ttl > 0) {
+		if (mc->mc_flags & IEEE80211_MESH_AE_01) {
+			/*
+			 * Forward of MSDUs from the MBSS to DS group addressed
+			 * (according to 13.11.3.2)
+			 * This happens by delivering the packet, and a bridge
+			 * will sent it on another port member.
+			 */
+			if (ms->ms_flags & IEEE80211_MESHFLAGS_PORTAL &&
+			    ms->ms_flags & IEEE80211_MESHFLAGS_FWD)
+				IEEE80211_NOTE_MAC(vap, IEEE80211_MSG_MESH,
+				    MC01(mc)->mc_addr4, "%s",
+				    "forward from MBSS to the DS");
+		}
+	}
+	return (0); /* process locally */
+#undef	MC01
+}
+
 static int
 mesh_input(struct ieee80211_node *ni, struct mbuf *m, int rssi, int nf)
 {
 #define	HAS_SEQ(type)	((type & 0x4) == 0)
+#define	MC01(mc)	((const struct ieee80211_meshcntl_ae01 *)mc)
+#define	MC10(mc)	((const struct ieee80211_meshcntl_ae10 *)mc)
 	struct ieee80211vap *vap = ni->ni_vap;
 	struct ieee80211com *ic = ni->ni_ic;
 	struct ifnet *ifp = vap->iv_ifp;
 	struct ieee80211_frame *wh;
 	const struct ieee80211_meshcntl *mc;
-	int hdrspace, meshdrlen, need_tap;
-	uint8_t dir, type, subtype;
+	int hdrspace, meshdrlen, need_tap, error;
+	uint8_t dir, type, subtype, ae;
 	uint32_t seq;
-	uint8_t *addr, qos[2];
+	const uint8_t *addr;
+	uint8_t qos[2];
 	ieee80211_seq rxseq;
 
 	KASSERT(ni != NULL, ("null node"));
@@ -1189,7 +1326,7 @@ mesh_input(struct ieee80211_node *ni, st
 			    ni->ni_mlstate);
 			vap->iv_stats.is_mesh_nolink++;
 			goto out;
-		}	
+		}
 		if (dir != IEEE80211_FC1_DIR_FROMDS &&
 		    dir != IEEE80211_FC1_DIR_DSTODS) {
 			IEEE80211_DISCARD(vap, IEEE80211_MSG_INPUT,
@@ -1271,12 +1408,28 @@ mesh_input(struct ieee80211_node *ni, st
 		 */
 		mc = (const struct ieee80211_meshcntl *)
 		    (mtod(m, const uint8_t *) + hdrspace);
+		ae = mc->mc_flags & IEEE80211_MESH_AE_MASK;
 		meshdrlen = sizeof(struct ieee80211_meshcntl) +
-		    (mc->mc_flags & 3) * IEEE80211_ADDR_LEN;
+		    ae * IEEE80211_ADDR_LEN;
 		hdrspace += meshdrlen;
+
+		/* pull complete hdrspace = ieee80211_hdrspace + meshcontrol */
+		if ((meshdrlen > sizeof(struct ieee80211_meshcntl)) &&
+		    (m->m_len < hdrspace) &&
+		    ((m = m_pullup(m, hdrspace)) == NULL)) {
+			IEEE80211_DISCARD_MAC(vap, IEEE80211_MSG_ANY,
+			    ni->ni_macaddr, NULL,
+			    "data too short: expecting %u", hdrspace);
+			vap->iv_stats.is_rx_tooshort++;
+			goto out;		/* XXX */
+		}
+		/* XXX: are we sure there is no reallocating after m_pullup? */
+
 		seq = LE_READ_4(mc->mc_seq);
 		if (IEEE80211_IS_MULTICAST(wh->i_addr1))
 			addr = wh->i_addr3;
+		else if (ae == IEEE80211_MESH_AE_01)
+			addr = MC01(mc)->mc_addr4;
 		else
 			addr = ((struct ieee80211_qosframe_addr4 *)wh)->i_addr4;
 		if (IEEE80211_ADDR_EQ(vap->iv_myaddr, addr)) {
@@ -1290,17 +1443,22 @@ mesh_input(struct ieee80211_node *ni, st
 			goto out;
 		}
 
-		/*
-		 * Potentially forward packet.  See table s36 (p140)
-		 * for the rules.  XXX tap fwd'd packets not for us?
-		 */
-		if (dir == IEEE80211_FC1_DIR_FROMDS ||
-		    !mesh_isucastforme(vap, wh, mc)) {
-			mesh_forward(vap, m, mc);
-			if (dir == IEEE80211_FC1_DIR_DSTODS)
-				goto out;
-			/* NB: fall thru to deliver mcast frames locally */
-		}
+		/* This code "routes" the frame to the right control path */
+		if (!IEEE80211_IS_MULTICAST(wh->i_addr1)) {
+			if (IEEE80211_ADDR_EQ(vap->iv_myaddr, wh->i_addr3))
+				error =
+				    mesh_recv_indiv_data_to_me(vap, m, wh, mc);
+			else if (IEEE80211_IS_MULTICAST(wh->i_addr3))
+				error = mesh_recv_group_data(vap, m, wh, mc);
+			else
+				error = mesh_recv_indiv_data_to_fwrd(vap, m,
+				    wh, mc);
+		} else
+			error = mesh_recv_group_data(vap, m, wh, mc);
+		if (error < 0)
+			goto err;
+		else if (error > 0)
+			goto out;
 
 		if (ieee80211_radiotap_active_vap(vap))
 			ieee80211_radiotap_rx(vap, m);
@@ -1382,6 +1540,9 @@ out:
 		m_freem(m);
 	}
 	return type;
+#undef	HAS_SEQ
+#undef	MC01
+#undef	MC10
 }
 
 static void
@@ -2616,7 +2777,7 @@ ieee80211_add_meshpeer(uint8_t *frm, uin
  */
 #define IEEE80211_MESH_MAXOVERHEAD \
 	(sizeof(struct ieee80211_qosframe_addr4) \
-	 + sizeof(struct ieee80211_meshcntl_ae11) \
+	 + sizeof(struct ieee80211_meshcntl_ae10) \
 	+ sizeof(struct llc) \
 	+ IEEE80211_ADDR_LEN \
 	+ IEEE80211_WEP_IVLEN \

Modified: head/sys/net80211/ieee80211_mesh.h
==============================================================================
--- head/sys/net80211/ieee80211_mesh.h	Tue May  1 15:47:30 2012	(r234877)
+++ head/sys/net80211/ieee80211_mesh.h	Tue May  1 15:56:26 2012	(r234878)
@@ -390,19 +390,18 @@ struct ieee80211_meshcntl_ae10 {
 	uint8_t		mc_flags;	/* Address Extension 10 */
 	uint8_t		mc_ttl;		/* TTL */
 	uint8_t		mc_seq[4];	/* Sequence No. */
-	uint8_t		mc_addr4[IEEE80211_ADDR_LEN];
-	uint8_t		mc_addr5[IEEE80211_ADDR_LEN];
-} __packed;
-
-struct ieee80211_meshcntl_ae11 {
-	uint8_t		mc_flags;	/* Address Extension 11 */
-	uint8_t		mc_ttl;		/* TTL */
-	uint8_t		mc_seq[4];	/* Sequence No. */
-	uint8_t		mc_addr4[IEEE80211_ADDR_LEN];
 	uint8_t		mc_addr5[IEEE80211_ADDR_LEN];
 	uint8_t		mc_addr6[IEEE80211_ADDR_LEN];
 } __packed;
 
+#define IEEE80211_MESH_AE_MASK		0x03
+enum {
+	IEEE80211_MESH_AE_00		= 0,	/* MC has no AE subfield */
+	IEEE80211_MESH_AE_01		= 1,	/* MC contain addr4 */
+	IEEE80211_MESH_AE_10		= 2,	/* MC contain addr5 & addr6 */
+	IEEE80211_MESH_AE_11		= 3,	/* RESERVED */
+};
+
 #ifdef _KERNEL
 MALLOC_DECLARE(M_80211_MESH_PREQ);
 MALLOC_DECLARE(M_80211_MESH_PREP);
@@ -423,6 +422,7 @@ struct ieee80211_mesh_route {
 	struct mtx		rt_lock;	/* fine grained route lock */
 	int			rt_updtime;	/* last update time */
 	uint8_t			rt_dest[IEEE80211_ADDR_LEN];
+	uint8_t			rt_mesh_gate[IEEE80211_ADDR_LEN]; /* meshDA */
 	uint8_t			rt_nexthop[IEEE80211_ADDR_LEN];
 	uint32_t		rt_metric;	/* path metric */
 	uint16_t		rt_nhops;	/* number of hops */
@@ -431,6 +431,7 @@ struct ieee80211_mesh_route {
 #define	IEEE80211_MESHRT_FLAGS_PROXY	0x02	/* proxy entry */
 	uint32_t		rt_lifetime;	/* route timeout */
 	uint32_t		rt_lastmseq;	/* last seq# seen dest */
+	uint32_t		rt_ext_seq;	/* proxy seq number */
 	void			*rt_priv;	/* private data */
 };
 #define	IEEE80211_MESH_ROUTE_PRIV(rt, cast)	((cast *)rt->rt_priv)

Modified: head/sys/net80211/ieee80211_output.c
==============================================================================
--- head/sys/net80211/ieee80211_output.c	Tue May  1 15:47:30 2012	(r234877)
+++ head/sys/net80211/ieee80211_output.c	Tue May  1 15:56:26 2012	(r234878)
@@ -254,7 +254,7 @@ ieee80211_start(struct ifnet *ifp)
 				if (!ieee80211_mesh_isproxyena(vap)) {
 					IEEE80211_DISCARD_MAC(vap,
 					    IEEE80211_MSG_OUTPUT |
-						IEEE80211_MSG_MESH,
+					    IEEE80211_MSG_MESH,
 					    eh->ether_dhost, NULL,
 					    "%s", "proxy not enabled");
 					vap->iv_stats.is_mesh_notproxy++;
@@ -363,7 +363,6 @@ ieee80211_start(struct ifnet *ifp)
 				continue;
 			}
 		}
-
 		error = parent->if_transmit(parent, m);
 		if (error != 0) {
 			/* NB: IFQ_HANDOFF reclaims mbuf */
@@ -556,7 +555,6 @@ ieee80211_send_setup(
 			break;
 		case IEEE80211_M_MBSS:
 #ifdef IEEE80211_SUPPORT_MESH
-			/* XXX add support for proxied addresses */
 			if (IEEE80211_IS_MULTICAST(da)) {
 				wh->i_fc[1] = IEEE80211_FC1_DIR_FROMDS;
 				/* XXX next hop */
@@ -1016,10 +1014,13 @@ ieee80211_encap(struct ieee80211vap *vap
     struct mbuf *m)
 {
 #define	WH4(wh)	((struct ieee80211_frame_addr4 *)(wh))
+#define MC01(mc)	((struct ieee80211_meshcntl_ae01 *)mc)
 	struct ieee80211com *ic = ni->ni_ic;
 #ifdef IEEE80211_SUPPORT_MESH
 	struct ieee80211_mesh_state *ms = vap->iv_mesh;
 	struct ieee80211_meshcntl_ae10 *mc;
+	struct ieee80211_mesh_route *rt = NULL;
+	int dir = -1;
 #endif
 	struct ether_header eh;
 	struct ieee80211_frame *wh;
@@ -1100,21 +1101,40 @@ ieee80211_encap(struct ieee80211vap *vap
 		 *   w/ 4-address format and address extension mode 10
 		 */
 		is4addr = 0;		/* NB: don't use, disable */
-		if (!IEEE80211_IS_MULTICAST(eh.ether_dhost))
-			hdrsize += IEEE80211_ADDR_LEN;	/* unicast are 4-addr */
-		meshhdrsize = sizeof(struct ieee80211_meshcntl);
-		/* XXX defines for AE modes */
-		if (IEEE80211_ADDR_EQ(eh.ether_shost, vap->iv_myaddr)) {
-			if (!IEEE80211_IS_MULTICAST(eh.ether_dhost))
-				meshae = 0;
-			else
-				meshae = 4;		/* NB: pseudo */
-		} else if (IEEE80211_IS_MULTICAST(eh.ether_dhost)) {
-			meshae = 1;
-			meshhdrsize += 1*IEEE80211_ADDR_LEN;
+		if (!IEEE80211_IS_MULTICAST(eh.ether_dhost)) {
+			rt = ieee80211_mesh_rt_find(vap, eh.ether_dhost);
+			KASSERT(rt != NULL, ("route is NULL"));
+			dir = IEEE80211_FC1_DIR_DSTODS;
+			hdrsize += IEEE80211_ADDR_LEN;
+			if (rt->rt_flags & IEEE80211_MESHRT_FLAGS_PROXY) {
+				if (IEEE80211_ADDR_EQ(rt->rt_mesh_gate,
+				    vap->iv_myaddr)) {
+					IEEE80211_NOTE_MAC(vap,
+					    IEEE80211_MSG_MESH,
+					    eh.ether_dhost,
+					    "%s", "trying to send to ourself");
+					goto bad;
+				}
+				meshae = IEEE80211_MESH_AE_10;
+				meshhdrsize =
+				    sizeof(struct ieee80211_meshcntl_ae10);
+			} else {
+				meshae = IEEE80211_MESH_AE_00;
+				meshhdrsize =
+				    sizeof(struct ieee80211_meshcntl);
+			}
 		} else {
-			meshae = 2;
-			meshhdrsize += 2*IEEE80211_ADDR_LEN;
+			dir = IEEE80211_FC1_DIR_FROMDS;
+			if (!IEEE80211_ADDR_EQ(eh.ether_shost, vap->iv_myaddr)) {
+				/* proxy group */
+				meshae = IEEE80211_MESH_AE_01;
+				meshhdrsize =
+				    sizeof(struct ieee80211_meshcntl_ae01);
+			} else {
+				/* group */
+				meshae = IEEE80211_MESH_AE_00;
+				meshhdrsize = sizeof(struct ieee80211_meshcntl);
+			}
 		}
 	} else {
 #endif
@@ -1215,44 +1235,52 @@ ieee80211_encap(struct ieee80211vap *vap
 		/* NB: offset by hdrspace to deal with DATAPAD */
 		mc = (struct ieee80211_meshcntl_ae10 *)
 		     (mtod(m, uint8_t *) + hdrspace);
+		wh->i_fc[1] = dir;
 		switch (meshae) {
-		case 0:			/* ucast, no proxy */
-			wh->i_fc[1] = IEEE80211_FC1_DIR_DSTODS;
-			IEEE80211_ADDR_COPY(wh->i_addr1, ni->ni_macaddr);
-			IEEE80211_ADDR_COPY(wh->i_addr2, vap->iv_myaddr);
-			IEEE80211_ADDR_COPY(wh->i_addr3, eh.ether_dhost);
-			IEEE80211_ADDR_COPY(WH4(wh)->i_addr4, eh.ether_shost);
+		case IEEE80211_MESH_AE_00:	/* no proxy */
 			mc->mc_flags = 0;
-			qos = ((struct ieee80211_qosframe_addr4 *) wh)->i_qos;
-			break;
-		case 4:			/* mcast, no proxy */
-			wh->i_fc[1] = IEEE80211_FC1_DIR_FROMDS;
-			IEEE80211_ADDR_COPY(wh->i_addr1, eh.ether_dhost);
-			IEEE80211_ADDR_COPY(wh->i_addr2, vap->iv_myaddr);
-			IEEE80211_ADDR_COPY(wh->i_addr3, eh.ether_shost);
-			mc->mc_flags = 0;		/* NB: AE is really 0 */
-			qos = ((struct ieee80211_qosframe *) wh)->i_qos;
+			if (dir == IEEE80211_FC1_DIR_DSTODS) { /* ucast */
+				IEEE80211_ADDR_COPY(wh->i_addr1,
+				    ni->ni_macaddr);
+				IEEE80211_ADDR_COPY(wh->i_addr2,
+				    vap->iv_myaddr);
+				IEEE80211_ADDR_COPY(wh->i_addr3,
+				    eh.ether_dhost);
+				IEEE80211_ADDR_COPY(WH4(wh)->i_addr4,
+				    eh.ether_shost);
+				qos =((struct ieee80211_qosframe_addr4 *)
+				    wh)->i_qos;
+			} else if (dir == IEEE80211_FC1_DIR_FROMDS) {
+				 /* mcast */
+				IEEE80211_ADDR_COPY(wh->i_addr1,
+				    eh.ether_dhost);
+				IEEE80211_ADDR_COPY(wh->i_addr2,
+				    vap->iv_myaddr);
+				IEEE80211_ADDR_COPY(wh->i_addr3,
+				    eh.ether_shost);
+				qos = ((struct ieee80211_qosframe *)
+				    wh)->i_qos;
+			}
 			break;
-		case 1:			/* mcast, proxy */
+		case IEEE80211_MESH_AE_01:	/* mcast, proxy */
 			wh->i_fc[1] = IEEE80211_FC1_DIR_FROMDS;
 			IEEE80211_ADDR_COPY(wh->i_addr1, eh.ether_dhost);
 			IEEE80211_ADDR_COPY(wh->i_addr2, vap->iv_myaddr);
 			IEEE80211_ADDR_COPY(wh->i_addr3, vap->iv_myaddr);
 			mc->mc_flags = 1;
-			IEEE80211_ADDR_COPY(mc->mc_addr4, eh.ether_shost);
+			IEEE80211_ADDR_COPY(MC01(mc)->mc_addr4,
+			    eh.ether_shost);
 			qos = ((struct ieee80211_qosframe *) wh)->i_qos;
 			break;
-		case 2:			/* ucast, proxy */
-			wh->i_fc[1] = IEEE80211_FC1_DIR_DSTODS;
-			IEEE80211_ADDR_COPY(wh->i_addr1, ni->ni_macaddr);
+		case IEEE80211_MESH_AE_10:	/* ucast, proxy */
+			KASSERT(rt != NULL, ("route is NULL"));
+			IEEE80211_ADDR_COPY(wh->i_addr1, rt->rt_nexthop);
 			IEEE80211_ADDR_COPY(wh->i_addr2, vap->iv_myaddr);
-			/* XXX not right, need MeshDA */
-			IEEE80211_ADDR_COPY(wh->i_addr3, eh.ether_dhost);
-			/* XXX assume are MeshSA */
+			IEEE80211_ADDR_COPY(wh->i_addr3, rt->rt_mesh_gate);
 			IEEE80211_ADDR_COPY(WH4(wh)->i_addr4, vap->iv_myaddr);
-			mc->mc_flags = 2;
-			IEEE80211_ADDR_COPY(mc->mc_addr4, eh.ether_dhost);
-			IEEE80211_ADDR_COPY(mc->mc_addr5, eh.ether_shost);
+			mc->mc_flags = IEEE80211_MESH_AE_10;
+			IEEE80211_ADDR_COPY(mc->mc_addr5, eh.ether_dhost);
+			IEEE80211_ADDR_COPY(mc->mc_addr6, eh.ether_shost);
 			qos = ((struct ieee80211_qosframe_addr4 *) wh)->i_qos;
 			break;
 		default:
@@ -1363,6 +1391,7 @@ bad:
 		m_freem(m);
 	return NULL;
 #undef WH4
+#undef MC01
 }
 
 /*


More information about the svn-src-all mailing list