2022-11-02 16:59:53 +02:00
|
|
|
// SPDX-License-Identifier: GPL-2.0 OR BSD-3-Clause
|
|
|
|
/*
|
|
|
|
* Copyright (C) 2022 Intel Corporation
|
|
|
|
*/
|
|
|
|
#include <linux/kernel.h>
|
|
|
|
#include <net/mac80211.h>
|
|
|
|
#include "mvm.h"
|
|
|
|
#include "fw/api/context.h"
|
|
|
|
#include "fw/api/datapath.h"
|
|
|
|
|
|
|
|
static u32 iwl_mvm_get_sec_sta_mask(struct iwl_mvm *mvm,
|
|
|
|
struct ieee80211_vif *vif,
|
|
|
|
struct ieee80211_sta *sta,
|
|
|
|
struct ieee80211_key_conf *keyconf)
|
|
|
|
{
|
|
|
|
struct iwl_mvm_vif *mvmvif = iwl_mvm_vif_from_mac80211(vif);
|
|
|
|
|
|
|
|
if (vif->type == NL80211_IFTYPE_AP &&
|
|
|
|
!(keyconf->flags & IEEE80211_KEY_FLAG_PAIRWISE))
|
wifi: iwlwifi: mvm: vif preparation for MLO
In MLO, some fields of iwl_mvm_vif should be defined in the
context of a link. Define a separate structure for these fields and
add a deflink object to hold it as part of iwl_mvm_vif. Non-MLO legacy
code will use only deflink object while MLO related code will use the
corresponding link from the link array.
It follows the strategy applied in mac80211 for introducing MLO
changes.
The below spatch takes care of updating all driver code to access
fields separated into MLD specific data structure via deflink (need
to convert all references to the fields listed in var to deflink.var
and also to take care of calls like iwl_mvm_vif_from_mac80211(vif)->field).
@iwl_mld_vif@
struct iwl_mvm_vif *v;
struct ieee80211_vif *vv;
identifier fn;
identifier var = {bssid, ap_sta_id, bcast_sta, mcast_sta,
beacon_stats, smps_requests, probe_resp_data,
he_ru_2mhz_block, cab_queue, phy_ctxt,
queue_params};
@@
(
v->
- var
+ deflink.var
|
fn(vv)->
- var
+ deflink.var
)
Signed-off-by: Gregory Greenman <gregory.greenman@intel.com>
Link: https://lore.kernel.org/r/20230328104948.4896576f0a9f.Ifaf0187c96b9fe52b24bd629331165831a877691@changeid
Signed-off-by: Johannes Berg <johannes.berg@intel.com>
2023-03-28 10:58:41 +03:00
|
|
|
return BIT(mvmvif->deflink.mcast_sta.sta_id);
|
2022-11-02 16:59:53 +02:00
|
|
|
|
|
|
|
if (sta) {
|
|
|
|
struct iwl_mvm_sta *mvmsta = iwl_mvm_sta_from_mac80211(sta);
|
|
|
|
|
2023-03-28 10:58:42 +03:00
|
|
|
return BIT(mvmsta->deflink.sta_id);
|
2022-11-02 16:59:53 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
if (vif->type == NL80211_IFTYPE_STATION &&
|
wifi: iwlwifi: mvm: vif preparation for MLO
In MLO, some fields of iwl_mvm_vif should be defined in the
context of a link. Define a separate structure for these fields and
add a deflink object to hold it as part of iwl_mvm_vif. Non-MLO legacy
code will use only deflink object while MLO related code will use the
corresponding link from the link array.
It follows the strategy applied in mac80211 for introducing MLO
changes.
The below spatch takes care of updating all driver code to access
fields separated into MLD specific data structure via deflink (need
to convert all references to the fields listed in var to deflink.var
and also to take care of calls like iwl_mvm_vif_from_mac80211(vif)->field).
@iwl_mld_vif@
struct iwl_mvm_vif *v;
struct ieee80211_vif *vv;
identifier fn;
identifier var = {bssid, ap_sta_id, bcast_sta, mcast_sta,
beacon_stats, smps_requests, probe_resp_data,
he_ru_2mhz_block, cab_queue, phy_ctxt,
queue_params};
@@
(
v->
- var
+ deflink.var
|
fn(vv)->
- var
+ deflink.var
)
Signed-off-by: Gregory Greenman <gregory.greenman@intel.com>
Link: https://lore.kernel.org/r/20230328104948.4896576f0a9f.Ifaf0187c96b9fe52b24bd629331165831a877691@changeid
Signed-off-by: Johannes Berg <johannes.berg@intel.com>
2023-03-28 10:58:41 +03:00
|
|
|
mvmvif->deflink.ap_sta_id != IWL_MVM_INVALID_STA)
|
|
|
|
return BIT(mvmvif->deflink.ap_sta_id);
|
2022-11-02 16:59:53 +02:00
|
|
|
|
|
|
|
/* invalid */
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
static u32 iwl_mvm_get_sec_flags(struct iwl_mvm *mvm,
|
|
|
|
struct ieee80211_vif *vif,
|
|
|
|
struct ieee80211_sta *sta,
|
|
|
|
struct ieee80211_key_conf *keyconf)
|
|
|
|
{
|
|
|
|
struct iwl_mvm_vif *mvmvif = iwl_mvm_vif_from_mac80211(vif);
|
|
|
|
u32 flags = 0;
|
|
|
|
|
|
|
|
if (!(keyconf->flags & IEEE80211_KEY_FLAG_PAIRWISE))
|
|
|
|
flags |= IWL_SEC_KEY_FLAG_MCAST_KEY;
|
|
|
|
|
|
|
|
switch (keyconf->cipher) {
|
|
|
|
case WLAN_CIPHER_SUITE_WEP104:
|
|
|
|
flags |= IWL_SEC_KEY_FLAG_KEY_SIZE;
|
|
|
|
fallthrough;
|
|
|
|
case WLAN_CIPHER_SUITE_WEP40:
|
|
|
|
flags |= IWL_SEC_KEY_FLAG_CIPHER_WEP;
|
|
|
|
break;
|
|
|
|
case WLAN_CIPHER_SUITE_TKIP:
|
|
|
|
flags |= IWL_SEC_KEY_FLAG_CIPHER_TKIP;
|
|
|
|
break;
|
|
|
|
case WLAN_CIPHER_SUITE_AES_CMAC:
|
|
|
|
case WLAN_CIPHER_SUITE_CCMP:
|
|
|
|
flags |= IWL_SEC_KEY_FLAG_CIPHER_CCMP;
|
|
|
|
break;
|
|
|
|
case WLAN_CIPHER_SUITE_GCMP_256:
|
|
|
|
case WLAN_CIPHER_SUITE_BIP_GMAC_256:
|
|
|
|
flags |= IWL_SEC_KEY_FLAG_KEY_SIZE;
|
|
|
|
fallthrough;
|
|
|
|
case WLAN_CIPHER_SUITE_GCMP:
|
|
|
|
case WLAN_CIPHER_SUITE_BIP_GMAC_128:
|
|
|
|
flags |= IWL_SEC_KEY_FLAG_CIPHER_GCMP;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
|
|
|
rcu_read_lock();
|
|
|
|
if (!sta && vif->type == NL80211_IFTYPE_STATION &&
|
wifi: iwlwifi: mvm: vif preparation for MLO
In MLO, some fields of iwl_mvm_vif should be defined in the
context of a link. Define a separate structure for these fields and
add a deflink object to hold it as part of iwl_mvm_vif. Non-MLO legacy
code will use only deflink object while MLO related code will use the
corresponding link from the link array.
It follows the strategy applied in mac80211 for introducing MLO
changes.
The below spatch takes care of updating all driver code to access
fields separated into MLD specific data structure via deflink (need
to convert all references to the fields listed in var to deflink.var
and also to take care of calls like iwl_mvm_vif_from_mac80211(vif)->field).
@iwl_mld_vif@
struct iwl_mvm_vif *v;
struct ieee80211_vif *vv;
identifier fn;
identifier var = {bssid, ap_sta_id, bcast_sta, mcast_sta,
beacon_stats, smps_requests, probe_resp_data,
he_ru_2mhz_block, cab_queue, phy_ctxt,
queue_params};
@@
(
v->
- var
+ deflink.var
|
fn(vv)->
- var
+ deflink.var
)
Signed-off-by: Gregory Greenman <gregory.greenman@intel.com>
Link: https://lore.kernel.org/r/20230328104948.4896576f0a9f.Ifaf0187c96b9fe52b24bd629331165831a877691@changeid
Signed-off-by: Johannes Berg <johannes.berg@intel.com>
2023-03-28 10:58:41 +03:00
|
|
|
mvmvif->deflink.ap_sta_id != IWL_MVM_INVALID_STA) {
|
|
|
|
u8 sta_id = mvmvif->deflink.ap_sta_id;
|
2022-11-02 16:59:53 +02:00
|
|
|
|
|
|
|
sta = rcu_dereference_check(mvm->fw_id_to_mac_id[sta_id],
|
|
|
|
lockdep_is_held(&mvm->mutex));
|
|
|
|
}
|
|
|
|
|
|
|
|
if (!IS_ERR_OR_NULL(sta) && sta->mfp)
|
|
|
|
flags |= IWL_SEC_KEY_FLAG_MFP;
|
|
|
|
rcu_read_unlock();
|
|
|
|
|
|
|
|
return flags;
|
|
|
|
}
|
|
|
|
|
|
|
|
static int __iwl_mvm_sec_key_del(struct iwl_mvm *mvm, u32 sta_mask,
|
|
|
|
u32 key_flags, u32 keyidx, u32 flags)
|
|
|
|
{
|
|
|
|
u32 cmd_id = WIDE_ID(DATA_PATH_GROUP, SEC_KEY_CMD);
|
|
|
|
struct iwl_sec_key_cmd cmd = {
|
|
|
|
.action = cpu_to_le32(FW_CTXT_ACTION_REMOVE),
|
|
|
|
.u.remove.sta_mask = cpu_to_le32(sta_mask),
|
|
|
|
.u.remove.key_id = cpu_to_le32(keyidx),
|
|
|
|
.u.remove.key_flags = cpu_to_le32(key_flags),
|
|
|
|
};
|
|
|
|
|
|
|
|
return iwl_mvm_send_cmd_pdu(mvm, cmd_id, flags, sizeof(cmd), &cmd);
|
|
|
|
}
|
|
|
|
|
|
|
|
int iwl_mvm_sec_key_add(struct iwl_mvm *mvm,
|
|
|
|
struct ieee80211_vif *vif,
|
|
|
|
struct ieee80211_sta *sta,
|
|
|
|
struct ieee80211_key_conf *keyconf)
|
|
|
|
{
|
|
|
|
u32 sta_mask = iwl_mvm_get_sec_sta_mask(mvm, vif, sta, keyconf);
|
|
|
|
u32 key_flags = iwl_mvm_get_sec_flags(mvm, vif, sta, keyconf);
|
|
|
|
u32 cmd_id = WIDE_ID(DATA_PATH_GROUP, SEC_KEY_CMD);
|
|
|
|
struct iwl_sec_key_cmd cmd = {
|
|
|
|
.action = cpu_to_le32(FW_CTXT_ACTION_ADD),
|
|
|
|
.u.add.sta_mask = cpu_to_le32(sta_mask),
|
|
|
|
.u.add.key_id = cpu_to_le32(keyconf->keyidx),
|
|
|
|
.u.add.key_flags = cpu_to_le32(key_flags),
|
|
|
|
.u.add.tx_seq = cpu_to_le64(atomic64_read(&keyconf->tx_pn)),
|
|
|
|
};
|
|
|
|
int ret;
|
|
|
|
|
|
|
|
if (WARN_ON(keyconf->keylen > sizeof(cmd.u.add.key)))
|
|
|
|
return -EINVAL;
|
|
|
|
|
|
|
|
if (keyconf->cipher == WLAN_CIPHER_SUITE_WEP40 ||
|
|
|
|
keyconf->cipher == WLAN_CIPHER_SUITE_WEP104)
|
|
|
|
memcpy(cmd.u.add.key + IWL_SEC_WEP_KEY_OFFSET, keyconf->key,
|
|
|
|
keyconf->keylen);
|
|
|
|
else
|
|
|
|
memcpy(cmd.u.add.key, keyconf->key, keyconf->keylen);
|
|
|
|
|
|
|
|
if (keyconf->cipher == WLAN_CIPHER_SUITE_TKIP) {
|
|
|
|
memcpy(cmd.u.add.tkip_mic_rx_key,
|
|
|
|
keyconf->key + NL80211_TKIP_DATA_OFFSET_RX_MIC_KEY,
|
|
|
|
8);
|
|
|
|
memcpy(cmd.u.add.tkip_mic_tx_key,
|
|
|
|
keyconf->key + NL80211_TKIP_DATA_OFFSET_TX_MIC_KEY,
|
|
|
|
8);
|
|
|
|
}
|
|
|
|
|
|
|
|
ret = iwl_mvm_send_cmd_pdu(mvm, cmd_id, 0, sizeof(cmd), &cmd);
|
|
|
|
if (ret)
|
|
|
|
return ret;
|
|
|
|
|
|
|
|
/*
|
|
|
|
* For WEP, the same key is used for multicast and unicast so need to
|
|
|
|
* upload it again. If this fails, remove the original as well.
|
|
|
|
*/
|
|
|
|
if (keyconf->cipher == WLAN_CIPHER_SUITE_WEP40 ||
|
|
|
|
keyconf->cipher == WLAN_CIPHER_SUITE_WEP104) {
|
|
|
|
cmd.u.add.key_flags ^= cpu_to_le32(IWL_SEC_KEY_FLAG_MCAST_KEY);
|
|
|
|
ret = iwl_mvm_send_cmd_pdu(mvm, cmd_id, 0, sizeof(cmd), &cmd);
|
|
|
|
if (ret)
|
|
|
|
__iwl_mvm_sec_key_del(mvm, sta_mask, key_flags,
|
|
|
|
keyconf->keyidx, 0);
|
|
|
|
}
|
|
|
|
|
|
|
|
return ret;
|
|
|
|
}
|
|
|
|
|
|
|
|
static int _iwl_mvm_sec_key_del(struct iwl_mvm *mvm,
|
|
|
|
struct ieee80211_vif *vif,
|
|
|
|
struct ieee80211_sta *sta,
|
|
|
|
struct ieee80211_key_conf *keyconf,
|
|
|
|
u32 flags)
|
|
|
|
{
|
|
|
|
u32 sta_mask = iwl_mvm_get_sec_sta_mask(mvm, vif, sta, keyconf);
|
|
|
|
u32 key_flags = iwl_mvm_get_sec_flags(mvm, vif, sta, keyconf);
|
|
|
|
int ret;
|
|
|
|
|
|
|
|
ret = __iwl_mvm_sec_key_del(mvm, sta_mask, key_flags, keyconf->keyidx,
|
|
|
|
flags);
|
|
|
|
if (ret)
|
|
|
|
return ret;
|
|
|
|
|
|
|
|
/* For WEP, delete the key again as unicast */
|
|
|
|
if (keyconf->cipher == WLAN_CIPHER_SUITE_WEP40 ||
|
|
|
|
keyconf->cipher == WLAN_CIPHER_SUITE_WEP104) {
|
|
|
|
key_flags ^= IWL_SEC_KEY_FLAG_MCAST_KEY;
|
|
|
|
ret = __iwl_mvm_sec_key_del(mvm, sta_mask, key_flags,
|
|
|
|
keyconf->keyidx, flags);
|
|
|
|
}
|
|
|
|
|
|
|
|
return ret;
|
|
|
|
}
|
|
|
|
|
|
|
|
int iwl_mvm_sec_key_del(struct iwl_mvm *mvm,
|
|
|
|
struct ieee80211_vif *vif,
|
|
|
|
struct ieee80211_sta *sta,
|
|
|
|
struct ieee80211_key_conf *keyconf)
|
|
|
|
{
|
|
|
|
return _iwl_mvm_sec_key_del(mvm, vif, sta, keyconf, 0);
|
|
|
|
}
|
|
|
|
|
|
|
|
static void iwl_mvm_sec_key_remove_ap_iter(struct ieee80211_hw *hw,
|
|
|
|
struct ieee80211_vif *vif,
|
|
|
|
struct ieee80211_sta *sta,
|
|
|
|
struct ieee80211_key_conf *key,
|
|
|
|
void *data)
|
|
|
|
{
|
|
|
|
struct iwl_mvm *mvm = IWL_MAC80211_GET_MVM(hw);
|
2023-03-29 10:05:24 +03:00
|
|
|
unsigned int link_id = (uintptr_t)data;
|
2022-11-02 16:59:53 +02:00
|
|
|
|
|
|
|
if (key->hw_key_idx == STA_KEY_IDX_INVALID)
|
|
|
|
return;
|
|
|
|
|
|
|
|
if (sta)
|
|
|
|
return;
|
|
|
|
|
2023-03-29 10:05:24 +03:00
|
|
|
if (key->link_id >= 0 && key->link_id != link_id)
|
|
|
|
return;
|
|
|
|
|
2022-11-02 16:59:53 +02:00
|
|
|
_iwl_mvm_sec_key_del(mvm, vif, NULL, key, CMD_ASYNC);
|
|
|
|
key->hw_key_idx = STA_KEY_IDX_INVALID;
|
|
|
|
}
|
|
|
|
|
|
|
|
void iwl_mvm_sec_key_remove_ap(struct iwl_mvm *mvm,
|
2023-03-29 10:05:14 +03:00
|
|
|
struct ieee80211_vif *vif,
|
2023-03-29 10:05:24 +03:00
|
|
|
struct iwl_mvm_vif_link_info *link,
|
|
|
|
unsigned int link_id)
|
2022-11-02 16:59:53 +02:00
|
|
|
{
|
|
|
|
u32 sec_key_id = WIDE_ID(DATA_PATH_GROUP, SEC_KEY_CMD);
|
|
|
|
u8 sec_key_ver = iwl_fw_lookup_cmd_ver(mvm->fw, sec_key_id, 0);
|
|
|
|
|
2023-03-29 10:05:13 +03:00
|
|
|
if (WARN_ON_ONCE(vif->type != NL80211_IFTYPE_STATION ||
|
2023-03-29 10:05:14 +03:00
|
|
|
link->ap_sta_id == IWL_MVM_INVALID_STA))
|
2022-11-02 16:59:53 +02:00
|
|
|
return;
|
|
|
|
|
|
|
|
if (!sec_key_ver)
|
|
|
|
return;
|
|
|
|
|
|
|
|
ieee80211_iter_keys_rcu(mvm->hw, vif,
|
|
|
|
iwl_mvm_sec_key_remove_ap_iter,
|
2023-03-29 10:05:24 +03:00
|
|
|
(void *)(uintptr_t)link_id);
|
2022-11-02 16:59:53 +02:00
|
|
|
}
|