iwlwifi: mvm: add an option to add PASN station
authorAvraham Stern <avraham.stern@intel.com>
Fri, 11 Sep 2020 17:44:39 +0000 (20:44 +0300)
committerLuca Coelho <luciano.coelho@intel.com>
Thu, 1 Oct 2020 18:53:04 +0000 (21:53 +0300)
A FTM responder may do PASN authentication with unassociated stations
to allow secure ranging. In this case, the driver will add an internal
station and install the TK so the FW will accept protected FTM
request frames from this station and will send a protected FTM
response frame.

In addition, the driver needs to configure the HLTK to the FW so
the FW can derive the secure LTF bits. This is left for a later
patch since it is not yet supported by the FW.

Signed-off-by: Avraham Stern <avraham.stern@intel.com>
Signed-off-by: Luca Coelho <luciano.coelho@intel.com>
Link: https://lore.kernel.org/r/iwlwifi.20200911204056.c915b44ad7dd.I72ef7f9753964555561c27ec503241105eddb14e@changeid
Signed-off-by: Luca Coelho <luciano.coelho@intel.com>
drivers/net/wireless/intel/iwlwifi/mvm/ftm-responder.c
drivers/net/wireless/intel/iwlwifi/mvm/mac80211.c
drivers/net/wireless/intel/iwlwifi/mvm/mvm.h
drivers/net/wireless/intel/iwlwifi/mvm/ops.c
drivers/net/wireless/intel/iwlwifi/mvm/sta.c
drivers/net/wireless/intel/iwlwifi/mvm/sta.h

index 0b6c32098b5ac08933e4d216b66c25515b1377f7..179bd2bb0a8230f7c73dacc86df4046dad33927d 100644 (file)
@@ -6,7 +6,7 @@
  * GPL LICENSE SUMMARY
  *
  * Copyright(c) 2015 - 2017 Intel Deutschland GmbH
- * Copyright (C) 2018 - 2019 Intel Corporation
+ * Copyright (C) 2018 - 2020 Intel Corporation
  *
  * This program is free software; you can redistribute it and/or modify
  * it under the terms of version 2 of the GNU General Public License as
@@ -27,7 +27,7 @@
  * BSD LICENSE
  *
  * Copyright(c) 2015 - 2017 Intel Deutschland GmbH
- * Copyright (C) 2018 - 2019 Intel Corporation
+ * Copyright (C) 2018 - 2020 Intel Corporation
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
 #include "mvm.h"
 #include "constants.h"
 
+struct iwl_mvm_pasn_sta {
+       struct list_head list;
+       struct iwl_mvm_int_sta int_sta;
+       u8 addr[ETH_ALEN];
+};
+
 static int iwl_mvm_ftm_responder_set_bw_v1(struct cfg80211_chan_def *chandef,
                                           u8 *bw, u8 *ctrl_ch_position)
 {
@@ -207,6 +213,62 @@ iwl_mvm_ftm_responder_dyn_cfg_cmd(struct iwl_mvm *mvm,
        return iwl_mvm_send_cmd(mvm, &hcmd);
 }
 
+int iwl_mvm_ftm_respoder_add_pasn_sta(struct iwl_mvm *mvm,
+                                     struct ieee80211_vif *vif,
+                                     u8 *addr, u32 cipher, u8 *tk, u32 tk_len,
+                                     u8 *hltk, u32 hltk_len)
+{
+       int ret;
+       struct iwl_mvm_pasn_sta *sta;
+
+       lockdep_assert_held(&mvm->mutex);
+
+       sta = kmalloc(sizeof(*sta), GFP_KERNEL);
+       if (!sta)
+               return -ENOBUFS;
+
+       ret = iwl_mvm_add_pasn_sta(mvm, vif, &sta->int_sta, addr, cipher, tk,
+                                  tk_len);
+       if (ret) {
+               kfree(sta);
+               return ret;
+       }
+
+       // TODO: set the HLTK to fw
+
+       memcpy(sta->addr, addr, ETH_ALEN);
+       list_add_tail(&sta->list, &mvm->resp_pasn_list);
+       return 0;
+}
+
+static void iwl_mvm_resp_del_pasn_sta(struct iwl_mvm *mvm,
+                                     struct ieee80211_vif *vif,
+                                     struct iwl_mvm_pasn_sta *sta)
+{
+       list_del(&sta->list);
+       iwl_mvm_rm_sta_id(mvm, vif, sta->int_sta.sta_id);
+       iwl_mvm_dealloc_int_sta(mvm, &sta->int_sta);
+       kfree(sta);
+}
+
+int iwl_mvm_ftm_resp_remove_pasn_sta(struct iwl_mvm *mvm,
+                                    struct ieee80211_vif *vif, u8 *addr)
+{
+       struct iwl_mvm_pasn_sta *sta, *prev;
+
+       lockdep_assert_held(&mvm->mutex);
+
+       list_for_each_entry_safe(sta, prev, &mvm->resp_pasn_list, list) {
+               if (!memcmp(sta->addr, addr, ETH_ALEN)) {
+                       iwl_mvm_resp_del_pasn_sta(mvm, vif, sta);
+                       return 0;
+               }
+       }
+
+       IWL_ERR(mvm, "FTM: PASN station %pM not found\n", addr);
+       return -EINVAL;
+}
+
 int iwl_mvm_ftm_start_responder(struct iwl_mvm *mvm, struct ieee80211_vif *vif)
 {
        struct iwl_mvm_vif *mvmvif = iwl_mvm_vif_from_mac80211(vif);
@@ -255,12 +317,24 @@ int iwl_mvm_ftm_start_responder(struct iwl_mvm *mvm, struct ieee80211_vif *vif)
        return ret;
 }
 
+void iwl_mvm_ftm_responder_clear(struct iwl_mvm *mvm,
+                                struct ieee80211_vif *vif)
+{
+       struct iwl_mvm_pasn_sta *sta, *prev;
+
+       lockdep_assert_held(&mvm->mutex);
+
+       list_for_each_entry_safe(sta, prev, &mvm->resp_pasn_list, list)
+               iwl_mvm_resp_del_pasn_sta(mvm, vif, sta);
+}
+
 void iwl_mvm_ftm_restart_responder(struct iwl_mvm *mvm,
                                   struct ieee80211_vif *vif)
 {
        if (!vif->bss_conf.ftm_responder)
                return;
 
+       iwl_mvm_ftm_responder_clear(mvm, vif);
        iwl_mvm_ftm_start_responder(mvm, vif);
 }
 
index f9b261e36f2d4e267c20c5f564925e81e6a17c69..12f217f2d7b35b193eeeaffd77d83eb4517b0780 100644 (file)
@@ -2633,6 +2633,8 @@ static void iwl_mvm_stop_ap_ibss(struct ieee80211_hw *hw,
 
        iwl_mvm_update_quotas(mvm, false, NULL);
 
+       iwl_mvm_ftm_responder_clear(mvm, vif);
+
        /*
         * This is not very nice, but the simplest:
         * For older FWs removing the mcast sta before the bcast station may
index e2f7f6ec711e2e4beac4abcf986fe7fa5de1756b..f39be84aa279df3ce11f64b80d52a313adfbe539 100644 (file)
@@ -1115,6 +1115,8 @@ struct iwl_mvm {
                int responses[IWL_MVM_TOF_MAX_APS];
        } ftm_initiator;
 
+       struct list_head resp_pasn_list;
+
        struct {
                u8 d0i3_resp;
        } cmd_ver;
@@ -1996,6 +1998,14 @@ void iwl_mvm_ftm_restart_responder(struct iwl_mvm *mvm,
                                   struct ieee80211_vif *vif);
 void iwl_mvm_ftm_responder_stats(struct iwl_mvm *mvm,
                                 struct iwl_rx_cmd_buffer *rxb);
+int iwl_mvm_ftm_resp_remove_pasn_sta(struct iwl_mvm *mvm,
+                                    struct ieee80211_vif *vif, u8 *addr);
+int iwl_mvm_ftm_respoder_add_pasn_sta(struct iwl_mvm *mvm,
+                                     struct ieee80211_vif *vif,
+                                     u8 *addr, u32 cipher, u8 *tk, u32 tk_len,
+                                     u8 *hltk, u32 hltk_len);
+void iwl_mvm_ftm_responder_clear(struct iwl_mvm *mvm,
+                                struct ieee80211_vif *vif);
 
 /* FTM initiator */
 void iwl_mvm_ftm_restart(struct iwl_mvm *mvm);
index d095ff847be923bb7da5ff045ef596430ae9a077..e184a163946ab40515186595d8b6ba12ff842850 100644 (file)
@@ -695,6 +695,7 @@ iwl_op_mode_mvm_start(struct iwl_trans *trans, const struct iwl_cfg *cfg,
        INIT_LIST_HEAD(&mvm->async_handlers_list);
        spin_lock_init(&mvm->time_event_lock);
        INIT_LIST_HEAD(&mvm->ftm_initiator.loc_list);
+       INIT_LIST_HEAD(&mvm->resp_pasn_list);
 
        INIT_WORK(&mvm->async_handlers_wk, iwl_mvm_async_handlers_wk);
        INIT_WORK(&mvm->roc_done_wk, iwl_mvm_roc_done_wk);
index fc45ef4f6951fc60bc6f66adddb7067650f96d37..827e80ff5aa61c6b1fc2e9a0b648398faa7e2086 100644 (file)
@@ -1997,7 +1997,7 @@ static int iwl_mvm_enable_aux_snif_queue_tvqm(struct iwl_mvm *mvm, u8 sta_id)
 }
 
 static int iwl_mvm_add_int_sta_with_queue(struct iwl_mvm *mvm, int macidx,
-                                         int maccolor,
+                                         int maccolor, u8 *addr,
                                          struct iwl_mvm_int_sta *sta,
                                          u16 *queue, int fifo)
 {
@@ -2007,7 +2007,7 @@ static int iwl_mvm_add_int_sta_with_queue(struct iwl_mvm *mvm, int macidx,
        if (!iwl_mvm_has_new_tx_api(mvm))
                iwl_mvm_enable_aux_snif_queue(mvm, *queue, sta->sta_id, fifo);
 
-       ret = iwl_mvm_add_int_sta_common(mvm, sta, NULL, macidx, maccolor);
+       ret = iwl_mvm_add_int_sta_common(mvm, sta, addr, macidx, maccolor);
        if (ret) {
                if (!iwl_mvm_has_new_tx_api(mvm))
                        iwl_mvm_disable_txq(mvm, NULL, *queue,
@@ -2047,7 +2047,7 @@ int iwl_mvm_add_aux_sta(struct iwl_mvm *mvm)
        if (ret)
                return ret;
 
-       ret = iwl_mvm_add_int_sta_with_queue(mvm, MAC_INDEX_AUX, 0,
+       ret = iwl_mvm_add_int_sta_with_queue(mvm, MAC_INDEX_AUX, 0, NULL,
                                             &mvm->aux_sta, &mvm->aux_queue,
                                             IWL_MVM_TX_FIFO_MCAST);
        if (ret) {
@@ -2065,7 +2065,8 @@ int iwl_mvm_add_snif_sta(struct iwl_mvm *mvm, struct ieee80211_vif *vif)
        lockdep_assert_held(&mvm->mutex);
 
        return iwl_mvm_add_int_sta_with_queue(mvm, mvmvif->id, mvmvif->color,
-                                             &mvm->snif_sta, &mvm->snif_queue,
+                                             NULL, &mvm->snif_sta,
+                                             &mvm->snif_queue,
                                              IWL_MVM_TX_FIFO_BE);
 }
 
@@ -3903,3 +3904,43 @@ u16 iwl_mvm_tid_queued(struct iwl_mvm *mvm, struct iwl_mvm_tid_data *tid_data)
 
        return ieee80211_sn_sub(sn, tid_data->next_reclaimed);
 }
+
+int iwl_mvm_add_pasn_sta(struct iwl_mvm *mvm, struct ieee80211_vif *vif,
+                        struct iwl_mvm_int_sta *sta, u8 *addr, u32 cipher,
+                        u8 *key, u32 key_len)
+{
+       int ret;
+       u16 queue;
+       struct iwl_mvm_vif *mvmvif = iwl_mvm_vif_from_mac80211(vif);
+       struct ieee80211_key_conf *keyconf;
+
+       ret = iwl_mvm_allocate_int_sta(mvm, sta, 0,
+                                      NL80211_IFTYPE_UNSPECIFIED,
+                                      IWL_STA_LINK);
+       if (ret)
+               return ret;
+
+       ret = iwl_mvm_add_int_sta_with_queue(mvm, mvmvif->id, mvmvif->color,
+                                            addr, sta, &queue,
+                                            IWL_MVM_TX_FIFO_BE);
+       if (ret)
+               goto out;
+
+       keyconf = kzalloc(sizeof(*keyconf) + key_len, GFP_KERNEL);
+       if (!keyconf) {
+               ret = -ENOBUFS;
+               goto out;
+       }
+
+       keyconf->cipher = cipher;
+       memcpy(keyconf->key, key, key_len);
+       keyconf->keylen = key_len;
+
+       ret = iwl_mvm_send_sta_key(mvm, sta->sta_id, keyconf, false,
+                                  0, NULL, 0, 0, true);
+       kfree(keyconf);
+       return 0;
+out:
+       iwl_mvm_dealloc_int_sta(mvm, sta);
+       return ret;
+}
index da2d1ac012293cb7b5862478c65696b262a50e7d..55dd2fb0a779a70f056ea1b22679183240176f6f 100644 (file)
@@ -579,5 +579,8 @@ void iwl_mvm_modify_all_sta_disable_tx(struct iwl_mvm *mvm,
                                       bool disable);
 void iwl_mvm_csa_client_absent(struct iwl_mvm *mvm, struct ieee80211_vif *vif);
 void iwl_mvm_add_new_dqa_stream_wk(struct work_struct *wk);
+int iwl_mvm_add_pasn_sta(struct iwl_mvm *mvm, struct ieee80211_vif *vif,
+                        struct iwl_mvm_int_sta *sta, u8 *addr, u32 cipher,
+                        u8 *key, u32 key_len);
 
 #endif /* __sta_h__ */