wifi: iwlwifi: mvm: Add support for removing responder TKs
authorIlan Peer <ilan.peer@intel.com>
Wed, 31 Jan 2024 21:08:16 +0000 (23:08 +0200)
committerJohannes Berg <johannes.berg@intel.com>
Fri, 2 Feb 2024 12:46:40 +0000 (13:46 +0100)
When removing a PASN station, the TK must be removed before
the station is removed as otherwise the FW would assert.

To handle this, store the key configuration, and use it to remove
the key when the station is removed.

Signed-off-by: Ilan Peer <ilan.peer@intel.com>
Reviewed-by: Gregory Greenman <gregory.greenman@intel.com>
Signed-off-by: Miri Korenblit <miriam.rachel.korenblit@intel.com>
Link: https://msgid.link/20240131230734.3e6364730c04.Ia76dc4a9d399f1f68ac6b157d844b63f74d5159f@changeid
Signed-off-by: Johannes Berg <johannes.berg@intel.com>
drivers/net/wireless/intel/iwlwifi/mvm/ftm-responder.c
drivers/net/wireless/intel/iwlwifi/mvm/mld-key.c
drivers/net/wireless/intel/iwlwifi/mvm/mvm.h
drivers/net/wireless/intel/iwlwifi/mvm/sta.c
drivers/net/wireless/intel/iwlwifi/mvm/sta.h

index 8f10590f9cddfd716a86c9d6e0afa4bb0368fd71..f72ca38d7c0e1b67aef8ec237268eb2d4dea33a0 100644 (file)
@@ -12,6 +12,9 @@ struct iwl_mvm_pasn_sta {
        struct list_head list;
        struct iwl_mvm_int_sta int_sta;
        u8 addr[ETH_ALEN];
+
+       /* must be last as it followed by buffer holding the key */
+       struct ieee80211_key_conf keyconf;
 };
 
 struct iwl_mvm_pasn_hltk_data {
@@ -303,6 +306,10 @@ static void iwl_mvm_resp_del_pasn_sta(struct iwl_mvm *mvm,
 {
        list_del(&sta->list);
 
+       if (sta->keyconf.keylen)
+               iwl_mvm_sec_key_del_pasn(mvm, vif, BIT(sta->int_sta.sta_id),
+                                        &sta->keyconf);
+
        if (iwl_mvm_has_mld_api(mvm->fw))
                iwl_mvm_mld_rm_sta_id(mvm, sta->int_sta.sta_id);
        else
@@ -352,12 +359,12 @@ int iwl_mvm_ftm_respoder_add_pasn_sta(struct iwl_mvm *mvm,
        }
 
        if (tk && tk_len) {
-               sta = kzalloc(sizeof(*sta), GFP_KERNEL);
+               sta = kzalloc(sizeof(*sta) + tk_len, GFP_KERNEL);
                if (!sta)
                        return -ENOBUFS;
 
                ret = iwl_mvm_add_pasn_sta(mvm, vif, &sta->int_sta, addr,
-                                          cipher, tk, tk_len);
+                                          cipher, tk, tk_len, &sta->keyconf);
                if (ret) {
                        kfree(sta);
                        return ret;
index ea3e9e9c6e26c3b1753d58722ffc97f3f57df9b0..a1ce08a5527c1c92421e19489ebb462632a2927e 100644 (file)
@@ -335,6 +335,21 @@ static int _iwl_mvm_sec_key_del(struct iwl_mvm *mvm,
        return ret;
 }
 
+int iwl_mvm_sec_key_del_pasn(struct iwl_mvm *mvm,
+                            struct ieee80211_vif *vif,
+                            u32 sta_mask,
+                            struct ieee80211_key_conf *keyconf)
+{
+       u32 key_flags = iwl_mvm_get_sec_flags(mvm, vif, NULL, keyconf) |
+               IWL_SEC_KEY_FLAG_MFP;
+
+       if (WARN_ON(!sta_mask))
+               return -EINVAL;
+
+       return  __iwl_mvm_sec_key_del(mvm, sta_mask, key_flags, keyconf->keyidx,
+                                     0);
+}
+
 int iwl_mvm_sec_key_del(struct iwl_mvm *mvm,
                        struct ieee80211_vif *vif,
                        struct ieee80211_sta *sta,
index 9a89b91519dbd399d2c035df2e5cc876b644fefd..e148ef02ff737ec499083329a7deaf4650aff86b 100644 (file)
@@ -2402,6 +2402,10 @@ int iwl_mvm_sec_key_del(struct iwl_mvm *mvm,
                        struct ieee80211_vif *vif,
                        struct ieee80211_sta *sta,
                        struct ieee80211_key_conf *keyconf);
+int iwl_mvm_sec_key_del_pasn(struct iwl_mvm *mvm,
+                            struct ieee80211_vif *vif,
+                            u32 sta_mask,
+                            struct ieee80211_key_conf *keyconf);
 void iwl_mvm_sec_key_remove_ap(struct iwl_mvm *mvm,
                               struct ieee80211_vif *vif,
                               struct iwl_mvm_vif_link_info *link,
index 2a3ca97859749749fff954e097a9d62ae86f5d24..d57fcbe4f8ac8bd378ac2628b65e9ab43e622994 100644 (file)
@@ -4298,12 +4298,12 @@ u16 iwl_mvm_tid_queued(struct iwl_mvm *mvm, struct iwl_mvm_tid_data *tid_data)
 
 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)
+                        u8 *key, u32 key_len,
+                        struct ieee80211_key_conf *keyconf)
 {
        int ret;
        u16 queue;
        struct iwl_mvm_vif *mvmvif = iwl_mvm_vif_from_mac80211(vif);
-       struct ieee80211_key_conf *keyconf;
        unsigned int wdg_timeout =
                iwl_mvm_get_wd_timeout(mvm, vif, false, false);
        bool mld = iwl_mvm_has_mld_api(mvm->fw);
@@ -4328,12 +4328,6 @@ int iwl_mvm_add_pasn_sta(struct iwl_mvm *mvm, struct ieee80211_vif *vif,
        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;
@@ -4354,10 +4348,9 @@ int iwl_mvm_add_pasn_sta(struct iwl_mvm *mvm, struct ieee80211_vif *vif,
                                           0, NULL, 0, 0, true);
        }
 
-       kfree(keyconf);
-       return 0;
 out:
-       iwl_mvm_dealloc_int_sta(mvm, sta);
+       if (ret)
+               iwl_mvm_dealloc_int_sta(mvm, sta);
        return ret;
 }
 
index b33a0ce096d46c2f92eb127d8942062b42f39345..4668f413abd3f2f92529eeeaef311f535c4b0927 100644 (file)
@@ -574,7 +574,8 @@ 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);
+                        u8 *key, u32 key_len,
+                        struct ieee80211_key_conf *key_conf_out);
 void iwl_mvm_cancel_channel_switch(struct iwl_mvm *mvm,
                                   struct ieee80211_vif *vif,
                                   u32 id);