From: Assaf Krauss <[email protected]>

Add support for requesting an FTM (Fine Timing Measurement),
receiving a notification with its results, and aborting it.
There's no actual implementation as it depends entirely on
low-level device/driver support.

Signed-off-by: Assaf Krauss <[email protected]>
Signed-off-by: Beni Lev <[email protected]>
Signed-off-by: Johannes Berg <[email protected]>
---
 include/net/mac80211.h     | 10 +++++++++
 net/mac80211/cfg.c         | 56 ++++++++++++++++++++++++++++++++++++++++++++++
 net/mac80211/ieee80211_i.h |  4 +++-
 net/mac80211/main.c        |  3 +++
 4 files changed, 72 insertions(+), 1 deletion(-)

diff --git a/include/net/mac80211.h b/include/net/mac80211.h
index 7c30faff245f..52c6ea752a4a 100644
--- a/include/net/mac80211.h
+++ b/include/net/mac80211.h
@@ -3269,6 +3269,11 @@ enum ieee80211_reconfig_type {
  *     the function call.
  *
  * @wake_tx_queue: Called when new packets have been added to the queue.
+ *
+ * @perform_ftm: Perform a Fine Timing Measurement with the given request
+ *     parameters. The given request can only be used within the function call.
+ * @abort_ftm: Abort a Fine Timing Measurement request. The given cookie must
+ *     match that of the active FTM request.
  */
 struct ieee80211_ops {
        void (*tx)(struct ieee80211_hw *hw,
@@ -3508,6 +3513,11 @@ struct ieee80211_ops {
 
        void (*wake_tx_queue)(struct ieee80211_hw *hw,
                              struct ieee80211_txq *txq);
+
+       int (*perform_ftm)(struct ieee80211_hw *hw, u64 cookie,
+                          struct ieee80211_vif *vif,
+                          struct cfg80211_ftm_request *ftm_req);
+       int (*abort_ftm)(struct ieee80211_hw *hw, u64 cookie);
 };
 
 /**
diff --git a/net/mac80211/cfg.c b/net/mac80211/cfg.c
index 2d1c4c35186d..2afaa761cb16 100644
--- a/net/mac80211/cfg.c
+++ b/net/mac80211/cfg.c
@@ -3322,6 +3322,60 @@ static int ieee80211_del_tx_ts(struct wiphy *wiphy, 
struct net_device *dev,
        return -ENOENT;
 }
 
+static u64 ieee80211_msrment_cookie(struct ieee80211_local *local,
+                                   enum nl80211_msrment_type type)
+{
+       ASSERT_RTNL();
+
+       local->msrment_cookie_counter++;
+       if (local->msrment_cookie_counter == (1ULL << 48))
+               local->msrment_cookie_counter = 1;
+
+       return ((u64)type << 48) | local->msrment_cookie_counter;
+}
+
+static int ieee80211_perform_msrment(struct wiphy *wiphy,
+                                    struct wireless_dev *wdev,
+                                    struct cfg80211_msrment_request *request,
+                                    u64 *cookie)
+{
+       struct ieee80211_local *local = wiphy_priv(wiphy);
+       struct ieee80211_vif *vif = wdev_to_ieee80211_vif(wdev);
+
+       *cookie = ieee80211_msrment_cookie(local, request->type);
+
+       switch (request->type) {
+       case NL80211_MSRMENT_TYPE_FTM:
+               if (!local->ops->perform_ftm)
+                       return -EOPNOTSUPP;
+               return local->ops->perform_ftm(&local->hw, *cookie, vif,
+                                              &request->u.ftm);
+       default:
+               break;
+       }
+
+       return -EOPNOTSUPP;
+}
+
+static int ieee80211_abort_msrment(struct wiphy *wiphy,
+                                  struct wireless_dev *wdev, u64 cookie)
+{
+       struct ieee80211_local *local = wiphy_priv(wiphy);
+
+       enum nl80211_msrment_type type = cookie >> 48;
+
+       switch (type) {
+       case NL80211_MSRMENT_TYPE_FTM:
+               if (!local->ops->abort_ftm)
+                       return -EOPNOTSUPP;
+               return local->ops->abort_ftm(&local->hw, cookie);
+       default:
+               break;
+       }
+
+       return -EOPNOTSUPP;
+}
+
 const struct cfg80211_ops mac80211_config_ops = {
        .add_virtual_intf = ieee80211_add_iface,
        .del_virtual_intf = ieee80211_del_iface,
@@ -3342,6 +3396,8 @@ const struct cfg80211_ops mac80211_config_ops = {
        .get_station = ieee80211_get_station,
        .dump_station = ieee80211_dump_station,
        .dump_survey = ieee80211_dump_survey,
+       .perform_msrment = ieee80211_perform_msrment,
+       .abort_msrment = ieee80211_abort_msrment,
 #ifdef CONFIG_MAC80211_MESH
        .add_mpath = ieee80211_add_mpath,
        .del_mpath = ieee80211_del_mpath,
diff --git a/net/mac80211/ieee80211_i.h b/net/mac80211/ieee80211_i.h
index c30b6842ed9f..294aec41fca7 100644
--- a/net/mac80211/ieee80211_i.h
+++ b/net/mac80211/ieee80211_i.h
@@ -1347,11 +1347,13 @@ struct ieee80211_local {
        struct cfg80211_chan_def monitor_chandef;
 
        /* extended capabilities provided by mac80211 */
-       u8 ext_capa[8];
+       u8 ext_capa[9];
 
        /* TDLS channel switch */
        struct work_struct tdls_chsw_work;
        struct sk_buff_head skb_queue_tdls_chsw;
+
+       u64 msrment_cookie_counter;
 };
 
 static inline struct ieee80211_sub_if_data *
diff --git a/net/mac80211/main.c b/net/mac80211/main.c
index 6bcf0faa4a89..b7fbcecd40ef 100644
--- a/net/mac80211/main.c
+++ b/net/mac80211/main.c
@@ -1006,6 +1006,9 @@ int ieee80211_register_hw(struct ieee80211_hw *hw)
        if (ieee80211_hw_check(&local->hw, CHANCTX_STA_CSA))
                local->ext_capa[0] |= WLAN_EXT_CAPA1_EXT_CHANNEL_SWITCHING;
 
+       if (local->hw.wiphy->flags & WIPHY_FLAG_SUPPORTS_FTM_INITIATOR)
+               local->ext_capa[8] |= WLAN_EXT_CAPA9_FTM_INITIATOR;
+
        local->hw.wiphy->max_num_csa_counters = IEEE80211_MAX_CSA_COUNTERS_NUM;
 
        result = wiphy_register(local->hw.wiphy);
-- 
2.6.2

--
To unsubscribe from this list: send the line "unsubscribe linux-wireless" in
the body of a message to [email protected]
More majordomo info at  http://vger.kernel.org/majordomo-info.html

Reply via email to