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

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@changeidSigned-off-by: default avatarLuca Coelho <luciano.coelho@intel.com>
parent ddd83d32
...@@ -140,7 +140,8 @@ enum iwl_rx_phy_flags { ...@@ -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_TKIP_ENC: this frame is encrypted using TKIP
* @RX_MPDU_RES_STATUS_SEC_EXT_ENC: this frame is encrypted using extension * @RX_MPDU_RES_STATUS_SEC_EXT_ENC: this frame is encrypted using extension
* algorithm * 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_ERR: this frame couldn't be decrypted
* @RX_MPDU_RES_STATUS_SEC_ENC_MSK: bitmask of the encryption algorithm * @RX_MPDU_RES_STATUS_SEC_ENC_MSK: bitmask of the encryption algorithm
* @RX_MPDU_RES_STATUS_DEC_DONE: this frame has been successfully decrypted * @RX_MPDU_RES_STATUS_DEC_DONE: this frame has been successfully decrypted
...@@ -167,7 +168,7 @@ enum iwl_mvm_rx_status { ...@@ -167,7 +168,7 @@ enum iwl_mvm_rx_status {
RX_MPDU_RES_STATUS_SEC_CCM_ENC = (2 << 8), RX_MPDU_RES_STATUS_SEC_CCM_ENC = (2 << 8),
RX_MPDU_RES_STATUS_SEC_TKIP_ENC = (3 << 8), RX_MPDU_RES_STATUS_SEC_TKIP_ENC = (3 << 8),
RX_MPDU_RES_STATUS_SEC_EXT_ENC = (4 << 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_ERR = (7 << 8),
RX_MPDU_RES_STATUS_SEC_ENC_MSK = (7 << 8), RX_MPDU_RES_STATUS_SEC_ENC_MSK = (7 << 8),
RX_MPDU_RES_STATUS_DEC_DONE = BIT(11), RX_MPDU_RES_STATUS_DEC_DONE = BIT(11),
...@@ -239,6 +240,8 @@ enum iwl_rx_mpdu_status { ...@@ -239,6 +240,8 @@ enum iwl_rx_mpdu_status {
IWL_RX_MPDU_STATUS_ICV_OK = BIT(5), IWL_RX_MPDU_STATUS_ICV_OK = BIT(5),
IWL_RX_MPDU_STATUS_MIC_OK = BIT(6), IWL_RX_MPDU_STATUS_MIC_OK = BIT(6),
IWL_RX_MPDU_RES_STATUS_TTAK_OK = BIT(7), 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_MASK = 0x7 << 8,
IWL_RX_MPDU_STATUS_SEC_UNKNOWN = IWL_RX_MPDU_STATUS_SEC_MASK, IWL_RX_MPDU_STATUS_SEC_UNKNOWN = IWL_RX_MPDU_STATUS_SEC_MASK,
IWL_RX_MPDU_STATUS_SEC_NONE = 0x0 << 8, IWL_RX_MPDU_STATUS_SEC_NONE = 0x0 << 8,
......
...@@ -440,6 +440,8 @@ enum iwl_ucode_tlv_capa { ...@@ -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_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 NUM_IWL_UCODE_TLV_CAPA
#ifdef __CHECKER__ #ifdef __CHECKER__
/* sparse says it cannot increment the previous enum member */ /* sparse says it cannot increment the previous enum member */
......
...@@ -472,6 +472,11 @@ int iwl_mvm_mac_setup_register(struct iwl_mvm *mvm) ...@@ -472,6 +472,11 @@ int iwl_mvm_mac_setup_register(struct iwl_mvm *mvm)
hw->wiphy->pmsr_capa = &iwl_mvm_pmsr_capa; 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); ieee80211_hw_set(hw, SINGLE_SCAN_ON_ALL_BANDS);
hw->wiphy->features |= hw->wiphy->features |=
NL80211_FEATURE_SCHED_SCAN_RANDOM_MAC_ADDR | NL80211_FEATURE_SCHED_SCAN_RANDOM_MAC_ADDR |
...@@ -3419,6 +3424,10 @@ static int __iwl_mvm_mac_set_key(struct ieee80211_hw *hw, ...@@ -3419,6 +3424,10 @@ static int __iwl_mvm_mac_set_key(struct ieee80211_hw *hw,
switch (cmd) { switch (cmd) {
case SET_KEY: case SET_KEY:
if (keyidx == 6 || keyidx == 7)
rcu_assign_pointer(mvmvif->bcn_prot.keys[keyidx - 6],
key);
if ((vif->type == NL80211_IFTYPE_ADHOC || if ((vif->type == NL80211_IFTYPE_ADHOC ||
vif->type == NL80211_IFTYPE_AP) && !sta) { vif->type == NL80211_IFTYPE_AP) && !sta) {
/* /*
...@@ -3527,6 +3536,10 @@ static int __iwl_mvm_mac_set_key(struct ieee80211_hw *hw, ...@@ -3527,6 +3536,10 @@ static int __iwl_mvm_mac_set_key(struct ieee80211_hw *hw,
break; break;
case DISABLE_KEY: case DISABLE_KEY:
if (keyidx == 6 || keyidx == 7)
RCU_INIT_POINTER(mvmvif->bcn_prot.keys[keyidx - 6],
NULL);
ret = -ENOENT; ret = -ENOENT;
for (i = 0; i < ARRAY_SIZE(mvmvif->ap_early_keys); i++) { for (i = 0; i < ARRAY_SIZE(mvmvif->ap_early_keys); i++) {
if (mvmvif->ap_early_keys[i] == key) { if (mvmvif->ap_early_keys[i] == key) {
......
...@@ -419,6 +419,10 @@ struct iwl_mvm_vif { ...@@ -419,6 +419,10 @@ struct iwl_mvm_vif {
/* 26-tone RU OFDMA transmissions should be blocked */ /* 26-tone RU OFDMA transmissions should be blocked */
bool he_ru_2mhz_block; bool he_ru_2mhz_block;
struct {
struct ieee80211_key_conf __rcu *keys[2];
} bcn_prot;
}; };
static inline struct iwl_mvm_vif * static inline struct iwl_mvm_vif *
......
...@@ -272,7 +272,72 @@ static void iwl_mvm_get_signal_strength(struct iwl_mvm *mvm, ...@@ -272,7 +272,72 @@ static void iwl_mvm_get_signal_strength(struct iwl_mvm *mvm,
rx_status->chain_signal[2] = S8_MIN; 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 ieee80211_rx_status *stats, u16 phy_info,
struct iwl_rx_mpdu_desc *desc, struct iwl_rx_mpdu_desc *desc,
u32 pkt_flags, int queue, u8 *crypt_len) 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, ...@@ -345,6 +410,8 @@ static int iwl_mvm_rx_crypto(struct iwl_mvm *mvm, struct ieee80211_hdr *hdr,
return -1; return -1;
stats->flag |= RX_FLAG_DECRYPTED; stats->flag |= RX_FLAG_DECRYPTED;
return 0; return 0;
case RX_MPDU_RES_STATUS_SEC_CMAC_GMAC_ENC:
return iwl_mvm_rx_mgmt_crypto(sta, hdr, desc, status);
default: default:
/* /*
* Sometimes we can get frames that were not decrypted * 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, ...@@ -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); 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 * Keep packets with CRC errors (and with overrun) for monitor mode
* (otherwise the firmware discards them) but mark them as bad. * (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, ...@@ -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); 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) { if (sta) {
struct iwl_mvm_sta *mvmsta = iwl_mvm_sta_from_mac80211(sta); struct iwl_mvm_sta *mvmsta = iwl_mvm_sta_from_mac80211(sta);
struct ieee80211_vif *tx_blocked_vif = struct ieee80211_vif *tx_blocked_vif =
......
...@@ -3304,7 +3304,8 @@ static int iwl_mvm_send_sta_igtk(struct iwl_mvm *mvm, ...@@ -3304,7 +3304,8 @@ static int iwl_mvm_send_sta_igtk(struct iwl_mvm *mvm,
/* verify the key details match the required command's expectations */ /* verify the key details match the required command's expectations */
if (WARN_ON((keyconf->flags & IEEE80211_KEY_FLAG_PAIRWISE) || if (WARN_ON((keyconf->flags & IEEE80211_KEY_FLAG_PAIRWISE) ||
(keyconf->keyidx != 4 && keyconf->keyidx != 5) || (keyconf->keyidx != 4 && keyconf->keyidx != 5 &&
keyconf->keyidx != 6 && keyconf->keyidx != 7) ||
(keyconf->cipher != WLAN_CIPHER_SUITE_AES_CMAC && (keyconf->cipher != WLAN_CIPHER_SUITE_AES_CMAC &&
keyconf->cipher != WLAN_CIPHER_SUITE_BIP_GMAC_128 && keyconf->cipher != WLAN_CIPHER_SUITE_BIP_GMAC_128 &&
keyconf->cipher != WLAN_CIPHER_SUITE_BIP_GMAC_256))) keyconf->cipher != WLAN_CIPHER_SUITE_BIP_GMAC_256)))
...@@ -3353,9 +3354,10 @@ static int iwl_mvm_send_sta_igtk(struct iwl_mvm *mvm, ...@@ -3353,9 +3354,10 @@ static int iwl_mvm_send_sta_igtk(struct iwl_mvm *mvm,
((u64) pn[0] << 40)); ((u64) pn[0] << 40));
} }
IWL_DEBUG_INFO(mvm, "%s igtk for sta %u\n", IWL_DEBUG_INFO(mvm, "%s %sIGTK (%d) for sta %u\n",
remove_key ? "removing" : "installing", remove_key ? "removing" : "installing",
igtk_cmd.sta_id); keyconf->keyidx >= 6 ? "B" : "",
keyconf->keyidx, igtk_cmd.sta_id);
if (!iwl_mvm_has_new_rx_api(mvm)) { if (!iwl_mvm_has_new_rx_api(mvm)) {
struct iwl_mvm_mgmt_mcast_key_cmd_v1 igtk_cmd_v1 = { struct iwl_mvm_mgmt_mcast_key_cmd_v1 igtk_cmd_v1 = {
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment