Skip to content

Commit 79e561f

Browse files
jmberg-intellucacoelho
authored andcommitted
iwlwifi: mvm: d3: implement RSC command version 5
In later firmware we haven't needed the TSC anyway since we have it already (and firmware image doesn't change), but the new version adds the ability to send down replay counters for more than one GTK. Implement that. Signed-off-by: Johannes Berg <[email protected]> Signed-off-by: Luca Coelho <[email protected]> Link: https://lore.kernel.org/r/iwlwifi.20210805130823.28cd065e8c4a.Ic8406a78ee46b07e0ca1b8199522ef08ec6eef53@changeid Signed-off-by: Luca Coelho <[email protected]>
1 parent af3aab9 commit 79e561f

File tree

3 files changed

+191
-30
lines changed

3 files changed

+191
-30
lines changed

drivers/net/wireless/intel/iwlwifi/fw/api/commands.h

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -550,7 +550,8 @@ enum iwl_legacy_cmds {
550550
WOWLAN_CONFIGURATION = 0xe1,
551551

552552
/**
553-
* @WOWLAN_TSC_RSC_PARAM: &struct iwl_wowlan_rsc_tsc_params_cmd
553+
* @WOWLAN_TSC_RSC_PARAM: &struct iwl_wowlan_rsc_tsc_params_cmd_v4,
554+
* &struct iwl_wowlan_rsc_tsc_params_cmd
554555
*/
555556
WOWLAN_TSC_RSC_PARAM = 0xe2,
556557

drivers/net/wireless/intel/iwlwifi/fw/api/d3.h

Lines changed: 15 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@
66
*/
77
#ifndef __iwl_fw_api_d3_h__
88
#define __iwl_fw_api_d3_h__
9+
#include <iwl-trans.h>
910

1011
/**
1112
* enum iwl_d0i3_flags - d0i3 flags
@@ -389,11 +390,14 @@ struct iwl_wowlan_config_cmd {
389390
u8 reserved;
390391
} __packed; /* WOWLAN_CONFIG_API_S_VER_5 */
391392

393+
#define IWL_NUM_RSC 16
394+
#define WOWLAN_KEY_MAX_SIZE 32
395+
#define WOWLAN_GTK_KEYS_NUM 2
396+
#define WOWLAN_IGTK_KEYS_NUM 2
397+
392398
/*
393399
* WOWLAN_TSC_RSC_PARAMS
394400
*/
395-
#define IWL_NUM_RSC 16
396-
397401
struct tkip_sc {
398402
__le16 iv16;
399403
__le16 pad;
@@ -425,11 +429,19 @@ struct iwl_wowlan_rsc_tsc_params_cmd_ver_2 {
425429
union iwl_all_tsc_rsc all_tsc_rsc;
426430
} __packed; /* ALL_TSC_RSC_API_S_VER_2 */
427431

428-
struct iwl_wowlan_rsc_tsc_params_cmd {
432+
struct iwl_wowlan_rsc_tsc_params_cmd_v4 {
429433
struct iwl_wowlan_rsc_tsc_params_cmd_ver_2 params;
430434
__le32 sta_id;
431435
} __packed; /* ALL_TSC_RSC_API_S_VER_4 */
432436

437+
struct iwl_wowlan_rsc_tsc_params_cmd {
438+
__le64 ucast_rsc[IWL_MAX_TID_COUNT];
439+
__le64 mcast_rsc[WOWLAN_GTK_KEYS_NUM][IWL_MAX_TID_COUNT];
440+
__le32 sta_id;
441+
#define IWL_MCAST_KEY_MAP_INVALID 0xff
442+
u8 mcast_key_id_map[4];
443+
} __packed; /* ALL_TSC_RSC_API_S_VER_5 */
444+
433445
#define IWL_MIC_KEY_SIZE 8
434446
struct iwl_mic_keys {
435447
u8 tx[IWL_MIC_KEY_SIZE];
@@ -541,10 +553,6 @@ struct iwl_wowlan_gtk_status_v1 {
541553
struct iwl_wowlan_rsc_tsc_params_cmd_ver_2 rsc;
542554
} __packed; /* WOWLAN_GTK_MATERIAL_VER_1 */
543555

544-
#define WOWLAN_KEY_MAX_SIZE 32
545-
#define WOWLAN_GTK_KEYS_NUM 2
546-
#define WOWLAN_IGTK_KEYS_NUM 2
547-
548556
/**
549557
* struct iwl_wowlan_gtk_status - GTK status
550558
* @key: GTK material

drivers/net/wireless/intel/iwlwifi/mvm/d3.c

Lines changed: 174 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -211,7 +211,7 @@ static void iwl_mvm_wowlan_program_keys(struct ieee80211_hw *hw,
211211
}
212212

213213
struct wowlan_key_rsc_tsc_data {
214-
struct iwl_wowlan_rsc_tsc_params_cmd *rsc_tsc;
214+
struct iwl_wowlan_rsc_tsc_params_cmd_v4 *rsc_tsc;
215215
bool have_rsc_tsc;
216216
};
217217

@@ -327,42 +327,194 @@ static void iwl_mvm_wowlan_get_rsc_tsc_data(struct ieee80211_hw *hw,
327327
}
328328
}
329329

330+
struct wowlan_key_rsc_v5_data {
331+
struct iwl_wowlan_rsc_tsc_params_cmd *rsc;
332+
bool have_rsc;
333+
int gtks;
334+
int gtk_ids[4];
335+
};
336+
337+
static void iwl_mvm_wowlan_get_rsc_v5_data(struct ieee80211_hw *hw,
338+
struct ieee80211_vif *vif,
339+
struct ieee80211_sta *sta,
340+
struct ieee80211_key_conf *key,
341+
void *_data)
342+
{
343+
struct iwl_mvm *mvm = IWL_MAC80211_GET_MVM(hw);
344+
struct wowlan_key_rsc_v5_data *data = _data;
345+
struct ieee80211_key_seq seq;
346+
__le64 *rsc;
347+
int i;
348+
349+
/* only for ciphers that can be PTK/GTK */
350+
switch (key->cipher) {
351+
default:
352+
return;
353+
case WLAN_CIPHER_SUITE_TKIP:
354+
case WLAN_CIPHER_SUITE_CCMP:
355+
case WLAN_CIPHER_SUITE_GCMP:
356+
case WLAN_CIPHER_SUITE_GCMP_256:
357+
break;
358+
}
359+
360+
if (sta) {
361+
rsc = data->rsc->ucast_rsc;
362+
} else {
363+
if (WARN_ON(data->gtks > ARRAY_SIZE(data->gtk_ids)))
364+
return;
365+
data->gtk_ids[data->gtks] = key->keyidx;
366+
rsc = data->rsc->mcast_rsc[data->gtks % 2];
367+
if (WARN_ON(key->keyidx >
368+
ARRAY_SIZE(data->rsc->mcast_key_id_map)))
369+
return;
370+
data->rsc->mcast_key_id_map[key->keyidx] = data->gtks % 2;
371+
if (data->gtks >= 2) {
372+
int prev = data->gtks - 2;
373+
int prev_idx = data->gtk_ids[prev];
374+
375+
data->rsc->mcast_key_id_map[prev_idx] =
376+
IWL_MCAST_KEY_MAP_INVALID;
377+
}
378+
data->gtks++;
379+
}
380+
381+
switch (key->cipher) {
382+
default:
383+
WARN_ON(1);
384+
break;
385+
case WLAN_CIPHER_SUITE_TKIP:
386+
387+
/*
388+
* For non-QoS this relies on the fact that both the uCode and
389+
* mac80211 use TID 0 (as they need to to avoid replay attacks)
390+
* for checking the IV in the frames.
391+
*/
392+
for (i = 0; i < IWL_MAX_TID_COUNT; i++) {
393+
ieee80211_get_key_rx_seq(key, i, &seq);
394+
395+
rsc[i] = cpu_to_le64(((u64)seq.tkip.iv32 << 16) |
396+
seq.tkip.iv16);
397+
}
398+
399+
data->have_rsc = true;
400+
break;
401+
case WLAN_CIPHER_SUITE_CCMP:
402+
case WLAN_CIPHER_SUITE_GCMP:
403+
case WLAN_CIPHER_SUITE_GCMP_256:
404+
/*
405+
* For non-QoS this relies on the fact that both the uCode and
406+
* mac80211/our RX code use TID 0 for checking the PN.
407+
*/
408+
if (sta) {
409+
struct iwl_mvm_sta *mvmsta;
410+
struct iwl_mvm_key_pn *ptk_pn;
411+
const u8 *pn;
412+
413+
mvmsta = iwl_mvm_sta_from_mac80211(sta);
414+
rcu_read_lock();
415+
ptk_pn = rcu_dereference(mvmsta->ptk_pn[key->keyidx]);
416+
if (WARN_ON(!ptk_pn)) {
417+
rcu_read_unlock();
418+
break;
419+
}
420+
421+
for (i = 0; i < IWL_MAX_TID_COUNT; i++) {
422+
pn = iwl_mvm_find_max_pn(key, ptk_pn, &seq, i,
423+
mvm->trans->num_rx_queues);
424+
rsc[i] = cpu_to_le64((u64)pn[5] |
425+
((u64)pn[4] << 8) |
426+
((u64)pn[3] << 16) |
427+
((u64)pn[2] << 24) |
428+
((u64)pn[1] << 32) |
429+
((u64)pn[0] << 40));
430+
}
431+
432+
rcu_read_unlock();
433+
} else {
434+
for (i = 0; i < IWL_MAX_TID_COUNT; i++) {
435+
u8 *pn = seq.ccmp.pn;
436+
437+
ieee80211_get_key_rx_seq(key, i, &seq);
438+
rsc[i] = cpu_to_le64((u64)pn[5] |
439+
((u64)pn[4] << 8) |
440+
((u64)pn[3] << 16) |
441+
((u64)pn[2] << 24) |
442+
((u64)pn[1] << 32) |
443+
((u64)pn[0] << 40));
444+
}
445+
}
446+
data->have_rsc = true;
447+
break;
448+
}
449+
}
450+
330451
static int iwl_mvm_wowlan_config_rsc_tsc(struct iwl_mvm *mvm,
331452
struct ieee80211_vif *vif)
332453
{
333454
struct iwl_mvm_vif *mvmvif = iwl_mvm_vif_from_mac80211(vif);
334455
int ver = iwl_fw_lookup_cmd_ver(mvm->fw, LONG_GROUP,
335456
WOWLAN_TSC_RSC_PARAM,
336457
IWL_FW_CMD_VER_UNKNOWN);
337-
struct wowlan_key_rsc_tsc_data data = {};
338-
int size;
339458
int ret;
340459

341-
data.rsc_tsc = kzalloc(sizeof(*data.rsc_tsc), GFP_KERNEL);
342-
if (!data.rsc_tsc)
343-
return -ENOMEM;
460+
if (ver == 5) {
461+
struct wowlan_key_rsc_v5_data data = {};
462+
int i;
463+
464+
data.rsc = kmalloc(sizeof(*data.rsc), GFP_KERNEL);
465+
if (!data.rsc)
466+
return -ENOMEM;
467+
468+
memset(data.rsc, 0xff, sizeof(*data.rsc));
469+
470+
for (i = 0; i < ARRAY_SIZE(data.rsc->mcast_key_id_map); i++)
471+
data.rsc->mcast_key_id_map[i] =
472+
IWL_MCAST_KEY_MAP_INVALID;
473+
data.rsc->sta_id = cpu_to_le32(mvmvif->ap_sta_id);
474+
475+
ieee80211_iter_keys(mvm->hw, vif,
476+
iwl_mvm_wowlan_get_rsc_v5_data,
477+
&data);
478+
479+
if (data.have_rsc)
480+
ret = iwl_mvm_send_cmd_pdu(mvm, WOWLAN_TSC_RSC_PARAM,
481+
CMD_ASYNC, sizeof(*data.rsc),
482+
data.rsc);
483+
else
484+
ret = 0;
485+
kfree(data.rsc);
486+
} else if (ver == 4 || ver == 2 || ver == IWL_FW_CMD_VER_UNKNOWN) {
487+
struct wowlan_key_rsc_tsc_data data = {};
488+
int size;
344489

345-
if (ver == 4) {
346-
size = sizeof(*data.rsc_tsc);
347-
data.rsc_tsc->sta_id = cpu_to_le32(mvmvif->ap_sta_id);
348-
} else if (ver == 2 || ver == IWL_FW_CMD_VER_UNKNOWN) {
349-
size = sizeof(data.rsc_tsc->params);
490+
data.rsc_tsc = kzalloc(sizeof(*data.rsc_tsc), GFP_KERNEL);
491+
if (!data.rsc_tsc)
492+
return -ENOMEM;
493+
494+
if (ver == 4) {
495+
size = sizeof(*data.rsc_tsc);
496+
data.rsc_tsc->sta_id = cpu_to_le32(mvmvif->ap_sta_id);
497+
} else {
498+
/* ver == 2 || ver == IWL_FW_CMD_VER_UNKNOWN */
499+
size = sizeof(data.rsc_tsc->params);
500+
}
501+
502+
ieee80211_iter_keys(mvm->hw, vif,
503+
iwl_mvm_wowlan_get_rsc_tsc_data,
504+
&data);
505+
506+
if (data.have_rsc_tsc)
507+
ret = iwl_mvm_send_cmd_pdu(mvm, WOWLAN_TSC_RSC_PARAM,
508+
CMD_ASYNC, size,
509+
data.rsc_tsc);
510+
else
511+
ret = 0;
512+
kfree(data.rsc_tsc);
350513
} else {
351514
ret = 0;
352515
WARN_ON_ONCE(1);
353-
goto out;
354516
}
355517

356-
ieee80211_iter_keys(mvm->hw, vif, iwl_mvm_wowlan_get_rsc_tsc_data,
357-
&data);
358-
359-
if (data.have_rsc_tsc)
360-
ret = iwl_mvm_send_cmd_pdu(mvm, WOWLAN_TSC_RSC_PARAM,
361-
CMD_ASYNC, size, data.rsc_tsc);
362-
else
363-
ret = 0;
364-
out:
365-
kfree(data.rsc_tsc);
366518
return ret;
367519
}
368520

0 commit comments

Comments
 (0)