Skip to content

Commit

Permalink
iwlwifi: integrate with iwlmei
Browse files Browse the repository at this point in the history
iwlmei needs to know about the follwing events:

* Association
* De-association
* Country Code change
* SW Rfkill change
* SAR table changes

iwlmei can take the device away from us, so report the new
rfkill type when this happens.
Advertise the required data from the CSME firmware to the
usersapce: mostly, the AP that the CSME firmware is currently
associated to in case there is an active link protection
session.
Generate the HOST_ASSOC / HOST_DISSASSOC messages.

Don't support WPA1 (non-RSNA) for now.
Don't support shared wep either.
We can then determine the AUTH parameter by checking the AKM.
Feed the cipher from the key installation.

SW Rfkill will be implemented later when cfg80211 will
allow us to read the SW Rfkill state.

Co-Developed-by: Ayala Beker <ayala.beker@intel.com>
Signed-off-by: Emmanuel Grumbach <emmanuel.grumbach@intel.com>
Signed-off-by: Luca Coelho <luciano.coelho@intel.com>
Signed-off-by: Emmanuel Grumbach <emmanuel.grumbach@intel.com>
  • Loading branch information
egrumbach authored and intel-lab-lkp committed Jun 21, 2021
1 parent d960977 commit 6d71c3e
Show file tree
Hide file tree
Showing 11 changed files with 499 additions and 22 deletions.
61 changes: 61 additions & 0 deletions drivers/net/wireless/intel/iwlwifi/iwl-nvm-parse.c
Expand Up @@ -22,6 +22,7 @@
#include "fw/api/commands.h"
#include "fw/api/cmdhdr.h"
#include "fw/img.h"
#include "mei/iwl-mei.h"

