mac80211: implement the proactive PREP generation
authorChun-Yeow Yeoh <yeohchunyeow@gmail.com>
Sat, 16 Jun 2012 18:27:40 +0000 (02:27 +0800)
committerJohannes Berg <johannes.berg@intel.com>
Mon, 18 Jun 2012 11:54:38 +0000 (13:54 +0200)
Generate the proactive PREP element in Proactive PREQ mode as
defined in Sec. 13.10.10.3 (Case D) of IEEE Std. 802.11-2012.

Signed-off-by: Chun-Yeow Yeoh <yeohchunyeow@gmail.com>
Signed-off-by: Johannes Berg <johannes.berg@intel.com>
net/mac80211/mesh_hwmp.c

index a6b08f5c4612bfe60d56c64910f75a0b82e157a3..35e3acbe22624f3874f3cfbde8741dcbb9a40bc3 100644 (file)
@@ -516,10 +516,11 @@ static void hwmp_preq_frame_process(struct ieee80211_sub_if_data *sdata,
        struct mesh_path *mpath = NULL;
        u8 *target_addr, *orig_addr;
        const u8 *da;
-       u8 target_flags, ttl;
-       u32 orig_sn, target_sn, lifetime;
+       u8 target_flags, ttl, flags;
+       u32 orig_sn, target_sn, lifetime, orig_metric;
        bool reply = false;
        bool forward = true;
+       bool root_is_gate;
 
        /* Update target SN, if present */
        target_addr = PREQ_IE_TARGET_ADDR(preq_elem);
@@ -527,6 +528,10 @@ static void hwmp_preq_frame_process(struct ieee80211_sub_if_data *sdata,
        target_sn = PREQ_IE_TARGET_SN(preq_elem);
        orig_sn = PREQ_IE_ORIG_SN(preq_elem);
        target_flags = PREQ_IE_TARGET_F(preq_elem);
+       orig_metric = metric;
+       /* Proactive PREQ gate announcements */
+       flags = PREQ_IE_FLAGS(preq_elem);
+       root_is_gate = !!(flags & RANN_FLAG_IS_GATE);
 
        mhwmp_dbg("received PREQ from %pM", orig_addr);
 
@@ -541,6 +546,22 @@ static void hwmp_preq_frame_process(struct ieee80211_sub_if_data *sdata,
                        target_sn = ++ifmsh->sn;
                        ifmsh->last_sn_update = jiffies;
                }
+       } else if (is_broadcast_ether_addr(target_addr) &&
+                  (target_flags & IEEE80211_PREQ_TO_FLAG)) {
+               rcu_read_lock();
+               mpath = mesh_path_lookup(orig_addr, sdata);
+               if (mpath) {
+                       if (flags & IEEE80211_PREQ_PROACTIVE_PREP_FLAG) {
+                               reply = true;
+                               target_addr = sdata->vif.addr;
+                               target_sn = ++ifmsh->sn;
+                               metric = 0;
+                               ifmsh->last_sn_update = jiffies;
+                       }
+                       if (root_is_gate)
+                               mesh_path_add_gate(mpath);
+               }
+               rcu_read_unlock();
        } else {
                rcu_read_lock();
                mpath = mesh_path_lookup(target_addr, sdata);
@@ -573,13 +594,14 @@ static void hwmp_preq_frame_process(struct ieee80211_sub_if_data *sdata,
                                cpu_to_le32(target_sn), mgmt->sa, 0, ttl,
                                cpu_to_le32(lifetime), cpu_to_le32(metric),
                                0, sdata);
-               } else
+               } else {
                        ifmsh->mshstats.dropped_frames_ttl++;
+               }
        }
 
        if (forward && ifmsh->mshcfg.dot11MeshForwarding) {
                u32 preq_id;
-               u8 hopcount, flags;
+               u8 hopcount;
 
                ttl = PREQ_IE_TTL(preq_elem);
                lifetime = PREQ_IE_LIFETIME(preq_elem);
@@ -589,11 +611,17 @@ static void hwmp_preq_frame_process(struct ieee80211_sub_if_data *sdata,
                }
                mhwmp_dbg("forwarding the PREQ from %pM", orig_addr);
                --ttl;
-               flags = PREQ_IE_FLAGS(preq_elem);
                preq_id = PREQ_IE_PREQ_ID(preq_elem);
                hopcount = PREQ_IE_HOPCOUNT(preq_elem) + 1;
                da = (mpath && mpath->is_root) ?
                        mpath->rann_snd_addr : broadcast_addr;
+
+               if (flags & IEEE80211_PREQ_PROACTIVE_PREP_FLAG) {
+                       target_addr = PREQ_IE_TARGET_ADDR(preq_elem);
+                       target_sn = PREQ_IE_TARGET_SN(preq_elem);
+                       metric = orig_metric;
+               }
+
                mesh_path_sel_frame_tx(MPATH_PREQ, flags, orig_addr,
                                cpu_to_le32(orig_sn), target_flags, target_addr,
                                cpu_to_le32(target_sn), da,