|
@@ -855,15 +855,38 @@ iwl_mvm_get_wowlan_config(struct iwl_mvm *mvm,
|
|
|
return 0;
|
|
|
}
|
|
|
|
|
|
+static void
|
|
|
+iwl_mvm_iter_d0i3_ap_keys(struct iwl_mvm *mvm,
|
|
|
+ struct ieee80211_vif *vif,
|
|
|
+ void (*iter)(struct ieee80211_hw *hw,
|
|
|
+ struct ieee80211_vif *vif,
|
|
|
+ struct ieee80211_sta *sta,
|
|
|
+ struct ieee80211_key_conf *key,
|
|
|
+ void *data),
|
|
|
+ void *data)
|
|
|
+{
|
|
|
+ struct ieee80211_sta *ap_sta;
|
|
|
+
|
|
|
+ rcu_read_lock();
|
|
|
+
|
|
|
+ ap_sta = rcu_dereference(mvm->fw_id_to_mac_id[mvm->d0i3_ap_sta_id]);
|
|
|
+ if (IS_ERR_OR_NULL(ap_sta))
|
|
|
+ goto out;
|
|
|
+
|
|
|
+ ieee80211_iter_keys_rcu(mvm->hw, vif, iter, data);
|
|
|
+out:
|
|
|
+ rcu_read_unlock();
|
|
|
+}
|
|
|
+
|
|
|
int iwl_mvm_wowlan_config_key_params(struct iwl_mvm *mvm,
|
|
|
struct ieee80211_vif *vif,
|
|
|
- bool configure_keys,
|
|
|
+ bool d0i3,
|
|
|
u32 cmd_flags)
|
|
|
{
|
|
|
struct iwl_wowlan_kek_kck_material_cmd kek_kck_cmd = {};
|
|
|
struct iwl_wowlan_tkip_params_cmd tkip_cmd = {};
|
|
|
struct wowlan_key_data key_data = {
|
|
|
- .configure_keys = configure_keys,
|
|
|
+ .configure_keys = !d0i3,
|
|
|
.use_rsc_tsc = false,
|
|
|
.tkip = &tkip_cmd,
|
|
|
.use_tkip = false,
|
|
@@ -876,15 +899,28 @@ int iwl_mvm_wowlan_config_key_params(struct iwl_mvm *mvm,
|
|
|
return -ENOMEM;
|
|
|
|
|
|
/*
|
|
|
- * Note that currently we don't propagate cmd_flags
|
|
|
- * to the iterator. In case of key_data.configure_keys,
|
|
|
- * all the configured commands are SYNC, and
|
|
|
- * iwl_mvm_wowlan_program_keys() will take care of
|
|
|
- * locking/unlocking mvm->mutex.
|
|
|
+ * if we have to configure keys, call ieee80211_iter_keys(),
|
|
|
+ * as we need non-atomic context in order to take the
|
|
|
+ * required locks.
|
|
|
+ * for the d0i3 we can't use ieee80211_iter_keys(), as
|
|
|
+ * taking (almost) any mutex might result in deadlock.
|
|
|
*/
|
|
|
- ieee80211_iter_keys(mvm->hw, vif,
|
|
|
- iwl_mvm_wowlan_program_keys,
|
|
|
- &key_data);
|
|
|
+ if (!d0i3) {
|
|
|
+ /*
|
|
|
+ * Note that currently we don't propagate cmd_flags
|
|
|
+ * to the iterator. In case of key_data.configure_keys,
|
|
|
+ * all the configured commands are SYNC, and
|
|
|
+ * iwl_mvm_wowlan_program_keys() will take care of
|
|
|
+ * locking/unlocking mvm->mutex.
|
|
|
+ */
|
|
|
+ ieee80211_iter_keys(mvm->hw, vif,
|
|
|
+ iwl_mvm_wowlan_program_keys,
|
|
|
+ &key_data);
|
|
|
+ } else {
|
|
|
+ iwl_mvm_iter_d0i3_ap_keys(mvm, vif,
|
|
|
+ iwl_mvm_wowlan_program_keys,
|
|
|
+ &key_data);
|
|
|
+ }
|
|
|
|
|
|
if (key_data.error) {
|
|
|
ret = -EIO;
|
|
@@ -909,7 +945,8 @@ int iwl_mvm_wowlan_config_key_params(struct iwl_mvm *mvm,
|
|
|
goto out;
|
|
|
}
|
|
|
|
|
|
- if (mvmvif->rekey_data.valid) {
|
|
|
+ /* configure rekey data only if offloaded rekey is supported (d3) */
|
|
|
+ if (mvmvif->rekey_data.valid && !d0i3) {
|
|
|
memset(&kek_kck_cmd, 0, sizeof(kek_kck_cmd));
|
|
|
memcpy(kek_kck_cmd.kck, mvmvif->rekey_data.kck,
|
|
|
NL80211_KCK_LEN);
|
|
@@ -956,7 +993,7 @@ iwl_mvm_wowlan_config(struct iwl_mvm *mvm,
|
|
|
* that isn't really a problem though.
|
|
|
*/
|
|
|
mutex_unlock(&mvm->mutex);
|
|
|
- ret = iwl_mvm_wowlan_config_key_params(mvm, vif, true,
|
|
|
+ ret = iwl_mvm_wowlan_config_key_params(mvm, vif, false,
|
|
|
CMD_ASYNC);
|
|
|
mutex_lock(&mvm->mutex);
|
|
|
if (ret)
|
|
@@ -1727,6 +1764,29 @@ out_unlock:
|
|
|
return false;
|
|
|
}
|
|
|
|
|
|
+void iwl_mvm_d0i3_update_keys(struct iwl_mvm *mvm,
|
|
|
+ struct ieee80211_vif *vif,
|
|
|
+ struct iwl_wowlan_status *status)
|
|
|
+{
|
|
|
+ struct iwl_mvm_d3_gtk_iter_data gtkdata = {
|
|
|
+ .status = status,
|
|
|
+ };
|
|
|
+
|
|
|
+ /*
|
|
|
+ * rekey handling requires taking locks that can't be taken now.
|
|
|
+ * however, d0i3 doesn't offload rekey, so we're fine.
|
|
|
+ */
|
|
|
+ if (WARN_ON_ONCE(status->num_of_gtk_rekeys))
|
|
|
+ return;
|
|
|
+
|
|
|
+ /* find last GTK that we used initially, if any */
|
|
|
+ gtkdata.find_phase = true;
|
|
|
+ iwl_mvm_iter_d0i3_ap_keys(mvm, vif, iwl_mvm_d3_update_keys, >kdata);
|
|
|
+
|
|
|
+ gtkdata.find_phase = false;
|
|
|
+ iwl_mvm_iter_d0i3_ap_keys(mvm, vif, iwl_mvm_d3_update_keys, >kdata);
|
|
|
+}
|
|
|
+
|
|
|
struct iwl_mvm_nd_query_results {
|
|
|
u32 matched_profiles;
|
|
|
struct iwl_scan_offload_profile_match matches[IWL_SCAN_MAX_PROFILES];
|