Skip site navigation (1)Skip section navigation (2)
Date:      Tue, 6 Mar 2012 21:20:16 +0000 (UTC)
From:      Adrian Chadd <adrian@FreeBSD.org>
To:        src-committers@freebsd.org, svn-src-all@freebsd.org, svn-src-head@freebsd.org
Subject:   svn commit: r232625 - head/sys/net80211
Message-ID:  <201203062120.q26LKGUr058096@svn.freebsd.org>

next in thread | raw e-mail | index | archive | help
Author: adrian
Date: Tue Mar  6 21:20:16 2012
New Revision: 232625
URL: http://svn.freebsd.org/changeset/base/232625

Log:
  Modify HWMP to be able to allocate memory for PREQ/PREP/PERR for all scenarios.
  
  * Added verify_mesh_*_len functions that verify the length
    according to the amendment spec and return number of destination addresses
    for allocation of appropriate struct size in memory;
  * Modified hwmp_recv_action_meshpath to allocate HWMP ie instead of
    storing them on the stack and store all available field according the flags;
  * Modify hwmp_add_mesh* to work with all cases of HWMP according to amendment.
  * Modify hwmp_send_* to calculate correct len of bytes for the HWMP ie.
  * Added new M_80211_MESH_* malloc defines.
  * Added macros with magic numbers for HWMP ie sizes according to amendment.
  * Added the external address to all HWMP ie structs.
  
  Submitted by:	monthadar@gmail.com

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

Modified: head/sys/net80211/ieee80211_hwmp.c
==============================================================================
--- head/sys/net80211/ieee80211_hwmp.c	Tue Mar  6 21:13:12 2012	(r232624)
+++ head/sys/net80211/ieee80211_hwmp.c	Tue Mar  6 21:20:16 2012	(r232625)
@@ -279,17 +279,114 @@ hwmp_newstate(struct ieee80211vap *vap, 
 	return 0;
 }
 
