Skip to content

Commit 04f78e2

Browse files
yedidyaBenshjmberg-intel
authored andcommitted
wifi: iwlwifi: mvm: Add support for IGTK in D3 resume flow
As part of the new security API in the FW, all security keys are to be removed before station removal. Until now IGTK rekey wasn't supported in the D3 resume flow, and thus the driver might not know the right key to remove. If an IGTK was rekeyed during D3 the old IGTK is removed and the new key is updated. If not, the old key's IPN is updated. As opposed to GTK, which both the FW and the driver hold it's two most recent keys, only one IGTK is held. Signed-off-by: Yedidya Benshimol <[email protected]> Signed-off-by: Gregory Greenman <[email protected]> Link: https://lore.kernel.org/r/20230621144844.b53c301c07e6.I375277a10a1f756b93d4a343f6664351a80189c5@changeid Signed-off-by: Johannes Berg <[email protected]>
1 parent fa4e48f commit 04f78e2

File tree

2 files changed

+147
-25
lines changed
  • drivers/net/wireless/intel/iwlwifi

2 files changed

+147
-25
lines changed

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

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
/* SPDX-License-Identifier: GPL-2.0 OR BSD-3-Clause */
22
/*
3-
* Copyright (C) 2012-2014, 2018-2022 Intel Corporation
3+
* Copyright (C) 2012-2014, 2018-2023 Intel Corporation
44
* Copyright (C) 2013-2014 Intel Mobile Communications GmbH
55
* Copyright (C) 2015-2017 Intel Deutschland GmbH
66
*/
@@ -396,6 +396,7 @@ struct iwl_wowlan_config_cmd {
396396
#define WOWLAN_KEY_MAX_SIZE 32
397397
#define WOWLAN_GTK_KEYS_NUM 2
398398
#define WOWLAN_IGTK_KEYS_NUM 2
399+
#define WOWLAN_IGTK_MIN_INDEX 4
399400

400401
/*
401402
* WOWLAN_TSC_RSC_PARAMS
@@ -612,6 +613,7 @@ struct iwl_wowlan_gtk_status_v3 {
612613
} __packed; /* WOWLAN_GTK_MATERIAL_VER_3 */
613614

614615
#define IWL_WOWLAN_GTK_IDX_MASK (BIT(0) | BIT(1))
616+
#define IWL_WOWLAN_IGTK_BIGTK_IDX_MASK (BIT(0))
615617

616618
/**
617619
* struct iwl_wowlan_igtk_status - IGTK status

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

Lines changed: 144 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -1380,6 +1380,14 @@ int iwl_mvm_suspend(struct ieee80211_hw *hw, struct cfg80211_wowlan *wowlan)
13801380
return __iwl_mvm_suspend(hw, wowlan, false);
13811381
}
13821382

1383+
struct iwl_multicast_key_data {
1384+
u8 key[WOWLAN_KEY_MAX_SIZE];
1385+
u8 len;
1386+
u8 flags;
1387+
u8 id;
1388+
u8 ipn[6];
1389+
};
1390+
13831391
/* converted data from the different status responses */
13841392
struct iwl_wowlan_status_data {
13851393
u64 replay_ctr;
@@ -1429,12 +1437,7 @@ struct iwl_wowlan_status_data {
14291437
} tkip, aes;
14301438
} ptk;
14311439

1432-
struct {
1433-
u64 ipn;
1434-
u8 key[WOWLAN_KEY_MAX_SIZE];
1435-
u8 len;
1436-
u8 flags;
1437-
} igtk;
1440+
struct iwl_multicast_key_data igtk;
14381441

14391442
u8 *wake_packet;
14401443
};
@@ -1778,8 +1781,8 @@ static void iwl_mvm_set_key_rx_seq(struct ieee80211_key_conf *key,
17781781
struct iwl_mvm_d3_gtk_iter_data {
17791782
struct iwl_mvm *mvm;
17801783
struct iwl_wowlan_status_data *status;
1781-
u32 gtk_cipher;
1782-
bool unhandled_cipher;
1784+
u32 gtk_cipher, igtk_cipher;
1785+
bool unhandled_cipher, igtk_support;
17831786
int num_keys;
17841787
};
17851788

@@ -1806,6 +1809,19 @@ static void iwl_mvm_d3_find_last_keys(struct ieee80211_hw *hw,
18061809
/* we support these */
18071810
data->gtk_cipher = key->cipher;
18081811
break;
1812+
case WLAN_CIPHER_SUITE_BIP_GMAC_128:
1813+
case WLAN_CIPHER_SUITE_BIP_GMAC_256:
1814+
case WLAN_CIPHER_SUITE_BIP_CMAC_256:
1815+
case WLAN_CIPHER_SUITE_AES_CMAC:
1816+
/* we support these */
1817+
if (data->igtk_support &&
1818+
(key->keyidx == 4 || key->keyidx == 5)) {
1819+
data->igtk_cipher = key->cipher;
1820+
} else {
1821+
data->unhandled_cipher = true;
1822+
return;
1823+
}
1824+
break;
18091825
default:
18101826
/* everything else - disconnect from AP */
18111827
data->unhandled_cipher = true;
@@ -1815,6 +1831,23 @@ static void iwl_mvm_d3_find_last_keys(struct ieee80211_hw *hw,
18151831
data->num_keys++;
18161832
}
18171833

1834+
static void
1835+
iwl_mvm_d3_set_igtk_bigtk_ipn(const struct iwl_multicast_key_data *key,
1836+
struct ieee80211_key_seq *seq, u32 cipher)
1837+
{
1838+
switch (cipher) {
1839+
case WLAN_CIPHER_SUITE_BIP_GMAC_128:
1840+
case WLAN_CIPHER_SUITE_BIP_GMAC_256:
1841+
BUILD_BUG_ON(sizeof(seq->aes_gmac.pn) != sizeof(key->ipn));
1842+
memcpy(seq->aes_gmac.pn, key->ipn, sizeof(seq->aes_gmac.pn));
1843+
break;
1844+
case WLAN_CIPHER_SUITE_BIP_CMAC_256:
1845+
BUILD_BUG_ON(sizeof(seq->aes_cmac.pn) != sizeof(key->ipn));
1846+
memcpy(seq->aes_cmac.pn, key->ipn, sizeof(seq->aes_cmac.pn));
1847+
break;
1848+
}
1849+
}
1850+
18181851
static void iwl_mvm_d3_update_keys(struct ieee80211_hw *hw,
18191852
struct ieee80211_vif *vif,
18201853
struct ieee80211_sta *sta,
@@ -1861,6 +1894,24 @@ static void iwl_mvm_d3_update_keys(struct ieee80211_hw *hw,
18611894
} else {
18621895
iwl_mvm_set_key_rx_seq(key, data->status, false);
18631896
}
1897+
break;
1898+
case WLAN_CIPHER_SUITE_BIP_GMAC_128:
1899+
case WLAN_CIPHER_SUITE_BIP_GMAC_256:
1900+
case WLAN_CIPHER_SUITE_BIP_CMAC_256:
1901+
case WLAN_CIPHER_SUITE_AES_CMAC:
1902+
if (key->keyidx == 4 || key->keyidx == 5) {
1903+
/* remove rekeyed key */
1904+
if (status->num_of_gtk_rekeys) {
1905+
ieee80211_remove_key(key);
1906+
} else {
1907+
struct ieee80211_key_seq seq;
1908+
1909+
iwl_mvm_d3_set_igtk_bigtk_ipn(&status->igtk,
1910+
&seq,
1911+
key->cipher);
1912+
ieee80211_set_key_rx_seq(key, 0, &seq);
1913+
}
1914+
}
18641915
}
18651916
}
18661917

@@ -1918,6 +1969,70 @@ static bool iwl_mvm_gtk_rekey(struct iwl_wowlan_status_data *status,
19181969
return true;
19191970
}
19201971

1972+
static bool
1973+
iwl_mvm_d3_igtk_bigtk_rekey_add(struct iwl_wowlan_status_data *status,
1974+
struct ieee80211_vif *vif, u32 cipher,
1975+
struct iwl_multicast_key_data *key_data)
1976+
{
1977+
struct ieee80211_key_conf *key_config;
1978+
struct {
1979+
struct ieee80211_key_conf conf;
1980+
u8 key[WOWLAN_KEY_MAX_SIZE];
1981+
} conf = {
1982+
.conf.cipher = cipher,
1983+
.conf.keyidx = key_data->id,
1984+
};
1985+
struct ieee80211_key_seq seq;
1986+
1987+
if (!key_data->len)
1988+
return true;
1989+
1990+
iwl_mvm_d3_set_igtk_bigtk_ipn(key_data, &seq, conf.conf.cipher);
1991+
1992+
switch (cipher) {
1993+
case WLAN_CIPHER_SUITE_BIP_GMAC_128:
1994+
conf.conf.keylen = WLAN_KEY_LEN_BIP_GMAC_128;
1995+
break;
1996+
case WLAN_CIPHER_SUITE_BIP_GMAC_256:
1997+
conf.conf.keylen = WLAN_KEY_LEN_BIP_GMAC_256;
1998+
break;
1999+
case WLAN_CIPHER_SUITE_AES_CMAC:
2000+
conf.conf.keylen = WLAN_KEY_LEN_AES_CMAC;
2001+
break;
2002+
case WLAN_CIPHER_SUITE_BIP_CMAC_256:
2003+
conf.conf.keylen = WLAN_KEY_LEN_BIP_CMAC_256;
2004+
break;
2005+
default:
2006+
WARN_ON(1);
2007+
}
2008+
BUILD_BUG_ON(sizeof(conf.key) < sizeof(key_data->key));
2009+
memcpy(conf.conf.key, key_data->key, conf.conf.keylen);
2010+
2011+
key_config = ieee80211_gtk_rekey_add(vif, &conf.conf);
2012+
if (IS_ERR(key_config))
2013+
return false;
2014+
ieee80211_set_key_rx_seq(key_config, 0, &seq);
2015+
return true;
2016+
}
2017+
2018+
static int iwl_mvm_lookup_wowlan_status_ver(struct iwl_mvm *mvm)
2019+
{
2020+
u8 notif_ver;
2021+
2022+
if (!fw_has_api(&mvm->fw->ucode_capa,
2023+
IWL_UCODE_TLV_API_WOWLAN_KEY_MATERIAL))
2024+
return 6;
2025+
2026+
/* default to 7 (when we have IWL_UCODE_TLV_API_WOWLAN_KEY_MATERIAL) */
2027+
notif_ver = iwl_fw_lookup_notif_ver(mvm->fw, LONG_GROUP,
2028+
WOWLAN_GET_STATUSES, 0);
2029+
if (!notif_ver)
2030+
notif_ver = iwl_fw_lookup_notif_ver(mvm->fw, LEGACY_GROUP,
2031+
WOWLAN_GET_STATUSES, 7);
2032+
2033+
return notif_ver;
2034+
}
2035+
19212036
static bool iwl_mvm_setup_connection_keep(struct iwl_mvm *mvm,
19222037
struct ieee80211_vif *vif,
19232038
struct iwl_wowlan_status_data *status)
@@ -1937,6 +2052,12 @@ static bool iwl_mvm_setup_connection_keep(struct iwl_mvm *mvm,
19372052
if (status->wakeup_reasons & disconnection_reasons)
19382053
return false;
19392054

2055+
if (iwl_mvm_lookup_wowlan_status_ver(mvm) > 6 ||
2056+
iwl_fw_lookup_notif_ver(mvm->fw, PROT_OFFLOAD_GROUP,
2057+
WOWLAN_INFO_NOTIFICATION,
2058+
0))
2059+
gtkdata.igtk_support = true;
2060+
19402061
/* find last GTK that we used initially, if any */
19412062
ieee80211_iter_keys(mvm->hw, vif,
19422063
iwl_mvm_d3_find_last_keys, &gtkdata);
@@ -1961,6 +2082,12 @@ static bool iwl_mvm_setup_connection_keep(struct iwl_mvm *mvm,
19612082

19622083
if (!iwl_mvm_gtk_rekey(status, vif, mvm, gtkdata.gtk_cipher))
19632084
return false;
2085+
2086+
if (!iwl_mvm_d3_igtk_bigtk_rekey_add(status, vif,
2087+
gtkdata.igtk_cipher,
2088+
&status->igtk))
2089+
return false;
2090+
19642091
ieee80211_gtk_rekey_notify(vif, vif->bss_conf.bssid,
19652092
(void *)&replay_ctr, GFP_KERNEL);
19662093
}
@@ -2030,21 +2157,19 @@ static void iwl_mvm_convert_gtk_v3(struct iwl_wowlan_status_data *status,
20302157
static void iwl_mvm_convert_igtk(struct iwl_wowlan_status_data *status,
20312158
struct iwl_wowlan_igtk_status *data)
20322159
{
2033-
const u8 *ipn = data->ipn;
2034-
20352160
BUILD_BUG_ON(sizeof(status->igtk.key) < sizeof(data->key));
20362161

2162+
if (!data->key_len)
2163+
return;
2164+
20372165
status->igtk.len = data->key_len;
20382166
status->igtk.flags = data->key_flags;
2167+
status->igtk.id = u32_get_bits(data->key_flags,
2168+
IWL_WOWLAN_IGTK_BIGTK_IDX_MASK)
2169+
+ WOWLAN_IGTK_MIN_INDEX;
20392170

20402171
memcpy(status->igtk.key, data->key, sizeof(data->key));
2041-
2042-
status->igtk.ipn = ((u64)ipn[5] << 0) |
2043-
((u64)ipn[4] << 8) |
2044-
((u64)ipn[3] << 16) |
2045-
((u64)ipn[2] << 24) |
2046-
((u64)ipn[1] << 32) |
2047-
((u64)ipn[0] << 40);
2172+
memcpy(status->igtk.ipn, data->ipn, sizeof(data->ipn));
20482173
}
20492174

20502175
static void iwl_mvm_parse_wowlan_info_notif(struct iwl_mvm *mvm,
@@ -2175,14 +2300,9 @@ iwl_mvm_send_wowlan_get_status(struct iwl_mvm *mvm, u8 sta_id)
21752300
len = iwl_rx_packet_payload_len(cmd.resp_pkt);
21762301

21772302
/* default to 7 (when we have IWL_UCODE_TLV_API_WOWLAN_KEY_MATERIAL) */
2178-
notif_ver = iwl_fw_lookup_notif_ver(mvm->fw, LONG_GROUP,
2179-
WOWLAN_GET_STATUSES, 0);
2180-
if (!notif_ver)
2181-
notif_ver = iwl_fw_lookup_notif_ver(mvm->fw, LEGACY_GROUP,
2182-
WOWLAN_GET_STATUSES, 7);
2303+
notif_ver = iwl_mvm_lookup_wowlan_status_ver(mvm);
21832304

2184-
if (!fw_has_api(&mvm->fw->ucode_capa,
2185-
IWL_UCODE_TLV_API_WOWLAN_KEY_MATERIAL)) {
2305+
if (notif_ver < 7) {
21862306
struct iwl_wowlan_status_v6 *v6 = (void *)cmd.resp_pkt->data;
21872307

21882308
status = iwl_mvm_parse_wowlan_status_common_v6(mvm, v6, len);

0 commit comments

Comments
 (0)