]> git.ipfire.org Git - thirdparty/linux.git/commitdiff
wifi: iwlwifi: mld: don't remove all keys in mcast rekey
authorMiri Korenblit <miriam.rachel.korenblit@intel.com>
Thu, 10 Jul 2025 18:28:30 +0000 (21:28 +0300)
committerMiri Korenblit <miriam.rachel.korenblit@intel.com>
Fri, 11 Jul 2025 15:28:31 +0000 (18:28 +0300)
In the current code, if there was a rekey, we remove all the existing keys
from mac80211, then re-add the ones that the FW sent with
ieee80211_gtk_rekey_add, (newer FW will send also the existing GTKs/BIGTKs)
and then update the sequence number.

Instead of removing and re-adding the existing keys for no good reason,
we can just update the sequence of all keys, also of the ones that are
going to be replaced, and update again after the replace.

This change is required because ieee80211_gtk_rekey_add is going to be
changed to lookup the cipher from the old key instead of receiving it as an
argument, and for this it will need the old key(s), so we can't remove all
keys.

Note that with this change, in case that a key that existed before wowlan
is replaced, mac80211 will now call the driver to remove the old key and
add the new one (as opposed the previous behaviour, in which the key was
removed by the driver itself).
Of course we don't want to run the set_key callbacks in this case, so just
return early.

Reviewed-by: Johannes Berg <johannes.berg@intel.com>
Signed-off-by: Miri Korenblit <miriam.rachel.korenblit@intel.com>
Link: https://patch.msgid.link/20250710212632.f0b5e19f77f5.I958f4926f168cdad6d4d7720ebde2f5e812b297d@changeid
drivers/net/wireless/intel/iwlwifi/mld/d3.c
drivers/net/wireless/intel/iwlwifi/mld/key.c
drivers/net/wireless/intel/iwlwifi/mld/mld.h

index af12b3d8189965dddacf0437431f454ac2190bcc..26255246a3208993932ccc3ad2bb1b047ef7815d 100644 (file)
@@ -646,51 +646,6 @@ iwl_mld_set_key_rx_seq(struct ieee80211_key_conf *key,
        }
 }
 
