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)
This commit is contained in:
parent
1f93ae9453
commit
3ca80f0dbc
Notes:
svn2git
2020-12-20 02:59:44 +00:00
svn path=/head/; revision=195908
@ -3952,9 +3952,9 @@ list_regdomain(int s, int channelsalso)
|
|||||||
static void
|
static void
|
||||||
list_mesh(int s)
|
list_mesh(int s)
|
||||||
{
|
{
|
||||||
int i;
|
|
||||||
struct ieee80211req ireq;
|
struct ieee80211req ireq;
|
||||||
struct ieee80211req_mesh_route routes[128];
|
struct ieee80211req_mesh_route routes[128];
|
||||||
|
struct ieee80211req_mesh_route *rt;
|
||||||
|
|
||||||
(void) memset(&ireq, 0, sizeof(ireq));
|
(void) memset(&ireq, 0, sizeof(ireq));
|
||||||
(void) strncpy(ireq.i_name, name, sizeof(ireq.i_name));
|
(void) strncpy(ireq.i_name, name, sizeof(ireq.i_name));
|
||||||
@ -3965,23 +3965,26 @@ list_mesh(int s)
|
|||||||
if (ioctl(s, SIOCG80211, &ireq) < 0)
|
if (ioctl(s, SIOCG80211, &ireq) < 0)
|
||||||
err(1, "unable to get the Mesh routing table");
|
err(1, "unable to get the Mesh routing table");
|
||||||
|
|
||||||
printf("%-17.17s %-17.17s %4s %4s %4s %6s\n"
|
printf("%-17.17s %-17.17s %4s %4s %4s %6s %s\n"
|
||||||
, "DEST"
|
, "DEST"
|
||||||
, "NEXT HOP"
|
, "NEXT HOP"
|
||||||
, "HOPS"
|
, "HOPS"
|
||||||
, "METRIC"
|
, "METRIC"
|
||||||
, "LIFETIME"
|
, "LIFETIME"
|
||||||
, "MSEQ");
|
, "MSEQ"
|
||||||
|
, "FLAGS");
|
||||||
|
|
||||||
for (i = 0; i < ireq.i_len / sizeof(*routes); i++) {
|
for (rt = &routes[0]; rt - &routes[0] < ireq.i_len / sizeof(*rt); rt++){
|
||||||
printf("%s ",
|
printf("%s ",
|
||||||
ether_ntoa((const struct ether_addr *)routes[i].imr_dest));
|
ether_ntoa((const struct ether_addr *)rt->imr_dest));
|
||||||
printf("%s %4u %4u %6u %6u\n",
|
printf("%s %4u %4u %6u %6u %c%c\n",
|
||||||
ether_ntoa((const struct ether_addr *)
|
ether_ntoa((const struct ether_addr *)rt->imr_nexthop),
|
||||||
routes[i].imr_nexthop),
|
rt->imr_nhops, rt->imr_metric, rt->imr_lifetime,
|
||||||
routes[i].imr_nhops, routes[i].imr_metric,
|
rt->imr_lastmseq,
|
||||||
routes[i].imr_lifetime,
|
(rt->imr_flags & IEEE80211_MESHRT_FLAGS_VALID) ?
|
||||||
routes[i].imr_lastmseq);
|
'V' : '!',
|
||||||
|
(rt->imr_flags & IEEE80211_MESHRT_FLAGS_PROXY) ?
|
||||||
|
'P' : ' ');
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -137,15 +137,18 @@ static const uint8_t broadcastaddr[IEEE80211_ADDR_LEN] =
|
|||||||
{ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff };
|
{ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff };
|
||||||
|
|
||||||
typedef uint32_t ieee80211_hwmp_seq;
|
typedef uint32_t ieee80211_hwmp_seq;
|
||||||
#define IEEE80211_HWMP_SEQ_LEQ(a, b) ((int32_t)((a)-(b)) <= 0)
|
#define HWMP_SEQ_LT(a, b) ((int32_t)((a)-(b)) < 0)
|
||||||
#define IEEE80211_HWMP_SEQ_GEQ(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.
|
* Private extension of ieee80211_mesh_route.
|
||||||
*/
|
*/
|
||||||
struct ieee80211_hwmp_route {
|
struct ieee80211_hwmp_route {
|
||||||
ieee80211_hwmp_seq hr_seq; /* HWMP sequence number */
|
ieee80211_hwmp_seq hr_seq; /* last HWMP seq seen from dst*/
|
||||||
ieee80211_hwmp_seq hr_preqid; /* Last PREQ ID seen */
|
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;
|
int hr_preqretries;
|
||||||
};
|
};
|
||||||
struct ieee80211_hwmp_state {
|
struct ieee80211_hwmp_state {
|
||||||
@ -274,7 +277,6 @@ hwmp_newstate(struct ieee80211vap *vap, enum ieee80211_state ostate, int arg)
|
|||||||
__func__, ieee80211_state_name[ostate],
|
__func__, ieee80211_state_name[ostate],
|
||||||
ieee80211_state_name[nstate], arg);
|
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)
|
if (nstate != IEEE80211_S_RUN && ostate == IEEE80211_S_RUN)
|
||||||
callout_drain(&hs->hs_roottimer);
|
callout_drain(&hs->hs_roottimer);
|
||||||
if (nstate == IEEE80211_S_RUN)
|
if (nstate == IEEE80211_S_RUN)
|
||||||
@ -656,8 +658,9 @@ hwmp_rootmode_cb(void *arg)
|
|||||||
IEEE80211_NOTE(vap, IEEE80211_MSG_HWMP, vap->iv_bss,
|
IEEE80211_NOTE(vap, IEEE80211_MSG_HWMP, vap->iv_bss,
|
||||||
"%s", "send broadcast PREQ");
|
"%s", "send broadcast PREQ");
|
||||||
|
|
||||||
/* XXX check portal role */
|
|
||||||
preq.preq_flags = IEEE80211_MESHPREQ_FLAGS_AM;
|
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)
|
if (hs->hs_rootmode == IEEE80211_HWMP_ROOTMODE_PROACTIVE)
|
||||||
preq.preq_flags |= IEEE80211_MESHPREQ_FLAGS_PP;
|
preq.preq_flags |= IEEE80211_MESHPREQ_FLAGS_PP;
|
||||||
preq.preq_hopcount = 0;
|
preq.preq_hopcount = 0;
|
||||||
@ -695,8 +698,8 @@ hwmp_rootmode_rann_cb(void *arg)
|
|||||||
IEEE80211_NOTE(vap, IEEE80211_MSG_HWMP, vap->iv_bss,
|
IEEE80211_NOTE(vap, IEEE80211_MSG_HWMP, vap->iv_bss,
|
||||||
"%s", "send broadcast RANN");
|
"%s", "send broadcast RANN");
|
||||||
|
|
||||||
/* XXX check portal role */
|
if (ms->ms_flags & IEEE80211_MESHFLAGS_PORTAL)
|
||||||
rann.rann_flags = 0;
|
rann.rann_flags |= IEEE80211_MESHRANN_FLAGS_PR;
|
||||||
rann.rann_hopcount = 0;
|
rann.rann_hopcount = 0;
|
||||||
rann.rann_ttl = ms->ms_ttl;
|
rann.rann_ttl = ms->ms_ttl;
|
||||||
IEEE80211_ADDR_COPY(rann.rann_addr, vap->iv_myaddr);
|
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_state *ms = vap->iv_mesh;
|
||||||
struct ieee80211_mesh_route *rt = NULL;
|
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_hwmp_state *hs = vap->iv_hwmp;
|
||||||
struct ieee80211_meshprep_ie prep;
|
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");
|
preq->preq_origaddr, NULL, "%s", "not accepting PREQ");
|
||||||
return;
|
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.
|
* 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))) {
|
if (IEEE80211_ADDR_EQ(vap->iv_myaddr, PREQ_TADDR(0))) {
|
||||||
IEEE80211_NOTE(vap, IEEE80211_MSG_HWMP, ni,
|
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));
|
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.
|
* 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 &&
|
if (rt != NULL &&
|
||||||
(rt->rt_flags & IEEE80211_MESHRT_FLAGS_VALID)) {
|
(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 &&
|
if (preq->preq_ttl > 1 &&
|
||||||
preq->preq_hopcount < hs->hs_maxhops) {
|
preq->preq_hopcount < hs->hs_maxhops) {
|
||||||
IEEE80211_NOTE(vap, IEEE80211_MSG_HWMP, ni,
|
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;
|
prep.prep_ttl = ms->ms_ttl;
|
||||||
IEEE80211_ADDR_COPY(&prep.prep_targetaddr,
|
IEEE80211_ADDR_COPY(&prep.prep_targetaddr,
|
||||||
preq->preq_origaddr);
|
preq->preq_origaddr);
|
||||||
prep.prep_targetseq = hr->hr_seq;
|
prep.prep_targetseq = hrorig->hr_seq;
|
||||||
prep.prep_lifetime = preq->preq_lifetime;
|
prep.prep_lifetime = preq->preq_lifetime;
|
||||||
prep.prep_metric = rt->rt_metric +
|
prep.prep_metric = rt->rt_metric +
|
||||||
ms->ms_pmetric->mpm_metric(ni);
|
ms->ms_pmetric->mpm_metric(ni);
|
||||||
IEEE80211_ADDR_COPY(&prep.prep_origaddr,
|
IEEE80211_ADDR_COPY(&prep.prep_origaddr,
|
||||||
PREQ_TADDR(0));
|
PREQ_TADDR(0));
|
||||||
prep.prep_origseq = hs->hs_seq++;
|
prep.prep_origseq = hrorig->hr_seq;
|
||||||
hwmp_send_prep(ni, vap->iv_myaddr,
|
hwmp_send_prep(ni, vap->iv_myaddr,
|
||||||
broadcastaddr, &prep);
|
broadcastaddr, &prep);
|
||||||
}
|
}
|
||||||
@ -906,12 +920,12 @@ hwmp_recv_preq(struct ieee80211vap *vap, struct ieee80211_node *ni,
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
hr = IEEE80211_MESH_ROUTE_PRIV(rt,
|
|
||||||
struct ieee80211_hwmp_route);
|
|
||||||
rt->rt_metric = preq->preq_metric;
|
rt->rt_metric = preq->preq_metric;
|
||||||
rt->rt_lifetime = preq->preq_lifetime;
|
rt->rt_lifetime = preq->preq_lifetime;
|
||||||
hr->hr_seq = preq->preq_origseq;
|
hrorig = IEEE80211_MESH_ROUTE_PRIV(rt,
|
||||||
hr->hr_preqid = preq->preq_id;
|
struct ieee80211_hwmp_route);
|
||||||
|
hrorig->hr_seq = preq->preq_origseq;
|
||||||
|
hrorig->hr_preqid = preq->preq_id;
|
||||||
|
|
||||||
IEEE80211_NOTE(vap, IEEE80211_MSG_HWMP, ni,
|
IEEE80211_NOTE(vap, IEEE80211_MSG_HWMP, ni,
|
||||||
"forward PREQ from %s",
|
"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,
|
IEEE80211_NOTE(vap, IEEE80211_MSG_HWMP, ni,
|
||||||
"received PREP from %s", ether_sprintf(prep->prep_origaddr));
|
"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);
|
rt = ieee80211_mesh_rt_find(vap, prep->prep_origaddr);
|
||||||
if (rt == NULL) {
|
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_lifetime = prep->prep_lifetime;
|
||||||
rt->rt_metric = prep->prep_metric;
|
rt->rt_metric = prep->prep_metric;
|
||||||
rt->rt_flags |= IEEE80211_MESHRT_FLAGS_VALID;
|
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;
|
||||||
}
|
}
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
/*
|
||||||
|
* Sequence number validation.
|
||||||
|
*/
|
||||||
hr = IEEE80211_MESH_ROUTE_PRIV(rt, struct ieee80211_hwmp_route);
|
hr = IEEE80211_MESH_ROUTE_PRIV(rt, struct ieee80211_hwmp_route);
|
||||||
if (prep->prep_targetseq == hr->hr_seq) {
|
if (HWMP_SEQ_LEQ(prep->prep_origseq, hr->hr_seq)) {
|
||||||
int useprep = 0;
|
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 (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.
|
* Check if we already have a path to this node.
|
||||||
* If we do, check if this path reply contains a
|
* If we do, check if this path reply contains a
|
||||||
* better route.
|
* better route.
|
||||||
*/
|
*/
|
||||||
if ((rt->rt_flags & IEEE80211_MESHRT_FLAGS_VALID) == 0)
|
if ((rt->rt_flags & IEEE80211_MESHRT_FLAGS_VALID) == 0 ||
|
||||||
useprep = 1;
|
(prep->prep_hopcount < rt->rt_nhops ||
|
||||||
else if (prep->prep_hopcount < rt->rt_nhops ||
|
prep->prep_metric < rt->rt_metric)) {
|
||||||
prep->prep_metric < rt->rt_metric)
|
IEEE80211_NOTE(vap, IEEE80211_MSG_HWMP, ni,
|
||||||
useprep = 1;
|
"%s path to %s, hopcount %d:%d metric %d:%d",
|
||||||
if (useprep) {
|
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);
|
IEEE80211_ADDR_COPY(rt->rt_nexthop, wh->i_addr2);
|
||||||
rt->rt_nhops = prep->prep_hopcount;
|
rt->rt_nhops = prep->prep_hopcount;
|
||||||
rt->rt_lifetime = prep->prep_lifetime;
|
rt->rt_lifetime = prep->prep_lifetime;
|
||||||
rt->rt_metric = prep->prep_metric;
|
rt->rt_metric = prep->prep_metric;
|
||||||
rt->rt_flags |= IEEE80211_MESHRT_FLAGS_VALID;
|
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 {
|
} else {
|
||||||
IEEE80211_NOTE(vap, IEEE80211_MSG_HWMP, ni,
|
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,
|
ether_sprintf(prep->prep_origaddr), prep->prep_targetseq,
|
||||||
hr->hr_seq);
|
hr->hr_seq);
|
||||||
vap->iv_stats.is_hwmp_wrongseq++;
|
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.
|
* Check for frames queued awaiting path discovery.
|
||||||
* XXX probably can tell exactly and avoid remove call
|
* XXX probably can tell exactly and avoid remove call
|
||||||
@ -1125,7 +1158,8 @@ hwmp_peerdown(struct ieee80211_node *ni)
|
|||||||
perr.perr_ndests = 1;
|
perr.perr_ndests = 1;
|
||||||
IEEE80211_ADDR_COPY(PERR_DADDR(0), rt->rt_dest);
|
IEEE80211_ADDR_COPY(PERR_DADDR(0), rt->rt_dest);
|
||||||
PERR_DSEQ(0) = hr->hr_seq;
|
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);
|
hwmp_send_perr(vap->iv_bss, vap->iv_myaddr, broadcastaddr, &perr);
|
||||||
}
|
}
|
||||||
#undef PERR_DADDR
|
#undef PERR_DADDR
|
||||||
@ -1160,8 +1194,9 @@ hwmp_recv_perr(struct ieee80211vap *vap, struct ieee80211_node *ni,
|
|||||||
continue;
|
continue;
|
||||||
hr = IEEE80211_MESH_ROUTE_PRIV(rt,
|
hr = IEEE80211_MESH_ROUTE_PRIV(rt,
|
||||||
struct ieee80211_hwmp_route);
|
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_del(vap, rt->rt_dest);
|
||||||
|
ieee80211_mesh_rt_flush_peer(vap, rt->rt_dest);
|
||||||
rt = NULL;
|
rt = NULL;
|
||||||
forward = 1;
|
forward = 1;
|
||||||
}
|
}
|
||||||
@ -1174,7 +1209,8 @@ hwmp_recv_perr(struct ieee80211vap *vap, struct ieee80211_node *ni,
|
|||||||
IEEE80211_NOTE(vap, IEEE80211_MSG_HWMP, ni,
|
IEEE80211_NOTE(vap, IEEE80211_MSG_HWMP, ni,
|
||||||
"propagate PERR from %s", ether_sprintf(wh->i_addr2));
|
"propagate PERR from %s", ether_sprintf(wh->i_addr2));
|
||||||
memcpy(&pperr, perr, sizeof(*perr));
|
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
|
#undef PEER_DADDR
|
||||||
@ -1233,7 +1269,7 @@ hwmp_recv_rann(struct ieee80211vap *vap, struct ieee80211_node *ni,
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
hr = IEEE80211_MESH_ROUTE_PRIV(rt, struct ieee80211_hwmp_route);
|
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 &&
|
rann->rann_hopcount < hs->hs_maxhops &&
|
||||||
(ms->ms_flags & IEEE80211_MESHFLAGS_FWD)) {
|
(ms->ms_flags & IEEE80211_MESHFLAGS_FWD)) {
|
||||||
memcpy(&prann, rann, sizeof(prann));
|
memcpy(&prann, rann, sizeof(prann));
|
||||||
@ -1302,10 +1338,8 @@ hwmp_discover(struct ieee80211vap *vap,
|
|||||||
hr = IEEE80211_MESH_ROUTE_PRIV(rt,
|
hr = IEEE80211_MESH_ROUTE_PRIV(rt,
|
||||||
struct ieee80211_hwmp_route);
|
struct ieee80211_hwmp_route);
|
||||||
if ((rt->rt_flags & IEEE80211_MESHRT_FLAGS_VALID) == 0) {
|
if ((rt->rt_flags & IEEE80211_MESHRT_FLAGS_VALID) == 0) {
|
||||||
if (hr->hr_preqid == 0) {
|
if (hr->hr_targetseq == 0)
|
||||||
hr->hr_seq = ++hs->hs_seq;
|
hr->hr_targetseq = ++hs->hs_seq;
|
||||||
hr->hr_preqid = ++hs->hs_preqid;
|
|
||||||
}
|
|
||||||
rt->rt_metric = IEEE80211_MESHLMETRIC_INITIALVAL;
|
rt->rt_metric = IEEE80211_MESHLMETRIC_INITIALVAL;
|
||||||
rt->rt_lifetime =
|
rt->rt_lifetime =
|
||||||
ticks_to_msecs(ieee80211_hwmp_pathtimeout);
|
ticks_to_msecs(ieee80211_hwmp_pathtimeout);
|
||||||
@ -1321,9 +1355,9 @@ hwmp_discover(struct ieee80211vap *vap,
|
|||||||
preq.preq_flags = 0;
|
preq.preq_flags = 0;
|
||||||
preq.preq_hopcount = 0;
|
preq.preq_hopcount = 0;
|
||||||
preq.preq_ttl = ms->ms_ttl;
|
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);
|
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_lifetime = rt->rt_lifetime;
|
||||||
preq.preq_metric = rt->rt_metric;
|
preq.preq_metric = rt->rt_metric;
|
||||||
preq.preq_tcount = 1;
|
preq.preq_tcount = 1;
|
||||||
|
@ -240,8 +240,9 @@ struct ieee80211_stats {
|
|||||||
uint32_t is_mesh_rtaddfailed; /* route add failed */
|
uint32_t is_mesh_rtaddfailed; /* route add failed */
|
||||||
uint32_t is_mesh_notproxy; /* dropped 'cuz not proxying */
|
uint32_t is_mesh_notproxy; /* dropped 'cuz not proxying */
|
||||||
uint32_t is_rx_badalign; /* dropped 'cuz misaligned */
|
uint32_t is_rx_badalign; /* dropped 'cuz misaligned */
|
||||||
|
uint32_t is_hwmp_proxy; /* PREP for proxy route */
|
||||||
|
|
||||||
uint32_t is_spare[12];
|
uint32_t is_spare[11];
|
||||||
};
|
};
|
||||||
|
|
||||||
/*
|
/*
|
||||||
@ -333,10 +334,13 @@ enum {
|
|||||||
};
|
};
|
||||||
|
|
||||||
struct ieee80211req_mesh_route {
|
struct ieee80211req_mesh_route {
|
||||||
|
uint8_t imr_flags;
|
||||||
|
#define IEEE80211_MESHRT_FLAGS_VALID 0x01
|
||||||
|
#define IEEE80211_MESHRT_FLAGS_PROXY 0x02
|
||||||
uint8_t imr_dest[IEEE80211_ADDR_LEN];
|
uint8_t imr_dest[IEEE80211_ADDR_LEN];
|
||||||
uint8_t imr_nexthop[IEEE80211_ADDR_LEN];
|
uint8_t imr_nexthop[IEEE80211_ADDR_LEN];
|
||||||
uint16_t imr_nhops;
|
uint16_t imr_nhops;
|
||||||
uint16_t imr_pad;
|
uint8_t imr_pad;
|
||||||
uint32_t imr_metric;
|
uint32_t imr_metric;
|
||||||
uint32_t imr_lifetime;
|
uint32_t imr_lifetime;
|
||||||
uint32_t imr_lastmseq;
|
uint32_t imr_lastmseq;
|
||||||
|
@ -236,6 +236,8 @@ ieee80211_mesh_proxy_check(struct ieee80211vap *vap,
|
|||||||
"%s", "unable to add proxy entry");
|
"%s", "unable to add proxy entry");
|
||||||
vap->iv_stats.is_mesh_rtaddfailed++;
|
vap->iv_stats.is_mesh_rtaddfailed++;
|
||||||
} else {
|
} else {
|
||||||
|
IEEE80211_NOTE_MAC(vap, IEEE80211_MSG_MESH, dest,
|
||||||
|
"%s", "add proxy entry");
|
||||||
IEEE80211_ADDR_COPY(rt->rt_nexthop, vap->iv_myaddr);
|
IEEE80211_ADDR_COPY(rt->rt_nexthop, vap->iv_myaddr);
|
||||||
rt->rt_flags |= IEEE80211_MESHRT_FLAGS_VALID
|
rt->rt_flags |= IEEE80211_MESHRT_FLAGS_VALID
|
||||||
| IEEE80211_MESHRT_FLAGS_PROXY;
|
| IEEE80211_MESHRT_FLAGS_PROXY;
|
||||||
@ -301,6 +303,21 @@ ieee80211_mesh_rt_flush(struct ieee80211vap *vap)
|
|||||||
MESH_RT_UNLOCK(ms);
|
MESH_RT_UNLOCK(ms);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
ieee80211_mesh_rt_flush_peer(struct ieee80211vap *vap,
|
||||||
|
const uint8_t peer[IEEE80211_ADDR_LEN])
|
||||||
|
{
|
||||||
|
struct ieee80211_mesh_state *ms = vap->iv_mesh;
|
||||||
|
struct ieee80211_mesh_route *rt, *next;
|
||||||
|
|
||||||
|
MESH_RT_LOCK(ms);
|
||||||
|
TAILQ_FOREACH_SAFE(rt, &ms->ms_routes, rt_next, next) {
|
||||||
|
if (IEEE80211_ADDR_EQ(rt->rt_nexthop, peer))
|
||||||
|
mesh_rt_del(ms, rt);
|
||||||
|
}
|
||||||
|
MESH_RT_UNLOCK(ms);
|
||||||
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Flush expired routing entries, i.e. those in invalid state for
|
* Flush expired routing entries, i.e. those in invalid state for
|
||||||
* some time.
|
* some time.
|
||||||
@ -770,6 +787,7 @@ mesh_generateid(struct ieee80211vap *vap)
|
|||||||
/*
|
/*
|
||||||
* Verifies if we already received this packet by checking its
|
* Verifies if we already received this packet by checking its
|
||||||
* sequence number.
|
* sequence number.
|
||||||
|
* Returns 0 if the frame is to be accepted, 1 otherwise.
|
||||||
*/
|
*/
|
||||||
static int
|
static int
|
||||||
mesh_checkpseq(struct ieee80211vap *vap,
|
mesh_checkpseq(struct ieee80211vap *vap,
|
||||||
@ -779,11 +797,16 @@ mesh_checkpseq(struct ieee80211vap *vap,
|
|||||||
|
|
||||||
rt = ieee80211_mesh_rt_find(vap, source);
|
rt = ieee80211_mesh_rt_find(vap, source);
|
||||||
if (rt == NULL) {
|
if (rt == NULL) {
|
||||||
|
rt = ieee80211_mesh_rt_add(vap, source);
|
||||||
|
if (rt == NULL) {
|
||||||
|
IEEE80211_NOTE_MAC(vap, IEEE80211_MSG_MESH, source,
|
||||||
|
"%s", "add mcast route failed");
|
||||||
|
vap->iv_stats.is_mesh_rtaddfailed++;
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
IEEE80211_NOTE_MAC(vap, IEEE80211_MSG_MESH, source,
|
IEEE80211_NOTE_MAC(vap, IEEE80211_MSG_MESH, source,
|
||||||
"add mcast route, mesh seqno %d", seq);
|
"add mcast route, mesh seqno %d", seq);
|
||||||
rt = ieee80211_mesh_rt_add(vap, source);
|
rt->rt_lastmseq = seq;
|
||||||
if (rt != NULL)
|
|
||||||
rt->rt_lastmseq = seq;
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
if (IEEE80211_MESH_SEQ_GEQ(rt->rt_lastmseq, seq)) {
|
if (IEEE80211_MESH_SEQ_GEQ(rt->rt_lastmseq, seq)) {
|
||||||
@ -1159,9 +1182,6 @@ mesh_input(struct ieee80211_node *ni, struct mbuf *m, int rssi, int nf)
|
|||||||
goto out;
|
goto out;
|
||||||
}
|
}
|
||||||
if (mesh_checkpseq(vap, addr, seq) != 0) {
|
if (mesh_checkpseq(vap, addr, seq) != 0) {
|
||||||
IEEE80211_DISCARD_MAC(vap, IEEE80211_MSG_MESH,
|
|
||||||
addr, "data", "duplicate mesh seqno %u ttl %u",
|
|
||||||
seq, mc->mc_ttl);
|
|
||||||
vap->iv_stats.is_rx_dup++;
|
vap->iv_stats.is_rx_dup++;
|
||||||
goto out;
|
goto out;
|
||||||
}
|
}
|
||||||
@ -2642,6 +2662,7 @@ mesh_ioctl_get80211(struct ieee80211vap *vap, struct ieee80211req *ireq)
|
|||||||
break;
|
break;
|
||||||
imr = (struct ieee80211req_mesh_route *)
|
imr = (struct ieee80211req_mesh_route *)
|
||||||
(p + off);
|
(p + off);
|
||||||
|
imr->imr_flags = rt->rt_flags;
|
||||||
IEEE80211_ADDR_COPY(imr->imr_dest,
|
IEEE80211_ADDR_COPY(imr->imr_dest,
|
||||||
rt->rt_dest);
|
rt->rt_dest);
|
||||||
IEEE80211_ADDR_COPY(imr->imr_nexthop,
|
IEEE80211_ADDR_COPY(imr->imr_nexthop,
|
||||||
|
@ -469,6 +469,8 @@ struct ieee80211_mesh_route *
|
|||||||
void ieee80211_mesh_rt_del(struct ieee80211vap *,
|
void ieee80211_mesh_rt_del(struct ieee80211vap *,
|
||||||
const uint8_t [IEEE80211_ADDR_LEN]);
|
const uint8_t [IEEE80211_ADDR_LEN]);
|
||||||
void ieee80211_mesh_rt_flush(struct ieee80211vap *);
|
void ieee80211_mesh_rt_flush(struct ieee80211vap *);
|
||||||
|
void ieee80211_mesh_rt_flush_peer(struct ieee80211vap *,
|
||||||
|
const uint8_t [IEEE80211_ADDR_LEN]);
|
||||||
void ieee80211_mesh_proxy_check(struct ieee80211vap *,
|
void ieee80211_mesh_proxy_check(struct ieee80211vap *,
|
||||||
const uint8_t [IEEE80211_ADDR_LEN]);
|
const uint8_t [IEEE80211_ADDR_LEN]);
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user