Date: Wed, 11 Jan 2012 05:40:58 +0100 From: Monthadar Al Jaberi <monthadar@gmail.com> To: freebsd-wireless@freebsd.org Subject: 11s mesh path setup problem Message-ID: <CA%2BsBSoJWXD5S-zvxHR_=iwh26G0bd00trR=E-jCUBD03uMrU%2BQ@mail.gmail.com>
next in thread | raw e-mail | index | archive | help
[-- Attachment #1 --] Hi, Current hwmp cant handle to setup a path between 4 nodes in a line topology (among other things it cant handle) Below you will find a small patch to correct this with some debug output cleanup and comments. After the patch, you should be able to e.g. ping from node 4 to node 1 and get a ping reply back, he is what the output from ifconfig list mesh should look like on all 4 nodes after one ping packet. Node1# ifconfig wlan1 list mesh DEST NEXT HOP HOPS METRIC LIFETIME MSEQ FLAGS Node2 Node2 1 17018 5000 0 V Node3 Node2 2 34036 5000 0 V Node4 Node2 3 34036 5000 3 V Node2# ifconfig wlan1 list mesh DEST NEXT HOP HOPS METRIC LIFETIME MSEQ FLAGS Node1 Node1 1 17018 5000 3 V Node3 Node3 1 17018 5000 0 V Node4 Node3 2 17018 5000 3 V Node3# ifconfig wlan1 list mesh DEST NEXT HOP HOPS METRIC LIFETIME MSEQ FLAGS Node2 Node2 1 0 5000 0 V Node4 Node4 1 0 5000 3 V Node1 Node2 2 34036 5000 3 V Node4# ifconfig wlan1 list mesh DEST NEXT HOP HOPS METRIC LIFETIME MSEQ FLAGS Node3 Node3 1 0 5000 0 V Node1 Node3 3 51054 5000 3 V If anyone could try it that would be nice, either on real hardware as I did above, or in a simulated environment (https://github.com/monthadar/FreeBSD-IEEE80211s-simulator/wiki) :) and please do test other scenarios :) patch is attached. -- Monthadar Al Jaberi [-- Attachment #2 --] diff --git a/sys/net/if_ethersubr.c b/sys/net/if_ethersubr.c index 1d16ae6..fc86c94 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)%2; + return (buf); } /* diff --git a/sys/net80211/ieee80211_hwmp.c b/sys/net80211/ieee80211_hwmp.c index 78729fc..7c99351 100644 --- a/sys/net80211/ieee80211_hwmp.c +++ b/sys/net80211/ieee80211_hwmp.c @@ -139,9 +139,13 @@ 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) + /* * Private extension of ieee80211_mesh_route. */ @@ -676,8 +680,10 @@ 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_mesh_route *rtorig = NULL; - struct ieee80211_hwmp_route *hrorig; + struct ieee80211_mesh_route *rtorig = NULL; // Originator route + struct ieee80211_mesh_route *rttarg = NULL; // Target route + struct ieee80211_hwmp_route *hrorig = NULL; + struct ieee80211_hwmp_route *hrtarg = NULL; struct ieee80211_hwmp_state *hs = vap->iv_hwmp; struct ieee80211_meshprep_ie prep; @@ -692,46 +698,83 @@ 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)) || /* need to check PROXY */ + !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"); return; } + /* + * Acceptance criteria: if unicast addressed + * AND no valid forwarding for Target of PREQ, discard this PREQ. + */ + rttarg = ieee80211_mesh_rt_find(vap, PREQ_TADDR(0)); + if(rttarg != NULL) + hrtarg = IEEE80211_MESH_ROUTE_PRIV(rttarg, struct ieee80211_hwmp_route); + if((preq->preq_flags & IEEE80211_MESHPREQ_FLAGS_AM) == 0 && /* address mode: ucast */ + rttarg == NULL && + !IEEE80211_ADDR_EQ(vap->iv_myaddr, PREQ_TADDR(0))) { + IEEE80211_DISCARD_MAC(vap, IEEE80211_MSG_HWMP, + preq->preq_origaddr, NULL, "unicast addressed PREQ of unknown target %s", + 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. + + /* Data creation and update of forwarding information + * according to Table 11C-8 for originator mesh STA. */ - if (HWMP_SEQ_LEQ(preq->preq_id, hrorig->hr_preqid) && - HWMP_SEQ_LEQ(preq->preq_origseq, hrorig->hr_seq)) { + 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)){ + 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); + rtorig->rt_flags |= IEEE80211_MESHRT_FLAGS_VALID; /* path to orig is valid now */ + }else if(hrtarg != NULL && + HWMP_SEQ_EQ(hrtarg->hr_seq, PREQ_TSEQ(0)) && + (rtorig->rt_flags & IEEE80211_MESHRT_FLAGS_VALID) == 0){ 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); + "received PREQ, originator %s", "unknown"); + }else{ + IEEE80211_DISCARD_MAC(vap, IEEE80211_MSG_HWMP, + preq->preq_origaddr, NULL, "%s, last seen orig.seq %d, preq orig.seq %d", "discarding PREQ", hrorig->hr_seq, preq->preq_origseq); return; } - hrorig->hr_preqid = preq->preq_id; - hrorig->hr_seq = preq->preq_origseq; + + /* + * Forwarding information for transmitter mesh STA + * [OPTIONAL: if metric improved] + */ /* * 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)); + "reply PREP, originator %s", ether_sprintf(preq->preq_origaddr)); /* * Build and send a PREP frame. */ @@ -819,11 +862,13 @@ hwmp_recv_preq(struct ieee80211vap *vap, struct ieee80211_node *ni, 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)); + "forward PREQ, originator %s, to %s", + ether_sprintf(preq->preq_origaddr), ether_sprintf(rt->rt_nexthop)); /* * Propagate the original PREQ. + * PREQ is unicast now to rt->rt_nexthop */ + ppreq.preq_flags &= ~IEEE80211_MESHPREQ_FLAGS_AM; ppreq.preq_hopcount += 1; ppreq.preq_ttl -= 1; ppreq.preq_metric += @@ -837,7 +882,7 @@ hwmp_recv_preq(struct ieee80211vap *vap, struct ieee80211_node *ni, ppreq.preq_targets[0].target_flags &= ~IEEE80211_MESHPREQ_TFLAGS_RF; hwmp_send_preq(ni, vap->iv_myaddr, - broadcastaddr, &ppreq); + rt->rt_nexthop, &ppreq); } /* * Check if we can send an intermediate Path Reply, @@ -870,26 +915,11 @@ hwmp_recv_preq(struct ieee80211vap *vap, struct ieee80211_node *ni, */ } 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; - } - } - 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; - IEEE80211_NOTE(vap, IEEE80211_MSG_HWMP, ni, - "forward PREQ from %s", - ether_sprintf(preq->preq_origaddr)); + "broadcast PREQ, originator %s, target %s", + ether_sprintf(preq->preq_origaddr), + ether_sprintf(PREQ_TADDR(0))); + ppreq.preq_flags |= IEEE80211_MESHPREQ_FLAGS_AM; ppreq.preq_hopcount += 1; ppreq.preq_ttl -= 1; ppreq.preq_metric += ms->ms_pmetric->mpm_metric(ni); @@ -956,12 +986,14 @@ hwmp_recv_prep(struct ieee80211vap *vap, struct ieee80211_node *ni, return; 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 we have no entry this could be a reply to a root PREQ. + * XXX: not true anymore cause we dont create entry for target when + * propagating PREQs like the old code did. */ if (hs->hs_rootmode != IEEE80211_HWMP_ROOTMODE_DISABLED) { rt = ieee80211_mesh_rt_add(vap, prep->prep_targetaddr); @@ -989,13 +1021,23 @@ hwmp_recv_prep(struct ieee80211vap *vap, struct ieee80211_node *ni, * Sequence number validation. */ hr = IEEE80211_MESH_ROUTE_PRIV(rt, struct ieee80211_hwmp_route); - if (HWMP_SEQ_LEQ(prep->prep_targetseq, hr->hr_seq)) { + if((rt->rt_flags & IEEE80211_MESHRT_FLAGS_VALID)){ // Accept if route is not valid + if (HWMP_SEQ_LT(prep->prep_targetseq, hr->hr_seq)) { IEEE80211_NOTE(vap, IEEE80211_MSG_HWMP, ni, - "discard PREP from %s, old seq no %u <= %u", + "discard PREP from %s, old seq no %u < %u", ether_sprintf(prep->prep_targetaddr), prep->prep_targetseq, hr->hr_seq); return; + }else if(HWMP_SEQ_LEQ(prep->prep_targetseq, hr->hr_seq) && //If same seqno compare metric + prep->prep_metric > rt->rt_metric) { + IEEE80211_NOTE(vap, IEEE80211_MSG_HWMP, ni, + "discard PREP from %s, new metric %u > %u", + ether_sprintf(prep->prep_targetaddr), + prep->prep_metric, rt->rt_metric); + return; + } } + hr->hr_seq = prep->prep_targetseq; /* * If it's NOT for us, propagate the PREP. @@ -1012,7 +1054,6 @@ hwmp_recv_prep(struct ieee80211vap *vap, struct ieee80211_node *ni, 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); } hr = IEEE80211_MESH_ROUTE_PRIV(rt, struct ieee80211_hwmp_route); @@ -1022,7 +1063,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) { + } else if (hr->hr_origseq == 0 || prep->prep_origseq == hr->hr_origseq) { //first path discovery always fail! /* * Check if we already have a path to this node. * If we do, check if this path reply contains a @@ -1031,15 +1072,16 @@ hwmp_recv_prep(struct ieee80211vap *vap, struct ieee80211_node *ni, 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; 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, + ether_sprintf(prep->prep_targetaddr), + rt->rt_nhops, prep->prep_hopcount + 1, rt->rt_metric, prep->prep_metric); IEEE80211_ADDR_COPY(rt->rt_nexthop, wh->i_addr2); - rt->rt_nhops = prep->prep_hopcount; + rt->rt_nhops = prep->prep_hopcount + 1; rt->rt_lifetime = prep->prep_lifetime; rt->rt_metric = prep->prep_metric; rt->rt_flags |= IEEE80211_MESHRT_FLAGS_VALID; @@ -1052,9 +1094,9 @@ hwmp_recv_prep(struct ieee80211vap *vap, struct ieee80211_node *ni, } } else { IEEE80211_NOTE(vap, IEEE80211_MSG_HWMP, ni, - "discard PREP for %s, wrong seqno %u != %u", + "discard PREP for %s, wrong orig seqno %u != %u", ether_sprintf(prep->prep_targetaddr), prep->prep_origseq, - hr->hr_seq); + hr->hr_origseq); vap->iv_stats.is_hwmp_wrongseq++; } /* @@ -1323,13 +1365,13 @@ 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; /* Group addressed PREQ Case A */ preq.preq_hopcount = 0; preq.preq_ttl = ms->ms_ttl; preq.preq_id = ++hs->hs_preqid; @@ -1345,7 +1387,7 @@ hwmp_discover(struct ieee80211vap *vap, 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);
Want to link to this message? Use this URL: <https://mail-archive.FreeBSD.org/cgi/mid.cgi?CA%2BsBSoJWXD5S-zvxHR_=iwh26G0bd00trR=E-jCUBD03uMrU%2BQ>
