Commit 32fed470 authored by Naftali Goldstein's avatar Naftali Goldstein Committed by Gregory Greenman
Browse files

wifi: iwlwifi: mvm: d3: parse keys from wowlan info notification



This notification replaces the WOWLAN_GET_STATUSES command-and-response,
so it's required to parse all the keys in the notification just like
what happened when that command was used.

Move around a few required static functions in order to avoid forward
declarations.

Signed-off-by: default avatarNaftali Goldstein <naftali.goldstein@intel.com>
Signed-off-by: default avatarGregory Greenman <gregory.greenman@intel.com>
Link: https://lore.kernel.org/r/20220906161827.ca3fb23cab81.I0a9fe7729af4567b98813bc51bad13ee5512a0ae@changeid


Signed-off-by: default avatarGregory Greenman <gregory.greenman@intel.com>
parent 4a0e6422
Loading
Loading
Loading
Loading
+88 −83
Original line number Diff line number Diff line
@@ -1944,6 +1944,94 @@ static bool iwl_mvm_setup_connection_keep(struct iwl_mvm *mvm,
	return true;
}

static void iwl_mvm_convert_gtk_v2(struct iwl_wowlan_status_data *status,
				   struct iwl_wowlan_gtk_status_v2 *data)
{
	BUILD_BUG_ON(sizeof(status->gtk.key) < sizeof(data->key));
	BUILD_BUG_ON(NL80211_TKIP_DATA_OFFSET_RX_MIC_KEY +
		     sizeof(data->tkip_mic_key) >
		     sizeof(status->gtk.key));

	status->gtk.len = data->key_len;
	status->gtk.flags = data->key_flags;

	memcpy(status->gtk.key, data->key, sizeof(data->key));

	/* if it's as long as the TKIP encryption key, copy MIC key */
	if (status->gtk.len == NL80211_TKIP_DATA_OFFSET_TX_MIC_KEY)
		memcpy(status->gtk.key + NL80211_TKIP_DATA_OFFSET_RX_MIC_KEY,
		       data->tkip_mic_key, sizeof(data->tkip_mic_key));
}

static void iwl_mvm_convert_gtk_v3(struct iwl_wowlan_status_data *status,
				   struct iwl_wowlan_gtk_status_v3 *data)
{
	/* The parts we need are identical in v2 and v3 */
#define CHECK(_f) do {							\
	BUILD_BUG_ON(offsetof(struct iwl_wowlan_gtk_status_v2, _f) !=	\
		     offsetof(struct iwl_wowlan_gtk_status_v3, _f));	\
	BUILD_BUG_ON(offsetofend(struct iwl_wowlan_gtk_status_v2, _f) !=\
		     offsetofend(struct iwl_wowlan_gtk_status_v3, _f));	\
} while (0)

	CHECK(key);
	CHECK(key_len);
	CHECK(key_flags);
	CHECK(tkip_mic_key);
#undef CHECK

	iwl_mvm_convert_gtk_v2(status, (void *)data);
}

static void iwl_mvm_convert_igtk(struct iwl_wowlan_status_data *status,
				 struct iwl_wowlan_igtk_status *data)
{
	const u8 *ipn = data->ipn;

	BUILD_BUG_ON(sizeof(status->igtk.key) < sizeof(data->key));

	status->igtk.len = data->key_len;
	status->igtk.flags = data->key_flags;

	memcpy(status->igtk.key, data->key, sizeof(data->key));

	status->igtk.ipn = ((u64)ipn[5] <<  0) |
			   ((u64)ipn[4] <<  8) |
			   ((u64)ipn[3] << 16) |
			   ((u64)ipn[2] << 24) |
			   ((u64)ipn[1] << 32) |
			   ((u64)ipn[0] << 40);
}

static void iwl_mvm_parse_wowlan_info_notif(struct iwl_mvm *mvm,
					    struct iwl_wowlan_info_notif *data,
					    struct iwl_wowlan_status_data *status,
					    u32 len)
{
	u32 i;

	if (len < sizeof(*data)) {
		IWL_ERR(mvm, "Invalid WoWLAN info notification!\n");
		status = NULL;
		return;
	}

	iwl_mvm_convert_key_counters_v5(status, &data->gtk[0].sc);
	iwl_mvm_convert_gtk_v3(status, &data->gtk[0]);
	iwl_mvm_convert_igtk(status, &data->igtk[0]);

	status->replay_ctr = le64_to_cpu(data->replay_ctr);
	status->pattern_number = le16_to_cpu(data->pattern_number);
	for (i = 0; i < IWL_MAX_TID_COUNT; i++)
		status->qos_seq_ctr[i] =
			le16_to_cpu(data->qos_seq_ctr[i]);
	status->wakeup_reasons = le32_to_cpu(data->wakeup_reasons);
	status->num_of_gtk_rekeys =
		le32_to_cpu(data->num_of_gtk_rekeys);
	status->received_beacons = le32_to_cpu(data->received_beacons);
	status->tid_tear_down = data->tid_tear_down;
}

