[PATCH v2] mac80211: mesh: update target SN when new origin SN RX'ed

This patch is to address a HWMP mesh path selection bug
found by Bob Copeland.  If a STA sends a PREQ, it may
reach its target as multiple PREQs via PREQ propagation.
Previously, if the STA is the target, it would increment
its own SN if it was within net_traversal_jiffies of the
last update *and* use this as the target SN in the PREP.
The PREQs arriving just after (less than
net_traversal_jiffies later) would not meet the criteria
for SN update and would use the older SN.   Later, these
paths would be ignored during path selection since an
older SN indicates a staler path.

In the IEEE 802.11-2012 standard, section 13.10.8.3
indicates that the STA shall "shall update its own HWMP SN
to maximum (current HWMP SN, target HWMP SN in the PREQ) +
1 immediately before it generates a PREP in response to a
PREQ".

However, since this would result in all of the PREPs in
reponse to the single PREQ having different target SN's,
here we increment the STA's SN if we detect a new origin
SN.

As a result, now when the PREQ's are RX'ed at the target,
they will each receive the same target SN.

Note that net_traversal_jiffies should only
applies to updating a STA's origin SN as per section
13.10.8.6.  It only applies to when the station is an
originating station generating a PREQ.

Signed-off-by: Colleen Twitty <[email protected]>
---
changes:
        renaming old_sn to old_orig_sn, use SN_GT instead of LT (Bob Copeland)
        add macro for SN max which respects their arithmetic (Bob Copeland)
        whitespace (Bob Copeland)
        commit message which describes bug (Thomas Pederson)

 net/mac80211/mesh_hwmp.c | 44 ++++++++++++++++++++++++++++++++++++--------
 1 file changed, 36 insertions(+), 8 deletions(-)

diff --git a/net/mac80211/mesh_hwmp.c b/net/mac80211/mesh_hwmp.c
index f951468..27f2c677 100644
--- a/net/mac80211/mesh_hwmp.c
+++ b/net/mac80211/mesh_hwmp.c
@@ -79,6 +79,7 @@ static inline u32 u16_field_get(const u8 *preq_elem, int 
offset, bool ae)
 #define MSEC_TO_TU(x) (x*1000/1024)
 #define SN_GT(x, y) ((s32)(y - x) < 0)
 #define SN_LT(x, y) ((s32)(x - y) < 0)
+#define SN_MAX(x, y) (SN_GT((x), (y)) ? (x) : (y))
 
 #define net_traversal_jiffies(s) \
        msecs_to_jiffies(s->u.mesh.mshcfg.dot11MeshHWMPnetDiameterTraversalTime)
@@ -511,7 +512,8 @@ static u32 hwmp_route_info_get(struct ieee80211_sub_if_data 
*sdata,
 
 static void hwmp_preq_frame_process(struct ieee80211_sub_if_data *sdata,
                                    struct ieee80211_mgmt *mgmt,
-                                   const u8 *preq_elem, u32 metric)
+                                   const u8 *preq_elem, u32 metric,
+                                   bool chk_old_orig_sn, u32 old_sn)
 {
        struct ieee80211_if_mesh *ifmsh = &sdata->u.mesh;
        struct mesh_path *mpath = NULL;
@@ -541,12 +543,22 @@ static void hwmp_preq_frame_process(struct 
ieee80211_sub_if_data *sdata,
                forward = false;
                reply = true;
                metric = 0;
-               if (time_after(jiffies, ifmsh->last_sn_update +
-                                       net_traversal_jiffies(sdata)) ||
-                   time_before(jiffies, ifmsh->last_sn_update)) {
-                       target_sn = ++ifmsh->sn;
-                       ifmsh->last_sn_update = jiffies;
-               }
+
+               /* 802.11-2012 Sec. 13.10.8.3 HWMP sequence numbering calls for
+               * the target HWMP seq number to be incremented after each
+               * processed PREQ, but that would result in all but the last
+               * PREP metric info to be ignored.  Instead, we only increment
+               * the target SN when we detect that the originator SN has
+               * changed.  This results in all the PREPs generated in response
+               * to a single  PREQ to have the same seq num, and, therefore,
+               * for the metrics for the different paths to be taken into
+               * account.
+               */
+
+               if (chk_old_orig_sn && SN_GT(orig_sn, old_sn))
+                       ifmsh->sn = SN_MAX(ifmsh->sn, target_sn) + 1;
+
+               target_sn = ifmsh->sn;
        } else if (is_broadcast_ether_addr(target_addr) &&
                   (target_flags & IEEE80211_PREQ_TO_FLAG)) {
                rcu_read_lock();
@@ -856,6 +868,10 @@ void mesh_rx_path_sel_frame(struct ieee80211_sub_if_data 
*sdata,
        size_t baselen;
        u32 last_hop_metric;
        struct sta_info *sta;
+       struct mesh_path *mpath = NULL;
+       u32 old_orig_sn = 0;
+       const u8 *orig_addr;
+       bool chk_old_orig_sn = false;
 
        /* need action_code */
        if (len < IEEE80211_MIN_ACTION_SIZE + 1)
@@ -877,11 +893,23 @@ void mesh_rx_path_sel_frame(struct ieee80211_sub_if_data 
*sdata,
                if (elems.preq_len != 37)
                        /* Right now we support just 1 destination and no AE */
                        return;
+
+               orig_addr = PREQ_IE_ORIG_ADDR(elems.preq);
+
+               rcu_read_lock();
+               mpath = mesh_path_lookup(sdata, orig_addr);
+               if (mpath) {
+                       chk_old_orig_sn = true;
+                       old_orig_sn = mpath->sn;
+               }
+               rcu_read_unlock();
+
                last_hop_metric = hwmp_route_info_get(sdata, mgmt, elems.preq,
                                                      MPATH_PREQ);
                if (last_hop_metric)
                        hwmp_preq_frame_process(sdata, mgmt, elems.preq,
-                                               last_hop_metric);
+                                               last_hop_metric,
+                                               chk_old_orig_sn, old_orig_sn);
        }
        if (elems.prep) {
                if (elems.prep_len != 31)
-- 
1.8.4.3

_______________________________________________
Devel mailing list
[email protected]
http://lists.open80211s.org/cgi-bin/mailman/listinfo/devel

Reply via email to