Commit b1fdc250 authored by Johannes Berg's avatar Johannes Berg Committed by Luca Coelho
Browse files

iwlwifi: mvm: advertise BIGTK client support if available



If the firmware has support, then advertise it to the stack and
send the key down. Since we re-check the protection in the host
anyway, we don't really need to do anything on RX except that we
should drop frames that the firmware _knows_ are replay errors,
since beacon filtering might otherwise result in replays being
possible.

Signed-off-by: default avatarJohannes Berg <johannes.berg@intel.com>
Signed-off-by: default avatarLuca Coelho <luciano.coelho@intel.com>
Link: https://lore.kernel.org/r/iwlwifi.20210205110447.f5a3d53301b3.I23e84c9bb0b039d9106a07e9d6847776757f9029@changeid


Signed-off-by: default avatarLuca Coelho <luciano.coelho@intel.com>
parent ddd83d32
Loading
Loading
Loading
Loading
+5 −2
Original line number Diff line number Diff line
@@ -140,7 +140,8 @@ enum iwl_rx_phy_flags {
 * @RX_MPDU_RES_STATUS_SEC_TKIP_ENC: this frame is encrypted using TKIP
 * @RX_MPDU_RES_STATUS_SEC_EXT_ENC: this frame is encrypted using extension
 *	algorithm
 * @RX_MPDU_RES_STATUS_SEC_CCM_CMAC_ENC: this frame is encrypted using CCM_CMAC
 * @RX_MPDU_RES_STATUS_SEC_CMAC_GMAC_ENC: this frame is protected using
 *	CMAC or GMAC
 * @RX_MPDU_RES_STATUS_SEC_ENC_ERR: this frame couldn't be decrypted
 * @RX_MPDU_RES_STATUS_SEC_ENC_MSK: bitmask of the encryption algorithm
 * @RX_MPDU_RES_STATUS_DEC_DONE: this frame has been successfully decrypted
@@ -167,7 +168,7 @@ enum iwl_mvm_rx_status {
	RX_MPDU_RES_STATUS_SEC_CCM_ENC			= (2 << 8),
	RX_MPDU_RES_STATUS_SEC_TKIP_ENC			= (3 << 8),
	RX_MPDU_RES_STATUS_SEC_EXT_ENC			= (4 << 8),
	RX_MPDU_RES_STATUS_SEC_CCM_CMAC_ENC		= (6 << 8),
	RX_MPDU_RES_STATUS_SEC_CMAC_GMAC_ENC		= (6 << 8),
	RX_MPDU_RES_STATUS_SEC_ENC_ERR			= (7 << 8),
	RX_MPDU_RES_STATUS_SEC_ENC_MSK			= (7 << 8),
	RX_MPDU_RES_STATUS_DEC_DONE			= BIT(11),
@@ -239,6 +240,8 @@ enum iwl_rx_mpdu_status {
	IWL_RX_MPDU_STATUS_ICV_OK		= BIT(5),
	IWL_RX_MPDU_STATUS_MIC_OK		= BIT(6),
	IWL_RX_MPDU_RES_STATUS_TTAK_OK		= BIT(7),
	/* overlayed since IWL_UCODE_TLV_API_DEPRECATE_TTAK */
	IWL_RX_MPDU_STATUS_REPLAY_ERROR		= BIT(7),
	IWL_RX_MPDU_STATUS_SEC_MASK		= 0x7 << 8,
	IWL_RX_MPDU_STATUS_SEC_UNKNOWN		= IWL_RX_MPDU_STATUS_SEC_MASK,
	IWL_RX_MPDU_STATUS_SEC_NONE		= 0x0 << 8,
+2 −0
Original line number Diff line number Diff line
@@ -440,6 +440,8 @@ enum iwl_ucode_tlv_capa {
	 */
	IWL_UCODE_TLV_CAPA_PSC_CHAN_SUPPORT		= (__force iwl_ucode_tlv_capa_t)98,

	IWL_UCODE_TLV_CAPA_BIGTK_SUPPORT		= (__force iwl_ucode_tlv_capa_t)100,

	NUM_IWL_UCODE_TLV_CAPA
#ifdef __CHECKER__
		/* sparse says it cannot increment the previous enum member */
+13 −0
Original line number Diff line number Diff line
@@ -472,6 +472,11 @@ int iwl_mvm_mac_setup_register(struct iwl_mvm *mvm)
		hw->wiphy->pmsr_capa = &iwl_mvm_pmsr_capa;
	}

	if (fw_has_capa(&mvm->fw->ucode_capa,
			IWL_UCODE_TLV_CAPA_BIGTK_SUPPORT))
		wiphy_ext_feature_set(hw->wiphy,
				      NL80211_EXT_FEATURE_BEACON_PROTECTION_CLIENT);

	ieee80211_hw_set(hw, SINGLE_SCAN_ON_ALL_BANDS);
	hw->wiphy->features |=
		NL80211_FEATURE_SCHED_SCAN_RANDOM_MAC_ADDR |
@@ -3419,6 +3424,10 @@ static int __iwl_mvm_mac_set_key(struct ieee80211_hw *hw,

	switch (cmd) {
	case SET_KEY:
		if (keyidx == 6 || keyidx == 7)
			rcu_assign_pointer(mvmvif->bcn_prot.keys[keyidx - 6],
					   key);

		if ((vif->type == NL80211_IFTYPE_ADHOC ||
		     vif->type == NL80211_IFTYPE_AP) && !sta) {
			/*
@@ -3527,6 +3536,10 @@ static int __iwl_mvm_mac_set_key(struct ieee80211_hw *hw,

		break;
	case DISABLE_KEY:
		if (keyidx == 6 || keyidx == 7)
			RCU_INIT_POINTER(mvmvif->bcn_prot.keys[keyidx - 6],
					 NULL);

		ret = -ENOENT;
		for (i = 0; i < ARRAY_SIZE(mvmvif->ap_early_keys); i++) {
			if (mvmvif->ap_early_keys[i] == key) {
+4 −0
Original line number Diff line number Diff line
@@ -419,6 +419,10 @@ struct iwl_mvm_vif {

	/* 26-tone RU OFDMA transmissions should be blocked */
	bool he_ru_2mhz_block;

	struct {
		struct ieee80211_key_conf __rcu *keys[2];
	} bcn_prot;
};

static inline struct iwl_mvm_vif *
+75 −10
Original line number Diff line number Diff line
@@ -272,7 +272,72 @@ static void iwl_mvm_get_signal_strength(struct iwl_mvm *mvm,
	rx_status->chain_signal[2] = S8_MIN;
}

static int iwl_mvm_rx_crypto(struct iwl_mvm *mvm, struct ieee80211_hdr *hdr,
static int iwl_mvm_rx_mgmt_crypto(struct ieee80211_sta *sta,
				  struct ieee80211_hdr *hdr,
				  struct iwl_rx_mpdu_desc *desc,
				  u32 status)
{
	struct iwl_mvm_sta *mvmsta;
	struct iwl_mvm_vif *mvmvif;
	u8 fwkeyid = u32_get_bits(status, IWL_RX_MPDU_STATUS_KEY);
	u8 keyid;
	struct ieee80211_key_conf *key;
	u32 len = le16_to_cpu(desc->mpdu_len);
	const u8 *frame = (void *)hdr;

	/*
	 * For non-beacon, we don't really care. But beacons may
	 * be filtered out, and we thus need the firmware's replay
	 * detection, otherwise beacons the firmware previously
	 * filtered could be replayed, or something like that, and
	 * it can filter a lot - though usually only if nothing has
	 * changed.
	 */
	if (!ieee80211_is_beacon(hdr->frame_control))
		return 0;

	/* good cases */
	if (likely(status & IWL_RX_MPDU_STATUS_MIC_OK &&
		   !(status & IWL_RX_MPDU_STATUS_REPLAY_ERROR)))
		return 0;

	if (!sta)
		return -1;

	mvmsta = iwl_mvm_sta_from_mac80211(sta);

	/* what? */
	if (fwkeyid != 6 && fwkeyid != 7)
		return -1;

	mvmvif = iwl_mvm_vif_from_mac80211(mvmsta->vif);

	key = rcu_dereference(mvmvif->bcn_prot.keys[fwkeyid - 6]);
	if (!key)
		return -1;

	if (len < key->icv_len + IEEE80211_GMAC_PN_LEN + 2)
		return -1;

	/*
	 * See if the key ID matches - if not this may be due to a
	 * switch and the firmware may erroneously report !MIC_OK.
	 */
	keyid = frame[len - key->icv_len - IEEE80211_GMAC_PN_LEN - 2];
	if (keyid != fwkeyid)
		return -1;

	/* Report status to mac80211 */
	if (!(status & IWL_RX_MPDU_STATUS_MIC_OK))
		ieee80211_key_mic_failure(key);
	else if (status & IWL_RX_MPDU_STATUS_REPLAY_ERROR)
		ieee80211_key_replay(key);

	return -1;
}

static int iwl_mvm_rx_crypto(struct iwl_mvm *mvm, struct ieee80211_sta *sta,
			     struct ieee80211_hdr *hdr,
			     struct ieee80211_rx_status *stats, u16 phy_info,
			     struct iwl_rx_mpdu_desc *desc,
			     u32 pkt_flags, int queue, u8 *crypt_len)
@@ -345,6 +410,8 @@ static int iwl_mvm_rx_crypto(struct iwl_mvm *mvm, struct ieee80211_hdr *hdr,
			return -1;
		stats->flag |= RX_FLAG_DECRYPTED;
		return 0;
	case RX_MPDU_RES_STATUS_SEC_CMAC_GMAC_ENC:
		return iwl_mvm_rx_mgmt_crypto(sta, hdr, desc, status);
	default:
		/*
		 * Sometimes we can get frames that were not decrypted
@@ -1682,15 +1749,6 @@ void iwl_mvm_rx_mpdu_mq(struct iwl_mvm *mvm, struct napi_struct *napi,

	iwl_mvm_decode_lsig(skb, &phy_data);

	rx_status = IEEE80211_SKB_RXCB(skb);

	if (iwl_mvm_rx_crypto(mvm, hdr, rx_status, phy_info, desc,
			      le32_to_cpu(pkt->len_n_flags), queue,
			      &crypt_len)) {
		kfree_skb(skb);
		return;
	}

	/*
	 * Keep packets with CRC errors (and with overrun) for monitor mode
	 * (otherwise the firmware discards them) but mark them as bad.
@@ -1774,6 +1832,13 @@ void iwl_mvm_rx_mpdu_mq(struct iwl_mvm *mvm, struct napi_struct *napi,
		sta = ieee80211_find_sta_by_ifaddr(mvm->hw, hdr->addr2, NULL);
	}

	if (iwl_mvm_rx_crypto(mvm, sta, hdr, rx_status, phy_info, desc,
			      le32_to_cpu(pkt->len_n_flags), queue,
			      &crypt_len)) {
		kfree_skb(skb);
		goto out;
	}

	if (sta) {
		struct iwl_mvm_sta *mvmsta = iwl_mvm_sta_from_mac80211(sta);
		struct ieee80211_vif *tx_blocked_vif =
Loading