+/*
+ * Verify the length of an HWMP PREQ and return the number
+ * of destinations >= 1, if verification fails -1 is returned.
+ */
+static int
+verify_mesh_preq_len(struct ieee80211vap *vap,
+    const struct ieee80211_frame *wh, const uint8_t *iefrm)
+{
+	int alloc_sz = -1;
+	int ndest = -1;
+	if (iefrm[2] & IEEE80211_MESHPREQ_FLAGS_AE) {
+		/* Originator External Address  present */
+		alloc_sz =  IEEE80211_MESHPREQ_BASE_SZ_AE;
+		ndest = iefrm[IEEE80211_MESHPREQ_TCNT_OFFSET_AE];
+	} else {
+		/* w/o Originator External Address */
+		alloc_sz =  IEEE80211_MESHPREQ_BASE_SZ;
+		ndest = iefrm[IEEE80211_MESHPREQ_TCNT_OFFSET];
+	}
+	alloc_sz += ndest * IEEE80211_MESHPREQ_TRGT_SZ;
+
+	if(iefrm[1] != (alloc_sz)) {
+		IEEE80211_DISCARD(vap,
+		    IEEE80211_MSG_ACTION | IEEE80211_MSG_HWMP,
+		    wh, NULL, "PREQ (AE=%s) with wrong len",
+		    iefrm[2] & IEEE80211_MESHPREQ_FLAGS_AE ? "1" : "0");
+		return (-1);
+	}
+	return ndest;
+}
+
+/*
+ * Verify the length of an HWMP PREP and returns 1 on success,
+ * otherwise -1.
+ */
+static int
+verify_mesh_prep_len(struct ieee80211vap *vap,
+    const struct ieee80211_frame *wh, const uint8_t *iefrm)
+{
+	int alloc_sz = -1;
+	if (iefrm[2] & IEEE80211_MESHPREP_FLAGS_AE) {
+		if (iefrm[1] == IEEE80211_MESHPREP_BASE_SZ_AE)
+			alloc_sz = IEEE80211_MESHPREP_BASE_SZ_AE;
+	} else if (iefrm[1] == IEEE80211_MESHPREP_BASE_SZ)
+		alloc_sz = IEEE80211_MESHPREP_BASE_SZ;
+	if(alloc_sz < 0) {
+		IEEE80211_DISCARD(vap,
+		    IEEE80211_MSG_ACTION | IEEE80211_MSG_HWMP,
+		    wh, NULL, "PREP (AE=%s) with wrong len",
+		    iefrm[2] & IEEE80211_MESHPREP_FLAGS_AE ? "1" : "0");
+		return (-1);
+	}
+	return (1);
+}
+
+/*
+ * Verify the length of an HWMP PERR and return the number
+ * of destinations >= 1, if verification fails -1 is returned.
+ */
+static int
+verify_mesh_perr_len(struct ieee80211vap *vap,
+    const struct ieee80211_frame *wh, const uint8_t *iefrm)
+{
+	int alloc_sz = -1;
+	const uint8_t *iefrm_t = iefrm;
+	uint8_t ndest = iefrm_t[IEEE80211_MESHPERR_NDEST_OFFSET];
+	int i;
+
+	if(ndest > IEEE80211_MESHPERR_MAXDEST) {
+		IEEE80211_DISCARD(vap,
+		    IEEE80211_MSG_ACTION | IEEE80211_MSG_HWMP,
+		    wh, NULL, "PERR with wrong number of destionat (>19), %u",
+		    ndest);
+		return (-1);
+	}
+
+	iefrm_t += IEEE80211_MESHPERR_NDEST_OFFSET + 1; /* flag is next field */
+	/* We need to check each destionation flag to know size */
+	for(i = 0; i<ndest; i++) {
+		if ((*iefrm_t) & IEEE80211_MESHPERR_FLAGS_AE)
+			iefrm_t += IEEE80211_MESHPERR_DEST_SZ_AE;
+		else
+			iefrm_t += IEEE80211_MESHPERR_DEST_SZ;
+	}
+
+	alloc_sz = (iefrm_t - iefrm) - 2; /* action + code */
+	if(alloc_sz !=  iefrm[1]) {
+		IEEE80211_DISCARD(vap,
+		    IEEE80211_MSG_ACTION | IEEE80211_MSG_HWMP,
+		    wh, NULL, "%s", "PERR with wrong len");
+		return (-1);
+	}
+	return ndest;
+}
+
 static int
 hwmp_recv_action_meshpath(struct ieee80211_node *ni,
 	const struct ieee80211_frame *wh,
 	const uint8_t *frm, const uint8_t *efrm)
 {
 	struct ieee80211vap *vap = ni->ni_vap;
-	struct ieee80211_meshpreq_ie preq;
-	struct ieee80211_meshprep_ie prep;
-	struct ieee80211_meshperr_ie perr;
+	struct ieee80211_meshpreq_ie *preq;
+	struct ieee80211_meshprep_ie *prep;
+	struct ieee80211_meshperr_ie *perr;
 	struct ieee80211_meshrann_ie rann;
 	const uint8_t *iefrm = frm + 2; /* action + code */
+	const uint8_t *iefrm_t = iefrm; /* temporary pointer */
+	int ndest = -1;
 	int found = 0;
 
 	while (efrm - iefrm > 1) {
@@ -297,66 +394,132 @@ hwmp_recv_action_meshpath(struct ieee802
 		switch (*iefrm) {
 		case IEEE80211_ELEMID_MESHPREQ:
 		{
-			const struct ieee80211_meshpreq_ie *mpreq =
-			    (const struct ieee80211_meshpreq_ie *) iefrm;
-			/* XXX > 1 target */
-			if (mpreq->preq_len !=
-			    sizeof(struct ieee80211_meshpreq_ie) - 2) {
-				IEEE80211_DISCARD(vap,
-				    IEEE80211_MSG_ACTION | IEEE80211_MSG_HWMP,
-				    wh, NULL, "%s", "PREQ with wrong len");
+			int i = 0;
+
+			iefrm_t = iefrm;
+			ndest = verify_mesh_preq_len(vap, wh, iefrm_t);
+			if (ndest < 0) {
 				vap->iv_stats.is_rx_mgtdiscard++;
 				break;
 			}
-			memcpy(&preq, mpreq, sizeof(preq));
-			preq.preq_id = LE_READ_4(&mpreq->preq_id);
-			preq.preq_origseq = LE_READ_4(&mpreq->preq_origseq);
-			preq.preq_lifetime = LE_READ_4(&mpreq->preq_lifetime);
-			preq.preq_metric = LE_READ_4(&mpreq->preq_metric);
-			preq.preq_targets[0].target_seq =
-			    LE_READ_4(&mpreq->preq_targets[0].target_seq);
-			hwmp_recv_preq(vap, ni, wh, &preq);
+			preq = malloc(sizeof(*preq) +
+			    (ndest - 1) * sizeof(*preq->preq_targets),
+			    M_80211_MESH_PREQ, M_NOWAIT | M_ZERO);
+			KASSERT(preq != NULL, ("preq == NULL"));
+
+			preq->preq_ie = *iefrm_t++;
+			preq->preq_len = *iefrm_t++;
+			preq->preq_flags = *iefrm_t++;
+			preq->preq_hopcount = *iefrm_t++;
+			preq->preq_ttl = *iefrm_t++;
+			preq->preq_id = LE_READ_4(iefrm_t); iefrm_t += 4;
+			IEEE80211_ADDR_COPY(preq->preq_origaddr, iefrm_t);
+			iefrm_t += 6;
+			preq->preq_origseq = LE_READ_4(iefrm_t); iefrm_t += 4;
+			/* NB: may have Originator Proxied Address */
+			if (preq->preq_flags & IEEE80211_MESHPREQ_FLAGS_AE)  {
+				IEEE80211_ADDR_COPY(
+				    preq->preq_orig_ext_addr, iefrm_t);
+				iefrm_t += 6;
+			}
+			preq->preq_lifetime = LE_READ_4(iefrm_t); iefrm_t += 4;
+			preq->preq_metric = LE_READ_4(iefrm_t); iefrm_t += 4;
+			preq->preq_tcount = *iefrm_t++;
+			
+			for (i = 0; i < preq->preq_tcount; i++) {
+				preq->preq_targets[i].target_flags = *iefrm_t++;
+				IEEE80211_ADDR_COPY(
+				    preq->preq_targets[i].target_addr, iefrm_t);
+				iefrm_t += 6;
+				preq->preq_targets[i].target_seq =
+				    LE_READ_4(iefrm_t);
+				iefrm_t += 4;
+			}
+
+			hwmp_recv_preq(vap, ni, wh, preq);
+			free(preq, M_80211_MESH_PREQ);
 			found++;
-			break;	
+			break;
 		}
 		case IEEE80211_ELEMID_MESHPREP:
 		{
-			const struct ieee80211_meshprep_ie *mprep =
-			    (const struct ieee80211_meshprep_ie *) iefrm;
-			if (mprep->prep_len !=
-			    sizeof(struct ieee80211_meshprep_ie) - 2) {
-				IEEE80211_DISCARD(vap,
-				    IEEE80211_MSG_ACTION | IEEE80211_MSG_HWMP,
-				    wh, NULL, "%s", "PREP with wrong len");
+			iefrm_t = iefrm;
+			ndest = verify_mesh_prep_len(vap, wh, iefrm_t);
+			if (ndest < 0) {
 				vap->iv_stats.is_rx_mgtdiscard++;
 				break;
 			}
-			memcpy(&prep, mprep, sizeof(prep));
-			prep.prep_targetseq = LE_READ_4(&mprep->prep_targetseq);
-			prep.prep_lifetime = LE_READ_4(&mprep->prep_lifetime);
-			prep.prep_metric = LE_READ_4(&mprep->prep_metric);
-			prep.prep_origseq = LE_READ_4(&mprep->prep_origseq);
-			hwmp_recv_prep(vap, ni, wh, &prep);
+			prep = malloc(sizeof(*prep),
+			    M_80211_MESH_PREP, M_NOWAIT | M_ZERO);
+			KASSERT(prep != NULL, ("prep == NULL"));
+
+			prep->prep_ie = *iefrm_t++;
+			prep->prep_len = *iefrm_t++;
+			prep->prep_flags = *iefrm_t++;
+			prep->prep_hopcount = *iefrm_t++;
+			prep->prep_ttl = *iefrm_t++;
+			IEEE80211_ADDR_COPY(prep->prep_targetaddr, iefrm_t);
+			iefrm_t += 6;
+			prep->prep_targetseq = LE_READ_4(iefrm_t); iefrm_t += 4;
+			/* NB: May have Target Proxied Address */
+			if (prep->prep_flags & IEEE80211_MESHPREP_FLAGS_AE)  {
+				IEEE80211_ADDR_COPY(
+				    prep->prep_target_ext_addr, iefrm_t);
+				iefrm_t += 6;
+			}
+			prep->prep_lifetime = LE_READ_4(iefrm_t); iefrm_t += 4;
+			prep->prep_metric = LE_READ_4(iefrm_t); iefrm_t += 4;
+			IEEE80211_ADDR_COPY(prep->prep_origaddr, iefrm_t);
+			iefrm_t += 6;
+			prep->prep_origseq = LE_READ_4(iefrm_t); iefrm_t += 4;
+
+			hwmp_recv_prep(vap, ni, wh, prep);
+			free(prep, M_80211_MESH_PREP);
 			found++;
 			break;
 		}
 		case IEEE80211_ELEMID_MESHPERR:
 		{
-			const struct ieee80211_meshperr_ie *mperr =
-			    (const struct ieee80211_meshperr_ie *) iefrm;
-			/* XXX > 1 target */
-			if (mperr->perr_len !=
-			    sizeof(struct ieee80211_meshperr_ie) - 2) {
-				IEEE80211_DISCARD(vap,
-				    IEEE80211_MSG_ACTION | IEEE80211_MSG_HWMP,
-				    wh, NULL, "%s", "PERR with wrong len");
+			int i = 0;
+
+			iefrm_t = iefrm;
+			ndest = verify_mesh_perr_len(vap, wh, iefrm_t);
+			if (ndest < 0) {
 				vap->iv_stats.is_rx_mgtdiscard++;
 				break;
 			}
-			memcpy(&perr, mperr, sizeof(perr));
-			perr.perr_dests[0].dest_seq =
-			    LE_READ_4(&mperr->perr_dests[0].dest_seq);
-			hwmp_recv_perr(vap, ni, wh, &perr);
+			perr = malloc(sizeof(*perr) +
+			    (ndest - 1) * sizeof(*perr->perr_dests),
+			    M_80211_MESH_PERR, M_NOWAIT | M_ZERO);
+			KASSERT(perr != NULL, ("perr == NULL"));
+
+			perr->perr_ie = *iefrm_t++;
+			perr->perr_len = *iefrm_t++;
+			perr->perr_ttl = *iefrm_t++;
+			perr->perr_ndests = *iefrm_t++;
+
+			for (i = 0; i<perr->perr_ndests; i++) {
+				perr->perr_dests[i].dest_flags = *iefrm_t++;
+				IEEE80211_ADDR_COPY(
+				    perr->perr_dests[i].dest_addr, iefrm_t);
+				iefrm_t += 6;
+				perr->perr_dests[i].dest_seq = LE_READ_4(iefrm_t);
+				iefrm_t += 4;
+				/* NB: May have Target Proxied Address */
+				if (perr->perr_dests[i].dest_flags &
+				    IEEE80211_MESHPERR_FLAGS_AE) {
+					IEEE80211_ADDR_COPY(
+					    perr->perr_dests[i].dest_ext_addr,
+					    iefrm_t);
+					iefrm_t += 6;
+				}
+				perr->perr_dests[i].dest_rcode =
+				    LE_READ_2(iefrm_t);
+				iefrm_t += 2;
+			}
+
+			hwmp_recv_perr(vap, ni, wh, perr);
+			free(perr, M_80211_MESH_PERR);
 			found++;
 			break;
 		}
@@ -369,7 +532,7 @@ hwmp_recv_action_meshpath(struct ieee802
 				IEEE80211_DISCARD(vap,
 				    IEEE80211_MSG_ACTION | IEEE80211_MSG_HWMP,
 				    wh, NULL, "%s", "RAN with wrong len");
-				vap->iv_stats.is_rx_mgtdiscard++;
+				    vap->iv_stats.is_rx_mgtdiscard++;
 				return 1;
 			}
 			memcpy(&rann, mrann, sizeof(rann));
@@ -492,31 +655,40 @@ hwmp_send_action(struct ieee80211_node *
 /*
  * Add a Mesh Path Request IE to a frame.
  */
+#define	PREQ_TFLAGS(n)	preq->preq_targets[n].target_flags
+#define	PREQ_TADDR(n)	preq->preq_targets[n].target_addr
+#define	PREQ_TSEQ(n)	preq->preq_targets[n].target_seq
 static uint8_t *
 hwmp_add_meshpreq(uint8_t *frm, const struct ieee80211_meshpreq_ie *preq)
 {
 	int i;
 
 	*frm++ = IEEE80211_ELEMID_MESHPREQ;
-	*frm++ = sizeof(struct ieee80211_meshpreq_ie) - 2 +
-	    (preq->preq_tcount - 1) * sizeof(*preq->preq_targets);
+	*frm++ = preq->preq_len;	/* len already calculated */
 	*frm++ = preq->preq_flags;
 	*frm++ = preq->preq_hopcount;
 	*frm++ = preq->preq_ttl;
 	ADDWORD(frm, preq->preq_id);
 	IEEE80211_ADDR_COPY(frm, preq->preq_origaddr); frm += 6;
 	ADDWORD(frm, preq->preq_origseq);
+	if (preq->preq_flags & IEEE80211_MESHPREQ_FLAGS_AE) {
+		IEEE80211_ADDR_COPY(frm, preq->preq_orig_ext_addr);
+		frm += 6;
+	}
 	ADDWORD(frm, preq->preq_lifetime);
 	ADDWORD(frm, preq->preq_metric);
 	*frm++ = preq->preq_tcount;
 	for (i = 0; i < preq->preq_tcount; i++) {
-		*frm++ = preq->preq_targets[i].target_flags;
-		IEEE80211_ADDR_COPY(frm, preq->preq_targets[i].target_addr);
+		*frm++ = PREQ_TFLAGS(i);
+		IEEE80211_ADDR_COPY(frm, PREQ_TADDR(i));
 		frm += 6;
-		ADDWORD(frm, preq->preq_targets[i].target_seq);
+		ADDWORD(frm, PREQ_TSEQ(i));
 	}
 	return frm;
 }
+#undef	PREQ_TFLAGS
+#undef	PREQ_TADDR
+#undef	PREQ_TSEQ
 
 /*
  * Add a Mesh Path Reply IE to a frame.
@@ -525,12 +697,16 @@ static uint8_t *
 hwmp_add_meshprep(uint8_t *frm, const struct ieee80211_meshprep_ie *prep)
 {
 	*frm++ = IEEE80211_ELEMID_MESHPREP;
-	*frm++ = sizeof(struct ieee80211_meshprep_ie) - 2;
+	*frm++ = prep->prep_len;	/* len already calculated */
 	*frm++ = prep->prep_flags;
 	*frm++ = prep->prep_hopcount;
 	*frm++ = prep->prep_ttl;
 	IEEE80211_ADDR_COPY(frm, prep->prep_targetaddr); frm += 6;
 	ADDWORD(frm, prep->prep_targetseq);
+	if (prep->prep_flags & IEEE80211_MESHPREP_FLAGS_AE) {
+		IEEE80211_ADDR_COPY(frm, prep->prep_target_ext_addr);
+		frm += 6;
+	}
 	ADDWORD(frm, prep->prep_lifetime);
 	ADDWORD(frm, prep->prep_metric);
 	IEEE80211_ADDR_COPY(frm, prep->prep_origaddr); frm += 6;
@@ -541,25 +717,38 @@ hwmp_add_meshprep(uint8_t *frm, const st
 /*
  * Add a Mesh Path Error IE to a frame.
  */
+#define	PERR_DFLAGS(n)	perr->perr_dests[n].dest_flags
+#define	PERR_DADDR(n)	perr->perr_dests[n].dest_addr
+#define	PERR_DSEQ(n)	perr->perr_dests[n].dest_seq
+#define	PERR_EXTADDR(n)	perr->perr_dests[n].dest_ext_addr
+#define	PERR_DRCODE(n)	perr->perr_dests[n].dest_rcode
 static uint8_t *
 hwmp_add_meshperr(uint8_t *frm, const struct ieee80211_meshperr_ie *perr)
 {
 	int i;
 
 	*frm++ = IEEE80211_ELEMID_MESHPERR;
-	*frm++ = sizeof(struct ieee80211_meshperr_ie) - 2 +
-	    (perr->perr_ndests - 1) * sizeof(*perr->perr_dests);
+	*frm++ = perr->perr_len;	/* len already calculated */
 	*frm++ = perr->perr_ttl;
 	*frm++ = perr->perr_ndests;
 	for (i = 0; i < perr->perr_ndests; i++) {
-		*frm++ = perr->perr_dests[i].dest_flags;
-		IEEE80211_ADDR_COPY(frm, perr->perr_dests[i].dest_addr);
+		*frm++ = PERR_DFLAGS(i);
+		IEEE80211_ADDR_COPY(frm, PERR_DADDR(i));
 		frm += 6;
-		ADDWORD(frm, perr->perr_dests[i].dest_seq);
-		ADDSHORT(frm, perr->perr_dests[i].dest_rcode);
+		ADDWORD(frm, PERR_DSEQ(i));
+		if (PERR_DFLAGS(i) & IEEE80211_MESHPERR_FLAGS_AE) {
+			IEEE80211_ADDR_COPY(frm, PERR_EXTADDR(i));
+			frm += 6;
+		}
+		ADDSHORT(frm, PERR_DRCODE(i));
 	}
 	return frm;
 }
+#undef	PERR_DFLAGS
+#undef	PERR_DADDR
+#undef	PERR_DSEQ
+#undef	PERR_EXTADDR
+#undef	PERR_DRCODE
 
 /*
  * Add a Root Annoucement IE to a frame.
@@ -568,12 +757,13 @@ static uint8_t *
 hwmp_add_meshrann(uint8_t *frm, const struct ieee80211_meshrann_ie *rann)
 {
 	*frm++ = IEEE80211_ELEMID_MESHRANN;
-	*frm++ = sizeof(struct ieee80211_meshrann_ie) - 2;
+	*frm++ = rann->rann_len;
 	*frm++ = rann->rann_flags;
 	*frm++ = rann->rann_hopcount;
 	*frm++ = rann->rann_ttl;
 	IEEE80211_ADDR_COPY(frm, rann->rann_addr); frm += 6;
 	ADDWORD(frm, rann->rann_seq);
+	ADDWORD(frm, rann->rann_interval);
 	ADDWORD(frm, rann->rann_metric);
 	return frm;
 }
@@ -980,8 +1170,10 @@ hwmp_send_preq(struct ieee80211_node *ni
 	 *     [tlv] mesh path request
 	 */
 	preq->preq_ie = IEEE80211_ELEMID_MESHPREQ;
-	return hwmp_send_action(ni, sa, da, (uint8_t *)preq,
-	    sizeof(struct ieee80211_meshpreq_ie));
+	preq->preq_len = (preq->preq_flags & IEEE80211_MESHPREQ_FLAGS_AE ?
+	    IEEE80211_MESHPREQ_BASE_SZ_AE : IEEE80211_MESHPREQ_BASE_SZ) +
+	    preq->preq_tcount * IEEE80211_MESHPREQ_TRGT_SZ;
+	return hwmp_send_action(ni, sa, da, (uint8_t *)preq, preq->preq_len+2);
 }
 
 static void
@@ -1162,8 +1354,10 @@ hwmp_send_prep(struct ieee80211_node *ni
 	 *     [tlv] mesh path reply
 	 */
 	prep->prep_ie = IEEE80211_ELEMID_MESHPREP;
+	prep->prep_len = prep->prep_flags & IEEE80211_MESHPREP_FLAGS_AE ?
+	    IEEE80211_MESHPREP_BASE_SZ_AE : IEEE80211_MESHPREP_BASE_SZ;
 	return hwmp_send_action(ni, sa, da, (uint8_t *)prep,
-	    sizeof(struct ieee80211_meshprep_ie));
+	    prep->prep_len + 2);
 }
 
 #define	PERR_DFLAGS(n)	perr.perr_dests[n].dest_flags
@@ -1254,8 +1448,10 @@ hwmp_recv_perr(struct ieee80211vap *vap,
 		    &pperr);
 	}
 }
+#undef	PERR_DFLAGS
 #undef	PEER_DADDR
 #undef	PERR_DSEQ
+#undef	PERR_DRCODE
 
 static int
 hwmp_send_perr(struct ieee80211_node *ni,
@@ -1264,6 +1460,8 @@ hwmp_send_perr(struct ieee80211_node *ni
     struct ieee80211_meshperr_ie *perr)
 {
 	struct ieee80211_hwmp_state *hs = ni->ni_vap->iv_hwmp;
+	int i;
+	uint8_t length = 0;
 
 	/*
 	 * Enforce PERR interval.
@@ -1282,8 +1480,17 @@ hwmp_send_perr(struct ieee80211_node *ni
 	 *     [tlv] mesh path error
 	 */
 	perr->perr_ie = IEEE80211_ELEMID_MESHPERR;
-	return hwmp_send_action(ni, sa, da, (uint8_t *)perr,
-	    sizeof(struct ieee80211_meshperr_ie));
+	length = IEEE80211_MESHPERR_BASE_SZ;
+	for (i = 0; i<perr->perr_ndests; i++) {
+		if (perr->perr_dests[i].dest_flags &
+		    IEEE80211_MESHPERR_FLAGS_AE) {
+			length += IEEE80211_MESHPERR_DEST_SZ_AE;
+			continue ;
+		}
+		length += IEEE80211_MESHPERR_DEST_SZ;
+	}
+	perr->perr_len =length;
+	return hwmp_send_action(ni, sa, da, (uint8_t *)perr, perr->perr_len+2);
 }
 
 static void
@@ -1342,8 +1549,9 @@ hwmp_send_rann(struct ieee80211_node *ni
 	 *     [tlv] root annoucement
 	 */
 	rann->rann_ie = IEEE80211_ELEMID_MESHRANN;
+	rann->rann_len = IEEE80211_MESHRANN_BASE_SZ;
 	return hwmp_send_action(ni, sa, da, (uint8_t *)rann,
-	    sizeof(struct ieee80211_meshrann_ie));
+	    rann->rann_len + 2);
 }
 
 #define	PREQ_TFLAGS(n)	preq.preq_targets[n].target_flags

Modified: head/sys/net80211/ieee80211_mesh.c
==============================================================================
--- head/sys/net80211/ieee80211_mesh.c	Tue Mar  6 21:13:12 2012	(r232624)
+++ head/sys/net80211/ieee80211_mesh.c	Tue Mar  6 21:20:16 2012	(r232625)
@@ -142,6 +142,10 @@ static struct ieee80211_mesh_proto_metri
 #define	MESH_RT_LOCK_ASSERT(ms)	mtx_assert(&(ms)->ms_rt_lock, MA_OWNED)
 #define	MESH_RT_UNLOCK(ms)	mtx_unlock(&(ms)->ms_rt_lock)
 
+MALLOC_DEFINE(M_80211_MESH_PREQ, "80211preq", "802.11 MESH Path Request frame");
+MALLOC_DEFINE(M_80211_MESH_PREP, "80211prep", "802.11 MESH Path Reply frame");
+MALLOC_DEFINE(M_80211_MESH_PERR, "80211perr", "802.11 MESH Path Error frame");
+
 MALLOC_DEFINE(M_80211_MESH_RT, "80211mesh", "802.11s routing table");
 
 /*

Modified: head/sys/net80211/ieee80211_mesh.h
==============================================================================
--- head/sys/net80211/ieee80211_mesh.h	Tue Mar  6 21:13:12 2012	(r232624)
+++ head/sys/net80211/ieee80211_mesh.h	Tue Mar  6 21:20:16 2012	(r232625)
@@ -212,6 +212,7 @@ struct ieee80211_meshpann_ie {
 } __packed;
 
 /* Root (MP) Annoucement */
+#define	IEEE80211_MESHRANN_BASE_SZ 	(21)
 struct ieee80211_meshrann_ie {
 	uint8_t		rann_ie;		/* IEEE80211_ELEMID_MESHRANN */
 	uint8_t		rann_len;
@@ -221,10 +222,16 @@ struct ieee80211_meshrann_ie {
 	uint8_t		rann_ttl;
 	uint8_t		rann_addr[IEEE80211_ADDR_LEN];
 	uint32_t	rann_seq;		/* HWMP Sequence Number */
+	uint32_t	rann_interval;
 	uint32_t	rann_metric;
 } __packed;
 
 /* Mesh Path Request */
+#define	IEEE80211_MESHPREQ_BASE_SZ 		(26)
+#define	IEEE80211_MESHPREQ_BASE_SZ_AE 		(32)
+#define	IEEE80211_MESHPREQ_TRGT_SZ 		(11)
+#define	IEEE80211_MESHPREQ_TCNT_OFFSET		(27)
+#define	IEEE80211_MESHPREQ_TCNT_OFFSET_AE	(33)
 struct ieee80211_meshpreq_ie {
 	uint8_t		preq_ie;	/* IEEE80211_ELEMID_MESHPREQ */
 	uint8_t		preq_len;
@@ -238,7 +245,8 @@ struct ieee80211_meshpreq_ie {
 	uint32_t	preq_id;
 	uint8_t		preq_origaddr[IEEE80211_ADDR_LEN];
 	uint32_t	preq_origseq;	/* HWMP Sequence Number */
-	/* NB: may have Originator Proxied Address */
+	/* NB: may have Originator External Address */
+	uint8_t		preq_orig_ext_addr[IEEE80211_ADDR_LEN];
 	uint32_t	preq_lifetime;
 	uint32_t	preq_metric;
 	uint8_t		preq_tcount;	/* target count */
@@ -253,15 +261,19 @@ struct ieee80211_meshpreq_ie {
 } __packed;
 
 /* Mesh Path Reply */
+#define	IEEE80211_MESHPREP_BASE_SZ 	(31)
+#define	IEEE80211_MESHPREP_BASE_SZ_AE 	(37)
 struct ieee80211_meshprep_ie {
 	uint8_t		prep_ie;	/* IEEE80211_ELEMID_MESHPREP */
 	uint8_t		prep_len;
 	uint8_t		prep_flags;
+#define	IEEE80211_MESHPREP_FLAGS_AE	0x40	/* Address Extension */
 	uint8_t		prep_hopcount;
 	uint8_t		prep_ttl;
 	uint8_t		prep_targetaddr[IEEE80211_ADDR_LEN];
 	uint32_t	prep_targetseq;
-	/* NB: May have Target Proxied Address */
+	/* NB: May have Target External Address */
+	uint8_t		prep_target_ext_addr[IEEE80211_ADDR_LEN];
 	uint32_t	prep_lifetime;
 	uint32_t	prep_metric;
 	uint8_t		prep_origaddr[IEEE80211_ADDR_LEN];
@@ -269,6 +281,11 @@ struct ieee80211_meshprep_ie {
 } __packed;
 
 /* Mesh Path Error */
+#define	IEEE80211_MESHPERR_MAXDEST	(19)
+#define	IEEE80211_MESHPERR_NDEST_OFFSET	(3)
+#define	IEEE80211_MESHPERR_BASE_SZ 	(2)
+#define	IEEE80211_MESHPERR_DEST_SZ 	(13)
+#define	IEEE80211_MESHPERR_DEST_SZ_AE 	(19)
 struct ieee80211_meshperr_ie {
 	uint8_t		perr_ie;	/* IEEE80211_ELEMID_MESHPERR */
 	uint8_t		perr_len;
@@ -276,10 +293,13 @@ struct ieee80211_meshperr_ie {
 	uint8_t		perr_ndests;	/* Number of Destinations */
 	struct {
 		uint8_t		dest_flags;
-#define	IEEE80211_MESHPERR_DFLAGS_USN	0x01
-#define	IEEE80211_MESHPERR_DFLAGS_RC	0x02
+#define	IEEE80211_MESHPERR_DFLAGS_USN	0x01	/* XXX: not part of standard */
+#define	IEEE80211_MESHPERR_DFLAGS_RC	0x02	/* XXX: not part of standard */
+#define	IEEE80211_MESHPERR_FLAGS_AE	0x40	/* Address Extension */
 		uint8_t		dest_addr[IEEE80211_ADDR_LEN];
 		uint32_t	dest_seq;	/* HWMP Sequence Number */
+		/* NB: May have Destination External Address */
+		uint8_t		dest_ext_addr[IEEE80211_ADDR_LEN];
 		uint16_t	dest_rcode;
 	} __packed perr_dests[1];		/* NB: variable size */
 } __packed;
@@ -390,6 +410,10 @@ struct ieee80211_meshcntl_ae11 {
 } __packed;
 
 #ifdef _KERNEL
+MALLOC_DECLARE(M_80211_MESH_PREQ);
+MALLOC_DECLARE(M_80211_MESH_PREP);
+MALLOC_DECLARE(M_80211_MESH_PERR);
+
 MALLOC_DECLARE(M_80211_MESH_RT);
 struct ieee80211_mesh_route {
 	TAILQ_ENTRY(ieee80211_mesh_route)	rt_next;



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