Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 7c5a966e authored by Jouni Malinen's avatar Jouni Malinen Committed by Sasha Levin
Browse files

ath: Modify ath_key_delete() to not need full key entry



commit 144cd24dbc36650a51f7fe3bf1424a1432f1f480 upstream.

tkip_keymap can be used internally to avoid the reference to key->cipher
and with this, only the key index value itself is needed. This allows
ath_key_delete() call to be postponed to be handled after the upper
layer STA and key entry have already been removed. This is needed to
make ath9k key cache management safer.

Signed-off-by: default avatarJouni Malinen <jouni@codeaurora.org>
Signed-off-by: default avatarKalle Valo <kvalo@codeaurora.org>
Link: https://lore.kernel.org/r/20201214172118.18100-5-jouni@codeaurora.org


Cc: Pali Rohár <pali@kernel.org>
Signed-off-by: default avatarGreg Kroah-Hartman <gregkh@linuxfoundation.org>
parent fb924bfc
Loading
Loading
Loading
Loading
+1 −1
Original line number Diff line number Diff line
@@ -197,7 +197,7 @@ struct sk_buff *ath_rxbuf_alloc(struct ath_common *common,
bool ath_is_mybeacon(struct ath_common *common, struct ieee80211_hdr *hdr);

void ath_hw_setbssidmask(struct ath_common *common);
void ath_key_delete(struct ath_common *common, struct ieee80211_key_conf *key);
void ath_key_delete(struct ath_common *common, u8 hw_key_idx);
int ath_key_config(struct ath_common *common,
			  struct ieee80211_vif *vif,
			  struct ieee80211_sta *sta,
+1 −1
Original line number Diff line number Diff line
@@ -522,7 +522,7 @@ ath5k_set_key(struct ieee80211_hw *hw, enum set_key_cmd cmd,
		}
		break;
	case DISABLE_KEY:
		ath_key_delete(common, key);
		ath_key_delete(common, key->hw_key_idx);
		break;
	default:
		ret = -EINVAL;
+1 −1
Original line number Diff line number Diff line
@@ -1460,7 +1460,7 @@ static int ath9k_htc_set_key(struct ieee80211_hw *hw,
		}
		break;
	case DISABLE_KEY:
		ath_key_delete(common, key);
		ath_key_delete(common, key->hw_key_idx);
		break;
	default:
		ret = -EINVAL;
+2 −3
Original line number Diff line number Diff line
@@ -1546,12 +1546,11 @@ static void ath9k_del_ps_key(struct ath_softc *sc,
{
	struct ath_common *common = ath9k_hw_common(sc->sc_ah);
	struct ath_node *an = (struct ath_node *) sta->drv_priv;
	struct ieee80211_key_conf ps_key = { .hw_key_idx = an->ps_key };

	if (!an->ps_key)
	    return;

	ath_key_delete(common, &ps_key);
	ath_key_delete(common, an->ps_key);
	an->ps_key = 0;
	an->key_idx[0] = 0;
}
@@ -1742,7 +1741,7 @@ static int ath9k_set_key(struct ieee80211_hw *hw,
		}
		break;
	case DISABLE_KEY:
		ath_key_delete(common, key);
		ath_key_delete(common, key->hw_key_idx);
		if (an) {
			for (i = 0; i < ARRAY_SIZE(an->key_idx); i++) {
				if (an->key_idx[i] != key->hw_key_idx)
+17 −17
Original line number Diff line number Diff line
@@ -581,38 +581,38 @@ EXPORT_SYMBOL(ath_key_config);
/*
 * Delete Key.
 */
void ath_key_delete(struct ath_common *common, struct ieee80211_key_conf *key)
void ath_key_delete(struct ath_common *common, u8 hw_key_idx)
{
	/* Leave CCMP and TKIP (main key) configured to avoid disabling
	 * encryption for potentially pending frames already in a TXQ with the
	 * keyix pointing to this key entry. Instead, only clear the MAC address
	 * to prevent RX processing from using this key cache entry.
	 */
	if (test_bit(key->hw_key_idx, common->ccmp_keymap) ||
	    test_bit(key->hw_key_idx, common->tkip_keymap))
		ath_hw_keysetmac(common, key->hw_key_idx, NULL);
	if (test_bit(hw_key_idx, common->ccmp_keymap) ||
	    test_bit(hw_key_idx, common->tkip_keymap))
		ath_hw_keysetmac(common, hw_key_idx, NULL);
	else
		ath_hw_keyreset(common, key->hw_key_idx);
	if (key->hw_key_idx < IEEE80211_WEP_NKID)
		ath_hw_keyreset(common, hw_key_idx);
	if (hw_key_idx < IEEE80211_WEP_NKID)
		return;

	clear_bit(key->hw_key_idx, common->keymap);
	clear_bit(key->hw_key_idx, common->ccmp_keymap);
	if (key->cipher != WLAN_CIPHER_SUITE_TKIP)
	clear_bit(hw_key_idx, common->keymap);
	clear_bit(hw_key_idx, common->ccmp_keymap);
	if (!test_bit(hw_key_idx, common->tkip_keymap))
		return;

	clear_bit(key->hw_key_idx + 64, common->keymap);
	clear_bit(hw_key_idx + 64, common->keymap);

	clear_bit(key->hw_key_idx, common->tkip_keymap);
	clear_bit(key->hw_key_idx + 64, common->tkip_keymap);
	clear_bit(hw_key_idx, common->tkip_keymap);
	clear_bit(hw_key_idx + 64, common->tkip_keymap);

	if (!(common->crypt_caps & ATH_CRYPT_CAP_MIC_COMBINED)) {
		ath_hw_keyreset(common, key->hw_key_idx + 32);
		clear_bit(key->hw_key_idx + 32, common->keymap);
		clear_bit(key->hw_key_idx + 64 + 32, common->keymap);
		ath_hw_keyreset(common, hw_key_idx + 32);
		clear_bit(hw_key_idx + 32, common->keymap);
		clear_bit(hw_key_idx + 64 + 32, common->keymap);

		clear_bit(key->hw_key_idx + 32, common->tkip_keymap);
		clear_bit(key->hw_key_idx + 64 + 32, common->tkip_keymap);
		clear_bit(hw_key_idx + 32, common->tkip_keymap);
		clear_bit(hw_key_idx + 64 + 32, common->tkip_keymap);
	}
}
EXPORT_SYMBOL(ath_key_delete);