iwlwifi: mvm: refactor key add/remove functions
Refactor the key add/remove functions to be able to reuse parts of them later for RX WEP keys, which need to be uploaded twice. Signed-off-by: Johannes Berg <johannes.berg@intel.com> Signed-off-by: Emmanuel Grumbach <emmanuel.grumbach@intel.com>
This commit is contained in:
parent
bf5da87f60
commit
2f6319d1cf
|
@ -1072,8 +1072,7 @@ static u8 iwl_mvm_get_key_sta_id(struct ieee80211_vif *vif,
|
||||||
static int iwl_mvm_send_sta_key(struct iwl_mvm *mvm,
|
static int iwl_mvm_send_sta_key(struct iwl_mvm *mvm,
|
||||||
struct iwl_mvm_sta *mvm_sta,
|
struct iwl_mvm_sta *mvm_sta,
|
||||||
struct ieee80211_key_conf *keyconf,
|
struct ieee80211_key_conf *keyconf,
|
||||||
u8 sta_id, u32 tkip_iv32, u16 *tkip_p1k,
|
u32 tkip_iv32, u16 *tkip_p1k, u32 cmd_flags)
|
||||||
u32 cmd_flags)
|
|
||||||
{
|
{
|
||||||
struct iwl_mvm_add_sta_key_cmd cmd = {};
|
struct iwl_mvm_add_sta_key_cmd cmd = {};
|
||||||
__le16 key_flags;
|
__le16 key_flags;
|
||||||
|
@ -1081,6 +1080,7 @@ static int iwl_mvm_send_sta_key(struct iwl_mvm *mvm,
|
||||||
u32 status;
|
u32 status;
|
||||||
u16 keyidx;
|
u16 keyidx;
|
||||||
int i;
|
int i;
|
||||||
|
u8 sta_id = mvm_sta->sta_id;
|
||||||
|
|
||||||
keyidx = (keyconf->keyidx << STA_KEY_FLG_KEYID_POS) &
|
keyidx = (keyconf->keyidx << STA_KEY_FLG_KEYID_POS) &
|
||||||
STA_KEY_FLG_KEYID_MSK;
|
STA_KEY_FLG_KEYID_MSK;
|
||||||
|
@ -1196,141 +1196,45 @@ static inline u8 *iwl_mvm_get_mac_addr(struct iwl_mvm *mvm,
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
int iwl_mvm_set_sta_key(struct iwl_mvm *mvm,
|
static int __iwl_mvm_set_sta_key(struct iwl_mvm *mvm,
|
||||||
struct ieee80211_vif *vif,
|
struct ieee80211_vif *vif,
|
||||||
struct ieee80211_sta *sta,
|
struct ieee80211_sta *sta,
|
||||||
struct ieee80211_key_conf *keyconf,
|
struct ieee80211_key_conf *keyconf)
|
||||||
bool have_key_offset)
|
|
||||||
{
|
{
|
||||||
struct iwl_mvm_sta *mvm_sta;
|
struct iwl_mvm_sta *mvm_sta = iwl_mvm_sta_from_mac80211(sta);
|
||||||
int ret;
|
int ret;
|
||||||
u8 *addr, sta_id;
|
const u8 *addr;
|
||||||
struct ieee80211_key_seq seq;
|
struct ieee80211_key_seq seq;
|
||||||
u16 p1k[5];
|
u16 p1k[5];
|
||||||
|
|
||||||
lockdep_assert_held(&mvm->mutex);
|
|
||||||
|
|
||||||
/* Get the station id from the mvm local station table */
|
|
||||||
sta_id = iwl_mvm_get_key_sta_id(vif, sta);
|
|
||||||
if (sta_id == IWL_MVM_STATION_COUNT) {
|
|
||||||
IWL_ERR(mvm, "Failed to find station id\n");
|
|
||||||
return -EINVAL;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (keyconf->cipher == WLAN_CIPHER_SUITE_AES_CMAC) {
|
|
||||||
ret = iwl_mvm_send_sta_igtk(mvm, keyconf, sta_id, false);
|
|
||||||
goto end;
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
|
||||||
* It is possible that the 'sta' parameter is NULL, and thus
|
|
||||||
* there is a need to retrieve the sta from the local station table.
|
|
||||||
*/
|
|
||||||
if (!sta) {
|
|
||||||
sta = rcu_dereference_protected(mvm->fw_id_to_mac_id[sta_id],
|
|
||||||
lockdep_is_held(&mvm->mutex));
|
|
||||||
if (IS_ERR_OR_NULL(sta)) {
|
|
||||||
IWL_ERR(mvm, "Invalid station id\n");
|
|
||||||
return -EINVAL;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
mvm_sta = (struct iwl_mvm_sta *)sta->drv_priv;
|
|
||||||
if (WARN_ON_ONCE(mvm_sta->vif != vif))
|
|
||||||
return -EINVAL;
|
|
||||||
|
|
||||||
if (!have_key_offset) {
|
|
||||||
/*
|
|
||||||
* The D3 firmware hardcodes the PTK offset to 0, so we have to
|
|
||||||
* configure it there. As a result, this workaround exists to
|
|
||||||
* let the caller set the key offset (hw_key_idx), see d3.c.
|
|
||||||
*/
|
|
||||||
keyconf->hw_key_idx = iwl_mvm_set_fw_key_idx(mvm);
|
|
||||||
if (keyconf->hw_key_idx == STA_KEY_IDX_INVALID)
|
|
||||||
return -ENOSPC;
|
|
||||||
}
|
|
||||||
|
|
||||||
switch (keyconf->cipher) {
|
switch (keyconf->cipher) {
|
||||||
case WLAN_CIPHER_SUITE_TKIP:
|
case WLAN_CIPHER_SUITE_TKIP:
|
||||||
addr = iwl_mvm_get_mac_addr(mvm, vif, sta);
|
addr = iwl_mvm_get_mac_addr(mvm, vif, sta);
|
||||||
/* get phase 1 key from mac80211 */
|
/* get phase 1 key from mac80211 */
|
||||||
ieee80211_get_key_rx_seq(keyconf, 0, &seq);
|
ieee80211_get_key_rx_seq(keyconf, 0, &seq);
|
||||||
ieee80211_get_tkip_rx_p1k(keyconf, addr, seq.tkip.iv32, p1k);
|
ieee80211_get_tkip_rx_p1k(keyconf, addr, seq.tkip.iv32, p1k);
|
||||||
ret = iwl_mvm_send_sta_key(mvm, mvm_sta, keyconf, sta_id,
|
ret = iwl_mvm_send_sta_key(mvm, mvm_sta, keyconf,
|
||||||
seq.tkip.iv32, p1k, 0);
|
seq.tkip.iv32, p1k, 0);
|
||||||
break;
|
break;
|
||||||
case WLAN_CIPHER_SUITE_CCMP:
|
case WLAN_CIPHER_SUITE_CCMP:
|
||||||
ret = iwl_mvm_send_sta_key(mvm, mvm_sta, keyconf, sta_id,
|
ret = iwl_mvm_send_sta_key(mvm, mvm_sta, keyconf,
|
||||||
0, NULL, 0);
|
0, NULL, 0);
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
ret = iwl_mvm_send_sta_key(mvm, mvm_sta, keyconf,
|
ret = iwl_mvm_send_sta_key(mvm, mvm_sta, keyconf,
|
||||||
sta_id, 0, NULL, 0);
|
0, NULL, 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (ret)
|
|
||||||
__clear_bit(keyconf->hw_key_idx, mvm->fw_key_table);
|
|
||||||
|
|
||||||
end:
|
|
||||||
IWL_DEBUG_WEP(mvm, "key: cipher=%x len=%d idx=%d sta=%pM ret=%d\n",
|
|
||||||
keyconf->cipher, keyconf->keylen, keyconf->keyidx,
|
|
||||||
sta->addr, ret);
|
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
int iwl_mvm_remove_sta_key(struct iwl_mvm *mvm,
|
static int __iwl_mvm_remove_sta_key(struct iwl_mvm *mvm, u8 sta_id,
|
||||||
struct ieee80211_vif *vif,
|
struct ieee80211_key_conf *keyconf)
|
||||||
struct ieee80211_sta *sta,
|
|
||||||
struct ieee80211_key_conf *keyconf)
|
|
||||||
{
|
{
|
||||||
struct iwl_mvm_sta *mvm_sta;
|
|
||||||
struct iwl_mvm_add_sta_key_cmd cmd = {};
|
struct iwl_mvm_add_sta_key_cmd cmd = {};
|
||||||
__le16 key_flags;
|
__le16 key_flags;
|
||||||
int ret;
|
int ret;
|
||||||
u32 status;
|
u32 status;
|
||||||
u8 sta_id;
|
|
||||||
|
|
||||||
lockdep_assert_held(&mvm->mutex);
|
|
||||||
|
|
||||||
/* Get the station id from the mvm local station table */
|
|
||||||
sta_id = iwl_mvm_get_key_sta_id(vif, sta);
|
|
||||||
|
|
||||||
IWL_DEBUG_WEP(mvm, "mvm remove dynamic key: idx=%d sta=%d\n",
|
|
||||||
keyconf->keyidx, sta_id);
|
|
||||||
|
|
||||||
if (keyconf->cipher == WLAN_CIPHER_SUITE_AES_CMAC)
|
|
||||||
return iwl_mvm_send_sta_igtk(mvm, keyconf, sta_id, true);
|
|
||||||
|
|
||||||
ret = __test_and_clear_bit(keyconf->hw_key_idx, mvm->fw_key_table);
|
|
||||||
if (!ret) {
|
|
||||||
IWL_ERR(mvm, "offset %d not used in fw key table.\n",
|
|
||||||
keyconf->hw_key_idx);
|
|
||||||
return -ENOENT;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (sta_id == IWL_MVM_STATION_COUNT) {
|
|
||||||
IWL_DEBUG_WEP(mvm, "station non-existent, early return.\n");
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
|
||||||
* It is possible that the 'sta' parameter is NULL, and thus
|
|
||||||
* there is a need to retrieve the sta from the local station table,
|
|
||||||
* for example when a GTK is removed (where the sta_id will then be
|
|
||||||
* the AP ID, and no station was passed by mac80211.)
|
|
||||||
*/
|
|
||||||
if (!sta) {
|
|
||||||
sta = rcu_dereference_protected(mvm->fw_id_to_mac_id[sta_id],
|
|
||||||
lockdep_is_held(&mvm->mutex));
|
|
||||||
if (!sta) {
|
|
||||||
IWL_ERR(mvm, "Invalid station id\n");
|
|
||||||
return -EINVAL;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
mvm_sta = (struct iwl_mvm_sta *)sta->drv_priv;
|
|
||||||
if (WARN_ON_ONCE(mvm_sta->vif != vif))
|
|
||||||
return -EINVAL;
|
|
||||||
|
|
||||||
key_flags = cpu_to_le16((keyconf->keyidx << STA_KEY_FLG_KEYID_POS) &
|
key_flags = cpu_to_le16((keyconf->keyidx << STA_KEY_FLG_KEYID_POS) &
|
||||||
STA_KEY_FLG_KEYID_MSK);
|
STA_KEY_FLG_KEYID_MSK);
|
||||||
|
@ -1361,6 +1265,117 @@ int iwl_mvm_remove_sta_key(struct iwl_mvm *mvm,
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
int iwl_mvm_set_sta_key(struct iwl_mvm *mvm,
|
||||||
|
struct ieee80211_vif *vif,
|
||||||
|
struct ieee80211_sta *sta,
|
||||||
|
struct ieee80211_key_conf *keyconf,
|
||||||
|
bool have_key_offset)
|
||||||
|
{
|
||||||
|
u8 sta_id;
|
||||||
|
int ret;
|
||||||
|
|
||||||
|
lockdep_assert_held(&mvm->mutex);
|
||||||
|
|
||||||
|
/* Get the station id from the mvm local station table */
|
||||||
|
sta_id = iwl_mvm_get_key_sta_id(vif, sta);
|
||||||
|
if (sta_id == IWL_MVM_STATION_COUNT) {
|
||||||
|
IWL_ERR(mvm, "Failed to find station id\n");
|
||||||
|
return -EINVAL;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (keyconf->cipher == WLAN_CIPHER_SUITE_AES_CMAC) {
|
||||||
|
ret = iwl_mvm_send_sta_igtk(mvm, keyconf, sta_id, false);
|
||||||
|
goto end;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* It is possible that the 'sta' parameter is NULL, and thus
|
||||||
|
* there is a need to retrieve the sta from the local station table.
|
||||||
|
*/
|
||||||
|
if (!sta) {
|
||||||
|
sta = rcu_dereference_protected(mvm->fw_id_to_mac_id[sta_id],
|
||||||
|
lockdep_is_held(&mvm->mutex));
|
||||||
|
if (IS_ERR_OR_NULL(sta)) {
|
||||||
|
IWL_ERR(mvm, "Invalid station id\n");
|
||||||
|
return -EINVAL;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (WARN_ON_ONCE(iwl_mvm_sta_from_mac80211(sta)->vif != vif))
|
||||||
|
return -EINVAL;
|
||||||
|
|
||||||
|
if (!have_key_offset) {
|
||||||
|
/*
|
||||||
|
* The D3 firmware hardcodes the PTK offset to 0, so we have to
|
||||||
|
* configure it there. As a result, this workaround exists to
|
||||||
|
* let the caller set the key offset (hw_key_idx), see d3.c.
|
||||||
|
*/
|
||||||
|
keyconf->hw_key_idx = iwl_mvm_set_fw_key_idx(mvm);
|
||||||
|
if (keyconf->hw_key_idx == STA_KEY_IDX_INVALID)
|
||||||
|
return -ENOSPC;
|
||||||
|
}
|
||||||
|
|
||||||
|
ret = __iwl_mvm_set_sta_key(mvm, vif, sta, keyconf);
|
||||||
|
if (ret)
|
||||||
|
__clear_bit(keyconf->hw_key_idx, mvm->fw_key_table);
|
||||||
|
|
||||||
|
end:
|
||||||
|
IWL_DEBUG_WEP(mvm, "key: cipher=%x len=%d idx=%d sta=%pM ret=%d\n",
|
||||||
|
keyconf->cipher, keyconf->keylen, keyconf->keyidx,
|
||||||
|
sta->addr, ret);
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
int iwl_mvm_remove_sta_key(struct iwl_mvm *mvm,
|
||||||
|
struct ieee80211_vif *vif,
|
||||||
|
struct ieee80211_sta *sta,
|
||||||
|
struct ieee80211_key_conf *keyconf)
|
||||||
|
{
|
||||||
|
u8 sta_id;
|
||||||
|
|
||||||
|
lockdep_assert_held(&mvm->mutex);
|
||||||
|
|
||||||
|
/* Get the station id from the mvm local station table */
|
||||||
|
sta_id = iwl_mvm_get_key_sta_id(vif, sta);
|
||||||
|
|
||||||
|
IWL_DEBUG_WEP(mvm, "mvm remove dynamic key: idx=%d sta=%d\n",
|
||||||
|
keyconf->keyidx, sta_id);
|
||||||
|
|
||||||
|
if (keyconf->cipher == WLAN_CIPHER_SUITE_AES_CMAC)
|
||||||
|
return iwl_mvm_send_sta_igtk(mvm, keyconf, sta_id, true);
|
||||||
|
|
||||||
|
if (!__test_and_clear_bit(keyconf->hw_key_idx, mvm->fw_key_table)) {
|
||||||
|
IWL_ERR(mvm, "offset %d not used in fw key table.\n",
|
||||||
|
keyconf->hw_key_idx);
|
||||||
|
return -ENOENT;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (sta_id == IWL_MVM_STATION_COUNT) {
|
||||||
|
IWL_DEBUG_WEP(mvm, "station non-existent, early return.\n");
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* It is possible that the 'sta' parameter is NULL, and thus
|
||||||
|
* there is a need to retrieve the sta from the local station table,
|
||||||
|
* for example when a GTK is removed (where the sta_id will then be
|
||||||
|
* the AP ID, and no station was passed by mac80211.)
|
||||||
|
*/
|
||||||
|
if (!sta) {
|
||||||
|
sta = rcu_dereference_protected(mvm->fw_id_to_mac_id[sta_id],
|
||||||
|
lockdep_is_held(&mvm->mutex));
|
||||||
|
if (!sta) {
|
||||||
|
IWL_ERR(mvm, "Invalid station id\n");
|
||||||
|
return -EINVAL;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (WARN_ON_ONCE(iwl_mvm_sta_from_mac80211(sta)->vif != vif))
|
||||||
|
return -EINVAL;
|
||||||
|
|
||||||
|
return __iwl_mvm_remove_sta_key(mvm, sta_id, keyconf);
|
||||||
|
}
|
||||||
|
|
||||||
void iwl_mvm_update_tkip_key(struct iwl_mvm *mvm,
|
void iwl_mvm_update_tkip_key(struct iwl_mvm *mvm,
|
||||||
struct ieee80211_vif *vif,
|
struct ieee80211_vif *vif,
|
||||||
struct ieee80211_key_conf *keyconf,
|
struct ieee80211_key_conf *keyconf,
|
||||||
|
@ -1383,8 +1398,8 @@ void iwl_mvm_update_tkip_key(struct iwl_mvm *mvm,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
mvm_sta = (void *)sta->drv_priv;
|
mvm_sta = iwl_mvm_sta_from_mac80211(sta);
|
||||||
iwl_mvm_send_sta_key(mvm, mvm_sta, keyconf, sta_id,
|
iwl_mvm_send_sta_key(mvm, mvm_sta, keyconf,
|
||||||
iv32, phase1key, CMD_ASYNC);
|
iv32, phase1key, CMD_ASYNC);
|
||||||
rcu_read_unlock();
|
rcu_read_unlock();
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue