This enables us to specify a simulated loss probability per mesh peer link.
Useful to simulate and test different mesh topologies and test different mesh
metrics.

The simulated loss rate setting can be configured as a plink action.  The
intended use is:

iw dev mesh station set <MAC> plink_action loss 25

Signed-off-by: Andrey Yurovsky <[email protected]>
Signed-off-by: Javier Cardona <[email protected]>
---
 include/linux/nl80211.h   |    4 +++
 include/net/cfg80211.h    |    4 +++
 net/mac80211/cfg.c        |    6 +++++
 net/mac80211/mesh.c       |    1 +
 net/mac80211/mesh.h       |    1 +
 net/mac80211/mesh_hwmp.c  |    1 +
 net/mac80211/mesh_plink.c |    6 +++++
 net/mac80211/sta_info.h   |    1 +
 net/mac80211/tx.c         |   54 +++++++++++++++++++++++++++++++++++++++++++-
 net/wireless/nl80211.c    |    9 +++++++
 10 files changed, 85 insertions(+), 2 deletions(-)

diff --git a/include/linux/nl80211.h b/include/linux/nl80211.h
index a8d71ed..3de615b 100644
--- a/include/linux/nl80211.h
+++ b/include/linux/nl80211.h
@@ -713,6 +713,7 @@ enum nl80211_attrs {
        NL80211_ATTR_KEYS,
 
        NL80211_ATTR_PID,
+       NL80211_ATTR_SIM_LOSS,
 
        /* add attributes here, update the policy in nl80211.c */
 
@@ -1198,6 +1199,8 @@ enum nl80211_mntr_flags {
  *
  * @NL80211_MESHCONF_ATTR_MAX: highest possible mesh configuration attribute
  *
+ * @NL80211_MESHCONF_SIM_LOSS_RATE: simulated loss rate at this MP.
+ *
  * @__NL80211_MESHCONF_ATTR_AFTER_LAST: internal use
  */
 enum nl80211_meshconf_params {
@@ -1215,6 +1218,7 @@ enum nl80211_meshconf_params {
        NL80211_MESHCONF_HWMP_ACTIVE_PATH_TIMEOUT,
        NL80211_MESHCONF_HWMP_PREQ_MIN_INTERVAL,
        NL80211_MESHCONF_HWMP_NET_DIAM_TRVS_TIME,
+       NL80211_MESHCONF_SIM_LOSS_RATE,
 
        /* keep last */
        __NL80211_MESHCONF_ATTR_AFTER_LAST,
diff --git a/include/net/cfg80211.h b/include/net/cfg80211.h
index d5756c9..6bc5957 100644
--- a/include/net/cfg80211.h
+++ b/include/net/cfg80211.h
@@ -265,6 +265,7 @@ enum plink_actions {
        PLINK_ACTION_INVALID,
        PLINK_ACTION_OPEN,
        PLINK_ACTION_BLOCK,
+       PLINK_ACTION_LOSS,
 };
 
 /**
@@ -282,6 +283,7 @@ enum plink_actions {
  *     (bitmask of BIT(NL80211_STA_FLAG_...))
  * @listen_interval: listen interval or -1 for no change
  * @aid: AID or zero for no change
+ * @sim_loss_rate: simulated TX probable loss percentage
  */
 struct station_parameters {
        u8 *supported_rates;
@@ -292,6 +294,7 @@ struct station_parameters {
        u8 supported_rates_len;
        u8 plink_action;
        struct ieee80211_ht_cap *ht_capa;
+       u8 sim_loss_rate;
 };
 
 /**
@@ -508,6 +511,7 @@ struct mesh_config {
        u32 dot11MeshHWMPactivePathTimeout;
        u16 dot11MeshHWMPpreqMinInterval;
        u16 dot11MeshHWMPnetDiameterTraversalTime;
+       u8 dot11MeshSimLossRate;
 };
 
 /**
diff --git a/net/mac80211/cfg.c b/net/mac80211/cfg.c
index 5608f6c..8067f66 100644
--- a/net/mac80211/cfg.c
+++ b/net/mac80211/cfg.c
@@ -693,6 +693,9 @@ static void sta_apply_parameters(struct ieee80211_local 
*local,
                case PLINK_ACTION_BLOCK:
                        mesh_plink_block(sta);
                        break;
+               case PLINK_ACTION_LOSS:
+                       mesh_plink_sim_loss(sta, params->sim_loss_rate);
+                       break;
                }
        }
 }
@@ -1043,6 +1046,9 @@ static int ieee80211_set_mesh_params(struct wiphy *wiphy,
                           mask))
                conf->dot11MeshHWMPnetDiameterTraversalTime =
                        nconf->dot11MeshHWMPnetDiameterTraversalTime;
+       if (_chg_mesh_attr(NL80211_MESHCONF_SIM_LOSS_RATE, mask))
+               conf->dot11MeshSimLossRate =
+                       nconf->dot11MeshSimLossRate;
        return 0;
 }
 
diff --git a/net/mac80211/mesh.c b/net/mac80211/mesh.c
index 8c068e2..d9292a9 100644
--- a/net/mac80211/mesh.c
+++ b/net/mac80211/mesh.c
@@ -653,6 +653,7 @@ void ieee80211_mesh_init_sdata(struct ieee80211_sub_if_data 
*sdata)
                MESH_PATH_REFRESH_TIME;
        ifmsh->mshcfg.min_discovery_timeout =
                MESH_MIN_DISCOVERY_TIMEOUT;
+       ifmsh->mshcfg.dot11MeshSimLossRate = 0;
        ifmsh->accepting_plinks = true;
        ifmsh->preq_id = 0;
        ifmsh->dsn = 0;
diff --git a/net/mac80211/mesh.h b/net/mac80211/mesh.h
index 6aaf1ec..8e70dae 100644
--- a/net/mac80211/mesh.h
+++ b/net/mac80211/mesh.h
@@ -238,6 +238,7 @@ void mesh_plink_broken(struct sta_info *sta);
 void mesh_plink_deactivate(struct sta_info *sta);
 int mesh_plink_open(struct sta_info *sta);
 void mesh_plink_block(struct sta_info *sta);
+void mesh_plink_sim_loss(struct sta_info *sta, u8 rate);
 void mesh_rx_plink_frame(struct ieee80211_sub_if_data *sdata,
                         struct ieee80211_mgmt *mgmt, size_t len,
                         struct ieee80211_rx_status *rx_status);
diff --git a/net/mac80211/mesh_hwmp.c b/net/mac80211/mesh_hwmp.c
index 1cd1e72..b4309b2 100644
--- a/net/mac80211/mesh_hwmp.c
+++ b/net/mac80211/mesh_hwmp.c
@@ -272,6 +272,7 @@ static u32 hwmp_route_info_get(struct ieee80211_sub_if_data 
*sdata,
        }
 
        last_hop_metric = airtime_link_metric_get(local, sta);
+       printk("XXX: last_hop_metric = %d\n", last_hop_metric);
        /* Update and check originator routing info */
        fresh_info = true;
 
diff --git a/net/mac80211/mesh_plink.c b/net/mac80211/mesh_plink.c
index cb14253..7c49c95 100644
--- a/net/mac80211/mesh_plink.c
+++ b/net/mac80211/mesh_plink.c
@@ -382,6 +382,12 @@ void mesh_plink_block(struct sta_info *sta)
        spin_unlock_bh(&sta->lock);
 }
 
+void mesh_plink_sim_loss(struct sta_info *sta, u8 rate)
+{
+       spin_lock_bh(&sta->lock);
+       sta->plink_sim_loss = rate;
+       spin_unlock_bh(&sta->lock);
+}
 
 void mesh_rx_plink_frame(struct ieee80211_sub_if_data *sdata, struct 
ieee80211_mgmt *mgmt,
                         size_t len, struct ieee80211_rx_status *rx_status)
diff --git a/net/mac80211/sta_info.h b/net/mac80211/sta_info.h
index ccc3adf..a248a8b 100644
--- a/net/mac80211/sta_info.h
+++ b/net/mac80211/sta_info.h
@@ -294,6 +294,7 @@ struct sta_info {
        bool ignore_plink_timer;
        bool plink_timer_was_running;
        enum plink_state plink_state;
+       u8 plink_sim_loss;
        u32 plink_timeout;
        struct timer_list plink_timer;
 #endif
diff --git a/net/mac80211/tx.c b/net/mac80211/tx.c
index c9be9dc..0df5a96 100644
--- a/net/mac80211/tx.c
+++ b/net/mac80211/tx.c
@@ -18,6 +18,7 @@
 #include <linux/etherdevice.h>
 #include <linux/bitmap.h>
 #include <linux/rcupdate.h>
+#include <linux/random.h>
 #include <net/net_namespace.h>
 #include <net/ieee80211_radiotap.h>
 #include <net/cfg80211.h>
@@ -39,6 +40,47 @@
 
 /* misc utils */
 
+/* Decide whether we should simulate the loss of a frame based on the simulated
+ * plink loss probability and the frame's destination.  Used for testing.
+ *
+ * Must be invoked with the rcu read lock held.
+ * */
+static int random_tx_loss(struct ieee80211_sub_if_data *sdata, struct
+               ieee80211_hdr *hdr)
+{
+       struct sta_info *sta;
+       u8 r = 0;
+
+       get_random_bytes(&r, sizeof(r));
+
+       list_for_each_entry(sta, &sdata->local->sta_list, list) {
+               if (!memcmp(sta->sta.addr, hdr->addr1, 6))
+                       if (r*25 < sta->plink_sim_loss*64)
+                               return 1;
+       }
+
+       return 0;
+}
+
+
+static int simulate_tx_loss(struct ieee80211_sub_if_data *sdata,
+               struct ieee80211_hdr *hdr, struct sk_buff *skb)
+{
+       struct ieee80211_hw *hw = &sdata->local->hw;
+       struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb);
+
+       ieee80211_tx_info_clear_status(info);
+       info->flags = IEEE80211_TX_CTL_REQ_TX_STATUS;
+
+       info->status.rates[0].idx = 0;
+       info->status.rates[0].count = hw->max_rate_tries;
+
+       ieee80211_tx_status_irqsafe(hw, skb);
+
+       /* this will ensure that the frame is not queued in the tx path */
+       return IEEE80211_TX_OK;
+}
+
 static __le16 ieee80211_duration(struct ieee80211_tx_data *tx, int group_addr,
                                 int next_frag_len)
 {
@@ -1244,6 +1286,7 @@ static void ieee80211_tx(struct ieee80211_sub_if_data 
*sdata,
        struct ieee80211_tx_data tx;
        ieee80211_tx_result res_prepare;
        struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb);
+       struct ieee80211_hdr *hdr = (struct ieee80211_hdr *) skb->data;
        struct sk_buff *next;
        unsigned long flags;
        int ret, retries;
@@ -1278,7 +1321,10 @@ static void ieee80211_tx(struct ieee80211_sub_if_data 
*sdata,
 
        retries = 0;
  retry:
-       ret = __ieee80211_tx(local, &tx.skb, tx.sta, txpending);
+       if (ieee80211_vif_is_mesh(&sdata->vif) && random_tx_loss(sdata, hdr))
+               ret = simulate_tx_loss(sdata, hdr, skb);
+       else
+               ret = __ieee80211_tx(local, &tx.skb, tx.sta, txpending);
        switch (ret) {
        case IEEE80211_TX_OK:
                break;
@@ -1857,7 +1903,11 @@ static bool ieee80211_tx_pending_skb(struct 
ieee80211_local *local,
                hdr = (struct ieee80211_hdr *)skb->data;
                sta = sta_info_get(local, hdr->addr1);
 
-               ret = __ieee80211_tx(local, &skb, sta, true);
+               if (ieee80211_vif_is_mesh(&sdata->vif) &&
+                               random_tx_loss(sdata, hdr))
+                       ret = simulate_tx_loss(sdata, hdr, skb);
+               else
+                       ret = __ieee80211_tx(local, &skb, sta, true);
                if (ret != IEEE80211_TX_OK)
                        result = false;
        }
diff --git a/net/wireless/nl80211.c b/net/wireless/nl80211.c
index 667a87d..1dfe8ea 100644
--- a/net/wireless/nl80211.c
+++ b/net/wireless/nl80211.c
@@ -1878,6 +1878,10 @@ static int nl80211_set_station(struct sk_buff *skb, 
struct genl_info *info)
                params.plink_action =
                    nla_get_u8(info->attrs[NL80211_ATTR_STA_PLINK_ACTION]);
 
+       if (info->attrs[NL80211_ATTR_SIM_LOSS])
+               params.sim_loss_rate =
+                       nla_get_u8(info->attrs[NL80211_ATTR_SIM_LOSS]);
+
        rtnl_lock();
 
        err = get_rdev_dev_by_info_ifindex(info, &rdev, &dev);
@@ -2619,6 +2623,8 @@ static int nl80211_get_mesh_params(struct sk_buff *skb,
                        cur_params.dot11MeshHWMPpreqMinInterval);
        NLA_PUT_U16(msg, NL80211_MESHCONF_HWMP_NET_DIAM_TRVS_TIME,
                        cur_params.dot11MeshHWMPnetDiameterTraversalTime);
+       NLA_PUT_U8(msg, NL80211_MESHCONF_SIM_LOSS_RATE,
+                       cur_params.dot11MeshSimLossRate);
        nla_nest_end(msg, pinfoattr);
        genlmsg_end(msg, hdr);
        err = genlmsg_reply(msg, info);
@@ -2661,6 +2667,7 @@ 
nl80211_meshconf_params_policy[NL80211_MESHCONF_ATTR_MAX+1] __read_mostly = {
        [NL80211_MESHCONF_HWMP_ACTIVE_PATH_TIMEOUT] = { .type = NLA_U32 },
        [NL80211_MESHCONF_HWMP_PREQ_MIN_INTERVAL] = { .type = NLA_U16 },
        [NL80211_MESHCONF_HWMP_NET_DIAM_TRVS_TIME] = { .type = NLA_U16 },
+       [NL80211_MESHCONF_SIM_LOSS_RATE] = { .type = NLA_U8 },
 };
 
 static int nl80211_set_mesh_params(struct sk_buff *skb, struct genl_info *info)
@@ -2729,6 +2736,8 @@ static int nl80211_set_mesh_params(struct sk_buff *skb, 
struct genl_info *info)
                        dot11MeshHWMPnetDiameterTraversalTime,
                        mask, NL80211_MESHCONF_HWMP_NET_DIAM_TRVS_TIME,
                        nla_get_u16);
+       FILL_IN_MESH_PARAM_IF_SET(tb, cfg, dot11MeshSimLossRate,
+                       mask, NL80211_MESHCONF_SIM_LOSS_RATE, nla_get_u8);
 
        /* Apply changes */
        err = rdev->ops->set_mesh_params(&rdev->wiphy, dev, &cfg, mask);
-- 
1.5.4.3

_______________________________________________
Devel mailing list
[email protected]
http://open80211s.com/mailman/listinfo/devel

Reply via email to