/* Occasionally, templates would be nice. This is one of those times ... */
#define iwl_mvm_parse_wowlan_status_common(_ver)			\
static struct iwl_wowlan_status_data *					\
@@ -2005,89 +2093,6 @@ iwl_mvm_parse_wowlan_status_common(v7)
iwl_mvm_parse_wowlan_status_common(v9)
iwl_mvm_parse_wowlan_status_common(v12)

static void iwl_mvm_parse_wowlan_info_notif(struct iwl_mvm *mvm,
					    struct iwl_wowlan_info_notif *data,
					    struct iwl_wowlan_status_data *status,
					    u32 len)
{
	u32 i;

	if (len < sizeof(*data)) {
		IWL_ERR(mvm, "Invalid WoWLAN info notification!\n");
		status = NULL;
		return;
	}

	status->replay_ctr = le64_to_cpu(data->replay_ctr);
	status->pattern_number = le16_to_cpu(data->pattern_number);
	for (i = 0; i < IWL_MAX_TID_COUNT; i++)
		status->qos_seq_ctr[i] =
			le16_to_cpu(data->qos_seq_ctr[i]);
	status->wakeup_reasons = le32_to_cpu(data->wakeup_reasons);
	status->num_of_gtk_rekeys =
		le32_to_cpu(data->num_of_gtk_rekeys);
	status->received_beacons = le32_to_cpu(data->received_beacons);
}

static void iwl_mvm_convert_gtk_v2(struct iwl_wowlan_status_data *status,
				   struct iwl_wowlan_gtk_status_v2 *data)
{
	BUILD_BUG_ON(sizeof(status->gtk.key) < sizeof(data->key));
	BUILD_BUG_ON(NL80211_TKIP_DATA_OFFSET_RX_MIC_KEY +
		     sizeof(data->tkip_mic_key) >
		     sizeof(status->gtk.key));

	status->gtk.len = data->key_len;
	status->gtk.flags = data->key_flags;

	memcpy(status->gtk.key, data->key, sizeof(data->key));

	/* if it's as long as the TKIP encryption key, copy MIC key */
	if (status->gtk.len == NL80211_TKIP_DATA_OFFSET_TX_MIC_KEY)
		memcpy(status->gtk.key + NL80211_TKIP_DATA_OFFSET_RX_MIC_KEY,
		       data->tkip_mic_key, sizeof(data->tkip_mic_key));
}

static void iwl_mvm_convert_gtk_v3(struct iwl_wowlan_status_data *status,
				   struct iwl_wowlan_gtk_status_v3 *data)
{
	/* The parts we need are identical in v2 and v3 */
#define CHECK(_f) do {							\
	BUILD_BUG_ON(offsetof(struct iwl_wowlan_gtk_status_v2, _f) !=	\
		     offsetof(struct iwl_wowlan_gtk_status_v3, _f));	\
	BUILD_BUG_ON(offsetofend(struct iwl_wowlan_gtk_status_v2, _f) !=\
		     offsetofend(struct iwl_wowlan_gtk_status_v3, _f));	\
} while (0)

	CHECK(key);
	CHECK(key_len);
	CHECK(key_flags);
	CHECK(tkip_mic_key);
#undef CHECK

	iwl_mvm_convert_gtk_v2(status, (void *)data);
}

static void iwl_mvm_convert_igtk(struct iwl_wowlan_status_data *status,
				 struct iwl_wowlan_igtk_status *data)
{
	const u8 *ipn = data->ipn;

	BUILD_BUG_ON(sizeof(status->igtk.key) < sizeof(data->key));

	status->igtk.len = data->key_len;
	status->igtk.flags = data->key_flags;

	memcpy(status->igtk.key, data->key, sizeof(data->key));

	status->igtk.ipn = ((u64)ipn[5] <<  0) |
			   ((u64)ipn[4] <<  8) |
			   ((u64)ipn[3] << 16) |
			   ((u64)ipn[2] << 24) |
			   ((u64)ipn[1] << 32) |
			   ((u64)ipn[0] << 40);
}

static struct iwl_wowlan_status_data *
iwl_mvm_send_wowlan_get_status(struct iwl_mvm *mvm, u8 sta_id)
{