/* NVM offsets (in words) definitions */
enum nvm_offsets {
Expand Down Expand Up @@ -1060,6 +1061,66 @@ iwl_nvm_no_wide_in_5ghz(struct iwl_trans *trans, const struct iwl_cfg *cfg,
return false;
}

struct iwl_nvm_data *
iwl_parse_mei_nvm_data(struct iwl_trans *trans, const struct iwl_cfg *cfg,
const struct iwl_mei_nvm *mei_nvm,
const struct iwl_fw *fw)
{
struct iwl_nvm_data *data;
u32 sbands_flags = 0;
u8 rx_chains = fw->valid_rx_ant;
u8 tx_chains = fw->valid_rx_ant;

if (cfg->uhb_supported)
data = kzalloc(struct_size(data, channels,
IWL_NVM_NUM_CHANNELS_UHB),
GFP_KERNEL);
else
data = kzalloc(struct_size(data, channels,
IWL_NVM_NUM_CHANNELS_EXT),
GFP_KERNEL);
if (!data)
return NULL;

BUILD_BUG_ON(ARRAY_SIZE(mei_nvm->channels) !=
IWL_NVM_NUM_CHANNELS_UHB);
data->nvm_version = mei_nvm->nvm_version;

iwl_set_radio_cfg(cfg, data, mei_nvm->radio_cfg);
if (data->valid_tx_ant)
tx_chains &= data->valid_tx_ant;
if (data->valid_rx_ant)
rx_chains &= data->valid_rx_ant;

data->sku_cap_mimo_disabled = false;
data->sku_cap_band_24ghz_enable = true;
data->sku_cap_band_52ghz_enable = true;
data->sku_cap_11n_enable =
!(iwlwifi_mod_params.disable_11n & IWL_DISABLE_HT_ALL);
data->sku_cap_11ac_enable = true;
data->sku_cap_11ax_enable =
mei_nvm->caps & MEI_NVM_CAPS_11AX_SUPPORT;

data->lar_enabled = mei_nvm->caps & MEI_NVM_CAPS_LARI_SUPPORT;

data->n_hw_addrs = mei_nvm->n_hw_addrs;
/* If no valid mac address was found - bail out */
if (iwl_set_hw_address(trans, cfg, data, NULL, NULL)) {
kfree(data);
return NULL;
}

if (data->lar_enabled &&
fw_has_capa(&fw->ucode_capa, IWL_UCODE_TLV_CAPA_LAR_SUPPORT))
sbands_flags |= IWL_NVM_SBANDS_FLAGS_LAR;

iwl_init_sbands(trans, data, mei_nvm->channels, tx_chains, rx_chains,
sbands_flags, true, fw);

return data;
}
IWL_EXPORT_SYMBOL(iwl_parse_mei_nvm_data);

struct iwl_nvm_data *
iwl_parse_nvm_data(struct iwl_trans *trans, const struct iwl_cfg *cfg,
const struct iwl_fw *fw,
Expand Down
11 changes: 10 additions & 1 deletion drivers/net/wireless/intel/iwlwifi/iwl-nvm-parse.h
@@ -1,13 +1,14 @@
/* SPDX-License-Identifier: GPL-2.0 OR BSD-3-Clause */
/*
* Copyright (C) 2005-2015, 2018-2020 Intel Corporation
* Copyright (C) 2005-2015, 2018-2021 Intel Corporation
* Copyright (C) 2016-2017 Intel Deutschland GmbH
*/
#ifndef __iwl_nvm_parse_h__
#define __iwl_nvm_parse_h__

#include <net/cfg80211.h>
#include "iwl-eeprom-parse.h"
#include "mei/iwl-mei.h"

/**
* enum iwl_nvm_sbands_flags - modification flags for the channel profiles
Expand Down Expand Up @@ -81,4 +82,12 @@ void iwl_nvm_fixups(u32 hw_id, unsigned int section, u8 *data,
struct iwl_nvm_data *iwl_get_nvm(struct iwl_trans *trans,
const struct iwl_fw *fw);

/**
* iwl_parse_mei_nvm_data - parse the mei_nvm_data and get an iwl_nvm_data
*/
struct iwl_nvm_data *
iwl_parse_mei_nvm_data(struct iwl_trans *trans, const struct iwl_cfg *cfg,
const struct iwl_mei_nvm *mei_nvm,
const struct iwl_fw *fw);

#endif /* __iwl_nvm_parse_h__ */
2 changes: 2 additions & 0 deletions drivers/net/wireless/intel/iwlwifi/iwl-trans.h
Expand Up @@ -902,6 +902,7 @@ struct iwl_trans_txqs {
/**
* struct iwl_trans - transport common data
*
* @csme_own - true if we couldn't get ownership on the device
* @ops - pointer to iwl_trans_ops
* @op_mode - pointer to the op_mode
* @trans_cfg: the trans-specific configuration part
Expand Down Expand Up @@ -936,6 +937,7 @@ struct iwl_trans_txqs {
* @iwl_trans_txqs: transport tx queues data.
*/
struct iwl_trans {
bool csme_own;
const struct iwl_trans_ops *ops;
struct iwl_op_mode *op_mode;
const struct iwl_cfg_trans_params *trans_cfg;
Expand Down
3 changes: 2 additions & 1 deletion drivers/net/wireless/intel/iwlwifi/mvm/fw.c
Expand Up @@ -750,6 +750,8 @@ int iwl_mvm_sar_select_profile(struct iwl_mvm *mvm, int prof_a, int prof_b)
if (ret)
return ret;

iwl_mei_set_power_limit(per_chain);

IWL_DEBUG_RADIO(mvm, "Sending REDUCE_TX_POWER_CMD per chain\n");
return iwl_mvm_send_cmd_pdu(mvm, REDUCE_TX_POWER_CMD, 0, len, &cmd);
}
Expand Down Expand Up @@ -1297,7 +1299,6 @@ static int iwl_mvm_load_rt_fw(struct iwl_mvm *mvm)
if (iwl_mvm_has_unified_ucode(mvm))
return iwl_run_unified_mvm_ucode(mvm);

WARN_ON(!mvm->nvm_data);
ret = iwl_run_init_mvm_ucode(mvm);

if (ret) {
Expand Down
114 changes: 110 additions & 4 deletions drivers/net/wireless/intel/iwlwifi/mvm/mac80211.c
@@ -1,6 +1,6 @@
// SPDX-License-Identifier: GPL-2.0 OR BSD-3-Clause
/*
* Copyright (C) 2012-2014, 2018-2020 Intel Corporation
* Copyright (C) 2012-2014, 2018-2021 Intel Corporation
* Copyright (C) 2013-2015 Intel Mobile Communications GmbH
* Copyright (C) 2016-2017 Intel Deutschland GmbH
*/
Expand Down Expand Up @@ -189,6 +189,7 @@ struct ieee80211_regdomain *iwl_mvm_get_regdomain(struct wiphy *wiphy,
if (IS_ERR_OR_NULL(resp)) {
IWL_DEBUG_LAR(mvm, "Could not get update from FW %d\n",
PTR_ERR_OR_ZERO(resp));
resp = NULL;
goto out;
}

Expand All @@ -210,7 +211,6 @@ struct ieee80211_regdomain *iwl_mvm_get_regdomain(struct wiphy *wiphy,
__le16_to_cpu(resp->cap), resp_ver);
/* Store the return source id */
src_id = resp->source_id;
kfree(resp);
if (IS_ERR_OR_NULL(regd)) {
IWL_DEBUG_LAR(mvm, "Could not get parse update from FW %d\n",
PTR_ERR_OR_ZERO(regd));
Expand All @@ -222,7 +222,10 @@ struct ieee80211_regdomain *iwl_mvm_get_regdomain(struct wiphy *wiphy,
mvm->lar_regdom_set = true;
mvm->mcc_src = src_id;

iwl_mei_set_country_code(__le16_to_cpu(resp->mcc));

out:
kfree(resp);
return regd;
}

Expand Down Expand Up @@ -1082,6 +1085,27 @@ int __iwl_mvm_mac_start(struct iwl_mvm *mvm)

lockdep_assert_held(&mvm->mutex);

ret = iwl_mvm_mei_get_ownership(mvm);
if (ret)
return ret;

if (mvm->mei_nvm_data) {
/* We got the NIC, we can now free the MEI NVM data */
kfree(mvm->mei_nvm_data);
mvm->mei_nvm_data = NULL;

/*
* We can't free the nvm_data we allocated based on the SAP
* data because we registered to cfg80211 with the channels
* allocated on mvm->nvm_data. Keep a pointer in temp_nvm_data
* just in order to be able free it later.
* NULLify nvm_data so that we will read the NVM from the
* firmware this time.
*/
mvm->temp_nvm_data = mvm->nvm_data;
mvm->nvm_data = NULL;
}

if (test_bit(IWL_MVM_STATUS_HW_RESTART_REQUESTED, &mvm->status)) {
/*
* Now convert the HW_RESTART_REQUESTED flag to IN_HW_RESTART
Expand Down Expand Up @@ -1508,6 +1532,15 @@ static int iwl_mvm_mac_add_interface(struct ieee80211_hw *hw,
mvm->monitor_on = true;

iwl_mvm_vif_dbgfs_register(mvm, vif);

if (!test_bit(IWL_MVM_STATUS_IN_HW_RESTART, &mvm->status) &&
vif->type == NL80211_IFTYPE_STATION && !vif->p2p &&
!mvm->csme_vif && mvm->mei_registered) {
iwl_mei_set_nic_info(vif->addr, mvm->nvm_data->hw_addr);
iwl_mei_set_netdev(ieee80211_vif_to_wdev(vif)->netdev);
mvm->csme_vif = vif;
}

goto out_unlock;

out_unbind:
Expand Down Expand Up @@ -1560,6 +1593,11 @@ static void iwl_mvm_mac_remove_interface(struct ieee80211_hw *hw,

mutex_lock(&mvm->mutex);

if (vif == mvm->csme_vif) {
iwl_mei_set_netdev(NULL);
mvm->csme_vif = NULL;
}

probe_data = rcu_dereference_protected(mvmvif->probe_resp_data,
lockdep_is_held(&mvm->mutex));
RCU_INIT_POINTER(mvmvif->probe_resp_data, NULL);
Expand Down Expand Up @@ -2327,6 +2365,7 @@ static void iwl_mvm_bss_info_changed_station(struct iwl_mvm *mvm,
IEEE80211_SMPS_DYNAMIC);
}
} else if (mvmvif->ap_sta_id != IWL_MVM_INVALID_STA) {
iwl_mvm_mei_host_disassociated(mvm);
/*
* If update fails - SF might be running in associated
* mode while disassociated - which is forbidden.
Expand Down Expand Up @@ -3056,6 +3095,69 @@ static void iwl_mvm_reset_cca_40mhz_workaround(struct iwl_mvm *mvm,
}
}

static void iwl_mvm_mei_host_associated(struct iwl_mvm *mvm,
struct ieee80211_vif *vif,
struct iwl_mvm_sta *mvm_sta)
{
#if IS_ENABLED(CONFIG_IWLMEI)
struct iwl_mvm_vif *mvmvif = iwl_mvm_vif_from_mac80211(vif);
struct iwl_mei_conn_info conn_info = {
.ssid_len = vif->bss_conf.ssid_len,
.channel = vif->bss_conf.chandef.chan->hw_value,
};

if (test_bit(IWL_MVM_STATUS_IN_HW_RESTART, &mvm->status))
return;

if (!mvm->mei_registered)
return;

switch (mvm_sta->pairwise_cipher) {
case WLAN_CIPHER_SUITE_CCMP:
conn_info.pairwise_cipher = IWL_MEI_CIPHER_CCMP;
break;
case WLAN_CIPHER_SUITE_GCMP:
conn_info.pairwise_cipher = IWL_MEI_CIPHER_GCMP;
break;
case WLAN_CIPHER_SUITE_GCMP_256:
conn_info.pairwise_cipher = IWL_MEI_CIPHER_GCMP_256;
break;
case 0:
/* open profile */
break;
default:
/* cipher not supported, don't send anything to iwlmei */
return;
};

switch (mvmvif->rekey_data.akm) {
case WLAN_AKM_SUITE_SAE & 0xff:
conn_info.auth_mode = IWL_MEI_AKM_AUTH_SAE;
break;
case WLAN_AKM_SUITE_PSK & 0xff:
conn_info.auth_mode = IWL_MEI_AKM_AUTH_RSNA_PSK;
break;
case WLAN_AKM_SUITE_8021X & 0xff:
conn_info.auth_mode = IWL_MEI_AKM_AUTH_RSNA;
break;
case 0:
/* open profile */
conn_info.auth_mode = IWL_MEI_AKM_AUTH_OPEN;
break;
default:
/* auth method / AKM not supported */
/* TODO: All the FT vesions of these? */
return;
}

memcpy(conn_info.ssid, vif->bss_conf.ssid, vif->bss_conf.ssid_len);
memcpy(conn_info.bssid, vif->bss_conf.bssid, ETH_ALEN);

/* TODO: add support for collocated AP data */
iwl_mei_host_associated(&conn_info, NULL);
#endif
}

static int iwl_mvm_mac_sta_state(struct ieee80211_hw *hw,
struct ieee80211_vif *vif,
struct ieee80211_sta *sta,
Expand Down Expand Up @@ -3217,6 +3319,7 @@ static int iwl_mvm_mac_sta_state(struct ieee80211_hw *hw,
if (vif->type == NL80211_IFTYPE_AP) {
mvmvif->ap_assoc_sta_count--;
iwl_mvm_mac_ctxt_changed(mvm, vif, false, NULL);
iwl_mvm_mei_host_associated(mvm, vif, mvm_sta);
}
ret = 0;
} else if (old_state == IEEE80211_STA_AUTH &&
Expand Down Expand Up @@ -3400,6 +3503,8 @@ static int __iwl_mvm_mac_set_key(struct ieee80211_hw *hw,
int ret, i;
u8 key_offset;

mvmsta = iwl_mvm_sta_from_mac80211(sta);

switch (key->cipher) {
case WLAN_CIPHER_SUITE_TKIP:
if (!mvm->trans->trans_cfg->gen2) {
Expand Down Expand Up @@ -3508,7 +3613,6 @@ static int __iwl_mvm_mac_set_key(struct ieee80211_hw *hw,
struct ieee80211_key_seq seq;
int tid, q;

mvmsta = iwl_mvm_sta_from_mac80211(sta);
WARN_ON(rcu_access_pointer(mvmsta->ptk_pn[keyidx]));
ptk_pn = kzalloc(struct_size(ptk_pn, q,
mvm->trans->num_rx_queues),
Expand All @@ -3535,6 +3639,9 @@ static int __iwl_mvm_mac_set_key(struct ieee80211_hw *hw,
else
key_offset = STA_KEY_IDX_INVALID;

if (key->flags & IEEE80211_KEY_FLAG_PAIRWISE)
mvmsta->pairwise_cipher = key->cipher;

IWL_DEBUG_MAC80211(mvm, "set hwcrypto key\n");
ret = iwl_mvm_set_sta_key(mvm, vif, sta, key, key_offset);
if (ret) {
Expand Down Expand Up @@ -3580,7 +3687,6 @@ static int __iwl_mvm_mac_set_key(struct ieee80211_hw *hw,
(key->cipher == WLAN_CIPHER_SUITE_CCMP ||
key->cipher == WLAN_CIPHER_SUITE_GCMP ||
key->cipher == WLAN_CIPHER_SUITE_GCMP_256)) {
mvmsta = iwl_mvm_sta_from_mac80211(sta);
ptk_pn = rcu_dereference_protected(
mvmsta->ptk_pn[keyidx],
lockdep_is_held(&mvm->mutex));
Expand Down

0 comments on commit 6d71c3e

Please sign in to comment.