3778 lines · c
1// SPDX-License-Identifier: GPL-2.0 OR BSD-3-Clause2/*3 * Copyright (C) 2012-2014, 2018-2024 Intel Corporation4 * Copyright (C) 2013-2015 Intel Mobile Communications GmbH5 * Copyright (C) 2016-2017 Intel Deutschland GmbH6 */7#include <linux/etherdevice.h>8#include <linux/ip.h>9#include <linux/fs.h>10#include <net/cfg80211.h>11#include <net/ipv6.h>12#include <net/tcp.h>13#include <net/addrconf.h>14#include "iwl-modparams.h"15#include "fw-api.h"16#include "mvm.h"17#include "fw/img.h"18 19void iwl_mvm_set_rekey_data(struct ieee80211_hw *hw,20 struct ieee80211_vif *vif,21 struct cfg80211_gtk_rekey_data *data)22{23 struct iwl_mvm *mvm = IWL_MAC80211_GET_MVM(hw);24 struct iwl_mvm_vif *mvmvif = iwl_mvm_vif_from_mac80211(vif);25 26 mutex_lock(&mvm->mutex);27 28 mvmvif->rekey_data.kek_len = data->kek_len;29 mvmvif->rekey_data.kck_len = data->kck_len;30 memcpy(mvmvif->rekey_data.kek, data->kek, data->kek_len);31 memcpy(mvmvif->rekey_data.kck, data->kck, data->kck_len);32 mvmvif->rekey_data.akm = data->akm & 0xFF;33 mvmvif->rekey_data.replay_ctr =34 cpu_to_le64(be64_to_cpup((const __be64 *)data->replay_ctr));35 mvmvif->rekey_data.valid = true;36 37 mutex_unlock(&mvm->mutex);38}39 40#if IS_ENABLED(CONFIG_IPV6)41void iwl_mvm_ipv6_addr_change(struct ieee80211_hw *hw,42 struct ieee80211_vif *vif,43 struct inet6_dev *idev)44{45 struct iwl_mvm_vif *mvmvif = iwl_mvm_vif_from_mac80211(vif);46 struct inet6_ifaddr *ifa;47 int idx = 0;48 49 memset(mvmvif->tentative_addrs, 0, sizeof(mvmvif->tentative_addrs));50 51 read_lock_bh(&idev->lock);52 list_for_each_entry(ifa, &idev->addr_list, if_list) {53 mvmvif->target_ipv6_addrs[idx] = ifa->addr;54 if (ifa->flags & IFA_F_TENTATIVE)55 __set_bit(idx, mvmvif->tentative_addrs);56 idx++;57 if (idx >= IWL_PROTO_OFFLOAD_NUM_IPV6_ADDRS_MAX)58 break;59 }60 read_unlock_bh(&idev->lock);61 62 mvmvif->num_target_ipv6_addrs = idx;63}64#endif65 66void iwl_mvm_set_default_unicast_key(struct ieee80211_hw *hw,67 struct ieee80211_vif *vif, int idx)68{69 struct iwl_mvm_vif *mvmvif = iwl_mvm_vif_from_mac80211(vif);70 71 mvmvif->tx_key_idx = idx;72}73 74static void iwl_mvm_convert_p1k(u16 *p1k, __le16 *out)75{76 int i;77 78 for (i = 0; i < IWL_P1K_SIZE; i++)79 out[i] = cpu_to_le16(p1k[i]);80}81 82static const u8 *iwl_mvm_find_max_pn(struct ieee80211_key_conf *key,83 struct iwl_mvm_key_pn *ptk_pn,84 struct ieee80211_key_seq *seq,85 int tid, int queues)86{87 const u8 *ret = seq->ccmp.pn;88 int i;89 90 /* get the PN from mac80211, used on the default queue */91 ieee80211_get_key_rx_seq(key, tid, seq);92 93 /* and use the internal data for the other queues */94 for (i = 1; i < queues; i++) {95 const u8 *tmp = ptk_pn->q[i].pn[tid];96 97 if (memcmp(ret, tmp, IEEE80211_CCMP_PN_LEN) <= 0)98 ret = tmp;99 }100 101 return ret;102}103 104struct wowlan_key_reprogram_data {105 bool error;106 int wep_key_idx;107};108 109static void iwl_mvm_wowlan_program_keys(struct ieee80211_hw *hw,110 struct ieee80211_vif *vif,111 struct ieee80211_sta *sta,112 struct ieee80211_key_conf *key,113 void *_data)114{115 struct iwl_mvm *mvm = IWL_MAC80211_GET_MVM(hw);116 struct iwl_mvm_vif *mvmvif = iwl_mvm_vif_from_mac80211(vif);117 struct wowlan_key_reprogram_data *data = _data;118 int ret;119 120 switch (key->cipher) {121 case WLAN_CIPHER_SUITE_WEP40:122 case WLAN_CIPHER_SUITE_WEP104: { /* hack it for now */123 struct {124 struct iwl_mvm_wep_key_cmd wep_key_cmd;125 struct iwl_mvm_wep_key wep_key;126 } __packed wkc = {127 .wep_key_cmd.mac_id_n_color =128 cpu_to_le32(FW_CMD_ID_AND_COLOR(mvmvif->id,129 mvmvif->color)),130 .wep_key_cmd.num_keys = 1,131 /* firmware sets STA_KEY_FLG_WEP_13BYTES */132 .wep_key_cmd.decryption_type = STA_KEY_FLG_WEP,133 .wep_key.key_index = key->keyidx,134 .wep_key.key_size = key->keylen,135 };136 137 /*138 * This will fail -- the key functions don't set support139 * pairwise WEP keys. However, that's better than silently140 * failing WoWLAN. Or maybe not?141 */142 if (key->flags & IEEE80211_KEY_FLAG_PAIRWISE)143 break;144 145 memcpy(&wkc.wep_key.key[3], key->key, key->keylen);146 if (key->keyidx == mvmvif->tx_key_idx) {147 /* TX key must be at offset 0 */148 wkc.wep_key.key_offset = 0;149 } else {150 /* others start at 1 */151 data->wep_key_idx++;152 wkc.wep_key.key_offset = data->wep_key_idx;153 }154 155 mutex_lock(&mvm->mutex);156 ret = iwl_mvm_send_cmd_pdu(mvm, WEP_KEY, 0, sizeof(wkc), &wkc);157 data->error = ret != 0;158 159 mvm->ptk_ivlen = key->iv_len;160 mvm->ptk_icvlen = key->icv_len;161 mvm->gtk_ivlen = key->iv_len;162 mvm->gtk_icvlen = key->icv_len;163 mutex_unlock(&mvm->mutex);164 165 /* don't upload key again */166 return;167 }168 default:169 data->error = true;170 return;171 case WLAN_CIPHER_SUITE_BIP_GMAC_256:172 case WLAN_CIPHER_SUITE_BIP_GMAC_128:173 return;174 case WLAN_CIPHER_SUITE_AES_CMAC:175 /*176 * Ignore CMAC keys -- the WoWLAN firmware doesn't support them177 * but we also shouldn't abort suspend due to that. It does have178 * support for the IGTK key renewal, but doesn't really use the179 * IGTK for anything. This means we could spuriously wake up or180 * be deauthenticated, but that was considered acceptable.181 */182 return;183 case WLAN_CIPHER_SUITE_TKIP:184 case WLAN_CIPHER_SUITE_CCMP:185 case WLAN_CIPHER_SUITE_GCMP:186 case WLAN_CIPHER_SUITE_GCMP_256:187 break;188 }189 190 mutex_lock(&mvm->mutex);191 /*192 * The D3 firmware hardcodes the key offset 0 as the key it193 * uses to transmit packets to the AP, i.e. the PTK.194 */195 if (key->flags & IEEE80211_KEY_FLAG_PAIRWISE) {196 mvm->ptk_ivlen = key->iv_len;197 mvm->ptk_icvlen = key->icv_len;198 ret = iwl_mvm_set_sta_key(mvm, vif, sta, key, 0);199 } else {200 /*201 * firmware only supports TSC/RSC for a single key,202 * so if there are multiple keep overwriting them203 * with new ones -- this relies on mac80211 doing204 * list_add_tail().205 */206 mvm->gtk_ivlen = key->iv_len;207 mvm->gtk_icvlen = key->icv_len;208 ret = iwl_mvm_set_sta_key(mvm, vif, sta, key, 1);209 }210 mutex_unlock(&mvm->mutex);211 data->error = ret != 0;212}213 214struct wowlan_key_rsc_tsc_data {215 struct iwl_wowlan_rsc_tsc_params_cmd_v4 *rsc_tsc;216 bool have_rsc_tsc;217};218 219static void iwl_mvm_wowlan_get_rsc_tsc_data(struct ieee80211_hw *hw,220 struct ieee80211_vif *vif,221 struct ieee80211_sta *sta,222 struct ieee80211_key_conf *key,223 void *_data)224{225 struct iwl_mvm *mvm = IWL_MAC80211_GET_MVM(hw);226 struct wowlan_key_rsc_tsc_data *data = _data;227 struct aes_sc *aes_sc;228 struct tkip_sc *tkip_sc, *tkip_tx_sc = NULL;229 struct ieee80211_key_seq seq;230 int i;231 232 switch (key->cipher) {233 default:234 break;235 case WLAN_CIPHER_SUITE_TKIP:236 if (sta) {237 u64 pn64;238 239 tkip_sc =240 data->rsc_tsc->params.all_tsc_rsc.tkip.unicast_rsc;241 tkip_tx_sc =242 &data->rsc_tsc->params.all_tsc_rsc.tkip.tsc;243 244 pn64 = atomic64_read(&key->tx_pn);245 tkip_tx_sc->iv16 = cpu_to_le16(TKIP_PN_TO_IV16(pn64));246 tkip_tx_sc->iv32 = cpu_to_le32(TKIP_PN_TO_IV32(pn64));247 } else {248 tkip_sc =249 data->rsc_tsc->params.all_tsc_rsc.tkip.multicast_rsc;250 }251 252 /*253 * For non-QoS this relies on the fact that both the uCode and254 * mac80211 use TID 0 (as they need to to avoid replay attacks)255 * for checking the IV in the frames.256 */257 for (i = 0; i < IWL_NUM_RSC; i++) {258 ieee80211_get_key_rx_seq(key, i, &seq);259 tkip_sc[i].iv16 = cpu_to_le16(seq.tkip.iv16);260 tkip_sc[i].iv32 = cpu_to_le32(seq.tkip.iv32);261 }262 263 data->have_rsc_tsc = true;264 break;265 case WLAN_CIPHER_SUITE_CCMP:266 case WLAN_CIPHER_SUITE_GCMP:267 case WLAN_CIPHER_SUITE_GCMP_256:268 if (sta) {269 struct aes_sc *aes_tx_sc;270 u64 pn64;271 272 aes_sc =273 data->rsc_tsc->params.all_tsc_rsc.aes.unicast_rsc;274 aes_tx_sc =275 &data->rsc_tsc->params.all_tsc_rsc.aes.tsc;276 277 pn64 = atomic64_read(&key->tx_pn);278 aes_tx_sc->pn = cpu_to_le64(pn64);279 } else {280 aes_sc =281 data->rsc_tsc->params.all_tsc_rsc.aes.multicast_rsc;282 }283 284 /*285 * For non-QoS this relies on the fact that both the uCode and286 * mac80211/our RX code use TID 0 for checking the PN.287 */288 if (sta && iwl_mvm_has_new_rx_api(mvm)) {289 struct iwl_mvm_sta *mvmsta;290 struct iwl_mvm_key_pn *ptk_pn;291 const u8 *pn;292 293 mvmsta = iwl_mvm_sta_from_mac80211(sta);294 rcu_read_lock();295 ptk_pn = rcu_dereference(mvmsta->ptk_pn[key->keyidx]);296 if (WARN_ON(!ptk_pn)) {297 rcu_read_unlock();298 break;299 }300 301 for (i = 0; i < IWL_MAX_TID_COUNT; i++) {302 pn = iwl_mvm_find_max_pn(key, ptk_pn, &seq, i,303 mvm->trans->num_rx_queues);304 aes_sc[i].pn = cpu_to_le64((u64)pn[5] |305 ((u64)pn[4] << 8) |306 ((u64)pn[3] << 16) |307 ((u64)pn[2] << 24) |308 ((u64)pn[1] << 32) |309 ((u64)pn[0] << 40));310 }311 312 rcu_read_unlock();313 } else {314 for (i = 0; i < IWL_NUM_RSC; i++) {315 u8 *pn = seq.ccmp.pn;316 317 ieee80211_get_key_rx_seq(key, i, &seq);318 aes_sc[i].pn = cpu_to_le64((u64)pn[5] |319 ((u64)pn[4] << 8) |320 ((u64)pn[3] << 16) |321 ((u64)pn[2] << 24) |322 ((u64)pn[1] << 32) |323 ((u64)pn[0] << 40));324 }325 }326 data->have_rsc_tsc = true;327 break;328 }329}330 331struct wowlan_key_rsc_v5_data {332 struct iwl_wowlan_rsc_tsc_params_cmd *rsc;333 bool have_rsc;334 int gtks;335 int gtk_ids[4];336};337 338static void iwl_mvm_wowlan_get_rsc_v5_data(struct ieee80211_hw *hw,339 struct ieee80211_vif *vif,340 struct ieee80211_sta *sta,341 struct ieee80211_key_conf *key,342 void *_data)343{344 struct iwl_mvm *mvm = IWL_MAC80211_GET_MVM(hw);345 struct wowlan_key_rsc_v5_data *data = _data;346 struct ieee80211_key_seq seq;347 __le64 *rsc;348 int i;349 350 /* only for ciphers that can be PTK/GTK */351 switch (key->cipher) {352 default:353 return;354 case WLAN_CIPHER_SUITE_TKIP:355 case WLAN_CIPHER_SUITE_CCMP:356 case WLAN_CIPHER_SUITE_GCMP:357 case WLAN_CIPHER_SUITE_GCMP_256:358 break;359 }360 361 if (sta) {362 rsc = data->rsc->ucast_rsc;363 } else {364 if (WARN_ON(data->gtks >= ARRAY_SIZE(data->gtk_ids)))365 return;366 data->gtk_ids[data->gtks] = key->keyidx;367 rsc = data->rsc->mcast_rsc[data->gtks % 2];368 if (WARN_ON(key->keyidx >=369 ARRAY_SIZE(data->rsc->mcast_key_id_map)))370 return;371 data->rsc->mcast_key_id_map[key->keyidx] = data->gtks % 2;372 if (data->gtks >= 2) {373 int prev = data->gtks - 2;374 int prev_idx = data->gtk_ids[prev];375 376 data->rsc->mcast_key_id_map[prev_idx] =377 IWL_MCAST_KEY_MAP_INVALID;378 }379 data->gtks++;380 }381 382 switch (key->cipher) {383 default:384 WARN_ON(1);385 break;386 case WLAN_CIPHER_SUITE_TKIP:387 388 /*389 * For non-QoS this relies on the fact that both the uCode and390 * mac80211 use TID 0 (as they need to to avoid replay attacks)391 * for checking the IV in the frames.392 */393 for (i = 0; i < IWL_MAX_TID_COUNT; i++) {394 ieee80211_get_key_rx_seq(key, i, &seq);395 396 rsc[i] = cpu_to_le64(((u64)seq.tkip.iv32 << 16) |397 seq.tkip.iv16);398 }399 400 data->have_rsc = true;401 break;402 case WLAN_CIPHER_SUITE_CCMP:403 case WLAN_CIPHER_SUITE_GCMP:404 case WLAN_CIPHER_SUITE_GCMP_256:405 /*406 * For non-QoS this relies on the fact that both the uCode and407 * mac80211/our RX code use TID 0 for checking the PN.408 */409 if (sta) {410 struct iwl_mvm_sta *mvmsta;411 struct iwl_mvm_key_pn *ptk_pn;412 const u8 *pn;413 414 mvmsta = iwl_mvm_sta_from_mac80211(sta);415 rcu_read_lock();416 ptk_pn = rcu_dereference(mvmsta->ptk_pn[key->keyidx]);417 if (WARN_ON(!ptk_pn)) {418 rcu_read_unlock();419 break;420 }421 422 for (i = 0; i < IWL_MAX_TID_COUNT; i++) {423 pn = iwl_mvm_find_max_pn(key, ptk_pn, &seq, i,424 mvm->trans->num_rx_queues);425 rsc[i] = cpu_to_le64((u64)pn[5] |426 ((u64)pn[4] << 8) |427 ((u64)pn[3] << 16) |428 ((u64)pn[2] << 24) |429 ((u64)pn[1] << 32) |430 ((u64)pn[0] << 40));431 }432 433 rcu_read_unlock();434 } else {435 for (i = 0; i < IWL_MAX_TID_COUNT; i++) {436 u8 *pn = seq.ccmp.pn;437 438 ieee80211_get_key_rx_seq(key, i, &seq);439 rsc[i] = cpu_to_le64((u64)pn[5] |440 ((u64)pn[4] << 8) |441 ((u64)pn[3] << 16) |442 ((u64)pn[2] << 24) |443 ((u64)pn[1] << 32) |444 ((u64)pn[0] << 40));445 }446 }447 data->have_rsc = true;448 break;449 }450}451 452static int iwl_mvm_wowlan_config_rsc_tsc(struct iwl_mvm *mvm,453 struct ieee80211_vif *vif,454 struct iwl_mvm_vif_link_info *mvm_link)455{456 int ver = iwl_fw_lookup_cmd_ver(mvm->fw, WOWLAN_TSC_RSC_PARAM,457 IWL_FW_CMD_VER_UNKNOWN);458 int ret;459 460 if (ver == 5) {461 struct wowlan_key_rsc_v5_data data = {};462 int i;463 464 data.rsc = kzalloc(sizeof(*data.rsc), GFP_KERNEL);465 if (!data.rsc)466 return -ENOMEM;467 468 for (i = 0; i < ARRAY_SIZE(data.rsc->mcast_key_id_map); i++)469 data.rsc->mcast_key_id_map[i] =470 IWL_MCAST_KEY_MAP_INVALID;471 data.rsc->sta_id = cpu_to_le32(mvm_link->ap_sta_id);472 473 ieee80211_iter_keys(mvm->hw, vif,474 iwl_mvm_wowlan_get_rsc_v5_data,475 &data);476 477 if (data.have_rsc)478 ret = iwl_mvm_send_cmd_pdu(mvm, WOWLAN_TSC_RSC_PARAM,479 CMD_ASYNC, sizeof(*data.rsc),480 data.rsc);481 else482 ret = 0;483 kfree(data.rsc);484 } else if (ver == 4 || ver == 2 || ver == IWL_FW_CMD_VER_UNKNOWN) {485 struct wowlan_key_rsc_tsc_data data = {};486 int size;487 488 data.rsc_tsc = kzalloc(sizeof(*data.rsc_tsc), GFP_KERNEL);489 if (!data.rsc_tsc)490 return -ENOMEM;491 492 if (ver == 4) {493 size = sizeof(*data.rsc_tsc);494 data.rsc_tsc->sta_id =495 cpu_to_le32(mvm_link->ap_sta_id);496 } else {497 /* ver == 2 || ver == IWL_FW_CMD_VER_UNKNOWN */498 size = sizeof(data.rsc_tsc->params);499 }500 501 ieee80211_iter_keys(mvm->hw, vif,502 iwl_mvm_wowlan_get_rsc_tsc_data,503 &data);504 505 if (data.have_rsc_tsc)506 ret = iwl_mvm_send_cmd_pdu(mvm, WOWLAN_TSC_RSC_PARAM,507 CMD_ASYNC, size,508 data.rsc_tsc);509 else510 ret = 0;511 kfree(data.rsc_tsc);512 } else {513 ret = 0;514 WARN_ON_ONCE(1);515 }516 517 return ret;518}519 520struct wowlan_key_tkip_data {521 struct iwl_wowlan_tkip_params_cmd tkip;522 bool have_tkip_keys;523};524 525static void iwl_mvm_wowlan_get_tkip_data(struct ieee80211_hw *hw,526 struct ieee80211_vif *vif,527 struct ieee80211_sta *sta,528 struct ieee80211_key_conf *key,529 void *_data)530{531 struct wowlan_key_tkip_data *data = _data;532 struct iwl_p1k_cache *rx_p1ks;533 u8 *rx_mic_key;534 struct ieee80211_key_seq seq;535 u32 cur_rx_iv32 = 0;536 u16 p1k[IWL_P1K_SIZE];537 int i;538 539 switch (key->cipher) {540 default:541 break;542 case WLAN_CIPHER_SUITE_TKIP:543 if (sta) {544 u64 pn64;545 546 rx_p1ks = data->tkip.rx_uni;547 548 pn64 = atomic64_read(&key->tx_pn);549 550 ieee80211_get_tkip_p1k_iv(key, TKIP_PN_TO_IV32(pn64),551 p1k);552 iwl_mvm_convert_p1k(p1k, data->tkip.tx.p1k);553 554 memcpy(data->tkip.mic_keys.tx,555 &key->key[NL80211_TKIP_DATA_OFFSET_TX_MIC_KEY],556 IWL_MIC_KEY_SIZE);557 558 rx_mic_key = data->tkip.mic_keys.rx_unicast;559 } else {560 rx_p1ks = data->tkip.rx_multi;561 rx_mic_key = data->tkip.mic_keys.rx_mcast;562 }563 564 for (i = 0; i < IWL_NUM_RSC; i++) {565 ieee80211_get_key_rx_seq(key, i, &seq);566 /* wrapping isn't allowed, AP must rekey */567 if (seq.tkip.iv32 > cur_rx_iv32)568 cur_rx_iv32 = seq.tkip.iv32;569 }570 571 ieee80211_get_tkip_rx_p1k(key, vif->bss_conf.bssid,572 cur_rx_iv32, p1k);573 iwl_mvm_convert_p1k(p1k, rx_p1ks[0].p1k);574 ieee80211_get_tkip_rx_p1k(key, vif->bss_conf.bssid,575 cur_rx_iv32 + 1, p1k);576 iwl_mvm_convert_p1k(p1k, rx_p1ks[1].p1k);577 578 memcpy(rx_mic_key,579 &key->key[NL80211_TKIP_DATA_OFFSET_RX_MIC_KEY],580 IWL_MIC_KEY_SIZE);581 582 data->have_tkip_keys = true;583 break;584 }585}586 587struct wowlan_key_gtk_type_iter {588 struct iwl_wowlan_kek_kck_material_cmd_v4 *kek_kck_cmd;589};590 591static void iwl_mvm_wowlan_gtk_type_iter(struct ieee80211_hw *hw,592 struct ieee80211_vif *vif,593 struct ieee80211_sta *sta,594 struct ieee80211_key_conf *key,595 void *_data)596{597 struct wowlan_key_gtk_type_iter *data = _data;598 __le32 *cipher = NULL;599 600 if (key->keyidx == 4 || key->keyidx == 5)601 cipher = &data->kek_kck_cmd->igtk_cipher;602 if (key->keyidx == 6 || key->keyidx == 7)603 cipher = &data->kek_kck_cmd->bigtk_cipher;604 605 switch (key->cipher) {606 default:607 return;608 case WLAN_CIPHER_SUITE_TKIP:609 if (!sta)610 data->kek_kck_cmd->gtk_cipher =611 cpu_to_le32(STA_KEY_FLG_TKIP);612 return;613 case WLAN_CIPHER_SUITE_BIP_GMAC_256:614 case WLAN_CIPHER_SUITE_BIP_GMAC_128:615 if (cipher)616 *cipher = cpu_to_le32(STA_KEY_FLG_GCMP);617 return;618 case WLAN_CIPHER_SUITE_AES_CMAC:619 case WLAN_CIPHER_SUITE_BIP_CMAC_256:620 if (cipher)621 *cipher = cpu_to_le32(STA_KEY_FLG_CCM);622 return;623 case WLAN_CIPHER_SUITE_CCMP:624 if (!sta)625 data->kek_kck_cmd->gtk_cipher =626 cpu_to_le32(STA_KEY_FLG_CCM);627 return;628 case WLAN_CIPHER_SUITE_GCMP:629 case WLAN_CIPHER_SUITE_GCMP_256:630 if (!sta)631 data->kek_kck_cmd->gtk_cipher =632 cpu_to_le32(STA_KEY_FLG_GCMP);633 return;634 }635}636 637static int iwl_mvm_send_patterns_v1(struct iwl_mvm *mvm,638 struct cfg80211_wowlan *wowlan)639{640 struct iwl_wowlan_patterns_cmd_v1 *pattern_cmd;641 struct iwl_host_cmd cmd = {642 .id = WOWLAN_PATTERNS,643 .dataflags[0] = IWL_HCMD_DFL_NOCOPY,644 };645 int i, err;646 647 if (!wowlan->n_patterns)648 return 0;649 650 cmd.len[0] = struct_size(pattern_cmd, patterns, wowlan->n_patterns);651 652 pattern_cmd = kmalloc(cmd.len[0], GFP_KERNEL);653 if (!pattern_cmd)654 return -ENOMEM;655 656 pattern_cmd->n_patterns = cpu_to_le32(wowlan->n_patterns);657 658 for (i = 0; i < wowlan->n_patterns; i++) {659 int mask_len = DIV_ROUND_UP(wowlan->patterns[i].pattern_len, 8);660 661 memcpy(&pattern_cmd->patterns[i].mask,662 wowlan->patterns[i].mask, mask_len);663 memcpy(&pattern_cmd->patterns[i].pattern,664 wowlan->patterns[i].pattern,665 wowlan->patterns[i].pattern_len);666 pattern_cmd->patterns[i].mask_size = mask_len;667 pattern_cmd->patterns[i].pattern_size =668 wowlan->patterns[i].pattern_len;669 }670 671 cmd.data[0] = pattern_cmd;672 err = iwl_mvm_send_cmd(mvm, &cmd);673 kfree(pattern_cmd);674 return err;675}676 677static int iwl_mvm_send_patterns(struct iwl_mvm *mvm,678 struct iwl_mvm_vif_link_info *mvm_link,679 struct cfg80211_wowlan *wowlan)680{681 struct iwl_wowlan_patterns_cmd *pattern_cmd;682 struct iwl_host_cmd cmd = {683 .id = WOWLAN_PATTERNS,684 .dataflags[0] = IWL_HCMD_DFL_NOCOPY,685 };686 int i, err;687 int ver = iwl_fw_lookup_cmd_ver(mvm->fw, cmd.id,688 IWL_FW_CMD_VER_UNKNOWN);689 690 if (!wowlan->n_patterns)691 return 0;692 693 cmd.len[0] = sizeof(*pattern_cmd) +694 wowlan->n_patterns * sizeof(struct iwl_wowlan_pattern_v2);695 696 pattern_cmd = kzalloc(cmd.len[0], GFP_KERNEL);697 if (!pattern_cmd)698 return -ENOMEM;699 700 pattern_cmd->n_patterns = wowlan->n_patterns;701 if (ver >= 3)702 pattern_cmd->sta_id = mvm_link->ap_sta_id;703 704 for (i = 0; i < wowlan->n_patterns; i++) {705 int mask_len = DIV_ROUND_UP(wowlan->patterns[i].pattern_len, 8);706 707 pattern_cmd->patterns[i].pattern_type =708 WOWLAN_PATTERN_TYPE_BITMASK;709 710 memcpy(&pattern_cmd->patterns[i].u.bitmask.mask,711 wowlan->patterns[i].mask, mask_len);712 memcpy(&pattern_cmd->patterns[i].u.bitmask.pattern,713 wowlan->patterns[i].pattern,714 wowlan->patterns[i].pattern_len);715 pattern_cmd->patterns[i].u.bitmask.mask_size = mask_len;716 pattern_cmd->patterns[i].u.bitmask.pattern_size =717 wowlan->patterns[i].pattern_len;718 }719 720 cmd.data[0] = pattern_cmd;721 err = iwl_mvm_send_cmd(mvm, &cmd);722 kfree(pattern_cmd);723 return err;724}725 726static int iwl_mvm_d3_reprogram(struct iwl_mvm *mvm, struct ieee80211_vif *vif,727 struct ieee80211_sta *ap_sta)728{729 struct iwl_mvm_vif *mvmvif = iwl_mvm_vif_from_mac80211(vif);730 struct ieee80211_chanctx_conf *ctx;731 u8 chains_static, chains_dynamic;732 struct cfg80211_chan_def chandef, ap_def;733 int ret, i;734 struct iwl_binding_cmd_v1 binding_cmd = {};735 struct iwl_time_quota_cmd quota_cmd = {};736 struct iwl_time_quota_data *quota;737 u32 status;738 739 if (WARN_ON_ONCE(iwl_mvm_is_cdb_supported(mvm) ||740 ieee80211_vif_is_mld(vif)))741 return -EINVAL;742 743 /* add back the PHY */744 if (WARN_ON(!mvmvif->deflink.phy_ctxt))745 return -EINVAL;746 747 rcu_read_lock();748 ctx = rcu_dereference(vif->bss_conf.chanctx_conf);749 if (WARN_ON(!ctx)) {750 rcu_read_unlock();751 return -EINVAL;752 }753 chandef = ctx->def;754 ap_def = ctx->ap;755 chains_static = ctx->rx_chains_static;756 chains_dynamic = ctx->rx_chains_dynamic;757 rcu_read_unlock();758 759 ret = iwl_mvm_phy_ctxt_add(mvm, mvmvif->deflink.phy_ctxt, &chandef,760 &ap_def, chains_static, chains_dynamic);761 if (ret)762 return ret;763 764 /* add back the MAC */765 mvmvif->uploaded = false;766 767 if (WARN_ON(!vif->cfg.assoc))768 return -EINVAL;769 770 ret = iwl_mvm_mac_ctxt_add(mvm, vif);771 if (ret)772 return ret;773 774 /* add back binding - XXX refactor? */775 binding_cmd.id_and_color =776 cpu_to_le32(FW_CMD_ID_AND_COLOR(mvmvif->deflink.phy_ctxt->id,777 mvmvif->deflink.phy_ctxt->color));778 binding_cmd.action = cpu_to_le32(FW_CTXT_ACTION_ADD);779 binding_cmd.phy =780 cpu_to_le32(FW_CMD_ID_AND_COLOR(mvmvif->deflink.phy_ctxt->id,781 mvmvif->deflink.phy_ctxt->color));782 binding_cmd.macs[0] = cpu_to_le32(FW_CMD_ID_AND_COLOR(mvmvif->id,783 mvmvif->color));784 for (i = 1; i < MAX_MACS_IN_BINDING; i++)785 binding_cmd.macs[i] = cpu_to_le32(FW_CTXT_INVALID);786 787 status = 0;788 ret = iwl_mvm_send_cmd_pdu_status(mvm, BINDING_CONTEXT_CMD,789 IWL_BINDING_CMD_SIZE_V1, &binding_cmd,790 &status);791 if (ret) {792 IWL_ERR(mvm, "Failed to add binding: %d\n", ret);793 return ret;794 }795 796 if (status) {797 IWL_ERR(mvm, "Binding command failed: %u\n", status);798 return -EIO;799 }800 801 ret = iwl_mvm_sta_send_to_fw(mvm, ap_sta, false, 0);802 if (ret)803 return ret;804 rcu_assign_pointer(mvm->fw_id_to_mac_id[mvmvif->deflink.ap_sta_id],805 ap_sta);806 807 ret = iwl_mvm_mac_ctxt_changed(mvm, vif, false, NULL);808 if (ret)809 return ret;810 811 /* and some quota */812 quota = iwl_mvm_quota_cmd_get_quota(mvm, "a_cmd, 0);813 quota->id_and_color =814 cpu_to_le32(FW_CMD_ID_AND_COLOR(mvmvif->deflink.phy_ctxt->id,815 mvmvif->deflink.phy_ctxt->color));816 quota->quota = cpu_to_le32(IWL_MVM_MAX_QUOTA);817 quota->max_duration = cpu_to_le32(IWL_MVM_MAX_QUOTA);818 819 for (i = 1; i < MAX_BINDINGS; i++) {820 quota = iwl_mvm_quota_cmd_get_quota(mvm, "a_cmd, i);821 quota->id_and_color = cpu_to_le32(FW_CTXT_INVALID);822 }823 824 ret = iwl_mvm_send_cmd_pdu(mvm, TIME_QUOTA_CMD, 0,825 iwl_mvm_quota_cmd_size(mvm), "a_cmd);826 if (ret)827 IWL_ERR(mvm, "Failed to send quota: %d\n", ret);828 829 if (iwl_mvm_is_lar_supported(mvm) && iwl_mvm_init_fw_regd(mvm, false))830 IWL_ERR(mvm, "Failed to initialize D3 LAR information\n");831 832 return 0;833}834 835static int iwl_mvm_get_last_nonqos_seq(struct iwl_mvm *mvm,836 struct ieee80211_vif *vif)837{838 struct iwl_mvm_vif *mvmvif = iwl_mvm_vif_from_mac80211(vif);839 struct iwl_nonqos_seq_query_cmd query_cmd = {840 .get_set_flag = cpu_to_le32(IWL_NONQOS_SEQ_GET),841 .mac_id_n_color =842 cpu_to_le32(FW_CMD_ID_AND_COLOR(mvmvif->id,843 mvmvif->color)),844 };845 struct iwl_host_cmd cmd = {846 .id = NON_QOS_TX_COUNTER_CMD,847 .flags = CMD_WANT_SKB,848 };849 int err;850 u32 size;851 852 cmd.data[0] = &query_cmd;853 cmd.len[0] = sizeof(query_cmd);854 855 err = iwl_mvm_send_cmd(mvm, &cmd);856 if (err)857 return err;858 859 size = iwl_rx_packet_payload_len(cmd.resp_pkt);860 if (size < sizeof(__le16)) {861 err = -EINVAL;862 } else {863 err = le16_to_cpup((__le16 *)cmd.resp_pkt->data);864 /* firmware returns next, not last-used seqno */865 err = (u16) (err - 0x10);866 }867 868 iwl_free_resp(&cmd);869 return err;870}871 872void iwl_mvm_set_last_nonqos_seq(struct iwl_mvm *mvm, struct ieee80211_vif *vif)873{874 struct iwl_mvm_vif *mvmvif = iwl_mvm_vif_from_mac80211(vif);875 struct iwl_nonqos_seq_query_cmd query_cmd = {876 .get_set_flag = cpu_to_le32(IWL_NONQOS_SEQ_SET),877 .mac_id_n_color =878 cpu_to_le32(FW_CMD_ID_AND_COLOR(mvmvif->id,879 mvmvif->color)),880 .value = cpu_to_le16(mvmvif->seqno),881 };882 883 /* return if called during restart, not resume from D3 */884 if (!mvmvif->seqno_valid)885 return;886 887 mvmvif->seqno_valid = false;888 889 if (iwl_mvm_send_cmd_pdu(mvm, NON_QOS_TX_COUNTER_CMD, 0,890 sizeof(query_cmd), &query_cmd))891 IWL_ERR(mvm, "failed to set non-QoS seqno\n");892}893 894static int iwl_mvm_switch_to_d3(struct iwl_mvm *mvm)895{896 iwl_mvm_scan_stop(mvm, IWL_MVM_SCAN_REGULAR, true);897 898 iwl_mvm_stop_device(mvm);899 /*900 * Set the HW restart bit -- this is mostly true as we're901 * going to load new firmware and reprogram that, though902 * the reprogramming is going to be manual to avoid adding903 * all the MACs that aren't support.904 * We don't have to clear up everything though because the905 * reprogramming is manual. When we resume, we'll actually906 * go through a proper restart sequence again to switch907 * back to the runtime firmware image.908 */909 set_bit(IWL_MVM_STATUS_IN_HW_RESTART, &mvm->status);910 911 /* the fw is reset, so all the keys are cleared */912 memset(mvm->fw_key_table, 0, sizeof(mvm->fw_key_table));913 914 mvm->ptk_ivlen = 0;915 mvm->ptk_icvlen = 0;916 mvm->ptk_ivlen = 0;917 mvm->ptk_icvlen = 0;918 919 return iwl_mvm_load_d3_fw(mvm);920}921 922static int923iwl_mvm_get_wowlan_config(struct iwl_mvm *mvm,924 struct cfg80211_wowlan *wowlan,925 struct iwl_wowlan_config_cmd *wowlan_config_cmd,926 struct ieee80211_vif *vif, struct iwl_mvm_vif *mvmvif,927 struct ieee80211_sta *ap_sta)928{929 struct iwl_mvm_sta *mvm_ap_sta = iwl_mvm_sta_from_mac80211(ap_sta);930 931 /* TODO: wowlan_config_cmd->wowlan_ba_teardown_tids */932 933 wowlan_config_cmd->is_11n_connection =934 ap_sta->deflink.ht_cap.ht_supported;935 wowlan_config_cmd->flags = ENABLE_L3_FILTERING |936 ENABLE_NBNS_FILTERING | ENABLE_DHCP_FILTERING;937 938 if (ap_sta->mfp)939 wowlan_config_cmd->flags |= IS_11W_ASSOC;940 941 if (iwl_fw_lookup_cmd_ver(mvm->fw, WOWLAN_CONFIGURATION, 0) < 6) {942 /* Query the last used seqno and set it */943 int ret = iwl_mvm_get_last_nonqos_seq(mvm, vif);944 945 if (ret < 0)946 return ret;947 948 wowlan_config_cmd->non_qos_seq = cpu_to_le16(ret);949 }950 951 iwl_mvm_set_wowlan_qos_seq(mvm_ap_sta, wowlan_config_cmd);952 953 if (wowlan->disconnect)954 wowlan_config_cmd->wakeup_filter |=955 cpu_to_le32(IWL_WOWLAN_WAKEUP_BEACON_MISS |956 IWL_WOWLAN_WAKEUP_LINK_CHANGE);957 if (wowlan->magic_pkt)958 wowlan_config_cmd->wakeup_filter |=959 cpu_to_le32(IWL_WOWLAN_WAKEUP_MAGIC_PACKET);960 if (wowlan->gtk_rekey_failure)961 wowlan_config_cmd->wakeup_filter |=962 cpu_to_le32(IWL_WOWLAN_WAKEUP_GTK_REKEY_FAIL);963 if (wowlan->eap_identity_req)964 wowlan_config_cmd->wakeup_filter |=965 cpu_to_le32(IWL_WOWLAN_WAKEUP_EAP_IDENT_REQ);966 if (wowlan->four_way_handshake)967 wowlan_config_cmd->wakeup_filter |=968 cpu_to_le32(IWL_WOWLAN_WAKEUP_4WAY_HANDSHAKE);969 if (wowlan->n_patterns)970 wowlan_config_cmd->wakeup_filter |=971 cpu_to_le32(IWL_WOWLAN_WAKEUP_PATTERN_MATCH);972 973 if (wowlan->rfkill_release)974 wowlan_config_cmd->wakeup_filter |=975 cpu_to_le32(IWL_WOWLAN_WAKEUP_RF_KILL_DEASSERT);976 977 if (wowlan->tcp) {978 /*979 * Set the "link change" (really "link lost") flag as well980 * since that implies losing the TCP connection.981 */982 wowlan_config_cmd->wakeup_filter |=983 cpu_to_le32(IWL_WOWLAN_WAKEUP_REMOTE_LINK_LOSS |984 IWL_WOWLAN_WAKEUP_REMOTE_SIGNATURE_TABLE |985 IWL_WOWLAN_WAKEUP_REMOTE_WAKEUP_PACKET |986 IWL_WOWLAN_WAKEUP_LINK_CHANGE);987 }988 989 if (wowlan->any) {990 wowlan_config_cmd->wakeup_filter |=991 cpu_to_le32(IWL_WOWLAN_WAKEUP_BEACON_MISS |992 IWL_WOWLAN_WAKEUP_LINK_CHANGE |993 IWL_WOWLAN_WAKEUP_RX_FRAME |994 IWL_WOWLAN_WAKEUP_BCN_FILTERING);995 }996 997 return 0;998}999 1000static int iwl_mvm_wowlan_config_key_params(struct iwl_mvm *mvm,1001 struct ieee80211_vif *vif,1002 struct iwl_mvm_vif_link_info *mvm_link)1003{1004 bool unified = fw_has_capa(&mvm->fw->ucode_capa,1005 IWL_UCODE_TLV_CAPA_CNSLDTD_D3_D0_IMG);1006 struct wowlan_key_reprogram_data key_data = {};1007 struct iwl_mvm_vif *mvmvif = iwl_mvm_vif_from_mac80211(vif);1008 int ret;1009 u8 cmd_ver;1010 size_t cmd_size;1011 1012 if (!unified) {1013 /*1014 * if we have to configure keys, call ieee80211_iter_keys(),1015 * as we need non-atomic context in order to take the1016 * required locks.1017 */1018 /*1019 * Note that currently we don't use CMD_ASYNC in the iterator.1020 * In case of key_data.configure_keys, all the configured1021 * commands are SYNC, and iwl_mvm_wowlan_program_keys() will1022 * take care of locking/unlocking mvm->mutex.1023 */1024 ieee80211_iter_keys(mvm->hw, vif, iwl_mvm_wowlan_program_keys,1025 &key_data);1026 1027 if (key_data.error)1028 return -EIO;1029 }1030 1031 ret = iwl_mvm_wowlan_config_rsc_tsc(mvm, vif, mvm_link);1032 if (ret)1033 return ret;1034 1035 if (!fw_has_api(&mvm->fw->ucode_capa,1036 IWL_UCODE_TLV_API_TKIP_MIC_KEYS)) {1037 int ver = iwl_fw_lookup_cmd_ver(mvm->fw, WOWLAN_TKIP_PARAM,1038 IWL_FW_CMD_VER_UNKNOWN);1039 struct wowlan_key_tkip_data tkip_data = {};1040 int size;1041 1042 if (ver == 2) {1043 size = sizeof(tkip_data.tkip);1044 tkip_data.tkip.sta_id =1045 cpu_to_le32(mvm_link->ap_sta_id);1046 } else if (ver == 1 || ver == IWL_FW_CMD_VER_UNKNOWN) {1047 size = sizeof(struct iwl_wowlan_tkip_params_cmd_ver_1);1048 } else {1049 WARN_ON_ONCE(1);1050 return -EINVAL;1051 }1052 1053 ieee80211_iter_keys(mvm->hw, vif, iwl_mvm_wowlan_get_tkip_data,1054 &tkip_data);1055 1056 if (tkip_data.have_tkip_keys) {1057 /* send relevant data according to CMD version */1058 ret = iwl_mvm_send_cmd_pdu(mvm,1059 WOWLAN_TKIP_PARAM,1060 CMD_ASYNC, size,1061 &tkip_data.tkip);1062 if (ret)1063 return ret;1064 }1065 }1066 1067 /* configure rekey data only if offloaded rekey is supported (d3) */1068 if (mvmvif->rekey_data.valid) {1069 struct iwl_wowlan_kek_kck_material_cmd_v4 kek_kck_cmd = {};1070 struct iwl_wowlan_kek_kck_material_cmd_v4 *_kek_kck_cmd =1071 &kek_kck_cmd;1072 struct wowlan_key_gtk_type_iter gtk_type_data = {1073 .kek_kck_cmd = _kek_kck_cmd,1074 };1075 1076 cmd_ver = iwl_fw_lookup_cmd_ver(mvm->fw,1077 WOWLAN_KEK_KCK_MATERIAL,1078 IWL_FW_CMD_VER_UNKNOWN);1079 if (WARN_ON(cmd_ver != 2 && cmd_ver != 3 && cmd_ver != 4 &&1080 cmd_ver != IWL_FW_CMD_VER_UNKNOWN))1081 return -EINVAL;1082 1083 ieee80211_iter_keys(mvm->hw, vif, iwl_mvm_wowlan_gtk_type_iter,1084 >k_type_data);1085 1086 memcpy(kek_kck_cmd.kck, mvmvif->rekey_data.kck,1087 mvmvif->rekey_data.kck_len);1088 kek_kck_cmd.kck_len = cpu_to_le16(mvmvif->rekey_data.kck_len);1089 memcpy(kek_kck_cmd.kek, mvmvif->rekey_data.kek,1090 mvmvif->rekey_data.kek_len);1091 kek_kck_cmd.kek_len = cpu_to_le16(mvmvif->rekey_data.kek_len);1092 kek_kck_cmd.replay_ctr = mvmvif->rekey_data.replay_ctr;1093 kek_kck_cmd.akm = cpu_to_le32(mvmvif->rekey_data.akm);1094 kek_kck_cmd.sta_id = cpu_to_le32(mvm_link->ap_sta_id);1095 1096 if (cmd_ver == 4) {1097 cmd_size = sizeof(struct iwl_wowlan_kek_kck_material_cmd_v4);1098 } else {1099 if (cmd_ver == 3)1100 cmd_size =1101 sizeof(struct iwl_wowlan_kek_kck_material_cmd_v3);1102 else1103 cmd_size =1104 sizeof(struct iwl_wowlan_kek_kck_material_cmd_v2);1105 /* skip the sta_id at the beginning */1106 _kek_kck_cmd = (void *)1107 ((u8 *)_kek_kck_cmd + sizeof(kek_kck_cmd.sta_id));1108 }1109 1110 IWL_DEBUG_WOWLAN(mvm, "setting akm %d\n",1111 mvmvif->rekey_data.akm);1112 1113 ret = iwl_mvm_send_cmd_pdu(mvm, WOWLAN_KEK_KCK_MATERIAL,1114 CMD_ASYNC, cmd_size, _kek_kck_cmd);1115 if (ret)1116 return ret;1117 }1118 1119 return 0;1120}1121 1122static int1123iwl_mvm_wowlan_config(struct iwl_mvm *mvm,1124 struct cfg80211_wowlan *wowlan,1125 struct iwl_wowlan_config_cmd *wowlan_config_cmd,1126 struct ieee80211_vif *vif, struct iwl_mvm_vif *mvmvif,1127 struct iwl_mvm_vif_link_info *mvm_link,1128 struct ieee80211_sta *ap_sta)1129{1130 int ret;1131 bool unified_image = fw_has_capa(&mvm->fw->ucode_capa,1132 IWL_UCODE_TLV_CAPA_CNSLDTD_D3_D0_IMG);1133 1134 mvm->offload_tid = wowlan_config_cmd->offloading_tid;1135 1136 if (!unified_image) {1137 ret = iwl_mvm_switch_to_d3(mvm);1138 if (ret)1139 return ret;1140 1141 ret = iwl_mvm_d3_reprogram(mvm, vif, ap_sta);1142 if (ret)1143 return ret;1144 }1145 1146 ret = iwl_mvm_wowlan_config_key_params(mvm, vif, mvm_link);1147 if (ret)1148 return ret;1149 1150 ret = iwl_mvm_send_cmd_pdu(mvm, WOWLAN_CONFIGURATION, 0,1151 sizeof(*wowlan_config_cmd),1152 wowlan_config_cmd);1153 if (ret)1154 return ret;1155 1156 if (fw_has_api(&mvm->fw->ucode_capa,1157 IWL_UCODE_TLV_API_WOWLAN_TCP_SYN_WAKE))1158 ret = iwl_mvm_send_patterns(mvm, mvm_link, wowlan);1159 else1160 ret = iwl_mvm_send_patterns_v1(mvm, wowlan);1161 if (ret)1162 return ret;1163 1164 return iwl_mvm_send_proto_offload(mvm, vif, false, true, 0,1165 mvm_link->ap_sta_id);1166}1167 1168static int1169iwl_mvm_netdetect_config(struct iwl_mvm *mvm,1170 struct cfg80211_wowlan *wowlan,1171 struct cfg80211_sched_scan_request *nd_config,1172 struct ieee80211_vif *vif)1173{1174 int ret;1175 bool unified_image = fw_has_capa(&mvm->fw->ucode_capa,1176 IWL_UCODE_TLV_CAPA_CNSLDTD_D3_D0_IMG);1177 1178 if (!unified_image) {1179 ret = iwl_mvm_switch_to_d3(mvm);1180 if (ret)1181 return ret;1182 } else {1183 /* In theory, we wouldn't have to stop a running sched1184 * scan in order to start another one (for1185 * net-detect). But in practice this doesn't seem to1186 * work properly, so stop any running sched_scan now.1187 */1188 ret = iwl_mvm_scan_stop(mvm, IWL_MVM_SCAN_SCHED, true);1189 if (ret)1190 return ret;1191 }1192 1193 ret = iwl_mvm_sched_scan_start(mvm, vif, nd_config, &mvm->nd_ies,1194 IWL_MVM_SCAN_NETDETECT);1195 if (ret)1196 return ret;1197 1198 if (WARN_ON(mvm->nd_match_sets || mvm->nd_channels))1199 return -EBUSY;1200 1201 /* save the sched scan matchsets... */1202 if (nd_config->n_match_sets) {1203 mvm->nd_match_sets = kmemdup(nd_config->match_sets,1204 sizeof(*nd_config->match_sets) *1205 nd_config->n_match_sets,1206 GFP_KERNEL);1207 if (mvm->nd_match_sets)1208 mvm->n_nd_match_sets = nd_config->n_match_sets;1209 }1210 1211 /* ...and the sched scan channels for later reporting */1212 mvm->nd_channels = kmemdup(nd_config->channels,1213 sizeof(*nd_config->channels) *1214 nd_config->n_channels,1215 GFP_KERNEL);1216 if (mvm->nd_channels)1217 mvm->n_nd_channels = nd_config->n_channels;1218 1219 return 0;1220}1221 1222static void iwl_mvm_free_nd(struct iwl_mvm *mvm)1223{1224 kfree(mvm->nd_match_sets);1225 mvm->nd_match_sets = NULL;1226 mvm->n_nd_match_sets = 0;1227 kfree(mvm->nd_channels);1228 mvm->nd_channels = NULL;1229 mvm->n_nd_channels = 0;1230}1231 1232static int __iwl_mvm_suspend(struct ieee80211_hw *hw,1233 struct cfg80211_wowlan *wowlan,1234 bool test)1235{1236 struct iwl_mvm *mvm = IWL_MAC80211_GET_MVM(hw);1237 struct ieee80211_vif *vif = NULL;1238 struct iwl_mvm_vif *mvmvif = NULL;1239 struct ieee80211_sta *ap_sta = NULL;1240 struct iwl_mvm_vif_link_info *mvm_link;1241 struct iwl_d3_manager_config d3_cfg_cmd_data = {1242 /*1243 * Program the minimum sleep time to 10 seconds, as many1244 * platforms have issues processing a wakeup signal while1245 * still being in the process of suspending.1246 */1247 .min_sleep_time = cpu_to_le32(10 * 1000 * 1000),1248 };1249 struct iwl_host_cmd d3_cfg_cmd = {1250 .id = D3_CONFIG_CMD,1251 .flags = CMD_WANT_SKB | CMD_SEND_IN_D3,1252 .data[0] = &d3_cfg_cmd_data,1253 .len[0] = sizeof(d3_cfg_cmd_data),1254 };1255 int ret;1256 int len __maybe_unused;1257 bool unified_image = fw_has_capa(&mvm->fw->ucode_capa,1258 IWL_UCODE_TLV_CAPA_CNSLDTD_D3_D0_IMG);1259 1260 if (!wowlan) {1261 /*1262 * mac80211 shouldn't get here, but for D3 test1263 * it doesn't warrant a warning1264 */1265 WARN_ON(!test);1266 return -EINVAL;1267 }1268 1269 vif = iwl_mvm_get_bss_vif(mvm);1270 if (IS_ERR_OR_NULL(vif))1271 return 1;1272 1273 ret = iwl_mvm_block_esr_sync(mvm, vif, IWL_MVM_ESR_BLOCKED_WOWLAN);1274 if (ret)1275 return ret;1276 1277 mutex_lock(&mvm->mutex);1278 1279 set_bit(IWL_MVM_STATUS_IN_D3, &mvm->status);1280 1281 synchronize_net();1282 1283 mvmvif = iwl_mvm_vif_from_mac80211(vif);1284 1285 mvm_link = mvmvif->link[iwl_mvm_get_primary_link(vif)];1286 if (WARN_ON_ONCE(!mvm_link)) {1287 ret = -EINVAL;1288 goto out_noreset;1289 }1290 1291 if (mvm_link->ap_sta_id == IWL_MVM_INVALID_STA) {1292 /* if we're not associated, this must be netdetect */1293 if (!wowlan->nd_config) {1294 ret = 1;1295 goto out_noreset;1296 }1297 1298 ret = iwl_mvm_netdetect_config(1299 mvm, wowlan, wowlan->nd_config, vif);1300 if (ret)1301 goto out;1302 1303 mvm->net_detect = true;1304 } else {1305 struct iwl_wowlan_config_cmd wowlan_config_cmd = {1306 .offloading_tid = 0,1307 };1308 1309 wowlan_config_cmd.sta_id = mvm_link->ap_sta_id;1310 1311 ap_sta = rcu_dereference_protected(1312 mvm->fw_id_to_mac_id[mvm_link->ap_sta_id],1313 lockdep_is_held(&mvm->mutex));1314 if (IS_ERR_OR_NULL(ap_sta)) {1315 ret = -EINVAL;1316 goto out_noreset;1317 }1318 1319 ret = iwl_mvm_sta_ensure_queue(1320 mvm, ap_sta->txq[wowlan_config_cmd.offloading_tid]);1321 if (ret)1322 goto out_noreset;1323 1324 ret = iwl_mvm_get_wowlan_config(mvm, wowlan, &wowlan_config_cmd,1325 vif, mvmvif, ap_sta);1326 if (ret)1327 goto out_noreset;1328 ret = iwl_mvm_wowlan_config(mvm, wowlan, &wowlan_config_cmd,1329 vif, mvmvif, mvm_link, ap_sta);1330 if (ret)1331 goto out;1332 1333 mvm->net_detect = false;1334 }1335 1336 ret = iwl_mvm_power_update_device(mvm);1337 if (ret)1338 goto out;1339 1340 ret = iwl_mvm_power_update_mac(mvm);1341 if (ret)1342 goto out;1343 1344#ifdef CONFIG_IWLWIFI_DEBUGFS1345 if (mvm->d3_wake_sysassert)1346 d3_cfg_cmd_data.wakeup_flags |=1347 cpu_to_le32(IWL_WAKEUP_D3_CONFIG_FW_ERROR);1348#endif1349 1350 /*1351 * Prior to 9000 device family the driver needs to stop the dbg1352 * recording before entering D3. In later devices the FW stops the1353 * recording automatically.1354 */1355 if (mvm->trans->trans_cfg->device_family < IWL_DEVICE_FAMILY_9000)1356 iwl_fw_dbg_stop_restart_recording(&mvm->fwrt, NULL, true);1357 1358 mvm->trans->system_pm_mode = IWL_PLAT_PM_MODE_D3;1359 1360 /* must be last -- this switches firmware state */1361 ret = iwl_mvm_send_cmd(mvm, &d3_cfg_cmd);1362 if (ret)1363 goto out;1364#ifdef CONFIG_IWLWIFI_DEBUGFS1365 len = iwl_rx_packet_payload_len(d3_cfg_cmd.resp_pkt);1366 if (len >= sizeof(u32)) {1367 mvm->d3_test_pme_ptr =1368 le32_to_cpup((__le32 *)d3_cfg_cmd.resp_pkt->data);1369 }1370#endif1371 iwl_free_resp(&d3_cfg_cmd);1372 1373 clear_bit(IWL_MVM_STATUS_IN_HW_RESTART, &mvm->status);1374 1375 ret = iwl_trans_d3_suspend(mvm->trans, test, !unified_image);1376 out:1377 if (ret < 0) {1378 iwl_mvm_free_nd(mvm);1379 1380 if (!unified_image) {1381 if (mvm->fw_restart > 0) {1382 mvm->fw_restart--;1383 ieee80211_restart_hw(mvm->hw);1384 }1385 }1386 1387 clear_bit(IWL_MVM_STATUS_IN_D3, &mvm->status);1388 }1389 out_noreset:1390 mutex_unlock(&mvm->mutex);1391 1392 return ret;1393}1394 1395int iwl_mvm_suspend(struct ieee80211_hw *hw, struct cfg80211_wowlan *wowlan)1396{1397 struct iwl_mvm *mvm = IWL_MAC80211_GET_MVM(hw);1398 1399 iwl_mvm_pause_tcm(mvm, true);1400 1401 mutex_lock(&mvm->mutex);1402 iwl_fw_runtime_suspend(&mvm->fwrt);1403 mutex_unlock(&mvm->mutex);1404 1405 return __iwl_mvm_suspend(hw, wowlan, false);1406}1407 1408struct iwl_multicast_key_data {1409 u8 key[WOWLAN_KEY_MAX_SIZE];1410 u8 len;1411 u8 flags;1412 u8 id;1413 u8 ipn[6];1414};1415 1416/* converted data from the different status responses */1417struct iwl_wowlan_status_data {1418 u64 replay_ctr;1419 u32 num_of_gtk_rekeys;1420 u32 received_beacons;1421 u32 wakeup_reasons;1422 u32 wake_packet_length;1423 u32 wake_packet_bufsize;1424 u16 pattern_number;1425 u16 non_qos_seq_ctr;1426 u16 qos_seq_ctr[8];1427 u8 tid_tear_down;1428 1429 struct {1430 /* including RX MIC key for TKIP */1431 u8 key[WOWLAN_KEY_MAX_SIZE];1432 u8 len;1433 u8 flags;1434 u8 id;1435 } gtk[WOWLAN_GTK_KEYS_NUM];1436 1437 struct {1438 /*1439 * We store both the TKIP and AES representations1440 * coming from the firmware because we decode the1441 * data from there before we iterate the keys and1442 * know which one we need.1443 */1444 struct {1445 struct ieee80211_key_seq seq[IWL_MAX_TID_COUNT];1446 } tkip, aes;1447 1448 /*1449 * We use -1 for when we have valid data but don't know1450 * the key ID from firmware, and thus it needs to be1451 * installed with the last key (depending on rekeying).1452 */1453 s8 key_id;1454 bool valid;1455 } gtk_seq[2];1456 1457 struct {1458 /* Same as above */1459 struct {1460 struct ieee80211_key_seq seq[IWL_MAX_TID_COUNT];1461 u64 tx_pn;1462 } tkip, aes;1463 } ptk;1464 1465 struct iwl_multicast_key_data igtk;1466 struct iwl_multicast_key_data bigtk[WOWLAN_BIGTK_KEYS_NUM];1467 1468 int num_mlo_keys;1469 struct iwl_wowlan_mlo_gtk mlo_keys[WOWLAN_MAX_MLO_KEYS];1470 1471 u8 *wake_packet;1472};1473 1474static void iwl_mvm_report_wakeup_reasons(struct iwl_mvm *mvm,1475 struct ieee80211_vif *vif,1476 struct iwl_wowlan_status_data *status)1477{1478 struct sk_buff *pkt = NULL;1479 struct cfg80211_wowlan_wakeup wakeup = {1480 .pattern_idx = -1,1481 };1482 struct cfg80211_wowlan_wakeup *wakeup_report = &wakeup;1483 u32 reasons = status->wakeup_reasons;1484 1485 if (reasons == IWL_WOWLAN_WAKEUP_BY_NON_WIRELESS) {1486 wakeup_report = NULL;1487 goto report;1488 }1489 1490 pm_wakeup_event(mvm->dev, 0);1491 1492 if (reasons & IWL_WOWLAN_WAKEUP_BY_MAGIC_PACKET)1493 wakeup.magic_pkt = true;1494 1495 if (reasons & IWL_WOWLAN_WAKEUP_BY_PATTERN)1496 wakeup.pattern_idx =1497 status->pattern_number;1498 1499 if (reasons & (IWL_WOWLAN_WAKEUP_BY_DISCONNECTION_ON_MISSED_BEACON |1500 IWL_WOWLAN_WAKEUP_BY_DISCONNECTION_ON_DEAUTH |1501 IWL_WOWLAN_WAKEUP_BY_GTK_REKEY_FAILURE))1502 wakeup.disconnect = true;1503 1504 if (reasons & IWL_WOWLAN_WAKEUP_BY_GTK_REKEY_FAILURE)1505 wakeup.gtk_rekey_failure = true;1506 1507 if (reasons & IWL_WOWLAN_WAKEUP_BY_RFKILL_DEASSERTED)1508 wakeup.rfkill_release = true;1509 1510 if (reasons & IWL_WOWLAN_WAKEUP_BY_EAPOL_REQUEST)1511 wakeup.eap_identity_req = true;1512 1513 if (reasons & IWL_WOWLAN_WAKEUP_BY_FOUR_WAY_HANDSHAKE)1514 wakeup.four_way_handshake = true;1515 1516 if (reasons & IWL_WOWLAN_WAKEUP_BY_REM_WAKE_LINK_LOSS)1517 wakeup.tcp_connlost = true;1518 1519 if (reasons & IWL_WOWLAN_WAKEUP_BY_REM_WAKE_SIGNATURE_TABLE)1520 wakeup.tcp_nomoretokens = true;1521 1522 if (reasons & IWL_WOWLAN_WAKEUP_BY_REM_WAKE_WAKEUP_PACKET)1523 wakeup.tcp_match = true;1524 1525 if (reasons & IWL_WAKEUP_BY_11W_UNPROTECTED_DEAUTH_OR_DISASSOC)1526 wakeup.unprot_deauth_disassoc = true;1527 1528 if (status->wake_packet) {1529 int pktsize = status->wake_packet_bufsize;1530 int pktlen = status->wake_packet_length;1531 const u8 *pktdata = status->wake_packet;1532 const struct ieee80211_hdr *hdr = (const void *)pktdata;1533 int truncated = pktlen - pktsize;1534 1535 /* this would be a firmware bug */1536 if (WARN_ON_ONCE(truncated < 0))1537 truncated = 0;1538 1539 if (ieee80211_is_data(hdr->frame_control)) {1540 int hdrlen = ieee80211_hdrlen(hdr->frame_control);1541 int ivlen = 0, icvlen = 4; /* also FCS */1542 1543 pkt = alloc_skb(pktsize, GFP_KERNEL);1544 if (!pkt)1545 goto report;1546 1547 skb_put_data(pkt, pktdata, hdrlen);1548 pktdata += hdrlen;1549 pktsize -= hdrlen;1550 1551 if (ieee80211_has_protected(hdr->frame_control)) {1552 /*1553 * This is unlocked and using gtk_i(c)vlen,1554 * but since everything is under RTNL still1555 * that's not really a problem - changing1556 * it would be difficult.1557 */1558 if (is_multicast_ether_addr(hdr->addr1)) {1559 ivlen = mvm->gtk_ivlen;1560 icvlen += mvm->gtk_icvlen;1561 } else {1562 ivlen = mvm->ptk_ivlen;1563 icvlen += mvm->ptk_icvlen;1564 }1565 }1566 1567 /* if truncated, FCS/ICV is (partially) gone */1568 if (truncated >= icvlen) {1569 icvlen = 0;1570 truncated -= icvlen;1571 } else {1572 icvlen -= truncated;1573 truncated = 0;1574 }1575 1576 pktsize -= ivlen + icvlen;1577 pktdata += ivlen;1578 1579 skb_put_data(pkt, pktdata, pktsize);1580 1581 if (ieee80211_data_to_8023(pkt, vif->addr, vif->type))1582 goto report;1583 wakeup.packet = pkt->data;1584 wakeup.packet_present_len = pkt->len;1585 wakeup.packet_len = pkt->len - truncated;1586 wakeup.packet_80211 = false;1587 } else {1588 int fcslen = 4;1589 1590 if (truncated >= 4) {1591 truncated -= 4;1592 fcslen = 0;1593 } else {1594 fcslen -= truncated;1595 truncated = 0;1596 }1597 pktsize -= fcslen;1598 wakeup.packet = status->wake_packet;1599 wakeup.packet_present_len = pktsize;1600 wakeup.packet_len = pktlen - truncated;1601 wakeup.packet_80211 = true;1602 }1603 }1604 1605 report:1606 ieee80211_report_wowlan_wakeup(vif, wakeup_report, GFP_KERNEL);1607 kfree_skb(pkt);1608}1609 1610static void iwl_mvm_le64_to_aes_seq(__le64 le_pn, struct ieee80211_key_seq *seq)1611{1612 u64 pn = le64_to_cpu(le_pn);1613 1614 seq->ccmp.pn[0] = pn >> 40;1615 seq->ccmp.pn[1] = pn >> 32;1616 seq->ccmp.pn[2] = pn >> 24;1617 seq->ccmp.pn[3] = pn >> 16;1618 seq->ccmp.pn[4] = pn >> 8;1619 seq->ccmp.pn[5] = pn;1620}1621 1622static void iwl_mvm_aes_sc_to_seq(struct aes_sc *sc,1623 struct ieee80211_key_seq *seq)1624{1625 iwl_mvm_le64_to_aes_seq(sc->pn, seq);1626}1627 1628static void iwl_mvm_le64_to_tkip_seq(__le64 le_pn, struct ieee80211_key_seq *seq)1629{1630 u64 pn = le64_to_cpu(le_pn);1631 1632 seq->tkip.iv16 = (u16)pn;1633 seq->tkip.iv32 = (u32)(pn >> 16);1634}1635 1636static void iwl_mvm_tkip_sc_to_seq(struct tkip_sc *sc,1637 struct ieee80211_key_seq *seq)1638{1639 seq->tkip.iv32 = le32_to_cpu(sc->iv32);1640 seq->tkip.iv16 = le16_to_cpu(sc->iv16);1641}1642 1643static void iwl_mvm_set_key_rx_seq_tids(struct ieee80211_key_conf *key,1644 struct ieee80211_key_seq *seq)1645{1646 int tid;1647 1648 for (tid = 0; tid < IWL_MAX_TID_COUNT; tid++)1649 ieee80211_set_key_rx_seq(key, tid, &seq[tid]);1650}1651 1652static void iwl_mvm_set_aes_ptk_rx_seq(struct iwl_mvm *mvm,1653 struct iwl_wowlan_status_data *status,1654 struct ieee80211_sta *sta,1655 struct ieee80211_key_conf *key)1656{1657 struct iwl_mvm_sta *mvmsta = iwl_mvm_sta_from_mac80211(sta);1658 struct iwl_mvm_key_pn *ptk_pn;1659 int tid;1660 1661 iwl_mvm_set_key_rx_seq_tids(key, status->ptk.aes.seq);1662 1663 if (!iwl_mvm_has_new_rx_api(mvm))1664 return;1665 1666 1667 rcu_read_lock();1668 ptk_pn = rcu_dereference(mvmsta->ptk_pn[key->keyidx]);1669 if (WARN_ON(!ptk_pn)) {1670 rcu_read_unlock();1671 return;1672 }1673 1674 for (tid = 0; tid < IWL_MAX_TID_COUNT; tid++) {1675 int i;1676 1677 for (i = 1; i < mvm->trans->num_rx_queues; i++)1678 memcpy(ptk_pn->q[i].pn[tid],1679 status->ptk.aes.seq[tid].ccmp.pn,1680 IEEE80211_CCMP_PN_LEN);1681 }1682 rcu_read_unlock();1683}1684 1685static void iwl_mvm_convert_key_counters(struct iwl_wowlan_status_data *status,1686 union iwl_all_tsc_rsc *sc)1687{1688 int i;1689 1690 BUILD_BUG_ON(IWL_MAX_TID_COUNT > IWL_MAX_TID_COUNT);1691 BUILD_BUG_ON(IWL_MAX_TID_COUNT > IWL_NUM_RSC);1692 1693 /* GTK RX counters */1694 for (i = 0; i < IWL_MAX_TID_COUNT; i++) {1695 iwl_mvm_tkip_sc_to_seq(&sc->tkip.multicast_rsc[i],1696 &status->gtk_seq[0].tkip.seq[i]);1697 iwl_mvm_aes_sc_to_seq(&sc->aes.multicast_rsc[i],1698 &status->gtk_seq[0].aes.seq[i]);1699 }1700 status->gtk_seq[0].valid = true;1701 status->gtk_seq[0].key_id = -1;1702 1703 /* PTK TX counter */1704 status->ptk.tkip.tx_pn = (u64)le16_to_cpu(sc->tkip.tsc.iv16) |1705 ((u64)le32_to_cpu(sc->tkip.tsc.iv32) << 16);1706 status->ptk.aes.tx_pn = le64_to_cpu(sc->aes.tsc.pn);1707 1708 /* PTK RX counters */1709 for (i = 0; i < IWL_MAX_TID_COUNT; i++) {1710 iwl_mvm_tkip_sc_to_seq(&sc->tkip.unicast_rsc[i],1711 &status->ptk.tkip.seq[i]);1712 iwl_mvm_aes_sc_to_seq(&sc->aes.unicast_rsc[i],1713 &status->ptk.aes.seq[i]);1714 }1715}1716 1717static void1718iwl_mvm_convert_key_counters_v5_gtk_seq(struct iwl_wowlan_status_data *status,1719 struct iwl_wowlan_all_rsc_tsc_v5 *sc,1720 unsigned int idx, unsigned int key_id)1721{1722 int tid;1723 1724 for (tid = 0; tid < IWL_MAX_TID_COUNT; tid++) {1725 iwl_mvm_le64_to_tkip_seq(sc->mcast_rsc[idx][tid],1726 &status->gtk_seq[idx].tkip.seq[tid]);1727 iwl_mvm_le64_to_aes_seq(sc->mcast_rsc[idx][tid],1728 &status->gtk_seq[idx].aes.seq[tid]);1729 }1730 1731 status->gtk_seq[idx].valid = true;1732 status->gtk_seq[idx].key_id = key_id;1733}1734 1735static void1736iwl_mvm_convert_key_counters_v5(struct iwl_wowlan_status_data *status,1737 struct iwl_wowlan_all_rsc_tsc_v5 *sc)1738{1739 int i, tid;1740 1741 BUILD_BUG_ON(IWL_MAX_TID_COUNT > IWL_MAX_TID_COUNT);1742 BUILD_BUG_ON(IWL_MAX_TID_COUNT > IWL_NUM_RSC);1743 BUILD_BUG_ON(ARRAY_SIZE(sc->mcast_rsc) != ARRAY_SIZE(status->gtk_seq));1744 1745 /* GTK RX counters */1746 for (i = 0; i < ARRAY_SIZE(sc->mcast_key_id_map); i++) {1747 u8 entry = sc->mcast_key_id_map[i];1748 1749 if (entry < ARRAY_SIZE(sc->mcast_rsc))1750 iwl_mvm_convert_key_counters_v5_gtk_seq(status, sc,1751 entry, i);1752 }1753 1754 /* PTK TX counters not needed, assigned in device */1755 1756 /* PTK RX counters */1757 for (tid = 0; tid < IWL_MAX_TID_COUNT; tid++) {1758 iwl_mvm_le64_to_tkip_seq(sc->ucast_rsc[tid],1759 &status->ptk.tkip.seq[tid]);1760 iwl_mvm_le64_to_aes_seq(sc->ucast_rsc[tid],1761 &status->ptk.aes.seq[tid]);1762 }1763}1764 1765static void iwl_mvm_set_key_rx_seq_idx(struct ieee80211_key_conf *key,1766 struct iwl_wowlan_status_data *status,1767 int idx)1768{1769 switch (key->cipher) {1770 case WLAN_CIPHER_SUITE_CCMP:1771 case WLAN_CIPHER_SUITE_GCMP:1772 case WLAN_CIPHER_SUITE_GCMP_256:1773 iwl_mvm_set_key_rx_seq_tids(key, status->gtk_seq[idx].aes.seq);1774 break;1775 case WLAN_CIPHER_SUITE_TKIP:1776 iwl_mvm_set_key_rx_seq_tids(key, status->gtk_seq[idx].tkip.seq);1777 break;1778 default:1779 WARN_ON(1);1780 }1781}1782 1783static void iwl_mvm_set_key_rx_seq(struct ieee80211_key_conf *key,1784 struct iwl_wowlan_status_data *status,1785 bool installed)1786{1787 int i;1788 1789 for (i = 0; i < ARRAY_SIZE(status->gtk_seq); i++) {1790 if (!status->gtk_seq[i].valid)1791 continue;1792 1793 /* Handle the case where we know the key ID */1794 if (status->gtk_seq[i].key_id == key->keyidx) {1795 s8 new_key_id = -1;1796 1797 if (status->num_of_gtk_rekeys)1798 new_key_id = status->gtk[0].flags &1799 IWL_WOWLAN_GTK_IDX_MASK;1800 1801 /* Don't install a new key's value to an old key */1802 if (new_key_id != key->keyidx)1803 iwl_mvm_set_key_rx_seq_idx(key, status, i);1804 continue;1805 }1806 1807 /* handle the case where we didn't, last key only */1808 if (status->gtk_seq[i].key_id == -1 &&1809 (!status->num_of_gtk_rekeys || installed))1810 iwl_mvm_set_key_rx_seq_idx(key, status, i);1811 }1812}1813 1814struct iwl_mvm_d3_gtk_iter_data {1815 struct iwl_mvm *mvm;1816 struct iwl_wowlan_status_data *status;1817 u32 gtk_cipher, igtk_cipher, bigtk_cipher;1818 bool unhandled_cipher, igtk_support, bigtk_support;1819 int num_keys;1820};1821 1822static void iwl_mvm_d3_find_last_keys(struct ieee80211_hw *hw,1823 struct ieee80211_vif *vif,1824 struct ieee80211_sta *sta,1825 struct ieee80211_key_conf *key,1826 void *_data)1827{1828 struct iwl_mvm_d3_gtk_iter_data *data = _data;1829 int link_id = vif->active_links ? __ffs(vif->active_links) : -1;1830 1831 if (link_id >= 0 && key->link_id >= 0 && link_id != key->link_id)1832 return;1833 1834 if (data->unhandled_cipher)1835 return;1836 1837 switch (key->cipher) {1838 case WLAN_CIPHER_SUITE_WEP40:1839 case WLAN_CIPHER_SUITE_WEP104:1840 /* ignore WEP completely, nothing to do */1841 return;1842 case WLAN_CIPHER_SUITE_CCMP:1843 case WLAN_CIPHER_SUITE_GCMP:1844 case WLAN_CIPHER_SUITE_GCMP_256:1845 case WLAN_CIPHER_SUITE_TKIP:1846 /* we support these */1847 data->gtk_cipher = key->cipher;1848 break;1849 case WLAN_CIPHER_SUITE_BIP_GMAC_128:1850 case WLAN_CIPHER_SUITE_BIP_GMAC_256:1851 case WLAN_CIPHER_SUITE_BIP_CMAC_256:1852 case WLAN_CIPHER_SUITE_AES_CMAC:1853 /* we support these */1854 if (data->igtk_support &&1855 (key->keyidx == 4 || key->keyidx == 5)) {1856 data->igtk_cipher = key->cipher;1857 } else if (data->bigtk_support &&1858 (key->keyidx == 6 || key->keyidx == 7)) {1859 data->bigtk_cipher = key->cipher;1860 } else {1861 data->unhandled_cipher = true;1862 return;1863 }1864 break;1865 default:1866 /* everything else - disconnect from AP */1867 data->unhandled_cipher = true;1868 return;1869 }1870 1871 data->num_keys++;1872}1873 1874static void1875iwl_mvm_d3_set_igtk_bigtk_ipn(const struct iwl_multicast_key_data *key,1876 struct ieee80211_key_seq *seq, u32 cipher)1877{1878 switch (cipher) {1879 case WLAN_CIPHER_SUITE_BIP_GMAC_128:1880 case WLAN_CIPHER_SUITE_BIP_GMAC_256:1881 BUILD_BUG_ON(sizeof(seq->aes_gmac.pn) != sizeof(key->ipn));1882 memcpy(seq->aes_gmac.pn, key->ipn, sizeof(seq->aes_gmac.pn));1883 break;1884 case WLAN_CIPHER_SUITE_BIP_CMAC_256:1885 case WLAN_CIPHER_SUITE_AES_CMAC:1886 BUILD_BUG_ON(sizeof(seq->aes_cmac.pn) != sizeof(key->ipn));1887 memcpy(seq->aes_cmac.pn, key->ipn, sizeof(seq->aes_cmac.pn));1888 break;1889 default:1890 WARN_ON(1);1891 }1892}1893 1894static void1895iwl_mvm_d3_update_igtk_bigtk(struct iwl_wowlan_status_data *status,1896 struct ieee80211_key_conf *key,1897 struct iwl_multicast_key_data *key_data)1898{1899 if (status->num_of_gtk_rekeys && key_data->len) {1900 /* remove rekeyed key */1901 ieee80211_remove_key(key);1902 } else {1903 struct ieee80211_key_seq seq;1904 1905 iwl_mvm_d3_set_igtk_bigtk_ipn(key_data,1906 &seq,1907 key->cipher);1908 ieee80211_set_key_rx_seq(key, 0, &seq);1909 }1910}1911 1912static void iwl_mvm_d3_update_keys(struct ieee80211_hw *hw,1913 struct ieee80211_vif *vif,1914 struct ieee80211_sta *sta,1915 struct ieee80211_key_conf *key,1916 void *_data)1917{1918 struct iwl_mvm_d3_gtk_iter_data *data = _data;1919 struct iwl_wowlan_status_data *status = data->status;1920 s8 keyidx;1921 int link_id = vif->active_links ? __ffs(vif->active_links) : -1;1922 1923 if (link_id >= 0 && key->link_id >= 0 && link_id != key->link_id)1924 return;1925 1926 if (data->unhandled_cipher)1927 return;1928 1929 switch (key->cipher) {1930 case WLAN_CIPHER_SUITE_WEP40:1931 case WLAN_CIPHER_SUITE_WEP104:1932 /* ignore WEP completely, nothing to do */1933 return;1934 case WLAN_CIPHER_SUITE_CCMP:1935 case WLAN_CIPHER_SUITE_GCMP:1936 case WLAN_CIPHER_SUITE_GCMP_256:1937 if (sta) {1938 atomic64_set(&key->tx_pn, status->ptk.aes.tx_pn);1939 iwl_mvm_set_aes_ptk_rx_seq(data->mvm, status, sta, key);1940 return;1941 }1942 fallthrough;1943 case WLAN_CIPHER_SUITE_TKIP:1944 if (sta) {1945 atomic64_set(&key->tx_pn, status->ptk.tkip.tx_pn);1946 iwl_mvm_set_key_rx_seq_tids(key, status->ptk.tkip.seq);1947 return;1948 }1949 keyidx = key->keyidx;1950 /* The current key is always sent by the FW, even if it wasn't1951 * rekeyed during D3.1952 * We remove an existing key if it has the same index as1953 * a new key1954 */1955 if (status->num_of_gtk_rekeys &&1956 ((status->gtk[0].len && keyidx == status->gtk[0].id) ||1957 (status->gtk[1].len && keyidx == status->gtk[1].id))) {1958 ieee80211_remove_key(key);1959 } else {1960 iwl_mvm_set_key_rx_seq(key, data->status, false);1961 }1962 break;1963 case WLAN_CIPHER_SUITE_BIP_GMAC_128:1964 case WLAN_CIPHER_SUITE_BIP_GMAC_256:1965 case WLAN_CIPHER_SUITE_BIP_CMAC_256:1966 case WLAN_CIPHER_SUITE_AES_CMAC:1967 if (key->keyidx == 4 || key->keyidx == 5) {1968 iwl_mvm_d3_update_igtk_bigtk(status, key,1969 &status->igtk);1970 }1971 if (key->keyidx == 6 || key->keyidx == 7) {1972 u8 idx = key->keyidx == status->bigtk[1].id;1973 1974 iwl_mvm_d3_update_igtk_bigtk(status, key,1975 &status->bigtk[idx]);1976 }1977 }1978}1979 1980struct iwl_mvm_d3_mlo_old_keys {1981 u32 cipher[IEEE80211_MLD_MAX_NUM_LINKS][WOWLAN_MLO_GTK_KEY_NUM_TYPES];1982 struct ieee80211_key_conf *key[IEEE80211_MLD_MAX_NUM_LINKS][8];1983};1984 1985static void iwl_mvm_mlo_key_ciphers(struct ieee80211_hw *hw,1986 struct ieee80211_vif *vif,1987 struct ieee80211_sta *sta,1988 struct ieee80211_key_conf *key,1989 void *data)1990{1991 struct iwl_mvm_d3_mlo_old_keys *old_keys = data;1992 enum iwl_wowlan_mlo_gtk_type key_type;1993 1994 if (key->link_id < 0)1995 return;1996 1997 if (WARN_ON(key->link_id >= IEEE80211_MLD_MAX_NUM_LINKS ||1998 key->keyidx >= 8))1999 return;2000 2001 if (WARN_ON(old_keys->key[key->link_id][key->keyidx]))2002 return;2003 2004 switch (key->cipher) {2005 case WLAN_CIPHER_SUITE_CCMP:2006 case WLAN_CIPHER_SUITE_GCMP:2007 case WLAN_CIPHER_SUITE_GCMP_256:2008 key_type = WOWLAN_MLO_GTK_KEY_TYPE_GTK;2009 break;2010 case WLAN_CIPHER_SUITE_BIP_GMAC_128:2011 case WLAN_CIPHER_SUITE_BIP_GMAC_256:2012 case WLAN_CIPHER_SUITE_BIP_CMAC_256:2013 case WLAN_CIPHER_SUITE_AES_CMAC:2014 if (key->keyidx == 4 || key->keyidx == 5) {2015 key_type = WOWLAN_MLO_GTK_KEY_TYPE_IGTK;2016 break;2017 } else if (key->keyidx == 6 || key->keyidx == 7) {2018 key_type = WOWLAN_MLO_GTK_KEY_TYPE_BIGTK;2019 break;2020 }2021 return;2022 default:2023 /* ignore WEP/TKIP or unknown ciphers */2024 return;2025 }2026 2027 old_keys->cipher[key->link_id][key_type] = key->cipher;2028 old_keys->key[key->link_id][key->keyidx] = key;2029}2030 2031static bool iwl_mvm_mlo_gtk_rekey(struct iwl_wowlan_status_data *status,2032 struct ieee80211_vif *vif,2033 struct iwl_mvm *mvm)2034{2035 int i;2036 struct iwl_mvm_d3_mlo_old_keys *old_keys;2037 bool ret = true;2038 2039 IWL_DEBUG_WOWLAN(mvm, "Num of MLO Keys: %d\n", status->num_mlo_keys);2040 if (!status->num_mlo_keys)2041 return true;2042 2043 old_keys = kzalloc(sizeof(*old_keys), GFP_KERNEL);2044 if (!old_keys)2045 return false;2046 2047 /* find the cipher for each mlo key */2048 ieee80211_iter_keys(mvm->hw, vif, iwl_mvm_mlo_key_ciphers, old_keys);2049 2050 for (i = 0; i < status->num_mlo_keys; i++) {2051 struct iwl_wowlan_mlo_gtk *mlo_key = &status->mlo_keys[i];2052 struct ieee80211_key_conf *key, *old_key;2053 struct ieee80211_key_seq seq;2054 struct {2055 struct ieee80211_key_conf conf;2056 u8 key[32];2057 } conf = {};2058 u16 flags = le16_to_cpu(mlo_key->flags);2059 int j, link_id, key_id, key_type;2060 2061 link_id = u16_get_bits(flags, WOWLAN_MLO_GTK_FLAG_LINK_ID_MSK);2062 key_id = u16_get_bits(flags, WOWLAN_MLO_GTK_FLAG_KEY_ID_MSK);2063 key_type = u16_get_bits(flags,2064 WOWLAN_MLO_GTK_FLAG_KEY_TYPE_MSK);2065 2066 if (!(vif->valid_links & BIT(link_id)))2067 continue;2068 2069 if (WARN_ON(link_id >= IEEE80211_MLD_MAX_NUM_LINKS ||2070 key_id >= 8 ||2071 key_type >= WOWLAN_MLO_GTK_KEY_NUM_TYPES))2072 continue;2073 2074 conf.conf.cipher = old_keys->cipher[link_id][key_type];2075 /* WARN_ON? */2076 if (!conf.conf.cipher)2077 continue;2078 2079 conf.conf.keylen = 0;2080 switch (conf.conf.cipher) {2081 case WLAN_CIPHER_SUITE_CCMP:2082 case WLAN_CIPHER_SUITE_GCMP:2083 conf.conf.keylen = WLAN_KEY_LEN_CCMP;2084 break;2085 case WLAN_CIPHER_SUITE_GCMP_256:2086 conf.conf.keylen = WLAN_KEY_LEN_GCMP_256;2087 break;2088 case WLAN_CIPHER_SUITE_BIP_GMAC_128:2089 conf.conf.keylen = WLAN_KEY_LEN_BIP_GMAC_128;2090 break;2091 case WLAN_CIPHER_SUITE_BIP_GMAC_256:2092 conf.conf.keylen = WLAN_KEY_LEN_BIP_GMAC_256;2093 break;2094 case WLAN_CIPHER_SUITE_AES_CMAC:2095 conf.conf.keylen = WLAN_KEY_LEN_AES_CMAC;2096 break;2097 case WLAN_CIPHER_SUITE_BIP_CMAC_256:2098 conf.conf.keylen = WLAN_KEY_LEN_BIP_CMAC_256;2099 break;2100 }2101 2102 if (WARN_ON(!conf.conf.keylen ||2103 conf.conf.keylen > sizeof(conf.key)))2104 continue;2105 2106 memcpy(conf.conf.key, mlo_key->key, conf.conf.keylen);2107 conf.conf.keyidx = key_id;2108 2109 old_key = old_keys->key[link_id][key_id];2110 if (old_key) {2111 IWL_DEBUG_WOWLAN(mvm,2112 "Remove MLO key id %d, link id %d\n",2113 key_id, link_id);2114 ieee80211_remove_key(old_key);2115 }2116 2117 IWL_DEBUG_WOWLAN(mvm, "Add MLO key id %d, link id %d\n",2118 key_id, link_id);2119 key = ieee80211_gtk_rekey_add(vif, &conf.conf, link_id);2120 if (WARN_ON(IS_ERR(key))) {2121 ret = false;2122 goto out;2123 }2124 2125 /*2126 * mac80211 expects the pn in big-endian2127 * also note that seq is a union of all cipher types2128 * (ccmp, gcmp, cmac, gmac), and they all have the same2129 * pn field (of length 6) so just copy it to ccmp.pn.2130 */2131 for (j = 5; j >= 0; j--)2132 seq.ccmp.pn[5 - j] = mlo_key->pn[j];2133 2134 /* group keys are non-QoS and use TID 0 */2135 ieee80211_set_key_rx_seq(key, 0, &seq);2136 }2137 2138out:2139 kfree(old_keys);2140 return ret;2141}2142 2143static bool iwl_mvm_gtk_rekey(struct iwl_wowlan_status_data *status,2144 struct ieee80211_vif *vif,2145 struct iwl_mvm *mvm, u32 gtk_cipher)2146{2147 int i, j;2148 struct ieee80211_key_conf *key;2149 struct {2150 struct ieee80211_key_conf conf;2151 u8 key[32];2152 } conf = {2153 .conf.cipher = gtk_cipher,2154 };2155 int link_id = vif->active_links ? __ffs(vif->active_links) : -1;2156 2157 BUILD_BUG_ON(WLAN_KEY_LEN_CCMP != WLAN_KEY_LEN_GCMP);2158 BUILD_BUG_ON(sizeof(conf.key) < WLAN_KEY_LEN_CCMP);2159 BUILD_BUG_ON(sizeof(conf.key) < WLAN_KEY_LEN_GCMP_256);2160 BUILD_BUG_ON(sizeof(conf.key) < WLAN_KEY_LEN_TKIP);2161 BUILD_BUG_ON(sizeof(conf.key) < sizeof(status->gtk[0].key));2162 2163 switch (gtk_cipher) {2164 case WLAN_CIPHER_SUITE_CCMP:2165 case WLAN_CIPHER_SUITE_GCMP:2166 conf.conf.keylen = WLAN_KEY_LEN_CCMP;2167 break;2168 case WLAN_CIPHER_SUITE_GCMP_256:2169 conf.conf.keylen = WLAN_KEY_LEN_GCMP_256;2170 break;2171 case WLAN_CIPHER_SUITE_TKIP:2172 conf.conf.keylen = WLAN_KEY_LEN_TKIP;2173 break;2174 default:2175 WARN_ON(1);2176 }2177 2178 for (i = 0; i < ARRAY_SIZE(status->gtk); i++) {2179 if (!status->gtk[i].len)2180 continue;2181 2182 conf.conf.keyidx = status->gtk[i].id;2183 IWL_DEBUG_WOWLAN(mvm,2184 "Received from FW GTK cipher %d, key index %d\n",2185 conf.conf.cipher, conf.conf.keyidx);2186 memcpy(conf.conf.key, status->gtk[i].key,2187 sizeof(status->gtk[i].key));2188 2189 key = ieee80211_gtk_rekey_add(vif, &conf.conf, link_id);2190 if (IS_ERR(key))2191 return false;2192 2193 for (j = 0; j < ARRAY_SIZE(status->gtk_seq); j++) {2194 if (!status->gtk_seq[j].valid ||2195 status->gtk_seq[j].key_id != key->keyidx)2196 continue;2197 iwl_mvm_set_key_rx_seq_idx(key, status, j);2198 break;2199 }2200 WARN_ON(j == ARRAY_SIZE(status->gtk_seq));2201 }2202 2203 return true;2204}2205 2206static bool2207iwl_mvm_d3_igtk_bigtk_rekey_add(struct iwl_wowlan_status_data *status,2208 struct ieee80211_vif *vif, u32 cipher,2209 struct iwl_multicast_key_data *key_data)2210{2211 struct ieee80211_key_conf *key_config;2212 struct {2213 struct ieee80211_key_conf conf;2214 u8 key[WOWLAN_KEY_MAX_SIZE];2215 } conf = {2216 .conf.cipher = cipher,2217 .conf.keyidx = key_data->id,2218 };2219 struct ieee80211_key_seq seq;2220 int link_id = vif->active_links ? __ffs(vif->active_links) : -1;2221 2222 if (!key_data->len)2223 return true;2224 2225 iwl_mvm_d3_set_igtk_bigtk_ipn(key_data, &seq, conf.conf.cipher);2226 2227 switch (cipher) {2228 case WLAN_CIPHER_SUITE_BIP_GMAC_128:2229 conf.conf.keylen = WLAN_KEY_LEN_BIP_GMAC_128;2230 break;2231 case WLAN_CIPHER_SUITE_BIP_GMAC_256:2232 conf.conf.keylen = WLAN_KEY_LEN_BIP_GMAC_256;2233 break;2234 case WLAN_CIPHER_SUITE_AES_CMAC:2235 conf.conf.keylen = WLAN_KEY_LEN_AES_CMAC;2236 break;2237 case WLAN_CIPHER_SUITE_BIP_CMAC_256:2238 conf.conf.keylen = WLAN_KEY_LEN_BIP_CMAC_256;2239 break;2240 default:2241 WARN_ON(1);2242 }2243 BUILD_BUG_ON(sizeof(conf.key) < sizeof(key_data->key));2244 memcpy(conf.conf.key, key_data->key, conf.conf.keylen);2245 2246 key_config = ieee80211_gtk_rekey_add(vif, &conf.conf, link_id);2247 if (IS_ERR(key_config))2248 return false;2249 ieee80211_set_key_rx_seq(key_config, 0, &seq);2250 2251 if (key_config->keyidx == 4 || key_config->keyidx == 5) {2252 struct iwl_mvm_vif *mvmvif = iwl_mvm_vif_from_mac80211(vif);2253 struct iwl_mvm_vif_link_info *mvm_link;2254 2255 link_id = link_id < 0 ? 0 : link_id;2256 mvm_link = mvmvif->link[link_id];2257 mvm_link->igtk = key_config;2258 }2259 2260 return true;2261}2262 2263static int iwl_mvm_lookup_wowlan_status_ver(struct iwl_mvm *mvm)2264{2265 u8 notif_ver;2266 2267 if (!fw_has_api(&mvm->fw->ucode_capa,2268 IWL_UCODE_TLV_API_WOWLAN_KEY_MATERIAL))2269 return 6;2270 2271 /* default to 7 (when we have IWL_UCODE_TLV_API_WOWLAN_KEY_MATERIAL) */2272 notif_ver = iwl_fw_lookup_notif_ver(mvm->fw, LONG_GROUP,2273 WOWLAN_GET_STATUSES, 0);2274 if (!notif_ver)2275 notif_ver = iwl_fw_lookup_notif_ver(mvm->fw, LEGACY_GROUP,2276 WOWLAN_GET_STATUSES, 7);2277 2278 return notif_ver;2279}2280 2281static bool iwl_mvm_setup_connection_keep(struct iwl_mvm *mvm,2282 struct ieee80211_vif *vif,2283 struct iwl_wowlan_status_data *status)2284{2285 struct iwl_mvm_vif *mvmvif = iwl_mvm_vif_from_mac80211(vif);2286 struct iwl_mvm_d3_gtk_iter_data gtkdata = {2287 .mvm = mvm,2288 .status = status,2289 };2290 int i;2291 u32 disconnection_reasons =2292 IWL_WOWLAN_WAKEUP_BY_DISCONNECTION_ON_MISSED_BEACON |2293 IWL_WOWLAN_WAKEUP_BY_DISCONNECTION_ON_DEAUTH;2294 2295 if (!status || !vif->bss_conf.bssid)2296 return false;2297 2298 if (iwl_mvm_lookup_wowlan_status_ver(mvm) > 6 ||2299 iwl_fw_lookup_notif_ver(mvm->fw, PROT_OFFLOAD_GROUP,2300 WOWLAN_INFO_NOTIFICATION,2301 0))2302 gtkdata.igtk_support = true;2303 2304 if (iwl_fw_lookup_notif_ver(mvm->fw, PROT_OFFLOAD_GROUP,2305 WOWLAN_INFO_NOTIFICATION,2306 0) >= 3)2307 gtkdata.bigtk_support = true;2308 2309 /* find last GTK that we used initially, if any */2310 ieee80211_iter_keys(mvm->hw, vif,2311 iwl_mvm_d3_find_last_keys, >kdata);2312 /* not trying to keep connections with MFP/unhandled ciphers */2313 if (gtkdata.unhandled_cipher)2314 return false;2315 if (!gtkdata.num_keys)2316 goto out;2317 2318 /*2319 * invalidate all other GTKs that might still exist and update2320 * the one that we used2321 */2322 ieee80211_iter_keys(mvm->hw, vif,2323 iwl_mvm_d3_update_keys, >kdata);2324 2325 if (status->num_of_gtk_rekeys) {2326 __be64 replay_ctr = cpu_to_be64(status->replay_ctr);2327 2328 IWL_DEBUG_WOWLAN(mvm, "num of GTK rekeying %d\n",2329 status->num_of_gtk_rekeys);2330 2331 if (!iwl_mvm_gtk_rekey(status, vif, mvm, gtkdata.gtk_cipher))2332 return false;2333 2334 if (!iwl_mvm_d3_igtk_bigtk_rekey_add(status, vif,2335 gtkdata.igtk_cipher,2336 &status->igtk))2337 return false;2338 2339 for (i = 0; i < ARRAY_SIZE(status->bigtk); i++) {2340 if (!iwl_mvm_d3_igtk_bigtk_rekey_add(status, vif,2341 gtkdata.bigtk_cipher,2342 &status->bigtk[i]))2343 return false;2344 }2345 2346 if (!iwl_mvm_mlo_gtk_rekey(status, vif, mvm))2347 return false;2348 2349 ieee80211_gtk_rekey_notify(vif, vif->bss_conf.bssid,2350 (void *)&replay_ctr, GFP_KERNEL);2351 }2352 2353out:2354 if (iwl_fw_lookup_notif_ver(mvm->fw, LONG_GROUP,2355 WOWLAN_GET_STATUSES,2356 IWL_FW_CMD_VER_UNKNOWN) < 10) {2357 mvmvif->seqno_valid = true;2358 /* +0x10 because the set API expects next-to-use, not last-used */2359 mvmvif->seqno = status->non_qos_seq_ctr + 0x10;2360 }2361 2362 if (status->wakeup_reasons & disconnection_reasons)2363 return false;2364 2365 return true;2366}2367 2368static void iwl_mvm_convert_gtk_v2(struct iwl_wowlan_status_data *status,2369 struct iwl_wowlan_gtk_status_v2 *data)2370{2371 BUILD_BUG_ON(sizeof(status->gtk[0].key) < sizeof(data->key));2372 BUILD_BUG_ON(NL80211_TKIP_DATA_OFFSET_RX_MIC_KEY +2373 sizeof(data->tkip_mic_key) >2374 sizeof(status->gtk[0].key));2375 2376 status->gtk[0].len = data->key_len;2377 status->gtk[0].flags = data->key_flags;2378 2379 memcpy(status->gtk[0].key, data->key, sizeof(data->key));2380 2381 /* if it's as long as the TKIP encryption key, copy MIC key */2382 if (status->gtk[0].len == NL80211_TKIP_DATA_OFFSET_TX_MIC_KEY)2383 memcpy(status->gtk[0].key + NL80211_TKIP_DATA_OFFSET_RX_MIC_KEY,2384 data->tkip_mic_key, sizeof(data->tkip_mic_key));2385}2386 2387static void iwl_mvm_convert_gtk_v3(struct iwl_wowlan_status_data *status,2388 struct iwl_wowlan_gtk_status_v3 *data)2389{2390 int data_idx, status_idx = 0;2391 2392 BUILD_BUG_ON(sizeof(status->gtk[0].key) < sizeof(data[0].key));2393 BUILD_BUG_ON(NL80211_TKIP_DATA_OFFSET_RX_MIC_KEY +2394 sizeof(data[0].tkip_mic_key) >2395 sizeof(status->gtk[0].key));2396 BUILD_BUG_ON(ARRAY_SIZE(status->gtk) < WOWLAN_GTK_KEYS_NUM);2397 for (data_idx = 0; data_idx < ARRAY_SIZE(status->gtk); data_idx++) {2398 if (!(data[data_idx].key_len))2399 continue;2400 status->gtk[status_idx].len = data[data_idx].key_len;2401 status->gtk[status_idx].flags = data[data_idx].key_flags;2402 status->gtk[status_idx].id = status->gtk[status_idx].flags &2403 IWL_WOWLAN_GTK_IDX_MASK;2404 2405 memcpy(status->gtk[status_idx].key, data[data_idx].key,2406 sizeof(data[data_idx].key));2407 2408 /* if it's as long as the TKIP encryption key, copy MIC key */2409 if (status->gtk[status_idx].len ==2410 NL80211_TKIP_DATA_OFFSET_TX_MIC_KEY)2411 memcpy(status->gtk[status_idx].key +2412 NL80211_TKIP_DATA_OFFSET_RX_MIC_KEY,2413 data[data_idx].tkip_mic_key,2414 sizeof(data[data_idx].tkip_mic_key));2415 status_idx++;2416 }2417}2418 2419static void iwl_mvm_convert_igtk(struct iwl_wowlan_status_data *status,2420 struct iwl_wowlan_igtk_status *data)2421{2422 int i;2423 2424 BUILD_BUG_ON(sizeof(status->igtk.key) < sizeof(data->key));2425 BUILD_BUG_ON(sizeof(status->igtk.ipn) != sizeof(data->ipn));2426 2427 if (!data->key_len)2428 return;2429 2430 status->igtk.len = data->key_len;2431 status->igtk.flags = data->key_flags;2432 status->igtk.id = u32_get_bits(data->key_flags,2433 IWL_WOWLAN_IGTK_BIGTK_IDX_MASK)2434 + WOWLAN_IGTK_MIN_INDEX;2435 2436 memcpy(status->igtk.key, data->key, sizeof(data->key));2437 2438 /* mac80211 expects big endian for memcmp() to work, convert */2439 for (i = 0; i < sizeof(data->ipn); i++)2440 status->igtk.ipn[i] = data->ipn[sizeof(data->ipn) - i - 1];2441}2442 2443static void iwl_mvm_convert_bigtk(struct iwl_wowlan_status_data *status,2444 const struct iwl_wowlan_igtk_status *data)2445{2446 int data_idx, status_idx = 0;2447 2448 BUILD_BUG_ON(ARRAY_SIZE(status->bigtk) < WOWLAN_BIGTK_KEYS_NUM);2449 2450 for (data_idx = 0; data_idx < WOWLAN_BIGTK_KEYS_NUM; data_idx++) {2451 if (!data[data_idx].key_len)2452 continue;2453 2454 status->bigtk[status_idx].len = data[data_idx].key_len;2455 status->bigtk[status_idx].flags = data[data_idx].key_flags;2456 status->bigtk[status_idx].id =2457 u32_get_bits(data[data_idx].key_flags,2458 IWL_WOWLAN_IGTK_BIGTK_IDX_MASK)2459 + WOWLAN_BIGTK_MIN_INDEX;2460 2461 BUILD_BUG_ON(sizeof(status->bigtk[status_idx].key) <2462 sizeof(data[data_idx].key));2463 BUILD_BUG_ON(sizeof(status->bigtk[status_idx].ipn) <2464 sizeof(data[data_idx].ipn));2465 2466 memcpy(status->bigtk[status_idx].key, data[data_idx].key,2467 sizeof(data[data_idx].key));2468 memcpy(status->bigtk[status_idx].ipn, data[data_idx].ipn,2469 sizeof(data[data_idx].ipn));2470 status_idx++;2471 }2472}2473 2474static void iwl_mvm_parse_wowlan_info_notif(struct iwl_mvm *mvm,2475 struct iwl_wowlan_info_notif *data,2476 struct iwl_wowlan_status_data *status,2477 u32 len, bool has_mlo_keys)2478{2479 u32 i;2480 u32 expected_len = sizeof(*data);2481 2482 if (!data) {2483 IWL_ERR(mvm, "iwl_wowlan_info_notif data is NULL\n");2484 status = NULL;2485 return;2486 }2487 2488 if (has_mlo_keys)2489 expected_len += (data->num_mlo_link_keys *2490 sizeof(status->mlo_keys[0]));2491 2492 if (len < expected_len) {2493 IWL_ERR(mvm, "Invalid WoWLAN info notification!\n");2494 status = NULL;2495 return;2496 }2497 2498 if (mvm->fast_resume)2499 return;2500 2501 iwl_mvm_convert_key_counters_v5(status, &data->gtk[0].sc);2502 iwl_mvm_convert_gtk_v3(status, data->gtk);2503 iwl_mvm_convert_igtk(status, &data->igtk[0]);2504 iwl_mvm_convert_bigtk(status, data->bigtk);2505 status->replay_ctr = le64_to_cpu(data->replay_ctr);2506 status->pattern_number = le16_to_cpu(data->pattern_number);2507 for (i = 0; i < IWL_MAX_TID_COUNT; i++)2508 status->qos_seq_ctr[i] =2509 le16_to_cpu(data->qos_seq_ctr[i]);2510 status->wakeup_reasons = le32_to_cpu(data->wakeup_reasons);2511 status->num_of_gtk_rekeys =2512 le32_to_cpu(data->num_of_gtk_rekeys);2513 status->received_beacons = le32_to_cpu(data->received_beacons);2514 status->tid_tear_down = data->tid_tear_down;2515 2516 if (has_mlo_keys && data->num_mlo_link_keys) {2517 status->num_mlo_keys = data->num_mlo_link_keys;2518 if (IWL_FW_CHECK(mvm,2519 status->num_mlo_keys > WOWLAN_MAX_MLO_KEYS,2520 "Too many mlo keys: %d, max %d\n",2521 status->num_mlo_keys, WOWLAN_MAX_MLO_KEYS))2522 status->num_mlo_keys = WOWLAN_MAX_MLO_KEYS;2523 memcpy(status->mlo_keys, data->mlo_gtks,2524 status->num_mlo_keys * sizeof(status->mlo_keys[0]));2525 }2526}2527 2528static void2529iwl_mvm_parse_wowlan_info_notif_v2(struct iwl_mvm *mvm,2530 struct iwl_wowlan_info_notif_v2 *data,2531 struct iwl_wowlan_status_data *status,2532 u32 len)2533{2534 u32 i;2535 2536 if (!data) {2537 IWL_ERR(mvm, "iwl_wowlan_info_notif data is NULL\n");2538 status = NULL;2539 return;2540 }2541 2542 if (len < sizeof(*data)) {2543 IWL_ERR(mvm, "Invalid WoWLAN info notification!\n");2544 status = NULL;2545 return;2546 }2547 2548 iwl_mvm_convert_key_counters_v5(status, &data->gtk[0].sc);2549 iwl_mvm_convert_gtk_v3(status, data->gtk);2550 iwl_mvm_convert_igtk(status, &data->igtk[0]);2551 status->replay_ctr = le64_to_cpu(data->replay_ctr);2552 status->pattern_number = le16_to_cpu(data->pattern_number);2553 for (i = 0; i < IWL_MAX_TID_COUNT; i++)2554 status->qos_seq_ctr[i] =2555 le16_to_cpu(data->qos_seq_ctr[i]);2556 status->wakeup_reasons = le32_to_cpu(data->wakeup_reasons);2557 status->num_of_gtk_rekeys =2558 le32_to_cpu(data->num_of_gtk_rekeys);2559 status->received_beacons = le32_to_cpu(data->received_beacons);2560 status->tid_tear_down = data->tid_tear_down;2561}2562 2563/* Occasionally, templates would be nice. This is one of those times ... */2564#define iwl_mvm_parse_wowlan_status_common(_ver) \2565static struct iwl_wowlan_status_data * \2566iwl_mvm_parse_wowlan_status_common_ ## _ver(struct iwl_mvm *mvm, \2567 struct iwl_wowlan_status_ ##_ver *data,\2568 int len) \2569{ \2570 struct iwl_wowlan_status_data *status; \2571 int data_size, i; \2572 \2573 if (len < sizeof(*data)) { \2574 IWL_ERR(mvm, "Invalid WoWLAN status response!\n"); \2575 return NULL; \2576 } \2577 \2578 data_size = ALIGN(le32_to_cpu(data->wake_packet_bufsize), 4); \2579 if (len != sizeof(*data) + data_size) { \2580 IWL_ERR(mvm, "Invalid WoWLAN status response!\n"); \2581 return NULL; \2582 } \2583 \2584 status = kzalloc(sizeof(*status), GFP_KERNEL); \2585 if (!status) \2586 return NULL; \2587 \2588 /* copy all the common fields */ \2589 status->replay_ctr = le64_to_cpu(data->replay_ctr); \2590 status->pattern_number = le16_to_cpu(data->pattern_number); \2591 status->non_qos_seq_ctr = le16_to_cpu(data->non_qos_seq_ctr); \2592 for (i = 0; i < 8; i++) \2593 status->qos_seq_ctr[i] = \2594 le16_to_cpu(data->qos_seq_ctr[i]); \2595 status->wakeup_reasons = le32_to_cpu(data->wakeup_reasons); \2596 status->num_of_gtk_rekeys = \2597 le32_to_cpu(data->num_of_gtk_rekeys); \2598 status->received_beacons = le32_to_cpu(data->received_beacons); \2599 status->wake_packet_length = \2600 le32_to_cpu(data->wake_packet_length); \2601 status->wake_packet_bufsize = \2602 le32_to_cpu(data->wake_packet_bufsize); \2603 if (status->wake_packet_bufsize) { \2604 status->wake_packet = \2605 kmemdup(data->wake_packet, \2606 status->wake_packet_bufsize, \2607 GFP_KERNEL); \2608 if (!status->wake_packet) { \2609 kfree(status); \2610 return NULL; \2611 } \2612 } else { \2613 status->wake_packet = NULL; \2614 } \2615 \2616 return status; \2617}2618 2619iwl_mvm_parse_wowlan_status_common(v6)2620iwl_mvm_parse_wowlan_status_common(v7)2621iwl_mvm_parse_wowlan_status_common(v9)2622iwl_mvm_parse_wowlan_status_common(v12)2623 2624static struct iwl_wowlan_status_data *2625iwl_mvm_send_wowlan_get_status(struct iwl_mvm *mvm, u8 sta_id)2626{2627 struct iwl_wowlan_status_data *status;2628 struct iwl_wowlan_get_status_cmd get_status_cmd = {2629 .sta_id = cpu_to_le32(sta_id),2630 };2631 struct iwl_host_cmd cmd = {2632 .id = WOWLAN_GET_STATUSES,2633 .flags = CMD_WANT_SKB,2634 .data = { &get_status_cmd, },2635 .len = { sizeof(get_status_cmd), },2636 };2637 int ret, len;2638 u8 notif_ver;2639 u8 cmd_ver = iwl_fw_lookup_cmd_ver(mvm->fw, cmd.id,2640 IWL_FW_CMD_VER_UNKNOWN);2641 2642 if (cmd_ver == IWL_FW_CMD_VER_UNKNOWN)2643 cmd.len[0] = 0;2644 2645 lockdep_assert_held(&mvm->mutex);2646 2647 ret = iwl_mvm_send_cmd(mvm, &cmd);2648 if (ret) {2649 IWL_ERR(mvm, "failed to query wakeup status (%d)\n", ret);2650 return ERR_PTR(ret);2651 }2652 2653 len = iwl_rx_packet_payload_len(cmd.resp_pkt);2654 2655 /* default to 7 (when we have IWL_UCODE_TLV_API_WOWLAN_KEY_MATERIAL) */2656 notif_ver = iwl_mvm_lookup_wowlan_status_ver(mvm);2657 2658 if (notif_ver < 7) {2659 struct iwl_wowlan_status_v6 *v6 = (void *)cmd.resp_pkt->data;2660 2661 status = iwl_mvm_parse_wowlan_status_common_v6(mvm, v6, len);2662 if (!status)2663 goto out_free_resp;2664 2665 BUILD_BUG_ON(sizeof(v6->gtk.decrypt_key) >2666 sizeof(status->gtk[0].key));2667 BUILD_BUG_ON(NL80211_TKIP_DATA_OFFSET_RX_MIC_KEY +2668 sizeof(v6->gtk.tkip_mic_key) >2669 sizeof(status->gtk[0].key));2670 2671 /* copy GTK info to the right place */2672 memcpy(status->gtk[0].key, v6->gtk.decrypt_key,2673 sizeof(v6->gtk.decrypt_key));2674 memcpy(status->gtk[0].key + NL80211_TKIP_DATA_OFFSET_RX_MIC_KEY,2675 v6->gtk.tkip_mic_key,2676 sizeof(v6->gtk.tkip_mic_key));2677 2678 iwl_mvm_convert_key_counters(status, &v6->gtk.rsc.all_tsc_rsc);2679 2680 /* hardcode the key length to 16 since v6 only supports 16 */2681 status->gtk[0].len = 16;2682 2683 /*2684 * The key index only uses 2 bits (values 0 to 3) and2685 * we always set bit 7 which means this is the2686 * currently used key.2687 */2688 status->gtk[0].flags = v6->gtk.key_index | BIT(7);2689 } else if (notif_ver == 7) {2690 struct iwl_wowlan_status_v7 *v7 = (void *)cmd.resp_pkt->data;2691 2692 status = iwl_mvm_parse_wowlan_status_common_v7(mvm, v7, len);2693 if (!status)2694 goto out_free_resp;2695 2696 iwl_mvm_convert_key_counters(status, &v7->gtk[0].rsc.all_tsc_rsc);2697 iwl_mvm_convert_gtk_v2(status, &v7->gtk[0]);2698 iwl_mvm_convert_igtk(status, &v7->igtk[0]);2699 } else if (notif_ver == 9 || notif_ver == 10 || notif_ver == 11) {2700 struct iwl_wowlan_status_v9 *v9 = (void *)cmd.resp_pkt->data;2701 2702 /* these three command versions have same layout and size, the2703 * difference is only in a few not used (reserved) fields.2704 */2705 status = iwl_mvm_parse_wowlan_status_common_v9(mvm, v9, len);2706 if (!status)2707 goto out_free_resp;2708 2709 iwl_mvm_convert_key_counters(status, &v9->gtk[0].rsc.all_tsc_rsc);2710 iwl_mvm_convert_gtk_v2(status, &v9->gtk[0]);2711 iwl_mvm_convert_igtk(status, &v9->igtk[0]);2712 2713 status->tid_tear_down = v9->tid_tear_down;2714 } else if (notif_ver == 12) {2715 struct iwl_wowlan_status_v12 *v12 = (void *)cmd.resp_pkt->data;2716 2717 status = iwl_mvm_parse_wowlan_status_common_v12(mvm, v12, len);2718 if (!status)2719 goto out_free_resp;2720 2721 iwl_mvm_convert_key_counters_v5(status, &v12->gtk[0].sc);2722 iwl_mvm_convert_gtk_v3(status, v12->gtk);2723 iwl_mvm_convert_igtk(status, &v12->igtk[0]);2724 2725 status->tid_tear_down = v12->tid_tear_down;2726 } else {2727 IWL_ERR(mvm,2728 "Firmware advertises unknown WoWLAN status response %d!\n",2729 notif_ver);2730 status = NULL;2731 }2732 2733out_free_resp:2734 iwl_free_resp(&cmd);2735 return status;2736}2737 2738/* releases the MVM mutex */2739static bool iwl_mvm_query_wakeup_reasons(struct iwl_mvm *mvm,2740 struct ieee80211_vif *vif,2741 struct iwl_wowlan_status_data *status)2742{2743 int i;2744 bool keep = false;2745 struct iwl_mvm_sta *mvm_ap_sta;2746 struct iwl_mvm_vif *mvmvif = iwl_mvm_vif_from_mac80211(vif);2747 int link_id = vif->active_links ? __ffs(vif->active_links) : 0;2748 struct iwl_mvm_vif_link_info *mvm_link = mvmvif->link[link_id];2749 2750 if (WARN_ON(!mvm_link))2751 goto out_unlock;2752 2753 if (!status)2754 goto out_unlock;2755 2756 IWL_DEBUG_WOWLAN(mvm, "wakeup reason 0x%x\n",2757 status->wakeup_reasons);2758 2759 mvm_ap_sta = iwl_mvm_sta_from_staid_protected(mvm, mvm_link->ap_sta_id);2760 if (!mvm_ap_sta)2761 goto out_unlock;2762 2763 for (i = 0; i < IWL_MAX_TID_COUNT; i++) {2764 u16 seq = status->qos_seq_ctr[i];2765 /* firmware stores last-used value, we store next value */2766 seq += 0x10;2767 mvm_ap_sta->tid_data[i].seq_number = seq;2768 }2769 2770 if (mvm->trans->trans_cfg->device_family >= IWL_DEVICE_FAMILY_22000) {2771 i = mvm->offload_tid;2772 iwl_trans_set_q_ptrs(mvm->trans,2773 mvm_ap_sta->tid_data[i].txq_id,2774 mvm_ap_sta->tid_data[i].seq_number >> 4);2775 }2776 2777 iwl_mvm_report_wakeup_reasons(mvm, vif, status);2778 2779 keep = iwl_mvm_setup_connection_keep(mvm, vif, status);2780out_unlock:2781 mutex_unlock(&mvm->mutex);2782 return keep;2783}2784 2785#define ND_QUERY_BUF_LEN (sizeof(struct iwl_scan_offload_profile_match) * \2786 IWL_SCAN_MAX_PROFILES)2787 2788struct iwl_mvm_nd_results {2789 u32 matched_profiles;2790 u8 matches[ND_QUERY_BUF_LEN];2791};2792 2793static int2794iwl_mvm_netdetect_query_results(struct iwl_mvm *mvm,2795 struct iwl_mvm_nd_results *results)2796{2797 struct iwl_scan_offload_match_info *query;2798 struct iwl_host_cmd cmd = {2799 .id = SCAN_OFFLOAD_PROFILES_QUERY_CMD,2800 .flags = CMD_WANT_SKB,2801 };2802 int ret, len;2803 size_t query_len, matches_len;2804 int max_profiles = iwl_umac_scan_get_max_profiles(mvm->fw);2805 2806 ret = iwl_mvm_send_cmd(mvm, &cmd);2807 if (ret) {2808 IWL_ERR(mvm, "failed to query matched profiles (%d)\n", ret);2809 return ret;2810 }2811 2812 if (fw_has_api(&mvm->fw->ucode_capa,2813 IWL_UCODE_TLV_API_SCAN_OFFLOAD_CHANS)) {2814 query_len = sizeof(struct iwl_scan_offload_match_info);2815 matches_len = sizeof(struct iwl_scan_offload_profile_match) *2816 max_profiles;2817 } else {2818 query_len = sizeof(struct iwl_scan_offload_profiles_query_v1);2819 matches_len = sizeof(struct iwl_scan_offload_profile_match_v1) *2820 max_profiles;2821 }2822 2823 len = iwl_rx_packet_payload_len(cmd.resp_pkt);2824 if (len < query_len) {2825 IWL_ERR(mvm, "Invalid scan offload profiles query response!\n");2826 ret = -EIO;2827 goto out_free_resp;2828 }2829 2830 query = (void *)cmd.resp_pkt->data;2831 2832 results->matched_profiles = le32_to_cpu(query->matched_profiles);2833 memcpy(results->matches, query->matches, matches_len);2834 2835#ifdef CONFIG_IWLWIFI_DEBUGFS2836 mvm->last_netdetect_scans = le32_to_cpu(query->n_scans_done);2837#endif2838 2839out_free_resp:2840 iwl_free_resp(&cmd);2841 return ret;2842}2843 2844static int iwl_mvm_query_num_match_chans(struct iwl_mvm *mvm,2845 struct iwl_mvm_nd_results *results,2846 int idx)2847{2848 int n_chans = 0, i;2849 2850 if (fw_has_api(&mvm->fw->ucode_capa,2851 IWL_UCODE_TLV_API_SCAN_OFFLOAD_CHANS)) {2852 struct iwl_scan_offload_profile_match *matches =2853 (void *)results->matches;2854 2855 for (i = 0; i < SCAN_OFFLOAD_MATCHING_CHANNELS_LEN; i++)2856 n_chans += hweight8(matches[idx].matching_channels[i]);2857 } else {2858 struct iwl_scan_offload_profile_match_v1 *matches =2859 (void *)results->matches;2860 2861 for (i = 0; i < SCAN_OFFLOAD_MATCHING_CHANNELS_LEN_V1; i++)2862 n_chans += hweight8(matches[idx].matching_channels[i]);2863 }2864 2865 return n_chans;2866}2867 2868static void iwl_mvm_query_set_freqs(struct iwl_mvm *mvm,2869 struct iwl_mvm_nd_results *results,2870 struct cfg80211_wowlan_nd_match *match,2871 int idx)2872{2873 int i;2874 2875 if (fw_has_api(&mvm->fw->ucode_capa,2876 IWL_UCODE_TLV_API_SCAN_OFFLOAD_CHANS)) {2877 struct iwl_scan_offload_profile_match *matches =2878 (void *)results->matches;2879 2880 for (i = 0; i < SCAN_OFFLOAD_MATCHING_CHANNELS_LEN * 8; i++)2881 if (matches[idx].matching_channels[i / 8] & (BIT(i % 8)))2882 match->channels[match->n_channels++] =2883 mvm->nd_channels[i]->center_freq;2884 } else {2885 struct iwl_scan_offload_profile_match_v1 *matches =2886 (void *)results->matches;2887 2888 for (i = 0; i < SCAN_OFFLOAD_MATCHING_CHANNELS_LEN_V1 * 8; i++)2889 if (matches[idx].matching_channels[i / 8] & (BIT(i % 8)))2890 match->channels[match->n_channels++] =2891 mvm->nd_channels[i]->center_freq;2892 }2893}2894 2895/**2896 * enum iwl_d3_notif - d3 notifications2897 * @IWL_D3_NOTIF_WOWLAN_INFO: WOWLAN_INFO_NOTIF was received2898 * @IWL_D3_NOTIF_WOWLAN_WAKE_PKT: WOWLAN_WAKE_PKT_NOTIF was received2899 * @IWL_D3_NOTIF_PROT_OFFLOAD: PROT_OFFLOAD_NOTIF was received2900 * @IWL_D3_ND_MATCH_INFO: OFFLOAD_MATCH_INFO_NOTIF was received2901 * @IWL_D3_NOTIF_D3_END_NOTIF: D3_END_NOTIF was received2902 */2903enum iwl_d3_notif {2904 IWL_D3_NOTIF_WOWLAN_INFO = BIT(0),2905 IWL_D3_NOTIF_WOWLAN_WAKE_PKT = BIT(1),2906 IWL_D3_NOTIF_PROT_OFFLOAD = BIT(2),2907 IWL_D3_ND_MATCH_INFO = BIT(3),2908 IWL_D3_NOTIF_D3_END_NOTIF = BIT(4)2909};2910 2911/* manage d3 resume data */2912struct iwl_d3_data {2913 struct iwl_wowlan_status_data *status;2914 bool test;2915 u32 d3_end_flags;2916 u32 notif_expected; /* bitmap - see &enum iwl_d3_notif */2917 u32 notif_received; /* bitmap - see &enum iwl_d3_notif */2918 struct iwl_mvm_nd_results *nd_results;2919 bool nd_results_valid;2920};2921 2922static void iwl_mvm_query_netdetect_reasons(struct iwl_mvm *mvm,2923 struct ieee80211_vif *vif,2924 struct iwl_d3_data *d3_data)2925{2926 struct cfg80211_wowlan_nd_info *net_detect = NULL;2927 struct cfg80211_wowlan_wakeup wakeup = {2928 .pattern_idx = -1,2929 };2930 struct cfg80211_wowlan_wakeup *wakeup_report = &wakeup;2931 unsigned long matched_profiles;2932 u32 reasons = 0;2933 int i, n_matches, ret;2934 2935 if (WARN_ON(!d3_data || !d3_data->status))2936 goto out;2937 2938 reasons = d3_data->status->wakeup_reasons;2939 2940 if (reasons & IWL_WOWLAN_WAKEUP_BY_RFKILL_DEASSERTED)2941 wakeup.rfkill_release = true;2942 2943 if (reasons != IWL_WOWLAN_WAKEUP_BY_NON_WIRELESS)2944 goto out;2945 2946 if (!iwl_fw_lookup_notif_ver(mvm->fw, PROT_OFFLOAD_GROUP,2947 WOWLAN_INFO_NOTIFICATION, 0)) {2948 IWL_INFO(mvm, "Query FW for ND results\n");2949 ret = iwl_mvm_netdetect_query_results(mvm, d3_data->nd_results);2950 2951 } else {2952 IWL_INFO(mvm, "Notification based ND results\n");2953 ret = d3_data->nd_results_valid ? 0 : -1;2954 }2955 2956 if (ret || !d3_data->nd_results->matched_profiles) {2957 wakeup_report = NULL;2958 goto out;2959 }2960 2961 matched_profiles = d3_data->nd_results->matched_profiles;2962 if (mvm->n_nd_match_sets) {2963 n_matches = hweight_long(matched_profiles);2964 } else {2965 IWL_ERR(mvm, "no net detect match information available\n");2966 n_matches = 0;2967 }2968 2969 net_detect = kzalloc(struct_size(net_detect, matches, n_matches),2970 GFP_KERNEL);2971 if (!net_detect || !n_matches)2972 goto out_report_nd;2973 2974 for_each_set_bit(i, &matched_profiles, mvm->n_nd_match_sets) {2975 struct cfg80211_wowlan_nd_match *match;2976 int idx, n_channels = 0;2977 2978 n_channels = iwl_mvm_query_num_match_chans(mvm,2979 d3_data->nd_results,2980 i);2981 2982 match = kzalloc(struct_size(match, channels, n_channels),2983 GFP_KERNEL);2984 if (!match)2985 goto out_report_nd;2986 2987 net_detect->matches[net_detect->n_matches++] = match;2988 2989 /* We inverted the order of the SSIDs in the scan2990 * request, so invert the index here.2991 */2992 idx = mvm->n_nd_match_sets - i - 1;2993 match->ssid.ssid_len = mvm->nd_match_sets[idx].ssid.ssid_len;2994 memcpy(match->ssid.ssid, mvm->nd_match_sets[idx].ssid.ssid,2995 match->ssid.ssid_len);2996 2997 if (mvm->n_nd_channels < n_channels)2998 continue;2999 3000 iwl_mvm_query_set_freqs(mvm, d3_data->nd_results, match, i);3001 }3002 3003out_report_nd:3004 wakeup.net_detect = net_detect;3005out:3006 iwl_mvm_free_nd(mvm);3007 3008 mutex_unlock(&mvm->mutex);3009 ieee80211_report_wowlan_wakeup(vif, wakeup_report, GFP_KERNEL);3010 3011 if (net_detect) {3012 for (i = 0; i < net_detect->n_matches; i++)3013 kfree(net_detect->matches[i]);3014 kfree(net_detect);3015 }3016}3017 3018static void iwl_mvm_d3_disconnect_iter(void *data, u8 *mac,3019 struct ieee80211_vif *vif)3020{3021 /* skip the one we keep connection on */3022 if (data == vif)3023 return;3024 3025 if (vif->type == NL80211_IFTYPE_STATION)3026 ieee80211_resume_disconnect(vif);3027}3028 3029static bool iwl_mvm_rt_status(struct iwl_trans *trans, u32 base, u32 *err_id)3030{3031 struct error_table_start {3032 /* cf. struct iwl_error_event_table */3033 u32 valid;3034 __le32 err_id;3035 } err_info;3036 3037 if (!base)3038 return false;3039 3040 iwl_trans_read_mem_bytes(trans, base,3041 &err_info, sizeof(err_info));3042 if (err_info.valid && err_id)3043 *err_id = le32_to_cpu(err_info.err_id);3044 3045 return !!err_info.valid;3046}3047 3048static bool iwl_mvm_check_rt_status(struct iwl_mvm *mvm,3049 struct ieee80211_vif *vif)3050{3051 u32 err_id;3052 3053 /* check for lmac1 error */3054 if (iwl_mvm_rt_status(mvm->trans,3055 mvm->trans->dbg.lmac_error_event_table[0],3056 &err_id)) {3057 if (err_id == RF_KILL_INDICATOR_FOR_WOWLAN && vif) {3058 struct cfg80211_wowlan_wakeup wakeup = {3059 .rfkill_release = true,3060 };3061 ieee80211_report_wowlan_wakeup(vif, &wakeup,3062 GFP_KERNEL);3063 }3064 return true;3065 }3066 3067 /* check if we have lmac2 set and check for error */3068 if (iwl_mvm_rt_status(mvm->trans,3069 mvm->trans->dbg.lmac_error_event_table[1], NULL))3070 return true;3071 3072 /* check for umac error */3073 if (iwl_mvm_rt_status(mvm->trans,3074 mvm->trans->dbg.umac_error_event_table, NULL))3075 return true;3076 3077 return false;3078}3079 3080/*3081 * This function assumes:3082 * 1. The mutex is already held.3083 * 2. The callee functions unlock the mutex.3084 */3085static bool3086iwl_mvm_choose_query_wakeup_reasons(struct iwl_mvm *mvm,3087 struct ieee80211_vif *vif,3088 struct iwl_d3_data *d3_data)3089{3090 lockdep_assert_held(&mvm->mutex);3091 3092 /* if FW uses status notification, status shouldn't be NULL here */3093 if (!d3_data->status) {3094 struct iwl_mvm_vif *mvmvif = iwl_mvm_vif_from_mac80211(vif);3095 u8 sta_id = mvm->net_detect ? IWL_MVM_INVALID_STA :3096 mvmvif->deflink.ap_sta_id;3097 3098 /* bug - FW with MLO has status notification */3099 WARN_ON(ieee80211_vif_is_mld(vif));3100 3101 d3_data->status = iwl_mvm_send_wowlan_get_status(mvm, sta_id);3102 }3103 3104 if (mvm->net_detect) {3105 iwl_mvm_query_netdetect_reasons(mvm, vif, d3_data);3106 } else {3107 bool keep = iwl_mvm_query_wakeup_reasons(mvm, vif,3108 d3_data->status);3109 3110#ifdef CONFIG_IWLWIFI_DEBUGFS3111 if (keep)3112 mvm->keep_vif = vif;3113#endif3114 3115 return keep;3116 }3117 return false;3118}3119 3120#define IWL_WOWLAN_WAKEUP_REASON_HAS_WAKEUP_PKT (IWL_WOWLAN_WAKEUP_BY_MAGIC_PACKET | \3121 IWL_WOWLAN_WAKEUP_BY_PATTERN | \3122 IWL_WAKEUP_BY_PATTERN_IPV4_TCP_SYN |\3123 IWL_WAKEUP_BY_PATTERN_IPV4_TCP_SYN_WILDCARD |\3124 IWL_WAKEUP_BY_PATTERN_IPV6_TCP_SYN |\3125 IWL_WAKEUP_BY_PATTERN_IPV6_TCP_SYN_WILDCARD)3126 3127static int iwl_mvm_wowlan_store_wake_pkt(struct iwl_mvm *mvm,3128 struct iwl_wowlan_wake_pkt_notif *notif,3129 struct iwl_wowlan_status_data *status,3130 u32 len)3131{3132 u32 data_size, packet_len = le32_to_cpu(notif->wake_packet_length);3133 3134 if (len < sizeof(*notif)) {3135 IWL_ERR(mvm, "Invalid WoWLAN wake packet notification!\n");3136 return -EIO;3137 }3138 3139 if (WARN_ON(!status)) {3140 IWL_ERR(mvm, "Got wake packet notification but wowlan status data is NULL\n");3141 return -EIO;3142 }3143 3144 if (WARN_ON(!(status->wakeup_reasons &3145 IWL_WOWLAN_WAKEUP_REASON_HAS_WAKEUP_PKT))) {3146 IWL_ERR(mvm, "Got wakeup packet but wakeup reason is %x\n",3147 status->wakeup_reasons);3148 return -EIO;3149 }3150 3151 data_size = len - offsetof(struct iwl_wowlan_wake_pkt_notif, wake_packet);3152 3153 /* data_size got the padding from the notification, remove it. */3154 if (packet_len < data_size)3155 data_size = packet_len;3156 3157 status->wake_packet = kmemdup(notif->wake_packet, data_size,3158 GFP_ATOMIC);3159 3160 if (!status->wake_packet)3161 return -ENOMEM;3162 3163 status->wake_packet_length = packet_len;3164 status->wake_packet_bufsize = data_size;3165 3166 return 0;3167}3168 3169static void iwl_mvm_nd_match_info_handler(struct iwl_mvm *mvm,3170 struct iwl_d3_data *d3_data,3171 struct iwl_scan_offload_match_info *notif,3172 u32 len)3173{3174 struct iwl_wowlan_status_data *status = d3_data->status;3175 struct ieee80211_vif *vif = iwl_mvm_get_bss_vif(mvm);3176 struct iwl_mvm_nd_results *results = d3_data->nd_results;3177 size_t i, matches_len = sizeof(struct iwl_scan_offload_profile_match) *3178 iwl_umac_scan_get_max_profiles(mvm->fw);3179 3180 if (IS_ERR_OR_NULL(vif))3181 return;3182 3183 if (len < sizeof(struct iwl_scan_offload_match_info)) {3184 IWL_ERR(mvm, "Invalid scan match info notification\n");3185 return;3186 }3187 3188 if (!mvm->net_detect) {3189 IWL_ERR(mvm, "Unexpected scan match info notification\n");3190 return;3191 }3192 3193 if (!status || status->wakeup_reasons != IWL_WOWLAN_WAKEUP_BY_NON_WIRELESS) {3194 IWL_ERR(mvm,3195 "Ignore scan match info notification: no reason\n");3196 return;3197 }3198 3199#ifdef CONFIG_IWLWIFI_DEBUGFS3200 mvm->last_netdetect_scans = le32_to_cpu(notif->n_scans_done);3201#endif3202 3203 results->matched_profiles = le32_to_cpu(notif->matched_profiles);3204 IWL_INFO(mvm, "number of matched profiles=%u\n",3205 results->matched_profiles);3206 3207 if (results->matched_profiles) {3208 memcpy(results->matches, notif->matches, matches_len);3209 d3_data->nd_results_valid = true;3210 }3211 3212 /* no scan should be active at this point */3213 mvm->scan_status = 0;3214 for (i = 0; i < mvm->max_scans; i++)3215 mvm->scan_uid_status[i] = 0;3216}3217 3218static bool iwl_mvm_wait_d3_notif(struct iwl_notif_wait_data *notif_wait,3219 struct iwl_rx_packet *pkt, void *data)3220{3221 struct iwl_mvm *mvm =3222 container_of(notif_wait, struct iwl_mvm, notif_wait);3223 struct iwl_d3_data *d3_data = data;3224 u32 len = iwl_rx_packet_payload_len(pkt);3225 int ret;3226 int wowlan_info_ver = iwl_fw_lookup_notif_ver(mvm->fw,3227 PROT_OFFLOAD_GROUP,3228 WOWLAN_INFO_NOTIFICATION,3229 IWL_FW_CMD_VER_UNKNOWN);3230 3231 3232 switch (WIDE_ID(pkt->hdr.group_id, pkt->hdr.cmd)) {3233 case WIDE_ID(PROT_OFFLOAD_GROUP, WOWLAN_INFO_NOTIFICATION): {3234 3235 if (d3_data->notif_received & IWL_D3_NOTIF_WOWLAN_INFO) {3236 /* We might get two notifications due to dual bss */3237 IWL_DEBUG_WOWLAN(mvm,3238 "Got additional wowlan info notification\n");3239 break;3240 }3241 3242 if (wowlan_info_ver < 2) {3243 struct iwl_wowlan_info_notif_v1 *notif_v1 =3244 (void *)pkt->data;3245 struct iwl_wowlan_info_notif_v2 *notif_v2;3246 3247 notif_v2 = kmemdup(notif_v1, sizeof(*notif_v2), GFP_ATOMIC);3248 3249 if (!notif_v2)3250 return false;3251 3252 notif_v2->tid_tear_down = notif_v1->tid_tear_down;3253 notif_v2->station_id = notif_v1->station_id;3254 memset_after(notif_v2, 0, station_id);3255 iwl_mvm_parse_wowlan_info_notif_v2(mvm, notif_v2,3256 d3_data->status,3257 len);3258 kfree(notif_v2);3259 3260 } else if (wowlan_info_ver == 2) {3261 struct iwl_wowlan_info_notif_v2 *notif_v2 =3262 (void *)pkt->data;3263 3264 iwl_mvm_parse_wowlan_info_notif_v2(mvm, notif_v2,3265 d3_data->status,3266 len);3267 } else {3268 struct iwl_wowlan_info_notif *notif =3269 (void *)pkt->data;3270 3271 iwl_mvm_parse_wowlan_info_notif(mvm, notif,3272 d3_data->status, len,3273 wowlan_info_ver > 3);3274 }3275 3276 d3_data->notif_received |= IWL_D3_NOTIF_WOWLAN_INFO;3277 3278 if (d3_data->status &&3279 d3_data->status->wakeup_reasons & IWL_WOWLAN_WAKEUP_REASON_HAS_WAKEUP_PKT)3280 /* We are supposed to get also wake packet notif */3281 d3_data->notif_expected |= IWL_D3_NOTIF_WOWLAN_WAKE_PKT;3282 3283 break;3284 }3285 case WIDE_ID(PROT_OFFLOAD_GROUP, WOWLAN_WAKE_PKT_NOTIFICATION): {3286 struct iwl_wowlan_wake_pkt_notif *notif = (void *)pkt->data;3287 3288 if (d3_data->notif_received & IWL_D3_NOTIF_WOWLAN_WAKE_PKT) {3289 /* We shouldn't get two wake packet notifications */3290 IWL_ERR(mvm,3291 "Got additional wowlan wake packet notification\n");3292 } else {3293 d3_data->notif_received |= IWL_D3_NOTIF_WOWLAN_WAKE_PKT;3294 len = iwl_rx_packet_payload_len(pkt);3295 ret = iwl_mvm_wowlan_store_wake_pkt(mvm, notif,3296 d3_data->status,3297 len);3298 if (ret)3299 IWL_ERR(mvm,3300 "Can't parse WOWLAN_WAKE_PKT_NOTIFICATION\n");3301 }3302 3303 break;3304 }3305 case WIDE_ID(SCAN_GROUP, OFFLOAD_MATCH_INFO_NOTIF): {3306 struct iwl_scan_offload_match_info *notif = (void *)pkt->data;3307 3308 if (d3_data->notif_received & IWL_D3_ND_MATCH_INFO) {3309 IWL_ERR(mvm,3310 "Got additional netdetect match info\n");3311 break;3312 }3313 3314 d3_data->notif_received |= IWL_D3_ND_MATCH_INFO;3315 3316 /* explicitly set this in the 'expected' as well */3317 d3_data->notif_expected |= IWL_D3_ND_MATCH_INFO;3318 3319 len = iwl_rx_packet_payload_len(pkt);3320 iwl_mvm_nd_match_info_handler(mvm, d3_data, notif, len);3321 break;3322 }3323 case WIDE_ID(PROT_OFFLOAD_GROUP, D3_END_NOTIFICATION): {3324 struct iwl_mvm_d3_end_notif *notif = (void *)pkt->data;3325 3326 d3_data->d3_end_flags = __le32_to_cpu(notif->flags);3327 d3_data->notif_received |= IWL_D3_NOTIF_D3_END_NOTIF;3328 3329 break;3330 }3331 default:3332 WARN_ON(1);3333 }3334 3335 return d3_data->notif_received == d3_data->notif_expected;3336}3337 3338static int iwl_mvm_resume_firmware(struct iwl_mvm *mvm, bool test)3339{3340 int ret;3341 enum iwl_d3_status d3_status;3342 struct iwl_host_cmd cmd = {3343 .id = D0I3_END_CMD,3344 .flags = CMD_WANT_SKB | CMD_SEND_IN_D3,3345 };3346 bool reset = fw_has_capa(&mvm->fw->ucode_capa,3347 IWL_UCODE_TLV_CAPA_CNSLDTD_D3_D0_IMG);3348 3349 ret = iwl_trans_d3_resume(mvm->trans, &d3_status, test, !reset);3350 if (ret)3351 return ret;3352 3353 if (d3_status != IWL_D3_STATUS_ALIVE) {3354 IWL_INFO(mvm, "Device was reset during suspend\n");3355 return -ENOENT;3356 }3357 3358 /*3359 * We should trigger resume flow using command only for 22000 family3360 * AX210 and above don't need the command since they have3361 * the doorbell interrupt.3362 */3363 if (mvm->trans->trans_cfg->device_family <= IWL_DEVICE_FAMILY_22000 &&3364 fw_has_capa(&mvm->fw->ucode_capa, IWL_UCODE_TLV_CAPA_D0I3_END_FIRST)) {3365 ret = iwl_mvm_send_cmd(mvm, &cmd);3366 if (ret < 0)3367 IWL_ERR(mvm, "Failed to send D0I3_END_CMD first (%d)\n",3368 ret);3369 }3370 3371 return ret;3372}3373 3374#define IWL_MVM_D3_NOTIF_TIMEOUT (HZ / 3)3375 3376static int iwl_mvm_d3_notif_wait(struct iwl_mvm *mvm,3377 struct iwl_d3_data *d3_data)3378{3379 static const u16 d3_resume_notif[] = {3380 WIDE_ID(PROT_OFFLOAD_GROUP, WOWLAN_INFO_NOTIFICATION),3381 WIDE_ID(PROT_OFFLOAD_GROUP, WOWLAN_WAKE_PKT_NOTIFICATION),3382 WIDE_ID(SCAN_GROUP, OFFLOAD_MATCH_INFO_NOTIF),3383 WIDE_ID(PROT_OFFLOAD_GROUP, D3_END_NOTIFICATION)3384 };3385 static const u16 d3_fast_resume_notif[] = {3386 WIDE_ID(PROT_OFFLOAD_GROUP, D3_END_NOTIFICATION)3387 };3388 struct iwl_notification_wait wait_d3_notif;3389 int ret;3390 3391 if (mvm->fast_resume)3392 iwl_init_notification_wait(&mvm->notif_wait, &wait_d3_notif,3393 d3_fast_resume_notif,3394 ARRAY_SIZE(d3_fast_resume_notif),3395 iwl_mvm_wait_d3_notif, d3_data);3396 else3397 iwl_init_notification_wait(&mvm->notif_wait, &wait_d3_notif,3398 d3_resume_notif,3399 ARRAY_SIZE(d3_resume_notif),3400 iwl_mvm_wait_d3_notif, d3_data);3401 3402 ret = iwl_mvm_resume_firmware(mvm, d3_data->test);3403 if (ret) {3404 iwl_remove_notification(&mvm->notif_wait, &wait_d3_notif);3405 return ret;3406 }3407 3408 return iwl_wait_notification(&mvm->notif_wait, &wait_d3_notif,3409 IWL_MVM_D3_NOTIF_TIMEOUT);3410}3411 3412static inline bool iwl_mvm_d3_resume_notif_based(struct iwl_mvm *mvm)3413{3414 return iwl_fw_lookup_notif_ver(mvm->fw, PROT_OFFLOAD_GROUP,3415 WOWLAN_INFO_NOTIFICATION, 0) &&3416 iwl_fw_lookup_notif_ver(mvm->fw, PROT_OFFLOAD_GROUP,3417 WOWLAN_WAKE_PKT_NOTIFICATION, 0) &&3418 iwl_fw_lookup_notif_ver(mvm->fw, PROT_OFFLOAD_GROUP,3419 D3_END_NOTIFICATION, 0);3420}3421 3422static int __iwl_mvm_resume(struct iwl_mvm *mvm, bool test)3423{3424 struct ieee80211_vif *vif = NULL;3425 int ret = 1;3426 struct iwl_mvm_nd_results results = {};3427 struct iwl_d3_data d3_data = {3428 .test = test,3429 .notif_expected =3430 IWL_D3_NOTIF_WOWLAN_INFO |3431 IWL_D3_NOTIF_D3_END_NOTIF,3432 .nd_results_valid = false,3433 .nd_results = &results,3434 };3435 bool unified_image = fw_has_capa(&mvm->fw->ucode_capa,3436 IWL_UCODE_TLV_CAPA_CNSLDTD_D3_D0_IMG);3437 bool d0i3_first = fw_has_capa(&mvm->fw->ucode_capa,3438 IWL_UCODE_TLV_CAPA_D0I3_END_FIRST);3439 bool resume_notif_based = iwl_mvm_d3_resume_notif_based(mvm);3440 bool keep = false;3441 3442 mutex_lock(&mvm->mutex);3443 3444 /* Apparently, the device went away and device_powered_off() was called,3445 * don't even try to read the rt_status, the device is currently3446 * inaccessible.3447 */3448 if (!test_bit(IWL_MVM_STATUS_IN_D3, &mvm->status)) {3449 IWL_INFO(mvm,3450 "Can't resume, device_powered_off() was called during wowlan\n");3451 goto err;3452 }3453 3454 mvm->last_reset_or_resume_time_jiffies = jiffies;3455 3456 /* get the BSS vif pointer again */3457 vif = iwl_mvm_get_bss_vif(mvm);3458 if (IS_ERR_OR_NULL(vif))3459 goto err;3460 3461 iwl_fw_dbg_read_d3_debug_data(&mvm->fwrt);3462 3463 if (iwl_mvm_check_rt_status(mvm, vif)) {3464 set_bit(STATUS_FW_ERROR, &mvm->trans->status);3465 iwl_mvm_dump_nic_error_log(mvm);3466 iwl_dbg_tlv_time_point(&mvm->fwrt,3467 IWL_FW_INI_TIME_POINT_FW_ASSERT, NULL);3468 iwl_fw_dbg_collect_desc(&mvm->fwrt, &iwl_dump_desc_assert,3469 false, 0);3470 ret = 1;3471 goto err;3472 }3473 3474 if (resume_notif_based) {3475 d3_data.status = kzalloc(sizeof(*d3_data.status), GFP_KERNEL);3476 if (!d3_data.status) {3477 IWL_ERR(mvm, "Failed to allocate wowlan status\n");3478 ret = -ENOMEM;3479 goto err;3480 }3481 3482 ret = iwl_mvm_d3_notif_wait(mvm, &d3_data);3483 if (ret)3484 goto err;3485 } else {3486 ret = iwl_mvm_resume_firmware(mvm, test);3487 if (ret < 0)3488 goto err;3489 }3490 3491 iwl_mvm_unblock_esr(mvm, vif, IWL_MVM_ESR_BLOCKED_WOWLAN);3492 3493 /* after the successful handshake, we're out of D3 */3494 mvm->trans->system_pm_mode = IWL_PLAT_PM_MODE_DISABLED;3495 3496 /* when reset is required we can't send these following commands */3497 if (d3_data.d3_end_flags & IWL_D0I3_RESET_REQUIRE)3498 goto query_wakeup_reasons;3499 3500 /*3501 * Query the current location and source from the D3 firmware so we3502 * can play it back when we re-intiailize the D0 firmware3503 */3504 iwl_mvm_update_changed_regdom(mvm);3505 3506 /* Re-configure PPAG settings */3507 iwl_mvm_ppag_send_cmd(mvm);3508 3509 if (!unified_image)3510 /* Re-configure default SAR profile */3511 iwl_mvm_sar_select_profile(mvm, 1, 1);3512 3513 if (mvm->net_detect && unified_image) {3514 /* If this is a non-unified image, we restart the FW,3515 * so no need to stop the netdetect scan. If that3516 * fails, continue and try to get the wake-up reasons,3517 * but trigger a HW restart by keeping a failure code3518 * in ret.3519 */3520 ret = iwl_mvm_scan_stop(mvm, IWL_MVM_SCAN_NETDETECT,3521 false);3522 }3523 3524query_wakeup_reasons:3525 keep = iwl_mvm_choose_query_wakeup_reasons(mvm, vif, &d3_data);3526 /* has unlocked the mutex, so skip that */3527 goto out;3528 3529err:3530 mutex_unlock(&mvm->mutex);3531out:3532 if (d3_data.status)3533 kfree(d3_data.status->wake_packet);3534 kfree(d3_data.status);3535 iwl_mvm_free_nd(mvm);3536 3537 if (!d3_data.test && !mvm->net_detect)3538 ieee80211_iterate_active_interfaces_mtx(mvm->hw,3539 IEEE80211_IFACE_ITER_NORMAL,3540 iwl_mvm_d3_disconnect_iter,3541 keep ? vif : NULL);3542 3543 clear_bit(IWL_MVM_STATUS_IN_D3, &mvm->status);3544 3545 /* no need to reset the device in unified images, if successful */3546 if (unified_image && !ret) {3547 /* nothing else to do if we already sent D0I3_END_CMD */3548 if (d0i3_first)3549 return 0;3550 3551 if (!iwl_fw_lookup_notif_ver(mvm->fw, PROT_OFFLOAD_GROUP,3552 D3_END_NOTIFICATION, 0)) {3553 ret = iwl_mvm_send_cmd_pdu(mvm, D0I3_END_CMD, 0, 0, NULL);3554 if (!ret)3555 return 0;3556 } else if (!(d3_data.d3_end_flags & IWL_D0I3_RESET_REQUIRE)) {3557 return 0;3558 }3559 }3560 3561 /*3562 * Reconfigure the device in one of the following cases:3563 * 1. We are not using a unified image3564 * 2. We are using a unified image but had an error while exiting D33565 */3566 set_bit(IWL_MVM_STATUS_HW_RESTART_REQUESTED, &mvm->status);3567 3568 /* regardless of what happened, we're now out of D3 */3569 mvm->trans->system_pm_mode = IWL_PLAT_PM_MODE_DISABLED;3570 3571 return 1;3572}3573 3574int iwl_mvm_resume(struct ieee80211_hw *hw)3575{3576 struct iwl_mvm *mvm = IWL_MAC80211_GET_MVM(hw);3577 int ret;3578 3579 ret = __iwl_mvm_resume(mvm, false);3580 3581 iwl_mvm_resume_tcm(mvm);3582 3583 iwl_fw_runtime_resume(&mvm->fwrt);3584 3585 return ret;3586}3587 3588void iwl_mvm_set_wakeup(struct ieee80211_hw *hw, bool enabled)3589{3590 struct iwl_mvm *mvm = IWL_MAC80211_GET_MVM(hw);3591 3592 device_set_wakeup_enable(mvm->trans->dev, enabled);3593}3594 3595void iwl_mvm_fast_suspend(struct iwl_mvm *mvm)3596{3597 struct iwl_d3_manager_config d3_cfg_cmd_data = {};3598 int ret;3599 3600 lockdep_assert_held(&mvm->mutex);3601 3602 IWL_DEBUG_WOWLAN(mvm, "Starting fast suspend flow\n");3603 3604 mvm->fast_resume = true;3605 set_bit(IWL_MVM_STATUS_IN_D3, &mvm->status);3606 3607 WARN_ON(iwl_mvm_power_update_device(mvm));3608 mvm->trans->system_pm_mode = IWL_PLAT_PM_MODE_D3;3609 ret = iwl_mvm_send_cmd_pdu(mvm, D3_CONFIG_CMD, CMD_SEND_IN_D3,3610 sizeof(d3_cfg_cmd_data), &d3_cfg_cmd_data);3611 if (ret)3612 IWL_ERR(mvm,3613 "fast suspend: couldn't send D3_CONFIG_CMD %d\n", ret);3614 3615 WARN_ON(iwl_mvm_power_update_mac(mvm));3616 3617 ret = iwl_trans_d3_suspend(mvm->trans, false, false);3618 if (ret)3619 IWL_ERR(mvm, "fast suspend: trans_d3_suspend failed %d\n", ret);3620}3621 3622int iwl_mvm_fast_resume(struct iwl_mvm *mvm)3623{3624 struct iwl_d3_data d3_data = {3625 .notif_expected =3626 IWL_D3_NOTIF_D3_END_NOTIF,3627 };3628 int ret;3629 3630 lockdep_assert_held(&mvm->mutex);3631 3632 IWL_DEBUG_WOWLAN(mvm, "Starting the fast resume flow\n");3633 3634 mvm->last_reset_or_resume_time_jiffies = jiffies;3635 iwl_fw_dbg_read_d3_debug_data(&mvm->fwrt);3636 3637 if (iwl_mvm_check_rt_status(mvm, NULL)) {3638 set_bit(STATUS_FW_ERROR, &mvm->trans->status);3639 iwl_mvm_dump_nic_error_log(mvm);3640 iwl_dbg_tlv_time_point(&mvm->fwrt,3641 IWL_FW_INI_TIME_POINT_FW_ASSERT, NULL);3642 iwl_fw_dbg_collect_desc(&mvm->fwrt, &iwl_dump_desc_assert,3643 false, 0);3644 return -ENODEV;3645 }3646 ret = iwl_mvm_d3_notif_wait(mvm, &d3_data);3647 clear_bit(IWL_MVM_STATUS_IN_D3, &mvm->status);3648 mvm->trans->system_pm_mode = IWL_PLAT_PM_MODE_DISABLED;3649 mvm->fast_resume = false;3650 3651 if (ret)3652 IWL_ERR(mvm, "Couldn't get the d3 notif %d\n", ret);3653 3654 return ret;3655}3656 3657#ifdef CONFIG_IWLWIFI_DEBUGFS3658static int iwl_mvm_d3_test_open(struct inode *inode, struct file *file)3659{3660 struct iwl_mvm *mvm = inode->i_private;3661 int err;3662 3663 if (mvm->d3_test_active)3664 return -EBUSY;3665 3666 file->private_data = inode->i_private;3667 3668 iwl_mvm_pause_tcm(mvm, true);3669 3670 iwl_fw_runtime_suspend(&mvm->fwrt);3671 3672 /* start pseudo D3 */3673 rtnl_lock();3674 wiphy_lock(mvm->hw->wiphy);3675 err = __iwl_mvm_suspend(mvm->hw, mvm->hw->wiphy->wowlan_config, true);3676 wiphy_unlock(mvm->hw->wiphy);3677 rtnl_unlock();3678 if (err > 0)3679 err = -EINVAL;3680 if (err)3681 return err;3682 3683 mvm->d3_test_active = true;3684 mvm->keep_vif = NULL;3685 return 0;3686}3687 3688static ssize_t iwl_mvm_d3_test_read(struct file *file, char __user *user_buf,3689 size_t count, loff_t *ppos)3690{3691 struct iwl_mvm *mvm = file->private_data;3692 unsigned long end = jiffies + 60 * HZ;3693 u32 pme_asserted;3694 3695 while (true) {3696 /* read pme_ptr if available */3697 if (mvm->d3_test_pme_ptr) {3698 pme_asserted = iwl_trans_read_mem32(mvm->trans,3699 mvm->d3_test_pme_ptr);3700 if (pme_asserted)3701 break;3702 }3703 3704 if (msleep_interruptible(100))3705 break;3706 3707 if (time_is_before_jiffies(end)) {3708 IWL_ERR(mvm,3709 "ending pseudo-D3 with timeout after ~60 seconds\n");3710 return -ETIMEDOUT;3711 }3712 }3713 3714 return 0;3715}3716 3717static void iwl_mvm_d3_test_disconn_work_iter(void *_data, u8 *mac,3718 struct ieee80211_vif *vif)3719{3720 /* skip the one we keep connection on */3721 if (_data == vif)3722 return;3723 3724 if (vif->type == NL80211_IFTYPE_STATION)3725 ieee80211_connection_loss(vif);3726}3727 3728static int iwl_mvm_d3_test_release(struct inode *inode, struct file *file)3729{3730 struct iwl_mvm *mvm = inode->i_private;3731 bool unified_image = fw_has_capa(&mvm->fw->ucode_capa,3732 IWL_UCODE_TLV_CAPA_CNSLDTD_D3_D0_IMG);3733 3734 mvm->d3_test_active = false;3735 3736 iwl_fw_dbg_read_d3_debug_data(&mvm->fwrt);3737 3738 rtnl_lock();3739 wiphy_lock(mvm->hw->wiphy);3740 __iwl_mvm_resume(mvm, true);3741 wiphy_unlock(mvm->hw->wiphy);3742 rtnl_unlock();3743 3744 iwl_mvm_resume_tcm(mvm);3745 3746 iwl_fw_runtime_resume(&mvm->fwrt);3747 3748 iwl_abort_notification_waits(&mvm->notif_wait);3749 if (!unified_image) {3750 int remaining_time = 10;3751 3752 ieee80211_restart_hw(mvm->hw);3753 3754 /* wait for restart and disconnect all interfaces */3755 while (test_bit(IWL_MVM_STATUS_IN_HW_RESTART, &mvm->status) &&3756 remaining_time > 0) {3757 remaining_time--;3758 msleep(1000);3759 }3760 3761 if (remaining_time == 0)3762 IWL_ERR(mvm, "Timed out waiting for HW restart!\n");3763 }3764 3765 ieee80211_iterate_active_interfaces_atomic(3766 mvm->hw, IEEE80211_IFACE_ITER_NORMAL,3767 iwl_mvm_d3_test_disconn_work_iter, mvm->keep_vif);3768 3769 return 0;3770}3771 3772const struct file_operations iwl_dbgfs_d3_test_ops = {3773 .open = iwl_mvm_d3_test_open,3774 .read = iwl_mvm_d3_test_read,3775 .release = iwl_mvm_d3_test_release,3776};3777#endif3778