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