-static void
-iwl_mld_d3_update_mcast_key(struct iwl_mld *mld,
-                           struct ieee80211_vif *vif,
-                           struct iwl_mld_wowlan_status *wowlan_status,
-                           struct ieee80211_key_conf *key,
-                           struct iwl_mld_mcast_key_data *key_data)
-{
-       if (key->keyidx != key_data->id &&
-           (key->keyidx < 4 || key->keyidx > 5)) {
-               IWL_ERR(mld,
-                       "Unexpected keyId mismatch. Old keyId:%d, New keyId:%d\n",
-                       key->keyidx, key_data->id);
-               return;
-       }
-
-       /* All installed keys are sent by the FW, even weren't
-        * rekeyed during D3.
-        * We remove an existing key if it has the same index as
-        * a new key and a rekey has occurred during d3
-        */
-       if (wowlan_status->num_of_gtk_rekeys && key_data->len) {
-               if (key->keyidx == 4 || key->keyidx == 5) {
-                       struct iwl_mld_vif *mld_vif =
-                               iwl_mld_vif_from_mac80211(vif);
-                       struct iwl_mld_link *mld_link;
-                       int link_id = vif->active_links ?
-                               __ffs(vif->active_links) : 0;
-
-                       mld_link = iwl_mld_link_dereference_check(mld_vif,
-                                                                 link_id);
-                       if (WARN_ON(!mld_link))
-                               return;
-
-                       if (mld_link->igtk == key)
-                               mld_link->igtk = NULL;
-                       mld->num_igtks--;
-               }
-
-               ieee80211_remove_key(key);
-               return;
-       }
-
-       iwl_mld_set_key_rx_seq(key, key_data);
-}
-
 static void
 iwl_mld_update_ptk_rx_seq(struct iwl_mld *mld,
                          struct iwl_mld_wowlan_status *wowlan_status,
@@ -759,8 +714,7 @@ iwl_mld_resume_keys_iter(struct ieee80211_hw *hw,
 
                data->gtk_cipher = key->cipher;
                status_idx = key->keyidx == wowlan_status->gtk[1].id;
-               iwl_mld_d3_update_mcast_key(data->mld, vif, wowlan_status, key,
-                                           &wowlan_status->gtk[status_idx]);
+               iwl_mld_set_key_rx_seq(key, &wowlan_status->gtk[status_idx]);
                break;
        case WLAN_CIPHER_SUITE_BIP_GMAC_128:
        case WLAN_CIPHER_SUITE_BIP_GMAC_256:
@@ -772,9 +726,8 @@ iwl_mld_resume_keys_iter(struct ieee80211_hw *hw,
                                return;
 
                        data->igtk_cipher = key->cipher;
-                       iwl_mld_d3_update_mcast_key(data->mld, vif,
-                                                   wowlan_status,
-                                                   key, &wowlan_status->igtk);
+                       if (key->keyidx == wowlan_status->igtk.id)
+                               iwl_mld_set_key_rx_seq(key, &wowlan_status->igtk);
                }
                if (key->keyidx == 6 || key->keyidx == 7) {
                        if (WARN_ON(data->bigtk_cipher &&
@@ -783,9 +736,7 @@ iwl_mld_resume_keys_iter(struct ieee80211_hw *hw,
 
                        data->bigtk_cipher = key->cipher;
                        status_idx = key->keyidx == wowlan_status->bigtk[1].id;
-                       iwl_mld_d3_update_mcast_key(data->mld, vif,
-                                                   wowlan_status, key,
-                                                   &wowlan_status->bigtk[status_idx]);
+                       iwl_mld_set_key_rx_seq(key, &wowlan_status->bigtk[status_idx]);
                }
                break;
        default:
@@ -795,7 +746,7 @@ iwl_mld_resume_keys_iter(struct ieee80211_hw *hw,
        data->num_keys++;
 }
 
-static bool
+static void
 iwl_mld_add_mcast_rekey(struct ieee80211_vif *vif,
                        struct iwl_mld *mld,
                        struct iwl_mld_mcast_key_data *key_data,
@@ -822,7 +773,7 @@ iwl_mld_add_mcast_rekey(struct ieee80211_vif *vif,
        BUILD_BUG_ON(sizeof(conf.key) < sizeof(key_data->key));
 
        if (!key_data->len)
-               return true;
+               return;
 
        switch (cipher) {
        case WLAN_CIPHER_SUITE_CCMP:
@@ -854,7 +805,7 @@ iwl_mld_add_mcast_rekey(struct ieee80211_vif *vif,
        memcpy(conf.conf.key, key_data->key, conf.conf.keylen);
        key_config = ieee80211_gtk_rekey_add(vif, &conf.conf, link_id);
        if (IS_ERR(key_config))
-               return false;
+               return;
 
        iwl_mld_set_key_rx_seq(key_config, key_data);
 
@@ -862,10 +813,25 @@ iwl_mld_add_mcast_rekey(struct ieee80211_vif *vif,
        if (key_config->keyidx == 4 || key_config->keyidx == 5) {
                struct iwl_mld_link *mld_link =
                        iwl_mld_link_from_mac80211(link_conf);
-               mld_link->igtk = key_config;
-               mld->num_igtks++;
+
+               /* If we had more than one rekey, mac80211 will tell us to
+                * remove the old and add the new so we will update the IGTK in
+                * drv_set_key
+                */
+               if (mld_link->igtk && mld_link->igtk != key_config) {
+                       /* mark the old IGTK as not in FW */
+                       mld_link->igtk->hw_key_idx = STA_KEY_IDX_INVALID;
+                       mld_link->igtk = key_config;
+               }
+       }
+
+       /* Also keep track of the new BIGTK */
+       if ((key_config->keyidx == 6 || key_config->keyidx == 7) &&
+           vif->type == NL80211_IFTYPE_STATION) {
+               struct iwl_mld_vif *mld_vif = iwl_mld_vif_from_mac80211(vif);
+
+               rcu_assign_pointer(mld_vif->bigtks[key_config->keyidx - 6], key_config);
        }
-       return true;
 }
 
 static void
@@ -877,23 +843,20 @@ iwl_mld_add_all_rekeys(struct ieee80211_vif *vif,
        int i;
 
        for (i = 0; i < ARRAY_SIZE(wowlan_status->gtk); i++)
-               if (!iwl_mld_add_mcast_rekey(vif, key_iter_data->mld,
-                                            &wowlan_status->gtk[i],
-                                            link_conf,
-                                            key_iter_data->gtk_cipher))
-                       return;
+               iwl_mld_add_mcast_rekey(vif, key_iter_data->mld,
+                                       &wowlan_status->gtk[i],
+                                       link_conf,
+                                       key_iter_data->gtk_cipher);
 
-       if (!iwl_mld_add_mcast_rekey(vif, key_iter_data->mld,
-                                    &wowlan_status->igtk,
-                                    link_conf, key_iter_data->igtk_cipher))
-               return;
+       iwl_mld_add_mcast_rekey(vif, key_iter_data->mld,
+                               &wowlan_status->igtk,
+                               link_conf, key_iter_data->igtk_cipher);
 
        for (i = 0; i < ARRAY_SIZE(wowlan_status->bigtk); i++)
-               if (!iwl_mld_add_mcast_rekey(vif, key_iter_data->mld,
-                                            &wowlan_status->bigtk[i],
-                                            link_conf,
-                                            key_iter_data->bigtk_cipher))
-                       return;
+               iwl_mld_add_mcast_rekey(vif, key_iter_data->mld,
+                                       &wowlan_status->bigtk[i],
+                                       link_conf,
+                                       key_iter_data->bigtk_cipher);
 }
 
 static bool
@@ -1851,6 +1814,7 @@ int iwl_mld_wowlan_resume(struct iwl_mld *mld)
                goto err;
        }
 
+       mld->fw_status.resuming = true;
        mld->fw_status.in_d3 = false;
        mld->scan.last_start_time_jiffies = jiffies;
 
@@ -1926,6 +1890,8 @@ int iwl_mld_wowlan_resume(struct iwl_mld *mld)
        mld->fw_status.in_hw_restart = true;
        ret = 1;
  out:
+       mld->fw_status.resuming = false;
+
        if (resume_data.wowlan_status) {
                kfree(resume_data.wowlan_status->wake_packet);
                kfree(resume_data.wowlan_status);
index 0eff13e5ffd57a4ea6fef61799f6df3fca29fc16..13462a5ad79ac875593d9468bcd620e522856276 100644 (file)
@@ -129,6 +129,12 @@ static int iwl_mld_add_key_to_fw(struct iwl_mld *mld, u32 sta_mask,
        bool tkip = key->cipher == WLAN_CIPHER_SUITE_TKIP;
        int max_key_len = sizeof(cmd.u.add.key);
 
+#ifdef CONFIG_PM_SLEEP
+       /* If there was a rekey in wowlan, FW already has the key */
+       if (mld->fw_status.resuming)
+               return 0;
+#endif
+
        if (WARN_ON(!sta_mask))
                return -EINVAL;
 
@@ -160,6 +166,12 @@ static void iwl_mld_remove_key_from_fw(struct iwl_mld *mld, u32 sta_mask,
                .u.remove.key_flags = cpu_to_le32(key_flags),
        };
 
+#ifdef CONFIG_PM_SLEEP
+       /* If there was a rekey in wowlan, FW already removed the key */
+       if (mld->fw_status.resuming)
+               return;
+#endif
+
        if (WARN_ON(!sta_mask))
                return;
 
index 241ab3a00e5632102f0da8f120155f42bdba4bae..a9e59378f14271bcec4c222ef84ba64d2256a6d7 100644 (file)
  * @running: true if the firmware is running
  * @do_not_dump_once: true if firmware dump must be prevented once
  * @in_d3: indicates FW is in suspend mode and should be resumed
+ * @resuming: indicates the driver is resuming from wowlan
  * @in_hw_restart: indicates that we are currently in restart flow.
  *     rather than restarted. Should be unset upon restart.
  * @radio_kill: bitmap of radio kill status
@@ -237,6 +238,7 @@ struct iwl_mld {
                    do_not_dump_once:1,
 #ifdef CONFIG_PM_SLEEP
                    in_d3:1,
+                   resuming:1,
 #endif
                    in_hw_restart:1;