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

Commit 56363dde authored by Felix Fietkau's avatar Felix Fietkau Committed by John W. Linville
Browse files

ath9k: fix spurious MIC failure reports



According to the hardware documentation, the MIC failure bit is only
valid if the frame was decrypted using a valid TKIP key and is not a
fragment.
In some setups I've seen hardware-reported MIC failures on an AP that
was configured for CCMP only, so it's clear that additional checks are
necessary.

Signed-off-by: default avatarFelix Fietkau <nbd@openwrt.org>
Cc: stable@kernel.org
Signed-off-by: default avatarJohn W. Linville <linville@tuxdriver.com>
parent 36539107
Loading
Loading
Loading
Loading
+1 −0
Original line number Original line Diff line number Diff line
@@ -119,6 +119,7 @@ struct ath_common {


	u32 keymax;
	u32 keymax;
	DECLARE_BITMAP(keymap, ATH_KEYMAX);
	DECLARE_BITMAP(keymap, ATH_KEYMAX);
	DECLARE_BITMAP(tkip_keymap, ATH_KEYMAX);
	u8 splitmic;
	u8 splitmic;


	struct ath_regulatory regulatory;
	struct ath_regulatory regulatory;
+11 −0
Original line number Original line Diff line number Diff line
@@ -372,9 +372,13 @@ int ath9k_cmn_key_config(struct ath_common *common,
	set_bit(idx, common->keymap);
	set_bit(idx, common->keymap);
	if (key->cipher == WLAN_CIPHER_SUITE_TKIP) {
	if (key->cipher == WLAN_CIPHER_SUITE_TKIP) {
		set_bit(idx + 64, common->keymap);
		set_bit(idx + 64, common->keymap);
		set_bit(idx, common->tkip_keymap);
		set_bit(idx + 64, common->tkip_keymap);
		if (common->splitmic) {
		if (common->splitmic) {
			set_bit(idx + 32, common->keymap);
			set_bit(idx + 32, common->keymap);
			set_bit(idx + 64 + 32, common->keymap);
			set_bit(idx + 64 + 32, common->keymap);
			set_bit(idx + 32, common->tkip_keymap);
			set_bit(idx + 64 + 32, common->tkip_keymap);
		}
		}
	}
	}


@@ -399,10 +403,17 @@ void ath9k_cmn_key_delete(struct ath_common *common,
		return;
		return;


	clear_bit(key->hw_key_idx + 64, common->keymap);
	clear_bit(key->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);

	if (common->splitmic) {
	if (common->splitmic) {
		ath9k_hw_keyreset(ah, key->hw_key_idx + 32);
		ath9k_hw_keyreset(ah, key->hw_key_idx + 32);
		clear_bit(key->hw_key_idx + 32, common->keymap);
		clear_bit(key->hw_key_idx + 32, common->keymap);
		clear_bit(key->hw_key_idx + 64 + 32, common->keymap);
		clear_bit(key->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);
	}
	}
}
}
EXPORT_SYMBOL(ath9k_cmn_key_delete);
EXPORT_SYMBOL(ath9k_cmn_key_delete);
+2 −1
Original line number Original line Diff line number Diff line
@@ -711,7 +711,8 @@ int ath9k_hw_rxprocdesc(struct ath_hw *ah, struct ath_desc *ds,
			rs->rs_phyerr = phyerr;
			rs->rs_phyerr = phyerr;
		} else if (ads.ds_rxstatus8 & AR_DecryptCRCErr)
		} else if (ads.ds_rxstatus8 & AR_DecryptCRCErr)
			rs->rs_status |= ATH9K_RXERR_DECRYPT;
			rs->rs_status |= ATH9K_RXERR_DECRYPT;
		else if (ads.ds_rxstatus8 & AR_MichaelErr)
		else if ((ads.ds_rxstatus8 & AR_MichaelErr) &&
		         rs->rs_keyix != ATH9K_RXKEYIX_INVALID)
			rs->rs_status |= ATH9K_RXERR_MIC;
			rs->rs_status |= ATH9K_RXERR_MIC;
	}
	}


+11 −8
Original line number Original line Diff line number Diff line
@@ -870,15 +870,18 @@ static bool ath9k_rx_accept(struct ath_common *common,
		if (rx_stats->rs_status & ATH9K_RXERR_DECRYPT) {
		if (rx_stats->rs_status & ATH9K_RXERR_DECRYPT) {
			*decrypt_error = true;
			*decrypt_error = true;
		} else if (rx_stats->rs_status & ATH9K_RXERR_MIC) {
		} else if (rx_stats->rs_status & ATH9K_RXERR_MIC) {
			if (ieee80211_is_ctl(fc))
			/*
			/*
				 * Sometimes, we get invalid
			 * The MIC error bit is only valid if the frame
				 * MIC failures on valid control frames.
			 * is not a control frame or fragment, and it was
				 * Remove these mic errors.
			 * decrypted using a valid TKIP key.
			 */
			 */
				rx_stats->rs_status &= ~ATH9K_RXERR_MIC;
			if (!ieee80211_is_ctl(fc) &&
			else
			    !ieee80211_has_morefrags(fc) &&
			    !(le16_to_cpu(hdr->seq_ctrl) & IEEE80211_SCTL_FRAG) &&
			    test_bit(rx_stats->rs_keyix, common->tkip_keymap))
				rxs->flag |= RX_FLAG_MMIC_ERROR;
				rxs->flag |= RX_FLAG_MMIC_ERROR;
			else
				rx_stats->rs_status &= ~ATH9K_RXERR_MIC;
		}
		}
		/*
		/*
		 * Reject error frames with the exception of
		 * Reject error frames with the exception of