aboutsummaryrefslogtreecommitdiff
path: root/sys/net80211/ieee80211_hwmp.c
diff options
context:
space:
mode:
authorRui Paulo <rpaulo@FreeBSD.org>2009-07-27 14:22:09 +0000
committerRui Paulo <rpaulo@FreeBSD.org>2009-07-27 14:22:09 +0000
commit3ca80f0dbc5894b39e40a5198763bc37773e9bc5 (patch)
treecb443c30550ddfac3a0cbff2cf9dc6f1efaf229d /sys/net80211/ieee80211_hwmp.c
parent1f93ae9453aceed4c329afec71ce74167f217d6e (diff)
downloadsrc-3ca80f0dbc5894b39e40a5198763bc37773e9bc5.tar.gz
src-3ca80f0dbc5894b39e40a5198763bc37773e9bc5.zip
Mesh fixes, namely:
* don't clobber proxy entries * HWMP seq number processing, including discard of old frames * flush routing table entries based on nexthop * print route flags in ifconfig * more debugging messages and comments Proxy changes submitted by sam. Approved by: re (kib)
Notes
Notes: svn path=/head/; revision=195908
Diffstat (limited to 'sys/net80211/ieee80211_hwmp.c')
-rw-r--r--sys/net80211/ieee80211_hwmp.c178
1 files changed, 106 insertions, 72 deletions
diff --git a/sys/net80211/ieee80211_hwmp.c b/sys/net80211/ieee80211_hwmp.c
index 5ad0d41a32e6..040941e8425d 100644
--- a/sys/net80211/ieee80211_hwmp.c
+++ b/sys/net80211/ieee80211_hwmp.c
@@ -137,15 +137,18 @@ static const uint8_t broadcastaddr[IEEE80211_ADDR_LEN] =
{ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff };
typedef uint32_t ieee80211_hwmp_seq;
-#define IEEE80211_HWMP_SEQ_LEQ(a, b) ((int32_t)((a)-(b)) <= 0)
-#define IEEE80211_HWMP_SEQ_GEQ(a, b) ((int32_t)((a)-(b)) >= 0)
+#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_GT(a, b) ((int32_t)((a)-(b)) > 0)
+#define HWMP_SEQ_GEQ(a, b) ((int32_t)((a)-(b)) >= 0)
/*
* Private extension of ieee80211_mesh_route.
*/
struct ieee80211_hwmp_route {
- ieee80211_hwmp_seq hr_seq; /* HWMP sequence number */
- ieee80211_hwmp_seq hr_preqid; /* Last PREQ ID seen */
+ ieee80211_hwmp_seq hr_seq; /* last HWMP seq seen from dst*/
+ ieee80211_hwmp_seq hr_preqid; /* last PREQ ID seen from dst */
+ ieee80211_hwmp_seq hr_targetseq; /* seq. no. on our latest PREQ*/
int hr_preqretries;
};
struct ieee80211_hwmp_state {
@@ -274,7 +277,6 @@ hwmp_newstate(struct ieee80211vap *vap, enum ieee80211_state ostate, int arg)
__func__, ieee80211_state_name[ostate],
ieee80211_state_name[nstate], arg);
- /* Flush the table on RUN -> !RUN, e.g. interface down & up */
if (nstate != IEEE80211_S_RUN && ostate == IEEE80211_S_RUN)
callout_drain(&hs->hs_roottimer);
if (nstate == IEEE80211_S_RUN)
@@ -656,8 +658,9 @@ hwmp_rootmode_cb(void *arg)
IEEE80211_NOTE(vap, IEEE80211_MSG_HWMP, vap->iv_bss,
"%s", "send broadcast PREQ");
- /* XXX check portal role */
preq.preq_flags = IEEE80211_MESHPREQ_FLAGS_AM;
+ if (ms->ms_flags & IEEE80211_MESHFLAGS_PORTAL)
+ preq.preq_flags |= IEEE80211_MESHPREQ_FLAGS_PR;
if (hs->hs_rootmode == IEEE80211_HWMP_ROOTMODE_PROACTIVE)
preq.preq_flags |= IEEE80211_MESHPREQ_FLAGS_PP;
preq.preq_hopcount = 0;
@@ -695,8 +698,8 @@ hwmp_rootmode_rann_cb(void *arg)
IEEE80211_NOTE(vap, IEEE80211_MSG_HWMP, vap->iv_bss,
"%s", "send broadcast RANN");
- /* XXX check portal role */
- rann.rann_flags = 0;
+ if (ms->ms_flags & IEEE80211_MESHFLAGS_PORTAL)
+ rann.rann_flags |= IEEE80211_MESHRANN_FLAGS_PR;
rann.rann_hopcount = 0;
rann.rann_ttl = ms->ms_ttl;
IEEE80211_ADDR_COPY(rann.rann_addr, vap->iv_myaddr);
@@ -717,7 +720,8 @@ hwmp_recv_preq(struct ieee80211vap *vap, struct ieee80211_node *ni,
{
struct ieee80211_mesh_state *ms = vap->iv_mesh;
struct ieee80211_mesh_route *rt = NULL;
- struct ieee80211_hwmp_route *hr;
+ struct ieee80211_mesh_route *rtorig = NULL;
+ struct ieee80211_hwmp_route *hrorig;
struct ieee80211_hwmp_state *hs = vap->iv_hwmp;
struct ieee80211_meshprep_ie prep;
@@ -744,9 +748,26 @@ hwmp_recv_preq(struct ieee80211vap *vap, struct ieee80211_node *ni,
preq->preq_origaddr, NULL, "%s", "not accepting PREQ");
return;
}
+ rtorig = ieee80211_mesh_rt_find(vap, preq->preq_origaddr);
+ if (rtorig == NULL)
+ rtorig = ieee80211_mesh_rt_add(vap, preq->preq_origaddr);
+ 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.
- * XXX: check if this is part of a proxy address.
*/
if (IEEE80211_ADDR_EQ(vap->iv_myaddr, PREQ_TADDR(0))) {
IEEE80211_NOTE(vap, IEEE80211_MSG_HWMP, ni,
@@ -823,8 +844,6 @@ hwmp_recv_preq(struct ieee80211vap *vap, struct ieee80211_node *ni,
}
rt = ieee80211_mesh_rt_find(vap, PREQ_TADDR(0));
- /* XXX missing. Check for AE bit and update proxy information */
-
/*
* Forwarding and Intermediate reply for PREQs with 1 target.
*/
@@ -837,11 +856,6 @@ hwmp_recv_preq(struct ieee80211vap *vap, struct ieee80211_node *ni,
*/
if (rt != NULL &&
(rt->rt_flags & IEEE80211_MESHRT_FLAGS_VALID)) {
-
- hr = IEEE80211_MESH_ROUTE_PRIV(rt,
- struct ieee80211_hwmp_route);
- hr->hr_preqid = preq->preq_id;
- hr->hr_seq = preq->preq_origseq;
if (preq->preq_ttl > 1 &&
preq->preq_hopcount < hs->hs_maxhops) {
IEEE80211_NOTE(vap, IEEE80211_MSG_HWMP, ni,
@@ -880,13 +894,13 @@ hwmp_recv_preq(struct ieee80211vap *vap, struct ieee80211_node *ni,
prep.prep_ttl = ms->ms_ttl;
IEEE80211_ADDR_COPY(&prep.prep_targetaddr,
preq->preq_origaddr);
- prep.prep_targetseq = hr->hr_seq;
+ prep.prep_targetseq = hrorig->hr_seq;
prep.prep_lifetime = preq->preq_lifetime;
prep.prep_metric = rt->rt_metric +
ms->ms_pmetric->mpm_metric(ni);
IEEE80211_ADDR_COPY(&prep.prep_origaddr,
PREQ_TADDR(0));
- prep.prep_origseq = hs->hs_seq++;
+ prep.prep_origseq = hrorig->hr_seq;
hwmp_send_prep(ni, vap->iv_myaddr,
broadcastaddr, &prep);
}
@@ -906,12 +920,12 @@ hwmp_recv_preq(struct ieee80211vap *vap, struct ieee80211_node *ni,
return;
}
}
- hr = IEEE80211_MESH_ROUTE_PRIV(rt,
- struct ieee80211_hwmp_route);
rt->rt_metric = preq->preq_metric;
rt->rt_lifetime = preq->preq_lifetime;
- hr->hr_seq = preq->preq_origseq;
- hr->hr_preqid = preq->preq_id;
+ hrorig = IEEE80211_MESH_ROUTE_PRIV(rt,
+ struct ieee80211_hwmp_route);
+ hrorig->hr_seq = preq->preq_origseq;
+ hrorig->hr_preqid = preq->preq_id;
IEEE80211_NOTE(vap, IEEE80211_MSG_HWMP, ni,
"forward PREQ from %s",
@@ -984,25 +998,6 @@ hwmp_recv_prep(struct ieee80211vap *vap, struct ieee80211_node *ni,
IEEE80211_NOTE(vap, IEEE80211_MSG_HWMP, ni,
"received PREP from %s", ether_sprintf(prep->prep_origaddr));
- /*
- * If it's NOT for us, propagate the PREP.
- */
- if (!IEEE80211_ADDR_EQ(vap->iv_myaddr, prep->prep_targetaddr) &&
- prep->prep_ttl > 1 && prep->prep_hopcount < hs->hs_maxhops) {
- struct ieee80211_meshprep_ie pprep; /* propagated PREP */
-
- IEEE80211_NOTE(vap, IEEE80211_MSG_HWMP, ni,
- "propagate PREP from %s",
- ether_sprintf(prep->prep_origaddr));
-
- memcpy(&pprep, prep, sizeof(pprep));
- pprep.prep_hopcount += 1;
- pprep.prep_ttl -= 1;
- pprep.prep_metric += ms->ms_pmetric->mpm_metric(ni);
- IEEE80211_ADDR_COPY(pprep.prep_origaddr, vap->iv_myaddr);
- hwmp_send_prep(ni, vap->iv_myaddr, broadcastaddr, &pprep);
- }
-
rt = ieee80211_mesh_rt_find(vap, prep->prep_origaddr);
if (rt == NULL) {
/*
@@ -1022,48 +1017,86 @@ hwmp_recv_prep(struct ieee80211vap *vap, struct ieee80211_node *ni,
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_origaddr),
+ rt->rt_nhops, rt->rt_metric);
return;
}
return;
}
+ /*
+ * Sequence number validation.
+ */
+ hr = IEEE80211_MESH_ROUTE_PRIV(rt, struct ieee80211_hwmp_route);
+ if (HWMP_SEQ_LEQ(prep->prep_origseq, hr->hr_seq)) {
+ IEEE80211_NOTE(vap, IEEE80211_MSG_HWMP, ni,
+ "discard PREP from %s, old seq no %u <= %u",
+ ether_sprintf(prep->prep_origaddr),
+ prep->prep_origseq, hr->hr_seq);
+ return;
+ }
+ hr->hr_seq = prep->prep_origseq;
+ /*
+ * If it's NOT for us, propagate the PREP.
+ */
+ if (!IEEE80211_ADDR_EQ(vap->iv_myaddr, prep->prep_targetaddr) &&
+ prep->prep_ttl > 1 && prep->prep_hopcount < hs->hs_maxhops) {
+ struct ieee80211_meshprep_ie pprep; /* propagated PREP */
+
+ IEEE80211_NOTE(vap, IEEE80211_MSG_HWMP, ni,
+ "propagate PREP from %s",
+ ether_sprintf(prep->prep_origaddr));
+
+ memcpy(&pprep, prep, sizeof(pprep));
+ pprep.prep_hopcount += 1;
+ pprep.prep_ttl -= 1;
+ pprep.prep_metric += ms->ms_pmetric->mpm_metric(ni);
+ IEEE80211_ADDR_COPY(pprep.prep_origaddr, vap->iv_myaddr);
+ hwmp_send_prep(ni, vap->iv_myaddr, broadcastaddr, &pprep);
+ }
hr = IEEE80211_MESH_ROUTE_PRIV(rt, struct ieee80211_hwmp_route);
- if (prep->prep_targetseq == hr->hr_seq) {
- int useprep = 0;
+ if (rt->rt_flags & IEEE80211_MESHRT_FLAGS_PROXY) {
+ /* NB: never clobber a proxy entry */;
+ IEEE80211_NOTE(vap, IEEE80211_MSG_HWMP, ni,
+ "discard PREP for %s, route is marked PROXY",
+ ether_sprintf(prep->prep_origaddr));
+ vap->iv_stats.is_hwmp_proxy++;
+ } else if (prep->prep_targetseq == hr->hr_targetseq) {
/*
* 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)
- useprep = 1;
- else if (prep->prep_hopcount < rt->rt_nhops ||
- prep->prep_metric < rt->rt_metric)
- useprep = 1;
- if (useprep) {
+ 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_origaddr),
+ rt->rt_nhops, prep->prep_hopcount,
+ rt->rt_metric, prep->prep_metric);
}
} else {
IEEE80211_NOTE(vap, IEEE80211_MSG_HWMP, ni,
- "discard PREP from %s, wrong seqno %u != %u",
+ "discard PREP for %s, wrong seqno %u != %u",
ether_sprintf(prep->prep_origaddr), prep->prep_targetseq,
hr->hr_seq);
vap->iv_stats.is_hwmp_wrongseq++;
}
-
- /*
- * XXX: If it's for us and the AE bit is set, update the
- * proxy information table.
- */
-
- /*
- * XXX: If it's NOT for us and the AE bit is set,
- * update the proxy information table.
- */
-
/*
* Check for frames queued awaiting path discovery.
* XXX probably can tell exactly and avoid remove call
@@ -1125,7 +1158,8 @@ hwmp_peerdown(struct ieee80211_node *ni)
perr.perr_ndests = 1;
IEEE80211_ADDR_COPY(PERR_DADDR(0), rt->rt_dest);
PERR_DSEQ(0) = hr->hr_seq;
- ieee80211_mesh_rt_del(vap, ni->ni_macaddr);
+ /* 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);
}
#undef PERR_DADDR
@@ -1160,8 +1194,9 @@ hwmp_recv_perr(struct ieee80211vap *vap, struct ieee80211_node *ni,
continue;
hr = IEEE80211_MESH_ROUTE_PRIV(rt,
struct ieee80211_hwmp_route);
- if (PERR_DSEQ(i) >= hr->hr_seq) {
+ if (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;
}
@@ -1174,7 +1209,8 @@ hwmp_recv_perr(struct ieee80211vap *vap, struct ieee80211_node *ni,
IEEE80211_NOTE(vap, IEEE80211_MSG_HWMP, ni,
"propagate PERR from %s", ether_sprintf(wh->i_addr2));
memcpy(&pperr, perr, sizeof(*perr));
- hwmp_send_perr(vap->iv_bss, vap->iv_myaddr, broadcastaddr, &pperr);
+ hwmp_send_perr(vap->iv_bss, vap->iv_myaddr, broadcastaddr,
+ &pperr);
}
}
#undef PEER_DADDR
@@ -1233,7 +1269,7 @@ hwmp_recv_rann(struct ieee80211vap *vap, struct ieee80211_node *ni,
return;
}
hr = IEEE80211_MESH_ROUTE_PRIV(rt, struct ieee80211_hwmp_route);
- if (rann->rann_seq > hr->hr_seq && rann->rann_ttl > 1 &&
+ if (HWMP_SEQ_GT(rann->rann_seq, hr->hr_seq) && rann->rann_ttl > 1 &&
rann->rann_hopcount < hs->hs_maxhops &&
(ms->ms_flags & IEEE80211_MESHFLAGS_FWD)) {
memcpy(&prann, rann, sizeof(prann));
@@ -1302,10 +1338,8 @@ hwmp_discover(struct ieee80211vap *vap,
hr = IEEE80211_MESH_ROUTE_PRIV(rt,
struct ieee80211_hwmp_route);
if ((rt->rt_flags & IEEE80211_MESHRT_FLAGS_VALID) == 0) {
- if (hr->hr_preqid == 0) {
- hr->hr_seq = ++hs->hs_seq;
- hr->hr_preqid = ++hs->hs_preqid;
- }
+ if (hr->hr_targetseq == 0)
+ hr->hr_targetseq = ++hs->hs_seq;
rt->rt_metric = IEEE80211_MESHLMETRIC_INITIALVAL;
rt->rt_lifetime =
ticks_to_msecs(ieee80211_hwmp_pathtimeout);
@@ -1321,9 +1355,9 @@ hwmp_discover(struct ieee80211vap *vap,
preq.preq_flags = 0;
preq.preq_hopcount = 0;
preq.preq_ttl = ms->ms_ttl;
- preq.preq_id = hr->hr_preqid;
+ preq.preq_id = ++hs->hs_preqid;
IEEE80211_ADDR_COPY(preq.preq_origaddr, vap->iv_myaddr);
- preq.preq_origseq = hr->hr_seq;
+ preq.preq_origseq = hr->hr_targetseq;
preq.preq_lifetime = rt->rt_lifetime;
preq.preq_metric = rt->rt_metric;
preq.preq_tcount = 1;