switch (key->cipher) { case WLAN_CIPHER_SUITE_WEP40: case WLAN_CIPHER_SUITE_WEP104: { /* hack it for now */
DEFINE_RAW_FLEX(struct iwl_mvm_wep_key_cmd, wkc, wep_key, 1); struct iwl_mvm_wep_key *wep_key = wkc->wep_key;
/* * This will fail -- the key functions don't set support * pairwise WEP keys. However, that's better than silently * failing WoWLAN. Or maybe not?
*/ if (key->flags & IEEE80211_KEY_FLAG_PAIRWISE) break;
memcpy(&wep_key->key[3], key->key, key->keylen); if (key->keyidx == mvmvif->tx_key_idx) { /* TX key must be at offset 0 */
wep_key->key_offset = 0;
} else { /* others start at 1 */
data->wep_key_idx++;
wep_key->key_offset = data->wep_key_idx;
}
mutex_lock(&mvm->mutex);
ret = iwl_mvm_send_cmd_pdu(mvm, WEP_KEY, 0,
__struct_size(wkc), wkc);
data->error = ret != 0;
/* don't upload key again */ return;
} default:
data->error = true; return; case WLAN_CIPHER_SUITE_BIP_GMAC_256: case WLAN_CIPHER_SUITE_BIP_GMAC_128: return; case WLAN_CIPHER_SUITE_AES_CMAC: /* * Ignore CMAC keys -- the WoWLAN firmware doesn't support them * but we also shouldn't abort suspend due to that. It does have * support for the IGTK key renewal, but doesn't really use the * IGTK for anything. This means we could spuriously wake up or * be deauthenticated, but that was considered acceptable.
*/ return; case WLAN_CIPHER_SUITE_TKIP: case WLAN_CIPHER_SUITE_CCMP: case WLAN_CIPHER_SUITE_GCMP: case WLAN_CIPHER_SUITE_GCMP_256: break;
}
mutex_lock(&mvm->mutex); /* * The D3 firmware hardcodes the key offset 0 as the key it * uses to transmit packets to the AP, i.e. the PTK.
*/ if (key->flags & IEEE80211_KEY_FLAG_PAIRWISE) {
mvm->ptk_ivlen = key->iv_len;
mvm->ptk_icvlen = key->icv_len;
ret = iwl_mvm_set_sta_key(mvm, vif, sta, key, 0);
} else { /* * firmware only supports TSC/RSC for a single key, * so if there are multiple keep overwriting them * with new ones -- this relies on mac80211 doing * list_add_tail().
*/
mvm->gtk_ivlen = key->iv_len;
mvm->gtk_icvlen = key->icv_len;
ret = iwl_mvm_set_sta_key(mvm, vif, sta, key, 1);
}
mutex_unlock(&mvm->mutex);
data->error = ret != 0;
}
/* * For non-QoS this relies on the fact that both the uCode and * mac80211 use TID 0 (as they need to avoid replay attacks) * for checking the IV in the frames.
*/ for (i = 0; i < IWL_NUM_RSC; i++) {
ieee80211_get_key_rx_seq(key, i, &seq);
tkip_sc[i].iv16 = cpu_to_le16(seq.tkip.iv16);
tkip_sc[i].iv32 = cpu_to_le32(seq.tkip.iv32);
}
data->have_rsc_tsc = true; break; case WLAN_CIPHER_SUITE_CCMP: case WLAN_CIPHER_SUITE_GCMP: case WLAN_CIPHER_SUITE_GCMP_256: if (sta) { struct aes_sc *aes_tx_sc;
u64 pn64;
/* * For non-QoS this relies on the fact that both the uCode and * mac80211/our RX code use TID 0 for checking the PN.
*/ if (sta && iwl_mvm_has_new_rx_api(mvm)) { struct iwl_mvm_sta *mvmsta; struct iwl_mvm_key_pn *ptk_pn; const u8 *pn;
/* only for ciphers that can be PTK/GTK */ switch (key->cipher) { default: return; case WLAN_CIPHER_SUITE_TKIP: case WLAN_CIPHER_SUITE_CCMP: case WLAN_CIPHER_SUITE_GCMP: case WLAN_CIPHER_SUITE_GCMP_256: break;
}
if (sta) {
rsc = data->rsc->ucast_rsc;
} else { if (WARN_ON(data->gtks >= ARRAY_SIZE(data->gtk_ids))) return;
data->gtk_ids[data->gtks] = key->keyidx;
rsc = data->rsc->mcast_rsc[data->gtks % 2]; if (WARN_ON(key->keyidx >=
ARRAY_SIZE(data->rsc->mcast_key_id_map))) return;
data->rsc->mcast_key_id_map[key->keyidx] = data->gtks % 2; if (data->gtks >= 2) { int prev = data->gtks - 2; int prev_idx = data->gtk_ids[prev];
switch (key->cipher) { default:
WARN_ON(1); break; case WLAN_CIPHER_SUITE_TKIP:
/* * For non-QoS this relies on the fact that both the uCode and * mac80211 use TID 0 (as they need to avoid replay attacks) * for checking the IV in the frames.
*/ for (i = 0; i < IWL_MAX_TID_COUNT; i++) {
ieee80211_get_key_rx_seq(key, i, &seq);
data->have_rsc = true; break; case WLAN_CIPHER_SUITE_CCMP: case WLAN_CIPHER_SUITE_GCMP: case WLAN_CIPHER_SUITE_GCMP_256: /* * For non-QoS this relies on the fact that both the uCode and * mac80211/our RX code use TID 0 for checking the PN.
*/ if (sta) { struct iwl_mvm_sta *mvmsta; struct iwl_mvm_key_pn *ptk_pn; const u8 *pn;
staticint iwl_mvm_wowlan_config_rsc_tsc(struct iwl_mvm *mvm, struct ieee80211_vif *vif, struct iwl_mvm_vif_link_info *mvm_link)
{ int ver = iwl_fw_lookup_cmd_ver(mvm->fw, WOWLAN_TSC_RSC_PARAM,
IWL_FW_CMD_VER_UNKNOWN); int ret;
if (ver == 5) { struct wowlan_key_rsc_v5_data data = {}; int i;
data.rsc = kzalloc(sizeof(*data.rsc), GFP_KERNEL); if (!data.rsc) return -ENOMEM;
for (i = 0; i < ARRAY_SIZE(data.rsc->mcast_key_id_map); i++)
data.rsc->mcast_key_id_map[i] =
IWL_MCAST_KEY_MAP_INVALID;
data.rsc->sta_id = cpu_to_le32(mvm_link->ap_sta_id);
for (i = 0; i < IWL_NUM_RSC; i++) {
ieee80211_get_key_rx_seq(key, i, &seq); /* wrapping isn't allowed, AP must rekey */ if (seq.tkip.iv32 > cur_rx_iv32)
cur_rx_iv32 = seq.tkip.iv32;
}
switch (key->cipher) { default: return; case WLAN_CIPHER_SUITE_TKIP: if (!sta)
data->kek_kck_cmd->gtk_cipher =
cpu_to_le32(STA_KEY_FLG_TKIP); return; case WLAN_CIPHER_SUITE_BIP_GMAC_256: case WLAN_CIPHER_SUITE_BIP_GMAC_128: if (cipher)
*cipher = cpu_to_le32(STA_KEY_FLG_GCMP); return; case WLAN_CIPHER_SUITE_AES_CMAC: case WLAN_CIPHER_SUITE_BIP_CMAC_256: if (cipher)
*cipher = cpu_to_le32(STA_KEY_FLG_CCM); return; case WLAN_CIPHER_SUITE_CCMP: if (!sta)
data->kek_kck_cmd->gtk_cipher =
cpu_to_le32(STA_KEY_FLG_CCM); return; case WLAN_CIPHER_SUITE_GCMP: case WLAN_CIPHER_SUITE_GCMP_256: if (!sta)
data->kek_kck_cmd->gtk_cipher =
cpu_to_le32(STA_KEY_FLG_GCMP); return;
}
}
iwl_mvm_stop_device(mvm); /* * Set the HW restart bit -- this is mostly true as we're * going to load new firmware and reprogram that, though * the reprogramming is going to be manual to avoid adding * all the MACs that aren't support. * We don't have to clear up everything though because the * reprogramming is manual. When we resume, we'll actually * go through a proper restart sequence again to switch * back to the runtime firmware image.
*/
set_bit(IWL_MVM_STATUS_IN_HW_RESTART, &mvm->status);
/* the fw is reset, so all the keys are cleared */
memset(mvm->fw_key_table, 0, sizeof(mvm->fw_key_table));
if (ap_sta->mfp)
wowlan_config_cmd->flags |= IS_11W_ASSOC;
if (iwl_fw_lookup_cmd_ver(mvm->fw, WOWLAN_CONFIGURATION, 0) < 6) { /* Query the last used seqno and set it */ int ret = iwl_mvm_get_last_nonqos_seq(mvm, vif);
if (iwl_fw_lookup_cmd_ver(mvm->fw, WOWLAN_CONFIGURATION, 0) < 7)
iwl_mvm_set_wowlan_qos_seq(mvm_ap_sta, wowlan_config_cmd);
if (wowlan->disconnect)
wowlan_config_cmd->wakeup_filter |=
cpu_to_le32(IWL_WOWLAN_WAKEUP_BEACON_MISS |
IWL_WOWLAN_WAKEUP_LINK_CHANGE); if (wowlan->magic_pkt)
wowlan_config_cmd->wakeup_filter |=
cpu_to_le32(IWL_WOWLAN_WAKEUP_MAGIC_PACKET); if (wowlan->gtk_rekey_failure)
wowlan_config_cmd->wakeup_filter |=
cpu_to_le32(IWL_WOWLAN_WAKEUP_GTK_REKEY_FAIL); if (wowlan->eap_identity_req)
wowlan_config_cmd->wakeup_filter |=
cpu_to_le32(IWL_WOWLAN_WAKEUP_EAP_IDENT_REQ); if (wowlan->four_way_handshake)
wowlan_config_cmd->wakeup_filter |=
cpu_to_le32(IWL_WOWLAN_WAKEUP_4WAY_HANDSHAKE); if (wowlan->n_patterns)
wowlan_config_cmd->wakeup_filter |=
cpu_to_le32(IWL_WOWLAN_WAKEUP_PATTERN_MATCH);
if (wowlan->rfkill_release)
wowlan_config_cmd->wakeup_filter |=
cpu_to_le32(IWL_WOWLAN_WAKEUP_RF_KILL_DEASSERT);
if (wowlan->tcp) { /* * Set the "link change" (really "link lost") flag as well * since that implies losing the TCP connection.
*/
wowlan_config_cmd->wakeup_filter |=
cpu_to_le32(IWL_WOWLAN_WAKEUP_REMOTE_LINK_LOSS |
IWL_WOWLAN_WAKEUP_REMOTE_SIGNATURE_TABLE |
IWL_WOWLAN_WAKEUP_REMOTE_WAKEUP_PACKET |
IWL_WOWLAN_WAKEUP_LINK_CHANGE);
}
if (!unified) { /* * if we have to configure keys, call ieee80211_iter_keys(), * as we need non-atomic context in order to take the * required locks.
*/ /* * Note that currently we don't use CMD_ASYNC in 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);
if (key_data.error) return -EIO;
}
ret = iwl_mvm_wowlan_config_rsc_tsc(mvm, vif, mvm_link); if (ret) return ret;
if (!fw_has_api(&mvm->fw->ucode_capa,
IWL_UCODE_TLV_API_TKIP_MIC_KEYS)) { int ver = iwl_fw_lookup_cmd_ver(mvm->fw, WOWLAN_TKIP_PARAM,
IWL_FW_CMD_VER_UNKNOWN); struct wowlan_key_tkip_data tkip_data = {}; int size;
if (tkip_data.have_tkip_keys) { /* send relevant data according to CMD version */
ret = iwl_mvm_send_cmd_pdu(mvm,
WOWLAN_TKIP_PARAM,
CMD_ASYNC, size,
&tkip_data.tkip); if (ret) return ret;
}
}
/* configure rekey data only if offloaded rekey is supported (d3) */ if (mvmvif->rekey_data.valid) { struct iwl_wowlan_kek_kck_material_cmd_v4 kek_kck_cmd = {}; struct iwl_wowlan_kek_kck_material_cmd_v4 *_kek_kck_cmd =
&kek_kck_cmd; struct wowlan_key_gtk_type_iter gtk_type_data = {
.kek_kck_cmd = _kek_kck_cmd,
};
ret = iwl_mvm_send_cmd_pdu(mvm, WOWLAN_CONFIGURATION, 0, sizeof(wowlan_config_cmd),
&wowlan_config_cmd);
} else {
ret = iwl_mvm_send_cmd_pdu(mvm, WOWLAN_CONFIGURATION, 0, sizeof(*wowlan_config_cmd_v6),
wowlan_config_cmd_v6);
} if (ret) return ret;
if (fw_has_api(&mvm->fw->ucode_capa,
IWL_UCODE_TLV_API_WOWLAN_TCP_SYN_WAKE))
ret = iwl_mvm_send_patterns(mvm, mvm_link, wowlan); else
ret = iwl_mvm_send_patterns_v1(mvm, wowlan); if (ret) return ret;
if (!unified_image) {
ret = iwl_mvm_switch_to_d3(mvm); if (ret) return ret;
} else { /* In theory, we wouldn't have to stop a running sched * scan in order to start another one (for * net-detect). But in practice this doesn't seem to * work properly, so stop any running sched_scan now.
*/
ret = iwl_mvm_scan_stop(mvm, IWL_MVM_SCAN_SCHED, true); if (ret) return ret;
}
ret = iwl_mvm_sched_scan_start(mvm, vif, nd_config, &mvm->nd_ies,
IWL_MVM_SCAN_NETDETECT); if (ret) return ret;
if (WARN_ON(mvm->nd_match_sets || mvm->nd_channels)) return -EBUSY;
/* save the sched scan matchsets... */ if (nd_config->n_match_sets) {
mvm->nd_match_sets = kmemdup(nd_config->match_sets, sizeof(*nd_config->match_sets) *
nd_config->n_match_sets,
GFP_KERNEL); if (mvm->nd_match_sets)
mvm->n_nd_match_sets = nd_config->n_match_sets;
}
/* ...and the sched scan channels for later reporting */
mvm->nd_channels = kmemdup(nd_config->channels, sizeof(*nd_config->channels) *
nd_config->n_channels,
GFP_KERNEL); if (mvm->nd_channels)
mvm->n_nd_channels = nd_config->n_channels;
staticint __iwl_mvm_suspend(struct ieee80211_hw *hw, struct cfg80211_wowlan *wowlan, bool test)
{ struct iwl_mvm *mvm = IWL_MAC80211_GET_MVM(hw); struct ieee80211_vif *vif = NULL; struct iwl_mvm_vif *mvmvif = NULL; struct ieee80211_sta *ap_sta = NULL; struct iwl_mvm_vif_link_info *mvm_link; struct iwl_d3_manager_config d3_cfg_cmd_data = { /* * Program the minimum sleep time to 10 seconds, as many * platforms have issues processing a wakeup signal while * still being in the process of suspending.
*/
.min_sleep_time = cpu_to_le32(10 * 1000 * 1000),
}; struct iwl_host_cmd d3_cfg_cmd = {
.id = D3_CONFIG_CMD,
.flags = CMD_WANT_SKB,
.data[0] = &d3_cfg_cmd_data,
.len[0] = sizeof(d3_cfg_cmd_data),
}; int ret; int len __maybe_unused; bool unified_image = fw_has_capa(&mvm->fw->ucode_capa,
IWL_UCODE_TLV_CAPA_CNSLDTD_D3_D0_IMG);
if (!wowlan) { /* * mac80211 shouldn't get here, but for D3 test * it doesn't warrant a warning
*/
WARN_ON(!test); return -EINVAL;
}
vif = iwl_mvm_get_bss_vif(mvm); if (IS_ERR_OR_NULL(vif)) return 1;
ret = iwl_mvm_block_esr_sync(mvm, vif, IWL_MVM_ESR_BLOCKED_WOWLAN); if (ret) return ret;
mutex_lock(&mvm->mutex);
set_bit(IWL_MVM_STATUS_IN_D3, &mvm->status);
synchronize_net();
mvmvif = iwl_mvm_vif_from_mac80211(vif);
mvm_link = mvmvif->link[iwl_mvm_get_primary_link(vif)]; if (WARN_ON_ONCE(!mvm_link)) {
ret = -EINVAL; goto out_noreset;
}
if (mvm_link->ap_sta_id == IWL_INVALID_STA) { /* if we're not associated, this must be netdetect */ if (!wowlan->nd_config) {
ret = 1; goto out_noreset;
}
ret = iwl_mvm_netdetect_config(
mvm, wowlan, wowlan->nd_config, vif); if (ret) goto out;
ap_sta = rcu_dereference_protected(
mvm->fw_id_to_mac_id[mvm_link->ap_sta_id],
lockdep_is_held(&mvm->mutex)); if (IS_ERR_OR_NULL(ap_sta)) {
ret = -EINVAL; goto out_noreset;
}
ret = iwl_mvm_sta_ensure_queue(
mvm, ap_sta->txq[wowlan_config_cmd.offloading_tid]); if (ret) goto out_noreset;
ret = iwl_mvm_get_wowlan_config(mvm, wowlan, &wowlan_config_cmd,
vif, mvmvif, ap_sta); if (ret) goto out_noreset;
ret = iwl_mvm_wowlan_config(mvm, wowlan, &wowlan_config_cmd,
vif, mvmvif, mvm_link, ap_sta); if (ret) goto out;
mvm->net_detect = false;
}
ret = iwl_mvm_power_update_device(mvm); if (ret) goto out;
ret = iwl_mvm_power_update_mac(mvm); if (ret) goto out;
#ifdef CONFIG_IWLWIFI_DEBUGFS if (mvm->d3_wake_sysassert)
d3_cfg_cmd_data.wakeup_flags |=
cpu_to_le32(IWL_WAKEUP_D3_CONFIG_FW_ERROR); #endif
/* * Prior to 9000 device family the driver needs to stop the dbg * recording before entering D3. In later devices the FW stops the * recording automatically.
*/ if (mvm->trans->mac_cfg->device_family < IWL_DEVICE_FAMILY_9000)
iwl_fw_dbg_stop_restart_recording(&mvm->fwrt, NULL, true);
/* must be last -- this switches firmware state */
ret = iwl_mvm_send_cmd(mvm, &d3_cfg_cmd); if (ret) goto out; #ifdef CONFIG_IWLWIFI_DEBUGFS
len = iwl_rx_packet_payload_len(d3_cfg_cmd.resp_pkt); if (len >= sizeof(u32)) {
mvm->d3_test_pme_ptr =
le32_to_cpup((__le32 *)d3_cfg_cmd.resp_pkt->data);
} #endif
iwl_free_resp(&d3_cfg_cmd);
/* converted data from the different status responses */ struct iwl_wowlan_status_data {
u64 replay_ctr;
u32 num_of_gtk_rekeys;
u32 received_beacons;
u32 wakeup_reasons;
u32 wake_packet_length;
u32 wake_packet_bufsize;
u16 pattern_number;
u16 non_qos_seq_ctr;
u16 qos_seq_ctr[8];
u8 tid_tear_down;
u8 tid_offloaded_tx;
struct { /* including RX MIC key for TKIP */
u8 key[WOWLAN_KEY_MAX_SIZE];
u8 len;
u8 flags;
u8 id;
} gtk[WOWLAN_GTK_KEYS_NUM];
struct { /* * We store both the TKIP and AES representations * coming from the firmware because we decode the * data from there before we iterate the keys and * know which one we need.
*/ struct { struct ieee80211_key_seq seq[IWL_MAX_TID_COUNT];
} tkip, aes;
/* * We use -1 for when we have valid data but don't know * the key ID from firmware, and thus it needs to be * installed with the last key (depending on rekeying).
*/
s8 key_id; bool valid;
} gtk_seq[2];
struct { /* Same as above */ struct { struct ieee80211_key_seq seq[IWL_MAX_TID_COUNT];
u64 tx_pn;
} tkip, aes;
} ptk;
if (ieee80211_has_protected(hdr->frame_control)) { /* * This is unlocked and using gtk_i(c)vlen, * but since everything is under RTNL still * that's not really a problem - changing * it would be difficult.
*/ if (is_multicast_ether_addr(hdr->addr1)) {
ivlen = mvm->gtk_ivlen;
icvlen += mvm->gtk_icvlen;
} else {
ivlen = mvm->ptk_ivlen;
icvlen += mvm->ptk_icvlen;
}
}
/* if truncated, FCS/ICV is (partially) gone */ if (truncated >= icvlen) {
icvlen = 0;
truncated -= icvlen;
} else {
icvlen -= truncated;
truncated = 0;
}
rcu_read_lock();
ptk_pn = rcu_dereference(mvmsta->ptk_pn[key->keyidx]); if (WARN_ON(!ptk_pn)) {
rcu_read_unlock(); return;
}
for (tid = 0; tid < IWL_MAX_TID_COUNT; tid++) { int i;
for (i = 1; i < mvm->trans->info.num_rxqs; i++)
memcpy(ptk_pn->q[i].pn[tid],
status->ptk.aes.seq[tid].ccmp.pn,
IEEE80211_CCMP_PN_LEN);
}
rcu_read_unlock();
}
staticvoid iwl_mvm_convert_key_counters(struct iwl_wowlan_status_data *status, union iwl_all_tsc_rsc *sc, u8 key_idx)
{ int i;
switch (key->cipher) { case WLAN_CIPHER_SUITE_WEP40: case WLAN_CIPHER_SUITE_WEP104: /* ignore WEP completely, nothing to do */ return; case WLAN_CIPHER_SUITE_CCMP: case WLAN_CIPHER_SUITE_GCMP: case WLAN_CIPHER_SUITE_GCMP_256: case WLAN_CIPHER_SUITE_TKIP: /* we support these */
data->gtk_cipher = key->cipher; break; case WLAN_CIPHER_SUITE_BIP_GMAC_128: case WLAN_CIPHER_SUITE_BIP_GMAC_256: case WLAN_CIPHER_SUITE_BIP_CMAC_256: case WLAN_CIPHER_SUITE_AES_CMAC: /* we support these */ if (data->igtk_support &&
(key->keyidx == 4 || key->keyidx == 5)) {
data->igtk_cipher = key->cipher;
} elseif (data->bigtk_support &&
(key->keyidx == 6 || key->keyidx == 7)) {
data->bigtk_cipher = key->cipher;
} else {
data->unhandled_cipher = true; return;
} break; default: /* everything else - disconnect from AP */
data->unhandled_cipher = true; return;
}
data->num_keys++;
}
staticvoid
iwl_mvm_d3_set_igtk_bigtk_ipn(conststruct iwl_multicast_key_data *key, struct ieee80211_key_seq *seq, u32 cipher)
{ switch (cipher) { case WLAN_CIPHER_SUITE_BIP_GMAC_128: case WLAN_CIPHER_SUITE_BIP_GMAC_256:
BUILD_BUG_ON(sizeof(seq->aes_gmac.pn) != sizeof(key->ipn));
memcpy(seq->aes_gmac.pn, key->ipn, sizeof(seq->aes_gmac.pn)); break; case WLAN_CIPHER_SUITE_BIP_CMAC_256: case WLAN_CIPHER_SUITE_AES_CMAC:
BUILD_BUG_ON(sizeof(seq->aes_cmac.pn) != sizeof(key->ipn));
memcpy(seq->aes_cmac.pn, key->ipn, sizeof(seq->aes_cmac.pn)); break; default:
WARN_ON(1);
}
}
switch (key->cipher) { case WLAN_CIPHER_SUITE_WEP40: case WLAN_CIPHER_SUITE_WEP104: /* ignore WEP completely, nothing to do */ return; case WLAN_CIPHER_SUITE_CCMP: case WLAN_CIPHER_SUITE_GCMP: case WLAN_CIPHER_SUITE_GCMP_256: if (sta) {
atomic64_set(&key->tx_pn, status->ptk.aes.tx_pn);
iwl_mvm_set_aes_ptk_rx_seq(data->mvm, status, sta, key); return;
}
fallthrough; case WLAN_CIPHER_SUITE_TKIP: if (sta) {
atomic64_set(&key->tx_pn, status->ptk.tkip.tx_pn);
iwl_mvm_set_key_rx_seq_tids(key, status->ptk.tkip.seq); return;
}
keyidx = key->keyidx; /* * Update the seq even if there was a rekey. If there was a * rekey, we will update again after replacing the key
*/ if ((status->gtk[0].len && keyidx == status->gtk[0].id) ||
(status->gtk[1].len && keyidx == status->gtk[1].id))
iwl_mvm_set_key_rx_seq(key, status); break; case WLAN_CIPHER_SUITE_BIP_GMAC_128: case WLAN_CIPHER_SUITE_BIP_GMAC_256: case WLAN_CIPHER_SUITE_BIP_CMAC_256: case WLAN_CIPHER_SUITE_AES_CMAC: if (key->keyidx == 4 || key->keyidx == 5) {
iwl_mvm_d3_update_igtk_bigtk(status, key,
&status->igtk);
} if (key->keyidx == 6 || key->keyidx == 7) {
u8 idx = key->keyidx == status->bigtk[1].id;
key = ieee80211_gtk_rekey_add(vif, status->gtk[i].id, key_data, sizeof(key_data), link_id); if (IS_ERR(key)) { /* FW may send also the old keys */ if (PTR_ERR(key) == -EALREADY) continue; returnfalse;
}
if (iwl_fw_lookup_notif_ver(mvm->fw, PROT_OFFLOAD_GROUP,
WOWLAN_INFO_NOTIFICATION,
0) >= 3)
gtkdata.bigtk_support = true;
/* find last GTK that we used initially, if any */
ieee80211_iter_keys(mvm->hw, vif,
iwl_mvm_d3_find_last_keys, >kdata); /* not trying to keep connections with MFP/unhandled ciphers */ if (gtkdata.unhandled_cipher) returnfalse; if (!gtkdata.num_keys) goto out;
/* * invalidate all other GTKs that might still exist and update * the one that we used
*/
ieee80211_iter_keys(mvm->hw, vif,
iwl_mvm_d3_update_keys, >kdata);
if (status->num_of_gtk_rekeys) {
__be64 replay_ctr = cpu_to_be64(status->replay_ctr);
IWL_DEBUG_WOWLAN(mvm, "num of GTK rekeying %d\n",
status->num_of_gtk_rekeys);
if (!iwl_mvm_gtk_rekey(status, vif, mvm, gtkdata.gtk_cipher)) returnfalse;
if (!iwl_mvm_d3_igtk_bigtk_rekey_add(status, vif,
gtkdata.igtk_cipher,
&status->igtk)) returnfalse;
for (i = 0; i < ARRAY_SIZE(status->bigtk); i++) { if (!iwl_mvm_d3_igtk_bigtk_rekey_add(status, vif,
gtkdata.bigtk_cipher,
&status->bigtk[i])) returnfalse;
}
out: if (iwl_fw_lookup_notif_ver(mvm->fw, LONG_GROUP,
WOWLAN_GET_STATUSES,
IWL_FW_CMD_VER_UNKNOWN) < 10) {
mvmvif->seqno_valid = true; /* +0x10 because the set API expects next-to-use, not last-used */
mvmvif->seqno = status->non_qos_seq_ctr + 0x10;
}
if (status->wakeup_reasons & disconnection_reasons) returnfalse;
/* if it's as long as the TKIP encryption key, copy MIC key */ if (status->gtk[0].len == NL80211_TKIP_DATA_OFFSET_TX_MIC_KEY)
memcpy(status->gtk[0].key + NL80211_TKIP_DATA_OFFSET_RX_MIC_KEY,
data->tkip_mic_key, sizeof(data->tkip_mic_key));
}
/* if it's as long as the TKIP encryption key, copy MIC key */ if (status->gtk[status_idx].len ==
NL80211_TKIP_DATA_OFFSET_TX_MIC_KEY)
memcpy(status->gtk[status_idx].key +
NL80211_TKIP_DATA_OFFSET_RX_MIC_KEY,
data[data_idx].tkip_mic_key, sizeof(data[data_idx].tkip_mic_key));
status_idx++;
}
}
staticvoid iwl_mvm_convert_igtk(struct iwl_wowlan_status_data *status, struct iwl_wowlan_igtk_status *data)
{ int i;
/* mac80211 expects big endian for memcmp() to work, convert */ for (i = 0; i < sizeof(data->ipn); i++)
status->igtk.ipn[i] = data->ipn[sizeof(data->ipn) - i - 1];
}
/* Occasionally, templates would be nice. This is one of those times ... */ #define iwl_mvm_parse_wowlan_status_common(_ver) \
--> --------------------
--> maximum size reached
--> --------------------
Messung V0.5
¤ Dauer der Verarbeitung: 0.14 Sekunden
(vorverarbeitet)
¤
Die Informationen auf dieser Webseite wurden
nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit,
noch Qualität der bereit gestellten Informationen zugesichert.
Bemerkung:
Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.