Skip to content

Commit

Permalink
iwlwifi: mvm: advertise BIGTK client support if available
Browse files Browse the repository at this point in the history
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: Johannes Berg <johannes.berg@intel.com>
Signed-off-by: Luca Coelho <luciano.coelho@intel.com>
Link: https://lore.kernel.org/r/iwlwifi.20210205110447.f5a3d53301b3.I23e84c9bb0b039d9106a07e9d6847776757f9029@changeid
Signed-off-by: Luca Coelho <luciano.coelho@intel.com>
  • Loading branch information
Johannes Berg authored and Luca Coelho committed Feb 5, 2021
1 parent ddd83d3 commit b1fdc25
Show file tree
Hide file tree
Showing 6 changed files with 104 additions and 15 deletions.
7 changes: 5 additions & 2 deletions drivers/net/wireless/intel/iwlwifi/fw/api/rx.h
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand All @@ -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),
Expand Down Expand Up @@ -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,
Expand Down
2 changes: 2 additions & 0 deletions drivers/net/wireless/intel/iwlwifi/fw/file.h
Original file line number Diff line number Diff line change
Expand Up @@ -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 */
Expand Down
13 changes: 13 additions & 0 deletions drivers/net/wireless/intel/iwlwifi/mvm/mac80211.c
Original file line number Diff line number Diff line change
Expand Up @@ -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 |
Expand Down Expand Up @@ -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) {
/*
Expand Down Expand Up @@ -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) {
Expand Down
4 changes: 4 additions & 0 deletions drivers/net/wireless/intel/iwlwifi/mvm/mvm.h
Original file line number Diff line number Diff line change
Expand Up @@ -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 *
Expand Down
85 changes: 75 additions & 10 deletions drivers/net/wireless/intel/iwlwifi/mvm/rxmq.c
Original file line number Diff line number Diff line change
Expand Up @@ -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)
Expand Down Expand Up @@ -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
Expand Down Expand Up @@ -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.
Expand Down Expand Up @@ -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 =
Expand Down
8 changes: 5 additions & 3 deletions drivers/net/wireless/intel/iwlwifi/mvm/sta.c
Original file line number Diff line number Diff line change
Expand Up @@ -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 */
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_BIP_GMAC_128 &&
keyconf->cipher != WLAN_CIPHER_SUITE_BIP_GMAC_256)))
Expand Down Expand Up @@ -3353,9 +3354,10 @@ static int iwl_mvm_send_sta_igtk(struct iwl_mvm *mvm,
((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",
igtk_cmd.sta_id);
keyconf->keyidx >= 6 ? "B" : "",
keyconf->keyidx, igtk_cmd.sta_id);

if (!iwl_mvm_has_new_rx_api(mvm)) {
struct iwl_mvm_mgmt_mcast_key_cmd_v1 igtk_cmd_v1 = {
Expand Down

0 comments on commit b1fdc25

Please sign in to comment.