Date: Fri, 23 Sep 2011 13:10:30 +0200 From: Monthadar Al Jaberi <monthadar@gmail.com> To: freebsd-wireless@freebsd.org, Adrian Chadd <adrian.chadd@gmail.com> Subject: Re: FreeBSD net80211s HWMP code Message-ID: <CA%2BsBSo%2Bs1bFw3KLvf%2BTh_vdR_5ato_xhEE5saLh6aK=1Avbb=w@mail.gmail.com> In-Reply-To: <CA%2BsBSoJwkVMTAbybPbHFdz6CHbjDzF5PRgxpXoWHVESpAfEQKg@mail.gmail.com> References: <CA%2BsBSoJwkVMTAbybPbHFdz6CHbjDzF5PRgxpXoWHVESpAfEQKg@mail.gmail.com>
index | next in thread | previous in thread | raw e-mail
[-- Attachment #1 --]
Hi again,
This diff fixed the broken parts in the last one. So it should be
usable instead of the current FreeBSD HWMP. Also this diff is updated
to draft 12.0.
I hope you could try it and let me know how it goes.
Will work with Adrian to break it into smaller commits to HEAD.
br,
On Fri, Sep 16, 2011 at 12:00 PM, Monthadar Al Jaberi
<monthadar@gmail.com> wrote:
> Hi,
>
> I am attaching my first update of the IEEE80211s HWMP code based on Draft 8.0.
>
> It is not complete, some stuff works better, others are broken and
> there are more things to todo.
>
> So I would like it if some are interesting in testing the code.
>
> Broken:
> For now only use ondemand routing and not proactive (HWMPROOTMODE=disabled).
>
> Works better:
> PERR frames: if an MP is removed PERR frames will make sure that all
> neighbour mesh nodes tables will be updated correctly.
> PREQ/PREP: had some errors in code and did not follow standard correct.
>
> Things todo:
> External address support (called Proxy in freebsd code, will change it
> to reflect standard naming)
> Lifetime of paths don't decrement (but because we have better PERR
> frames its not a big problem for now)
> And much more!!
>
> Attaching a diff of the code.
>
> In the hope it will be useful for someone.
> br,
> --
> //Monthadar Al Jaberi
>
--
//Monthadar Al Jaberi
[-- Attachment #2 --]
diff --git a/sys/net/if_ethersubr.c b/sys/net/if_ethersubr.c
index 1d16ae6..e73db40 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)%6;
+ return (buf);
}
/*
diff --git a/sys/net80211/ieee80211_hwmp.c b/sys/net80211/ieee80211_hwmp.c
index 78729fc..0f50203 100644
--- a/sys/net80211/ieee80211_hwmp.c
+++ b/sys/net80211/ieee80211_hwmp.c
@@ -1,6 +1,7 @@
/*-
* Copyright (c) 2009 The FreeBSD Foundation
- * All rights reserved.
+ * Copyright (c) 2011 Monthadar Al Jaberi, TerraNet AB.
+ * All rights reserved.
*
* This software was developed by Rui Paulo under sponsorship from the
* FreeBSD Foundation.
@@ -40,8 +41,8 @@ __FBSDID("$FreeBSD$");
#include "opt_wlan.h"
#include <sys/param.h>
-#include <sys/systm.h>
-#include <sys/mbuf.h>
+#include <sys/systm.h>
+#include <sys/mbuf.h>
#include <sys/malloc.h>
#include <sys/kernel.h>
@@ -118,6 +119,12 @@ static void hwmp_peerdown(struct ieee80211_node *);
static struct timeval ieee80211_hwmp_preqminint = { 0, 100000 };
static struct timeval ieee80211_hwmp_perrminint = { 0, 100000 };
+static struct timeval ieee80211_hwmp_rootmin_confint;
+
+MALLOC_DEFINE(M_80211_HWMP_RANN, "80211rann", "802.11 HWMP Root Announcment frame");
+MALLOC_DEFINE(M_80211_HWMP_PREQ, "80211preq", "802.11 HWMP Path Request frame");
+MALLOC_DEFINE(M_80211_HWMP_PREP, "80211prep", "802.11 HWMP Path Reply frame");
+MALLOC_DEFINE(M_80211_HWMP_PERR, "80211perr", "802.11 HWMP Path Error frame");
/* unalligned little endian access */
#define LE_WRITE_2(p, v) do { \
@@ -139,9 +146,17 @@ 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)
+
+#define MESH_RT_LOCK(ms) mtx_lock(&(ms)->ms_rt_lock)
+#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)
+
/*
* Private extension of ieee80211_mesh_route.
*/
@@ -150,12 +165,15 @@ struct ieee80211_hwmp_route {
ieee80211_hwmp_seq hr_preqid; /* last PREQ ID seen from dst */
ieee80211_hwmp_seq hr_origseq; /* seq. no. on our latest PREQ*/
int hr_preqretries;
+ int hr_pro_prep; /* whether mesh generates Proactive PREP */
+ int hr_sent_prep; /* whether mesh has sent a Proactive PREP */
};
struct ieee80211_hwmp_state {
ieee80211_hwmp_seq hs_seq; /* next seq to be used */
ieee80211_hwmp_seq hs_preqid; /* next PREQ ID to be used */
struct timeval hs_lastpreq; /* last time we sent a PREQ */
struct timeval hs_lastperr; /* last time we sent a PERR */
+ struct timeval hs_lastrootconf;/* last time we sent a PREQ to root */
int hs_rootmode; /* proactive HWMP */
struct callout hs_roottimer;
uint8_t hs_maxhops; /* max hop count */
@@ -166,17 +184,22 @@ SYSCTL_NODE(_net_wlan, OID_AUTO, hwmp, CTLFLAG_RD, 0,
static int ieee80211_hwmp_targetonly = 0;
SYSCTL_INT(_net_wlan_hwmp, OID_AUTO, targetonly, CTLTYPE_INT | CTLFLAG_RW,
&ieee80211_hwmp_targetonly, 0, "Set TO bit on generated PREQs");
-static int ieee80211_hwmp_replyforward = 1;
-SYSCTL_INT(_net_wlan_hwmp, OID_AUTO, replyforward, CTLTYPE_INT | CTLFLAG_RW,
- &ieee80211_hwmp_replyforward, 0, "Set RF bit on generated PREQs");
static int ieee80211_hwmp_pathtimeout = -1;
SYSCTL_PROC(_net_wlan_hwmp, OID_AUTO, pathlifetime, CTLTYPE_INT | CTLFLAG_RW,
&ieee80211_hwmp_pathtimeout, 0, ieee80211_sysctl_msecs_ticks, "I",
"path entry lifetime (ms)");
+static int ieee80211_hwmp_rootconfint = -1;
+SYSCTL_PROC(_net_wlan_hwmp, OID_AUTO, rootconfint, CTLTYPE_INT | CTLFLAG_RW,
+ &ieee80211_hwmp_rootconfint, 0, ieee80211_sysctl_msecs_ticks, "I",
+ "root confirmation interval (ms)");
static int ieee80211_hwmp_roottimeout = -1;
SYSCTL_PROC(_net_wlan_hwmp, OID_AUTO, roottimeout, CTLTYPE_INT | CTLFLAG_RW,
&ieee80211_hwmp_roottimeout, 0, ieee80211_sysctl_msecs_ticks, "I",
"root PREQ timeout (ms)");
+static int ieee80211_hwmp_ranntimeout = -1;
+SYSCTL_PROC(_net_wlan_hwmp, OID_AUTO, ranntimeout, CTLTYPE_INT | CTLFLAG_RW,
+ &ieee80211_hwmp_ranntimeout, 0, ieee80211_sysctl_msecs_ticks, "I",
+ "RANN PREQ timeout (ms)");
static int ieee80211_hwmp_rootint = -1;
SYSCTL_PROC(_net_wlan_hwmp, OID_AUTO, rootint, CTLTYPE_INT | CTLFLAG_RW,
&ieee80211_hwmp_rootint, 0, ieee80211_sysctl_msecs_ticks, "I",
@@ -187,6 +210,7 @@ SYSCTL_PROC(_net_wlan_hwmp, OID_AUTO, rannint, CTLTYPE_INT | CTLFLAG_RW,
"root announcement interval (ms)");
#define IEEE80211_HWMP_DEFAULT_MAXHOPS 31
+#define IEEE80211_HWMP_PERR_MAXDEST 10
static ieee80211_recv_action_func hwmp_recv_action_meshpath;
@@ -208,10 +232,15 @@ SYSCTL_PROC(_net_wlan_hwmp, OID_AUTO, inact, CTLTYPE_INT | CTLFLAG_RW,
static void
ieee80211_hwmp_init(void)
{
+ ieee80211_hwmp_rootconfint = msecs_to_ticks(5*1000);
ieee80211_hwmp_pathtimeout = msecs_to_ticks(5*1000);
ieee80211_hwmp_roottimeout = msecs_to_ticks(5*1000);
+ ieee80211_hwmp_ranntimeout = msecs_to_ticks(5*1000);
ieee80211_hwmp_rootint = msecs_to_ticks(2*1000);
ieee80211_hwmp_rannint = msecs_to_ticks(1*1000);
+
+ ieee80211_hwmp_rootmin_confint.tv_sec = ticks_to_secs(ieee80211_hwmp_rootconfint);
+ ieee80211_hwmp_rootmin_confint.tv_usec = 0;
/*
* Register action frame handler.
@@ -243,6 +272,7 @@ hwmp_vattach(struct ieee80211vap *vap)
printf("%s: couldn't alloc HWMP state\n", __func__);
return;
}
+
hs->hs_maxhops = IEEE80211_HWMP_DEFAULT_MAXHOPS;
callout_init(&hs->hs_roottimer, CALLOUT_MPSAFE);
vap->iv_hwmp = hs;
@@ -256,7 +286,7 @@ hwmp_vdetach(struct ieee80211vap *vap)
callout_drain(&hs->hs_roottimer);
free(vap->iv_hwmp, M_80211_VAP);
vap->iv_hwmp = NULL;
-}
+}
int
hwmp_newstate(struct ieee80211vap *vap, enum ieee80211_state ostate, int arg)
@@ -281,10 +311,10 @@ hwmp_recv_action_meshpath(struct ieee80211_node *ni,
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_meshrann_ie rann;
+ 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 */
int found = 0;
@@ -293,90 +323,156 @@ hwmp_recv_action_meshpath(struct ieee80211_node *ni,
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) {
+ int i = 0;
+ preq = malloc(sizeof(struct ieee80211_meshpreq_ie) +
+ (iefrm[27]-1)*sizeof(*preq->preq_targets),
+ M_80211_HWMP_PREQ, M_NOWAIT | M_ZERO);
+ KASSERT(preq != NULL, ("preq == NULL"));
+
+ preq->preq_ie = *iefrm++;
+ preq->preq_len = *iefrm++;
+ preq->preq_flags = *iefrm++;
+ preq->preq_hopcount = *iefrm++;
+ preq->preq_ttl = *iefrm++;
+ preq->preq_id = LE_READ_4(iefrm); iefrm += 4;
+ IEEE80211_ADDR_COPY(preq->preq_origaddr, iefrm);
+ iefrm += 6;
+ preq->preq_origseq = LE_READ_4(iefrm); iefrm += 4;
+ /* NB: may have Originator Proxied Address */
+ preq->preq_lifetime = LE_READ_4(iefrm); iefrm += 4;
+ preq->preq_metric = LE_READ_4(iefrm); iefrm += 4;
+ preq->preq_tcount = *iefrm++;
+
+ if (preq->preq_len != IEEE80211_MESHPREQ_BASE_SZ +
+ preq->preq_tcount * IEEE80211_MESHPREQ_TRGT_SZ) {
IEEE80211_DISCARD(vap,
IEEE80211_MSG_ACTION | IEEE80211_MSG_HWMP,
wh, NULL, "%s", "PREQ with wrong len");
vap->iv_stats.is_rx_mgtdiscard++;
+ free(preq, M_80211_HWMP_PREQ);
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);
+
+ for (i = 0; i < preq->preq_tcount; i++) {
+ preq->preq_targets[i].target_flags = *iefrm++;
+ IEEE80211_ADDR_COPY(
+ preq->preq_targets[i].target_addr, iefrm);
+ iefrm += 6;
+ preq->preq_targets[i].target_seq =
+ LE_READ_4(iefrm); iefrm += 4;
+ }
+
+ hwmp_recv_preq(vap, ni, wh, preq);
+ free(preq, M_80211_HWMP_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) {
+ prep = malloc(sizeof(struct ieee80211_meshprep_ie),
+ M_80211_HWMP_PREP, M_NOWAIT | M_ZERO);
+ KASSERT(prep != NULL, ("prep == NULL"));
+
+ prep->prep_ie = *iefrm++;
+ prep->prep_len = *iefrm++;
+
+ if (prep->prep_len != IEEE80211_MESHPREP_BASE_SZ) {
IEEE80211_DISCARD(vap,
IEEE80211_MSG_ACTION | IEEE80211_MSG_HWMP,
wh, NULL, "%s", "PREP with wrong len");
vap->iv_stats.is_rx_mgtdiscard++;
+ free(prep, M_80211_HWMP_PREP);
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->prep_flags = *iefrm++;
+ prep->prep_hopcount = *iefrm++;
+ prep->prep_ttl = *iefrm++;
+ IEEE80211_ADDR_COPY(prep->prep_targetaddr, iefrm);
+ iefrm += 6;
+ prep->prep_targetseq = LE_READ_4(iefrm); iefrm += 4;
+ /* NB: May have Target Proxied Address */
+ prep->prep_lifetime = LE_READ_4(iefrm); iefrm += 4;
+ prep->prep_metric = LE_READ_4(iefrm); iefrm += 4;
+ IEEE80211_ADDR_COPY(prep->prep_origaddr, iefrm);
+ iefrm += 6;
+ prep->prep_origseq = LE_READ_4(iefrm); iefrm += 4;
+
+ hwmp_recv_prep(vap, ni, wh, prep);
+ free(prep, M_80211_HWMP_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) {
+ int i = 0;
+ perr = malloc(sizeof(struct ieee80211_meshperr_ie) +
+ (iefrm[3]-1)*sizeof(*perr->perr_dests),
+ M_80211_HWMP_PERR, M_NOWAIT | M_ZERO);
+ KASSERT(perr != NULL, ("perr == NULL"));
+ perr->perr_ie = *iefrm++;
+ perr->perr_len = *iefrm++;
+ perr->perr_ttl = *iefrm++;
+ perr->perr_ndests = *iefrm++;
+
+ if (perr->perr_len != (IEEE80211_MESHPERR_BASE_SZ +
+ perr->perr_ndests * IEEE80211_MESHPERR_DEST_SZ)) {
IEEE80211_DISCARD(vap,
IEEE80211_MSG_ACTION | IEEE80211_MSG_HWMP,
- wh, NULL, "%s", "PERR with wrong len");
+ wh, NULL, "%s", "PERR with wrong len, %s",
+ perr->perr_len);
vap->iv_stats.is_rx_mgtdiscard++;
+ free(perr, M_80211_HWMP_PERR);
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);
+
+ for(i = 0; i<perr->perr_ndests; i++) {
+ perr->perr_dests[i].dest_flags = *iefrm++;
+ IEEE80211_ADDR_COPY(
+ perr->perr_dests[i].dest_addr, iefrm);
+ iefrm += 6;
+ perr->perr_dests[i].dest_seq = LE_READ_4(iefrm);
+ iefrm += 4;
+ /* NB: May have Target Proxied Address */
+ perr->perr_dests[i].dest_rcode =
+ LE_READ_2(iefrm);
+ iefrm += 2;
+ }
+
+ hwmp_recv_perr(vap, ni, wh, perr);
+ free(perr, M_80211_HWMP_PERR);
found++;
break;
}
case IEEE80211_ELEMID_MESHRANN:
{
- const struct ieee80211_meshrann_ie *mrann =
- (const struct ieee80211_meshrann_ie *) iefrm;
- if (mrann->rann_len !=
- sizeof(struct ieee80211_meshrann_ie) - 2) {
+ rann = malloc(sizeof(struct ieee80211_meshrann_ie),
+ M_80211_HWMP_RANN, M_NOWAIT | M_ZERO);
+ KASSERT(rann != NULL, ("perr == NULL"));
+ if (iefrm[1] != IEEE80211_MESHRANN_BASE_SZ) {
IEEE80211_DISCARD(vap,
IEEE80211_MSG_ACTION | IEEE80211_MSG_HWMP,
- wh, NULL, "%s", "RAN with wrong len");
+ wh, NULL, "RANN with wrong len=%d",
+ iefrm[1]);
vap->iv_stats.is_rx_mgtdiscard++;
- return 1;
+ free(rann, M_80211_HWMP_RANN);
+ break;
}
- memcpy(&rann, mrann, sizeof(rann));
- rann.rann_seq = LE_READ_4(&mrann->rann_seq);
- rann.rann_metric = LE_READ_4(&mrann->rann_metric);
- hwmp_recv_rann(vap, ni, wh, &rann);
+ rann->rann_ie = *iefrm++;
+ rann->rann_len = *iefrm++;;
+ rann->rann_flags = *iefrm++;
+ rann->rann_hopcount = *iefrm++;
+ rann->rann_ttl = *iefrm++;
+ IEEE80211_ADDR_COPY(rann->rann_addr, iefrm); iefrm += 6;
+ rann->rann_seq = LE_READ_4(iefrm); iefrm += 4;
+ rann->rann_interval = LE_READ_4(iefrm); iefrm += 4;
+ rann->rann_metric = LE_READ_4(iefrm); iefrm += 4;
+ hwmp_recv_rann(vap, ni, wh, rann);
+ free(rann, M_80211_HWMP_RANN);
found++;
break;
}
}
- iefrm += iefrm[1] + 2;
}
if (!found) {
IEEE80211_DISCARD(vap,
@@ -493,9 +589,8 @@ 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_ie;
+ *frm++ = preq->preq_len;
*frm++ = preq->preq_flags;
*frm++ = preq->preq_hopcount;
*frm++ = preq->preq_ttl;
@@ -520,8 +615,8 @@ hwmp_add_meshpreq(uint8_t *frm, const struct ieee80211_meshpreq_ie *preq)
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_ie;
+ *frm++ = prep->prep_len;
*frm++ = prep->prep_flags;
*frm++ = prep->prep_hopcount;
*frm++ = prep->prep_ttl;
@@ -542,9 +637,8 @@ 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_ie;
+ *frm++ = perr->perr_len;
*frm++ = perr->perr_ttl;
*frm++ = perr->perr_ndests;
for (i = 0; i < perr->perr_ndests; i++) {
@@ -563,13 +657,14 @@ hwmp_add_meshperr(uint8_t *frm, const struct ieee80211_meshperr_ie *perr)
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_ie;
+ *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;
}
@@ -628,7 +723,7 @@ hwmp_rootmode_cb(void *arg)
preq.preq_tcount = 1;
IEEE80211_ADDR_COPY(PREQ_TADDR(0), broadcastaddr);
PREQ_TFLAGS(0) = IEEE80211_MESHPREQ_TFLAGS_TO |
- IEEE80211_MESHPREQ_TFLAGS_RF;
+ IEEE80211_MESHPREQ_TFLAGS_USN;
PREQ_TSEQ(0) = 0;
vap->iv_stats.is_hwmp_rootreqs++;
hwmp_send_preq(vap->iv_bss, vap->iv_myaddr, broadcastaddr, &preq);
@@ -675,9 +770,10 @@ hwmp_recv_preq(struct ieee80211vap *vap, struct ieee80211_node *ni,
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 *rtorig = NULL;
- struct ieee80211_hwmp_route *hrorig;
+ struct ieee80211_mesh_route *rt = NULL; // Target route
+ struct ieee80211_mesh_route *rtorig = NULL; // Originator route
+ struct ieee80211_hwmp_route *hrorig = NULL;
+ struct ieee80211_hwmp_route *hr = NULL;
struct ieee80211_hwmp_state *hs = vap->iv_hwmp;
struct ieee80211_meshprep_ie prep;
@@ -692,169 +788,173 @@ 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)) || /* XXX: test for proxy address*/
+ !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");
+ ni->ni_macaddr, NULL, "not accepting PREQ, originator %s",
+ ether_sprintf(preq->preq_origaddr));
+ return;
+ }
+ /*
+ * Acceptance criteria: if unicast addressed
+ * AND no valid forwarding for Target of PREQ, discard this PREQ.
+ */
+ rt = ieee80211_mesh_rt_find(vap, PREQ_TADDR(0));
+ if(rt != NULL)
+ hr = IEEE80211_MESH_ROUTE_PRIV(rt, struct ieee80211_hwmp_route);
+ if((preq->preq_flags & IEEE80211_MESHPREQ_FLAGS_AM) == 0 && /* address mode: ucast */
+ rt == NULL &&
+ !IEEE80211_ADDR_EQ(vap->iv_myaddr, PREQ_TADDR(0))) {
+ IEEE80211_DISCARD_MAC(vap, IEEE80211_MSG_HWMP, ni->ni_macaddr,
+ NULL, "unicast addressed PREQ, originator %s, unknown target %s",
+ ether_sprintf(preq->preq_origaddr),
+ 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.
- */
- if (HWMP_SEQ_LEQ(preq->preq_id, hrorig->hr_preqid) &&
- HWMP_SEQ_LEQ(preq->preq_origseq, hrorig->hr_seq)) {
- 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);
- return;
- }
- hrorig->hr_preqid = preq->preq_id;
- hrorig->hr_seq = preq->preq_origseq;
- /*
- * 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));
+ 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)){
/*
- * Build and send a PREP frame.
+ * Data creation and update of forwarding information
+ * according to Table 11C-8 for originator mesh STA.
*/
- prep.prep_flags = 0;
- 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_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;
- hwmp_send_prep(ni, vap->iv_myaddr, wh->i_addr2, &prep);
+ 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);
+ /* path to orig is valid now */
+ rtorig->rt_flags |= IEEE80211_MESHRT_FLAGS_VALID;
+
/*
- * Build the reverse path, if we don't have it already.
+ * Data creation and update of forwarding information
+ * for transmitter mesh STA [OPTIONAL: if metric improved].
*/
- 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);
+ }else if(hr != NULL &&
+ HWMP_SEQ_EQ(hr->hr_seq, PREQ_TSEQ(0)) &&
+ HWMP_SEQ_GT(hrorig->hr_preqid, preq->preq_id) &&
+ (rtorig->rt_flags & IEEE80211_MESHRT_FLAGS_VALID) == 0){
+ /*
+ * Target is known, Target HWMP seq is equal and
+ * originator/Preq ID unkown.
+ * XXX: this is tricky, high probability that
+ * it is not intepreted correctly.
+ */
+ IEEE80211_NOTE(vap, IEEE80211_MSG_HWMP, ni,
+ "received PREQ, originator %s", "unknown");
+ }else{
+ IEEE80211_DISCARD_MAC(vap, IEEE80211_MSG_HWMP, ni->ni_macaddr,
+ NULL, "PREQ, originator %s, last seen orig.seq %d,"
+ "preq orig.seq %d",
+ ether_sprintf(preq->preq_origaddr), hrorig->hr_seq,
+ preq->preq_origseq);
return;
}
+
+ hrorig->hr_preqid = preq->preq_id; /* Record last seen Preq ID */
+
/*
- * Proactive PREQ: reply with a proactive PREP to the
- * root STA if requested.
+ * Processing of PREQs with target count = 1.
*/
- if (IEEE80211_ADDR_EQ(PREQ_TADDR(0), broadcastaddr) &&
- (PREQ_TFLAGS(0) &
- ((IEEE80211_MESHPREQ_TFLAGS_TO|IEEE80211_MESHPREQ_TFLAGS_RF) ==
- (IEEE80211_MESHPREQ_TFLAGS_TO|IEEE80211_MESHPREQ_TFLAGS_RF)))) {
- uint8_t rootmac[IEEE80211_ADDR_LEN];
-
- IEEE80211_ADDR_COPY(rootmac, preq->preq_origaddr);
- rt = ieee80211_mesh_rt_find(vap, rootmac);
- if (rt == NULL) {
- rt = ieee80211_mesh_rt_add(vap, rootmac);
- if (rt == NULL) {
- IEEE80211_NOTE(vap, IEEE80211_MSG_HWMP, ni,
- "unable to add root mesh path to %s",
- ether_sprintf(rootmac));
- vap->iv_stats.is_mesh_rtaddfailed++;
- return;
- }
- }
- IEEE80211_NOTE(vap, IEEE80211_MSG_HWMP, ni,
- "root mesh station @ %s", ether_sprintf(rootmac));
-
+ if (preq->preq_tcount == 1) {
+ struct ieee80211_meshpreq_ie ppreq; /* propagated PREQ */
+ const uint8_t *preq_transmit_addr = broadcastaddr;
+
/*
- * Reply with a PREP if we don't have a path to the root
- * or if the root sent us a proactive PREQ.
+ * Check if the PREQ is addressed to us.
+ * TODO: also check if we are the proxy of the target MAC.
*/
- if ((rt->rt_flags & IEEE80211_MESHRT_FLAGS_VALID) == 0 ||
- (preq->preq_flags & IEEE80211_MESHPREQ_FLAGS_PP)) {
+ if (IEEE80211_ADDR_EQ(vap->iv_myaddr, PREQ_TADDR(0))) {
+ IEEE80211_NOTE(vap, IEEE80211_MSG_HWMP, ni,
+ "reply PREP, originator %s",
+ ether_sprintf(preq->preq_origaddr));
+ /*
+ * Build and send a PREP frame.
+ */
prep.prep_flags = 0;
prep.prep_hopcount = 0;
prep.prep_ttl = ms->ms_ttl;
- IEEE80211_ADDR_COPY(prep.prep_origaddr, rootmac);
- prep.prep_origseq = preq->preq_origseq;
- prep.prep_lifetime = preq->preq_lifetime;
- prep.prep_metric = IEEE80211_MESHLMETRIC_INITIALVAL;
IEEE80211_ADDR_COPY(prep.prep_targetaddr,
vap->iv_myaddr);
prep.prep_targetseq = ++hs->hs_seq;
- hwmp_send_prep(vap->iv_bss, vap->iv_myaddr,
- broadcastaddr, &prep);
+ 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;
+ hwmp_send_prep(ni, vap->iv_myaddr, wh->i_addr2, &prep);
+ return;
+ /*
+ * PREQ is not for us, but has AE flag set. Update proxy
+ * forwarding information for originator external address.
+ */
+ } else if ((preq->preq_flags & IEEE80211_MESHPREQ_FLAGS_AE)) {
+ IEEE80211_NOTE(vap, IEEE80211_MSG_HWMP, ni,
+ "%s", "Proxy Update (PXU)");
+ /*
+ * NB: fall through to test for valid route
+ * and pro-active PREQ.
+ */
}
- hwmp_discover(vap, rootmac, NULL);
- return;
- }
- rt = ieee80211_mesh_rt_find(vap, PREQ_TADDR(0));
- /*
- * Forwarding and Intermediate reply for PREQs with 1 target.
- */
- if (preq->preq_tcount == 1) {
- struct ieee80211_meshpreq_ie ppreq; /* propagated PREQ */
+ memcpy(&ppreq, preq, sizeof(struct ieee80211_meshpreq_ie));
- memcpy(&ppreq, preq, sizeof(ppreq));
/*
* We have a valid route to this node.
*/
if (rt != NULL &&
(rt->rt_flags & IEEE80211_MESHRT_FLAGS_VALID)) {
- if (preq->preq_ttl > 1 &&
- preq->preq_hopcount < hs->hs_maxhops) {
+ /*
+ * Check if we can send an intermediate Path Reply,
+ * i.e., Target Only bit is not.
+ */
+ if (!(PREQ_TFLAGS(0) & IEEE80211_MESHPREQ_TFLAGS_TO) &&
+ HWMP_SEQ_GEQ(hr->hr_seq, PREQ_TSEQ(0))) {
+ struct ieee80211_meshprep_ie prep;
+
IEEE80211_NOTE(vap, IEEE80211_MSG_HWMP, ni,
- "forward PREQ from %s",
- ether_sprintf(preq->preq_origaddr));
+ "intermediate PREP, originator %s, target %s",
+ ether_sprintf(preq->preq_origaddr),
+ ether_sprintf(PREQ_TADDR(0)));
/*
- * Propagate the original PREQ.
- */
- ppreq.preq_hopcount += 1;
- ppreq.preq_ttl -= 1;
- ppreq.preq_metric +=
- ms->ms_pmetric->mpm_metric(ni);
- /*
- * Set TO and unset RF bits because we are going
+ * Set TO bit because we are going
* to send a PREP next.
*/
ppreq.preq_targets[0].target_flags |=
IEEE80211_MESHPREQ_TFLAGS_TO;
- ppreq.preq_targets[0].target_flags &=
- ~IEEE80211_MESHPREQ_TFLAGS_RF;
- hwmp_send_preq(ni, vap->iv_myaddr,
- broadcastaddr, &ppreq);
- }
- /*
- * Check if we can send an intermediate Path Reply,
- * i.e., Target Only bit is not set.
- */
- if (!(PREQ_TFLAGS(0) & IEEE80211_MESHPREQ_TFLAGS_TO)) {
- struct ieee80211_meshprep_ie prep;
- IEEE80211_NOTE(vap, IEEE80211_MSG_HWMP, ni,
- "intermediate reply for PREQ from %s",
- ether_sprintf(preq->preq_origaddr));
prep.prep_flags = 0;
- prep.prep_hopcount = rt->rt_nhops + 1;
+ prep.prep_hopcount = rt->rt_nhops;
prep.prep_ttl = ms->ms_ttl;
IEEE80211_ADDR_COPY(&prep.prep_targetaddr,
PREQ_TADDR(0));
- prep.prep_targetseq = hrorig->hr_seq;
+ prep.prep_targetseq = hr->hr_seq;
prep.prep_lifetime = preq->preq_lifetime;
prep.prep_metric = rt->rt_metric +
ms->ms_pmetric->mpm_metric(ni);
@@ -862,42 +962,75 @@ hwmp_recv_preq(struct ieee80211vap *vap, struct ieee80211_node *ni,
preq->preq_origaddr);
prep.prep_origseq = hrorig->hr_seq;
hwmp_send_prep(ni, vap->iv_myaddr,
- broadcastaddr, &prep);
+ wh->i_addr2, &prep);
+ }
+
+ /*
+ * This is a unicast PREQ, used e.g. when requesting
+ * a path to a root mesh with RANN mode.
+ */
+ if(!(preq->preq_flags & IEEE80211_MESHPREQ_FLAGS_AM)){
+ preq_transmit_addr = rt->rt_nexthop;
}
/*
- * We have no information about this path,
- * propagate the PREQ.
+ * Proactive PREQ: reply with a proactive PREP to the
+ * root STA if requested.
+ * NB: preq->preq_origaddr is the rootmac.
*/
- } 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;
- }
+ } else if (IEEE80211_ADDR_EQ(PREQ_TADDR(0), broadcastaddr) &&
+ (PREQ_TFLAGS(0) & IEEE80211_MESHPREQ_TFLAGS_TO)) {
+ IEEE80211_NOTE(vap, IEEE80211_MSG_HWMP, ni,
+ "root mesh station @ %s",
+ ether_sprintf(preq->preq_origaddr));
+
+ /*
+ * Reply with a PREP if we don't have a path to the root
+ * or if the root sent us a proactive PREQ.
+ * XXX: For now we assume we always need to send data to
+ * root even if it was not requested by root.
+ */
+ if ((rtorig->rt_flags & IEEE80211_MESHRT_FLAGS_VALID) == 0 ||
+ preq->preq_flags & IEEE80211_MESHPREQ_FLAGS_PP) {
+ IEEE80211_NOTE(vap, IEEE80211_MSG_HWMP, ni,
+ "reply proactive PREP, root %s, to %s",
+ ether_sprintf(preq->preq_origaddr),
+ ether_sprintf(rtorig->rt_nexthop));
+ prep.prep_flags = 0;
+ prep.prep_hopcount = 0;
+ prep.prep_ttl = ms->ms_ttl;
+ IEEE80211_ADDR_COPY(prep.prep_origaddr,
+ preq->preq_origaddr);
+ prep.prep_origseq = preq->preq_origseq;
+ prep.prep_lifetime = preq->preq_lifetime;
+ prep.prep_metric =
+ IEEE80211_MESHLMETRIC_INITIALVAL;
+ IEEE80211_ADDR_COPY(prep.prep_targetaddr,
+ vap->iv_myaddr);
+ prep.prep_targetseq = ++hs->hs_seq;
+ hwmp_send_prep(vap->iv_bss, vap->iv_myaddr,
+ rtorig->rt_nexthop, &prep);
}
- 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;
+ }
+ /* Propagate a PREQ. */
+ 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));
+ "propagate PREQ, originator %s, target %s, nexthop %s",
+ ether_sprintf(preq->preq_origaddr),
+ ether_sprintf(PREQ_TADDR(0)),
+ ether_sprintf(preq_transmit_addr));
+ ppreq.preq_flags |= IEEE80211_MESHPREQ_FLAGS_AM;
ppreq.preq_hopcount += 1;
ppreq.preq_ttl -= 1;
ppreq.preq_metric += ms->ms_pmetric->mpm_metric(ni);
- hwmp_send_preq(ni, vap->iv_myaddr, broadcastaddr,
+ hwmp_send_preq(ni, vap->iv_myaddr, preq_transmit_addr,
&ppreq);
}
+ }else{
+ IEEE80211_DISCARD_MAC(vap, IEEE80211_MSG_HWMP, ni->ni_macaddr,
+ NULL, "PREQ, with target count = %d", preq->preq_tcount);
}
-
}
#undef PREQ_TFLAGS
#undef PREQ_TADDR
@@ -914,22 +1047,28 @@ hwmp_send_preq(struct ieee80211_node *ni,
/*
* Enforce PREQ interval.
*/
- if (ratecheck(&hs->hs_lastpreq, &ieee80211_hwmp_preqminint) == 0)
+ if (ratecheck(&hs->hs_lastpreq, &ieee80211_hwmp_preqminint) == 0){
+ IEEE80211_DISCARD_MAC(ni->ni_vap, IEEE80211_MSG_HWMP,
+ ni->ni_macaddr, NULL, "PREQ rate limit, sa %s, da %s",
+ ether_sprintf(sa),
+ ether_sprintf(da));
return EALREADY;
+ }
getmicrouptime(&hs->hs_lastpreq);
/*
* mesh preq action frame format
* [6] da
- * [6] sa
+ * [6] sa
* [6] addr3 = sa
* [1] action
* [1] category
* [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 = 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
@@ -939,81 +1078,115 @@ hwmp_recv_prep(struct ieee80211vap *vap, struct ieee80211_node *ni,
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_hwmp_route *hr;
struct ieee80211com *ic = vap->iv_ic;
struct ifnet *ifp = vap->iv_ifp;
struct mbuf *m, *next;
+ uint32_t metric = 0;
/*
- * Acceptance criteria: if the corresponding PREQ was not generated
+ * Acceptance criteria: if the corresponding PREP was not generated
* by us and forwarding is disabled, discard this PREP.
*/
if (ni == vap->iv_bss ||
ni->ni_mlstate != IEEE80211_NODE_MESH_ESTABLISHED)
return;
- if (!IEEE80211_ADDR_EQ(vap->iv_myaddr, prep->prep_origaddr) &&
- !(ms->ms_flags & IEEE80211_MESHFLAGS_FWD))
+ /* XXX: test for proxy address */
+ if (!IEEE80211_ADDR_EQ(vap->iv_myaddr, prep->prep_origaddr) &&
+ !(ms->ms_flags & IEEE80211_MESHFLAGS_FWD)){
+ IEEE80211_DISCARD_MAC(vap, IEEE80211_MSG_HWMP,
+ ni->ni_macaddr, NULL,
+ "not accepting PREP, originator %s, forwarding disabled",
+ ether_sprintf(prep->prep_origaddr));
return;
+ }
+
+ /* PREP ACCEPTED */
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 (hs->hs_rootmode != IEEE80211_HWMP_ROOTMODE_DISABLED) {
- 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 %s",
- ether_sprintf(prep->prep_targetaddr));
- vap->iv_stats.is_mesh_rtaddfailed++;
- return;
- }
- IEEE80211_ADDR_COPY(rt->rt_nexthop, wh->i_addr2);
- rt->rt_nhops = prep->prep_hopcount;
- rt->rt_lifetime = prep->prep_lifetime;
- rt->rt_metric = prep->prep_metric;
- rt->rt_flags |= IEEE80211_MESHRT_FLAGS_VALID;
- IEEE80211_NOTE(vap, IEEE80211_MSG_HWMP, ni,
- "add root path to %s nhops %d metric %d (PREP)",
- ether_sprintf(prep->prep_targetaddr),
- rt->rt_nhops, rt->rt_metric);
+ rt = ieee80211_mesh_rt_add(vap, prep->prep_targetaddr);
+ IEEE80211_NOTE(vap, IEEE80211_MSG_HWMP, ni,
+ "adding target %s",
+ ether_sprintf(prep->prep_targetaddr));
+ if (rt == NULL) {
+ IEEE80211_NOTE(vap, IEEE80211_MSG_HWMP,
+ ni, "unable to add PREP path to %s",
+ ether_sprintf(prep->prep_targetaddr));
+ vap->iv_stats.is_mesh_rtaddfailed++;
return;
- }
- return;
+ }
}
+
/*
- * Sequence number validation.
+ * Data creation and update of forwarding information
+ * according to Table 11C-8 for originator mesh STA.
*/
hr = IEEE80211_MESH_ROUTE_PRIV(rt, struct ieee80211_hwmp_route);
- if (HWMP_SEQ_LEQ(prep->prep_targetseq, hr->hr_seq)) {
- IEEE80211_NOTE(vap, IEEE80211_MSG_HWMP, ni,
- "discard PREP from %s, old seq no %u <= %u",
- ether_sprintf(prep->prep_targetaddr),
- prep->prep_targetseq, hr->hr_seq);
+ if(HWMP_SEQ_GT(prep->prep_targetseq, hr->hr_seq) ||
+ (HWMP_SEQ_EQ(prep->prep_targetseq, hr->hr_seq) &&
+ prep->prep_metric < rt->rt_metric)){
+ metric = prep->prep_metric + ms->ms_pmetric->mpm_metric(ni);
+ if((rt->rt_flags & IEEE80211_MESHRT_FLAGS_VALID) == 0){
+ IEEE80211_NOTE(vap, IEEE80211_MSG_HWMP, ni,
+ "create path to %s, hopcount %d metric %d",
+ ether_sprintf(prep->prep_targetaddr),
+ prep->prep_hopcount + 1,
+ metric);
+ }else{
+ IEEE80211_NOTE(vap, IEEE80211_MSG_HWMP, ni,
+ "prefer path to %s, hopcount %d:[%d]"
+ "metric %d:[%d]",
+ ether_sprintf(prep->prep_targetaddr),
+ prep->prep_hopcount + 1, rt->rt_nhops,
+ metric, rt->rt_metric);
+ }
+ hr->hr_seq = prep->prep_targetseq;
+ IEEE80211_ADDR_COPY(rt->rt_nexthop, wh->i_addr2);
+ rt->rt_metric = metric;
+ rt->rt_nhops = prep->prep_hopcount + 1;
+ rt->rt_lifetime = MESH_ROUTE_LIFETIME_MAX(prep->prep_lifetime,
+ rt->rt_lifetime);
+ /* path target is valid now */
+ rt->rt_flags |= IEEE80211_MESHRT_FLAGS_VALID;
+ }else{
+ IEEE80211_DISCARD_MAC(vap, IEEE80211_MSG_HWMP, ni->ni_macaddr,
+ NULL, "PREP, originator %s, last seen orig.seq %d,"
+ "prep orig.seq %d", ether_sprintf(prep->prep_origaddr),
+ hr->hr_seq, prep->prep_origseq);
return;
}
- hr->hr_seq = prep->prep_targetseq;
+
/*
* If it's NOT for us, propagate the PREP.
*/
if (!IEEE80211_ADDR_EQ(vap->iv_myaddr, prep->prep_origaddr) &&
prep->prep_ttl > 1 && prep->prep_hopcount < hs->hs_maxhops) {
struct ieee80211_meshprep_ie pprep; /* propagated PREP */
-
+ rtorig = ieee80211_mesh_rt_find(vap, prep->prep_origaddr);
+ if(rtorig == NULL){
+ IEEE80211_DISCARD_MAC(vap, IEEE80211_MSG_HWMP,
+ ni->ni_macaddr, NULL, "PREP, originator %s unknown",
+ ether_sprintf(prep->prep_origaddr));
+ return;
+ }
IEEE80211_NOTE(vap, IEEE80211_MSG_HWMP, ni,
- "propagate PREP from %s",
- ether_sprintf(prep->prep_targetaddr));
+ "propagate PREP, originator %s, target %s, to %s",
+ ether_sprintf(prep->prep_origaddr),
+ ether_sprintf(prep->prep_targetaddr),
+ ether_sprintf(rtorig->rt_nexthop));
- memcpy(&pprep, prep, sizeof(pprep));
+ memcpy(&pprep, prep, sizeof(struct ieee80211_meshprep_ie));
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);
+ hwmp_send_prep(ni, vap->iv_myaddr, rtorig->rt_nexthop, &pprep);
}
hr = IEEE80211_MESH_ROUTE_PRIV(rt, struct ieee80211_hwmp_route);
if (rt->rt_flags & IEEE80211_MESHRT_FLAGS_PROXY) {
@@ -1022,41 +1195,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) {
- /*
- * 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)) {
- 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,
- rt->rt_metric, prep->prep_metric);
- IEEE80211_ADDR_COPY(rt->rt_nexthop, wh->i_addr2);
- rt->rt_nhops = prep->prep_hopcount;
- rt->rt_lifetime = prep->prep_lifetime;
- rt->rt_metric = prep->prep_metric;
- rt->rt_flags |= IEEE80211_MESHRT_FLAGS_VALID;
- } else {
- IEEE80211_NOTE(vap, IEEE80211_MSG_HWMP, ni,
- "ignore PREP for %s, hopcount %d:%d metric %d:%d",
- ether_sprintf(prep->prep_targetaddr),
- rt->rt_nhops, prep->prep_hopcount,
- rt->rt_metric, prep->prep_metric);
- }
- } else {
- IEEE80211_NOTE(vap, IEEE80211_MSG_HWMP, ni,
- "discard PREP for %s, wrong seqno %u != %u",
- ether_sprintf(prep->prep_targetaddr), prep->prep_origseq,
- hr->hr_seq);
- vap->iv_stats.is_hwmp_wrongseq++;
- }
+ }
/*
* Check for frames queued awaiting path discovery.
* XXX probably can tell exactly and avoid remove call
@@ -1064,9 +1203,9 @@ hwmp_recv_prep(struct ieee80211vap *vap, struct ieee80211_node *ni,
* stuck back on the stageq because there won't be
* a path.
*/
- m = ieee80211_ageq_remove(&ic->ic_stageq,
+ m = ieee80211_ageq_remove(&ic->ic_stageq,
(struct ieee80211_node *)(uintptr_t)
- ieee80211_mac_hash(ic, rt->rt_dest));
+ ieee80211_mac_hash(ic, rt->rt_dest));
for (; m != NULL; m = next) {
next = m->m_nextpkt;
m->m_nextpkt = NULL;
@@ -1094,22 +1233,28 @@ hwmp_send_prep(struct ieee80211_node *ni,
* [tlv] mesh path reply
*/
prep->prep_ie = IEEE80211_ELEMID_MESHPREP;
- return hwmp_send_action(ni, sa, da, (uint8_t *)prep,
- sizeof(struct ieee80211_meshprep_ie));
+ prep->prep_len = IEEE80211_MESHPREP_BASE_SZ;
+ return hwmp_send_action(ni, sa, da, (uint8_t *)prep, prep->prep_len + 2);
}
-#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_DRCODE(n) perr.perr_dests[n].dest_rcode
+#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_DRCODE(n) perr->perr_dests[n].dest_rcode
static void
hwmp_peerdown(struct ieee80211_node *ni)
{
struct ieee80211vap *vap = ni->ni_vap;
struct ieee80211_mesh_state *ms = vap->iv_mesh;
- struct ieee80211_meshperr_ie perr;
- struct ieee80211_mesh_route *rt;
+ struct ieee80211_meshperr_ie *perr;
+ struct ieee80211_mesh_route *rt, *next;
struct ieee80211_hwmp_route *hr;
+ int i = 0;
+
+ perr = malloc(sizeof(struct ieee80211_meshperr_ie) +
+ IEEE80211_HWMP_PERR_MAXDEST*sizeof(*perr->perr_dests),
+ M_80211_HWMP_PERR, M_NOWAIT | M_ZERO);
+ KASSERT(perr != NULL, ("error allocationg PERR"));
rt = ieee80211_mesh_rt_find(vap, ni->ni_macaddr);
if (rt == NULL)
@@ -1117,18 +1262,35 @@ hwmp_peerdown(struct ieee80211_node *ni)
hr = IEEE80211_MESH_ROUTE_PRIV(rt, struct ieee80211_hwmp_route);
IEEE80211_NOTE(vap, IEEE80211_MSG_HWMP, ni,
"%s", "delete route entry");
- perr.perr_ttl = ms->ms_ttl;
- perr.perr_ndests = 1;
- PERR_DFLAGS(0) = 0;
- if (hr->hr_seq == 0)
- PERR_DFLAGS(0) |= IEEE80211_MESHPERR_DFLAGS_USN;
- PERR_DFLAGS(0) |= IEEE80211_MESHPERR_DFLAGS_RC;
- IEEE80211_ADDR_COPY(PERR_DADDR(0), rt->rt_dest);
- PERR_DSEQ(0) = hr->hr_seq;
- PERR_DRCODE(0) = IEEE80211_REASON_MESH_PERR_DEST_UNREACH;
+ perr->perr_ttl = ms->ms_ttl;
+
+ /* find all destinations that have ni->ni_macaddr as nexthop and add to PERR*/
+ MESH_RT_LOCK(ms);
+ TAILQ_FOREACH_SAFE(rt, &ms->ms_routes, rt_next, next) {
+ if ((rt->rt_flags & IEEE80211_MESHRT_FLAGS_VALID) &&
+ IEEE80211_ADDR_EQ(rt->rt_nexthop, ni->ni_macaddr)){
+ hr = IEEE80211_MESH_ROUTE_PRIV(rt, struct ieee80211_hwmp_route);
+ KASSERT(i < IEEE80211_HWMP_PERR_MAXDEST, ("PERR max destination overflow"));
+ PERR_DFLAGS(i) = 0;
+ if (hr->hr_seq == 0)
+ PERR_DFLAGS(i) |= IEEE80211_MESHPERR_DFLAGS_USN;
+ IEEE80211_ADDR_COPY(PERR_DADDR(i), rt->rt_dest);
+ PERR_DSEQ(i) = ++hr->hr_seq;
+ PERR_DRCODE(i) = IEEE80211_REASON_MESH_PERR_DEST_UNREACH;
+ IEEE80211_NOTE(vap, IEEE80211_MSG_HWMP, ni,
+ "PERR: found unrechable destination %s",
+ ether_sprintf(PERR_DADDR(i)));
+ ++i;
+ }
+ }
+ MESH_RT_UNLOCK(ms);
+
+ perr->perr_ndests = i;
+
/* NB: flush everything passing through peer */
ieee80211_mesh_rt_flush_peer(vap, ni->ni_macaddr);
- hwmp_send_perr(vap->iv_bss, vap->iv_myaddr, broadcastaddr, &perr);
+ hwmp_send_perr(vap->iv_bss, vap->iv_myaddr, broadcastaddr, perr);
+ free(perr, M_80211_HWMP_PERR);
}
#undef PERR_DFLAGS
#undef PERR_DADDR
@@ -1146,44 +1308,101 @@ hwmp_recv_perr(struct ieee80211vap *vap, struct ieee80211_node *ni,
struct ieee80211_mesh_state *ms = vap->iv_mesh;
struct ieee80211_mesh_route *rt = NULL;
struct ieee80211_hwmp_route *hr;
- struct ieee80211_meshperr_ie pperr;
- int i, forward = 0;
+ struct ieee80211_meshperr_ie *pperr;
+ int i, k, forward = 0;
+ int num_unrchbl_dest = 0; /* Unreachable destination relevant to us. */
+ int unrchbl_dest[IEEE80211_HWMP_PERR_MAXDEST];
/*
* Acceptance criteria: check if we received a PERR from a
- * neighbor and forwarding is enabled.
+ * neighbor.
*/
if (ni == vap->iv_bss ||
- ni->ni_mlstate != IEEE80211_NODE_MESH_ESTABLISHED ||
- !(ms->ms_flags & IEEE80211_MESHFLAGS_FWD))
+ ni->ni_mlstate != IEEE80211_NODE_MESH_ESTABLISHED)
return;
+
/*
- * Find all routing entries that match and delete them.
+ * Acceptance criteria: check if one of the destination addresses
+ * in PERR is in forwarding information with next hop equals to
+ * transmitter address.
+ * Also build a list of unreachble destination relavant for us,
+ * if PERR gets accepted.
*/
+ k = 0;
for (i = 0; i < perr->perr_ndests; i++) {
rt = ieee80211_mesh_rt_find(vap, PERR_DADDR(i));
if (rt == NULL)
continue;
+ if((rt->rt_flags & IEEE80211_MESHRT_FLAGS_VALID) &&
+ IEEE80211_ADDR_EQ(rt->rt_nexthop, wh->i_addr2)){
+ unrchbl_dest[k++] = i;
+ ++num_unrchbl_dest;
+ }
+ }
+ if(!num_unrchbl_dest){
+ IEEE80211_DISCARD_MAC(vap, IEEE80211_MSG_HWMP, ni->ni_macaddr,
+ NULL, "%s", "PERR unrelevant");
+ return;
+ }
+
+ /* PERR ACCEPTED */
+
+ IEEE80211_NOTE(vap, IEEE80211_MSG_HWMP, ni,
+ "received PERR, number of destinations %d, unreachable %d",
+ perr->perr_ndests, num_unrchbl_dest);
+
+ for(i = 0; i<num_unrchbl_dest; i++) {
+ rt = ieee80211_mesh_rt_find(vap, PERR_DADDR(i));
+ if (rt == NULL) //XXX: we know it is not null!
+ continue;
hr = IEEE80211_MESH_ROUTE_PRIV(rt, struct ieee80211_hwmp_route);
- if (!(PERR_DFLAGS(0) & IEEE80211_MESHPERR_DFLAGS_USN) &&
- HWMP_SEQ_GEQ(PERR_DSEQ(i), hr->hr_seq)) {
- ieee80211_mesh_rt_del(vap, rt->rt_dest);
- ieee80211_mesh_rt_flush_peer(vap, rt->rt_dest);
- rt = NULL;
- forward = 1;
+
+ if((PERR_DRCODE(i) & IEEE80211_REASON_MESH_PERR_NO_FI) &&
+ PERR_DSEQ(i) == 0){
+ IEEE80211_NOTE(vap, IEEE80211_MSG_HWMP, ni,
+ "PERR: no forwarding information for destination %s",
+ ether_sprintf(PERR_DADDR(unrchbl_dest[i])));
+ hr->hr_seq++; // 11C.9.11.4.3 effect of receipt case b)
+ }else if(((PERR_DRCODE(i) & IEEE80211_REASON_MESH_PERR_NO_FI) &&
+ PERR_DSEQ(i) != 0)
+ ||
+ ((PERR_DRCODE(i) & IEEE80211_REASON_MESH_PERR_DEST_UNREACH)
+ && (HWMP_SEQ_GT(PERR_DSEQ(i), hr->hr_seq)))){ //case c)
+ IEEE80211_NOTE(vap, IEEE80211_MSG_HWMP, ni,
+ "PERR: unrechable destination %s with"
+ "perr seq %d > stored seq %d",
+ ether_sprintf(PERR_DADDR(unrchbl_dest[i])),
+ PERR_DSEQ(i), hr->hr_seq);
+ hr->hr_seq = PERR_DSEQ(i);
+ /* invlidate forwarding information */
+ rt->rt_flags &= ~IEEE80211_MESHRT_FLAGS_VALID;
+ ++forward;
+ }else{
+ IEEE80211_NOTE(vap, IEEE80211_MSG_HWMP, ni,
+ "PERR: unrechable destination %s with"
+ "perr seq %d < stored seq %d",
+ ether_sprintf(PERR_DADDR(unrchbl_dest[i])),
+ PERR_DSEQ(i), hr->hr_seq);
}
}
+
/*
* Propagate the PERR if we previously found it on our routing table.
- * XXX handle ndest > 1
*/
- if (forward && perr->perr_ttl > 1) {
+ if (forward > 100 && perr->perr_ttl > 1 &&
+ (ms->ms_flags & IEEE80211_MESHFLAGS_FWD)) {
+ pperr = malloc(sizeof(struct ieee80211_meshperr_ie) +
+ (perr->perr_ndests-1)*sizeof(*perr->perr_dests),
+ M_80211_HWMP_PERR, M_NOWAIT | M_ZERO);
+ KASSERT(pperr != NULL, ("error allocationg PERR"));
+ memcpy(pperr, perr, sizeof(struct ieee80211_meshperr_ie) +
+ (perr->perr_ndests-1)*sizeof(*perr->perr_dests));
IEEE80211_NOTE(vap, IEEE80211_MSG_HWMP, ni,
"propagate PERR from %s", ether_sprintf(wh->i_addr2));
- memcpy(&pperr, perr, sizeof(*perr));
- pperr.perr_ttl--;
- hwmp_send_perr(vap->iv_bss, vap->iv_myaddr, broadcastaddr,
- &pperr);
+ pperr->perr_ttl--;
+ hwmp_send_perr(vap->iv_bss, vap->iv_myaddr,
+ broadcastaddr, pperr);
+ free(pperr, M_80211_HWMP_PERR);
}
}
#undef PEER_DADDR
@@ -1214,10 +1433,14 @@ 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));
+ perr->perr_len = IEEE80211_MESHPERR_BASE_SZ +
+ perr->perr_ndests * IEEE80211_MESHPERR_DEST_SZ;
+ return hwmp_send_action(ni, sa, da, (uint8_t *)perr, perr->perr_len+2);
}
+#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 void
hwmp_recv_rann(struct ieee80211vap *vap, struct ieee80211_node *ni,
const struct ieee80211_frame *wh, const struct ieee80211_meshrann_ie *rann)
@@ -1226,7 +1449,9 @@ hwmp_recv_rann(struct ieee80211vap *vap, struct ieee80211_node *ni,
struct ieee80211_hwmp_state *hs = vap->iv_hwmp;
struct ieee80211_mesh_route *rt = NULL;
struct ieee80211_hwmp_route *hr;
+ struct ieee80211_meshpreq_ie preq;
struct ieee80211_meshrann_ie prann;
+ uint32_t metric = 0;
if (ni == vap->iv_bss ||
ni->ni_mlstate != IEEE80211_NODE_MESH_ESTABLISHED ||
@@ -1239,24 +1464,85 @@ hwmp_recv_rann(struct ieee80211vap *vap, struct ieee80211_node *ni,
* If we already know it, propagate the RANN element.
*/
if (rt == NULL) {
+ IEEE80211_NOTE(vap, IEEE80211_MSG_HWMP, ni,
+ "received RANN, new rootmac %s",
+ ether_sprintf(rann->rann_addr));
hwmp_discover(vap, rann->rann_addr, NULL);
return;
}
hr = IEEE80211_MESH_ROUTE_PRIV(rt, struct ieee80211_hwmp_route);
- if (HWMP_SEQ_GT(rann->rann_seq, hr->hr_seq)) {
- hr->hr_seq = rann->rann_seq;
- if (rann->rann_ttl > 1 &&
- rann->rann_hopcount < hs->hs_maxhops &&
- (ms->ms_flags & IEEE80211_MESHFLAGS_FWD)) {
- memcpy(&prann, rann, sizeof(prann));
- prann.rann_hopcount += 1;
- prann.rann_ttl -= 1;
- prann.rann_metric += ms->ms_pmetric->mpm_metric(ni);
- hwmp_send_rann(vap->iv_bss, vap->iv_myaddr,
- broadcastaddr, &prann);
- }
+
+ /*
+ * Acceptance criteria: if RANN has old sequence number
+ * or same sequence number but worse metric than in
+ * forwarding information, discard this RANN.
+ */
+ if (HWMP_SEQ_LT(rann->rann_seq, hr->hr_seq) ||
+ (HWMP_SEQ_EQ(rann->rann_seq, hr->hr_seq) &&
+ rann->rann_metric > rt->rt_metric)) {
+ IEEE80211_DISCARD_MAC(vap, IEEE80211_MSG_HWMP, ni->ni_macaddr,
+ NULL, "RANN, rootmac %s, last seen orig.seq %d, rann.seq %d",
+ ether_sprintf(rann->rann_addr), hr->hr_seq, rann->rann_seq);
+ return;
+ }
+
+ /* RANN ACCEPTED */
+ IEEE80211_NOTE(vap, IEEE80211_MSG_HWMP, ni,
+ "received RANN, rootmac %s",
+ ether_sprintf(rann->rann_addr));
+
+// ieee80211_hwmp_rannint = rann->rann_interval;
+
+ /*
+ * Mesh STA may initiate a PREQ/PREP exchange with root.
+ * See 11C.9.9.3 (condition for generating and sending a PREQ) Case D.
+ */
+ metric = rann->rann_metric + ms->ms_pmetric->mpm_metric(ni);
+ if(metric < rt->rt_metric ||
+ ratecheck(&hs->hs_lastrootconf, &ieee80211_hwmp_rootmin_confint)){
+ getmicrouptime(&hs->hs_lastrootconf);
+ IEEE80211_NOTE(vap, IEEE80211_MSG_HWMP, ni,
+ "PREQ/PREP exchange with root %s, nexthop %s",
+ ether_sprintf(rann->rann_addr),
+ ether_sprintf(rt->rt_nexthop));
+ preq.preq_flags = 0; /* unicast PREQ */
+ preq.preq_hopcount = 0;
+ preq.preq_ttl = ms->ms_ttl;
+ preq.preq_id = 0; /* NB: not used */
+ IEEE80211_ADDR_COPY(preq.preq_origaddr, vap->iv_myaddr);
+ preq.preq_origseq = ++hs->hs_seq;
+ preq.preq_lifetime = ieee80211_hwmp_ranntimeout;
+ preq.preq_metric = IEEE80211_MESHLMETRIC_INITIALVAL;
+ preq.preq_tcount = 1;
+ PREQ_TFLAGS(0) = IEEE80211_MESHPREQ_TFLAGS_TO;
+ IEEE80211_ADDR_COPY(PREQ_TADDR(0), rann->rann_addr);
+ PREQ_TSEQ(0) = rann->rann_seq;
+ hwmp_send_preq(vap->iv_bss, vap->iv_myaddr,
+ rt->rt_nexthop, &preq);
+ }
+
+ /* May update forwarding iformation to root. */
+ hr->hr_seq = rann->rann_seq;
+ rt->rt_nhops = rann->rann_hopcount+1;
+ rt->rt_metric = metric;
+
+ if (rann->rann_ttl > 1 &&
+ rann->rann_hopcount < hs->hs_maxhops &&
+ (ms->ms_flags & IEEE80211_MESHFLAGS_FWD)) {
+ memcpy(&prann, rann, sizeof(prann));
+ prann.rann_hopcount += 1;
+ prann.rann_ttl -= 1;
+ prann.rann_metric += ms->ms_pmetric->mpm_metric(ni);
+ IEEE80211_NOTE(vap, IEEE80211_MSG_HWMP, ni,
+ "propagate RANN, rootmac %s",
+ ether_sprintf(rann->rann_addr));
+ hwmp_send_rann(vap->iv_bss, vap->iv_myaddr,
+ broadcastaddr, &prann);
}
}
+#undef PREQ_TFLAGS
+#undef PREQ_TADDR
+#undef PREQ_TSEQ
static int
hwmp_send_rann(struct ieee80211_node *ni,
@@ -1274,8 +1560,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
@@ -1323,18 +1610,19 @@ 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;
preq.preq_hopcount = 0;
preq.preq_ttl = ms->ms_ttl;
preq.preq_id = ++hs->hs_preqid;
IEEE80211_ADDR_COPY(preq.preq_origaddr, vap->iv_myaddr);
- preq.preq_origseq = hr->hr_origseq;
+ preq.preq_origseq = ++hs->hs_seq;
preq.preq_lifetime = rt->rt_lifetime;
preq.preq_metric = rt->rt_metric;
preq.preq_tcount = 1;
@@ -1342,10 +1630,8 @@ hwmp_discover(struct ieee80211vap *vap,
PREQ_TFLAGS(0) = 0;
if (ieee80211_hwmp_targetonly)
PREQ_TFLAGS(0) |= IEEE80211_MESHPREQ_TFLAGS_TO;
- 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);
diff --git a/sys/net80211/ieee80211_mesh.h b/sys/net80211/ieee80211_mesh.h
index ad1b02a..ce92096 100644
--- a/sys/net80211/ieee80211_mesh.h
+++ b/sys/net80211/ieee80211_mesh.h
@@ -170,6 +170,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;
@@ -179,10 +180,15 @@ 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;
+MALLOC_DECLARE(M_80211_HWMP_RANN);
/* Mesh Path Request */
+#define IEEE80211_MESHPREQ_BASE_SZ (26)
+#define IEEE80211_MESHPREQ_BASE_SZ_AE (32)
+#define IEEE80211_MESHPREQ_TRGT_SZ (11)
struct ieee80211_meshpreq_ie {
uint8_t preq_ie; /* IEEE80211_ELEMID_MESHPREQ */
uint8_t preq_len;
@@ -196,21 +202,24 @@ 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 */
struct {
uint8_t target_flags;
#define IEEE80211_MESHPREQ_TFLAGS_TO 0x01 /* Target Only */
-#define IEEE80211_MESHPREQ_TFLAGS_RF 0x02 /* Reply and Forward */
#define IEEE80211_MESHPREQ_TFLAGS_USN 0x04 /* Unknown HWMP seq number */
uint8_t target_addr[IEEE80211_ADDR_LEN];
uint32_t target_seq; /* HWMP Sequence Number */
} __packed preq_targets[1]; /* NB: variable size */
} __packed;
+MALLOC_DECLARE(M_80211_HWMP_PREQ);
/* 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;
@@ -219,14 +228,19 @@ struct ieee80211_meshprep_ie {
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];
uint32_t prep_origseq; /* HWMP Sequence Number */
} __packed;
+MALLOC_DECLARE(M_80211_HWMP_PREP);
/* Mesh Path Error */
+#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;
@@ -238,9 +252,12 @@ struct ieee80211_meshperr_ie {
#define IEEE80211_MESHPERR_DFLAGS_RC 0x02
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;
+MALLOC_DECLARE(M_80211_HWMP_PERR);
#ifdef notyet
/* Mesh Proxy Update */
help
Want to link to this message? Use this URL: <https://mail-archive.FreeBSD.org/cgi/mid.cgi?CA%2BsBSo%2Bs1bFw3KLvf%2BTh_vdR_5ato_xhEE5saLh6aK=1Avbb=w>
