Commit 2a53d166 authored by Ayala Beker's avatar Ayala Beker Committed by Luca Coelho

iwlwifi: mvm: add support for GCMP encryption

Newer hardware supports GCMP and GCMP 256-bit ciphers.
Add support for adding/setting GCMP key for TX mode.

In the TX command handling GCMP-256 is handled in a different
way as the key size should be up to 128-bits:
Set the key value to the key index in the key table,
and specify that this key should be taken form the key table
instead of from the TX command.

While at it - convert security control flags to an enum.
Signed-off-by: default avatarAyala Beker <ayala.beker@intel.com>
Signed-off-by: default avatarLuca Coelho <luciano.coelho@intel.com>
parent 9c07e9aa
...@@ -141,6 +141,7 @@ enum iwl_sta_flags { ...@@ -141,6 +141,7 @@ enum iwl_sta_flags {
* @STA_KEY_FLG_CCM: CCMP encryption algorithm * @STA_KEY_FLG_CCM: CCMP encryption algorithm
* @STA_KEY_FLG_TKIP: TKIP encryption algorithm * @STA_KEY_FLG_TKIP: TKIP encryption algorithm
* @STA_KEY_FLG_EXT: extended cipher algorithm (depends on the FW support) * @STA_KEY_FLG_EXT: extended cipher algorithm (depends on the FW support)
* @STA_KEY_FLG_GCMP: GCMP encryption algorithm
* @STA_KEY_FLG_CMAC: CMAC encryption algorithm * @STA_KEY_FLG_CMAC: CMAC encryption algorithm
* @STA_KEY_FLG_ENC_UNKNOWN: unknown encryption algorithm * @STA_KEY_FLG_ENC_UNKNOWN: unknown encryption algorithm
* @STA_KEY_FLG_EN_MSK: mask for encryption algorithmi value * @STA_KEY_FLG_EN_MSK: mask for encryption algorithmi value
...@@ -149,6 +150,7 @@ enum iwl_sta_flags { ...@@ -149,6 +150,7 @@ enum iwl_sta_flags {
* @STA_KEY_FLG_KEYID_MSK: the index of the key * @STA_KEY_FLG_KEYID_MSK: the index of the key
* @STA_KEY_NOT_VALID: key is invalid * @STA_KEY_NOT_VALID: key is invalid
* @STA_KEY_FLG_WEP_13BYTES: set for 13 bytes WEP key * @STA_KEY_FLG_WEP_13BYTES: set for 13 bytes WEP key
* @STA_KEY_FLG_KEY_32BYTES for non-wep key set for 32 bytes key
* @STA_KEY_MULTICAST: set for multical key * @STA_KEY_MULTICAST: set for multical key
* @STA_KEY_MFP: key is used for Management Frame Protection * @STA_KEY_MFP: key is used for Management Frame Protection
*/ */
...@@ -158,6 +160,7 @@ enum iwl_sta_key_flag { ...@@ -158,6 +160,7 @@ enum iwl_sta_key_flag {
STA_KEY_FLG_CCM = (2 << 0), STA_KEY_FLG_CCM = (2 << 0),
STA_KEY_FLG_TKIP = (3 << 0), STA_KEY_FLG_TKIP = (3 << 0),
STA_KEY_FLG_EXT = (4 << 0), STA_KEY_FLG_EXT = (4 << 0),
STA_KEY_FLG_GCMP = (5 << 0),
STA_KEY_FLG_CMAC = (6 << 0), STA_KEY_FLG_CMAC = (6 << 0),
STA_KEY_FLG_ENC_UNKNOWN = (7 << 0), STA_KEY_FLG_ENC_UNKNOWN = (7 << 0),
STA_KEY_FLG_EN_MSK = (7 << 0), STA_KEY_FLG_EN_MSK = (7 << 0),
...@@ -167,6 +170,7 @@ enum iwl_sta_key_flag { ...@@ -167,6 +170,7 @@ enum iwl_sta_key_flag {
STA_KEY_FLG_KEYID_MSK = (3 << STA_KEY_FLG_KEYID_POS), STA_KEY_FLG_KEYID_MSK = (3 << STA_KEY_FLG_KEYID_POS),
STA_KEY_NOT_VALID = BIT(11), STA_KEY_NOT_VALID = BIT(11),
STA_KEY_FLG_WEP_13BYTES = BIT(12), STA_KEY_FLG_WEP_13BYTES = BIT(12),
STA_KEY_FLG_KEY_32BYTES = BIT(12),
STA_KEY_MULTICAST = BIT(14), STA_KEY_MULTICAST = BIT(14),
STA_KEY_MFP = BIT(15), STA_KEY_MFP = BIT(15),
}; };
...@@ -388,7 +392,6 @@ struct iwl_mvm_add_sta_cmd { ...@@ -388,7 +392,6 @@ struct iwl_mvm_add_sta_cmd {
* @key_offset: key offset in key storage * @key_offset: key offset in key storage
* @key_flags: type %iwl_sta_key_flag * @key_flags: type %iwl_sta_key_flag
* @key: key material data * @key: key material data
* @key2: key material data
* @rx_secur_seq_cnt: RX security sequence counter for the key * @rx_secur_seq_cnt: RX security sequence counter for the key
* @tkip_rx_tsc_byte2: TSC[2] for key mix ph1 detection * @tkip_rx_tsc_byte2: TSC[2] for key mix ph1 detection
* @tkip_rx_ttak: 10-byte unicast TKIP TTAK for Rx * @tkip_rx_ttak: 10-byte unicast TKIP TTAK for Rx
...@@ -397,8 +400,7 @@ struct iwl_mvm_add_sta_key_cmd { ...@@ -397,8 +400,7 @@ struct iwl_mvm_add_sta_key_cmd {
u8 sta_id; u8 sta_id;
u8 key_offset; u8 key_offset;
__le16 key_flags; __le16 key_flags;
u8 key[16]; u8 key[32];
u8 key2[16];
u8 rx_secur_seq_cnt[16]; u8 rx_secur_seq_cnt[16];
u8 tkip_rx_tsc_byte2; u8 tkip_rx_tsc_byte2;
u8 reserved; u8 reserved;
......
...@@ -137,17 +137,32 @@ enum iwl_tx_pm_timeouts { ...@@ -137,17 +137,32 @@ enum iwl_tx_pm_timeouts {
PM_FRAME_ASSOC = 3, PM_FRAME_ASSOC = 3,
}; };
/*
* TX command security control
*/
#define TX_CMD_SEC_WEP 0x01
#define TX_CMD_SEC_CCM 0x02
#define TX_CMD_SEC_TKIP 0x03
#define TX_CMD_SEC_EXT 0x04
#define TX_CMD_SEC_MSK 0x07 #define TX_CMD_SEC_MSK 0x07
#define TX_CMD_SEC_WEP_KEY_IDX_POS 6 #define TX_CMD_SEC_WEP_KEY_IDX_POS 6
#define TX_CMD_SEC_WEP_KEY_IDX_MSK 0xc0 #define TX_CMD_SEC_WEP_KEY_IDX_MSK 0xc0
#define TX_CMD_SEC_KEY128 0x08
/**
* enum iwl_tx_cmd_sec_ctrl - bitmasks for security control in TX command
* @TX_CMD_SEC_WEP: WEP encryption algorithm.
* @TX_CMD_SEC_CCM: CCM encryption algorithm.
* @TX_CMD_SEC_TKIP: TKIP encryption algorithm.
* @TX_CMD_SEC_EXT: extended cipher algorithm.
* @TX_CMD_SEC_GCMP: GCMP encryption algorithm.
* @TX_CMD_SEC_KEY128: set for 104 bits WEP key.
* @TC_CMD_SEC_KEY_FROM_TABLE: for a non-WEP key, set if the key should be taken
* from the table instead of from the TX command.
* If the key is taken from the key table its index should be given by the
* first byte of the TX command key field.
*/
enum iwl_tx_cmd_sec_ctrl {
TX_CMD_SEC_WEP = 0x01,
TX_CMD_SEC_CCM = 0x02,
TX_CMD_SEC_TKIP = 0x03,
TX_CMD_SEC_EXT = 0x04,
TX_CMD_SEC_GCMP = 0x05,
TX_CMD_SEC_KEY128 = 0x08,
TC_CMD_SEC_KEY_FROM_TABLE = 0x08,
};
/* TODO: how does these values are OK with only 16 bit variable??? */ /* TODO: how does these values are OK with only 16 bit variable??? */
/* /*
......
...@@ -465,11 +465,20 @@ int iwl_mvm_mac_setup_register(struct iwl_mvm *mvm) ...@@ -465,11 +465,20 @@ int iwl_mvm_mac_setup_register(struct iwl_mvm *mvm)
hw->uapsd_queues = IWL_MVM_UAPSD_QUEUES; hw->uapsd_queues = IWL_MVM_UAPSD_QUEUES;
hw->uapsd_max_sp_len = IWL_UAPSD_MAX_SP; hw->uapsd_max_sp_len = IWL_UAPSD_MAX_SP;
BUILD_BUG_ON(ARRAY_SIZE(mvm->ciphers) < ARRAY_SIZE(mvm_ciphers) + 2); BUILD_BUG_ON(ARRAY_SIZE(mvm->ciphers) < ARRAY_SIZE(mvm_ciphers) + 4);
memcpy(mvm->ciphers, mvm_ciphers, sizeof(mvm_ciphers)); memcpy(mvm->ciphers, mvm_ciphers, sizeof(mvm_ciphers));
hw->wiphy->n_cipher_suites = ARRAY_SIZE(mvm_ciphers); hw->wiphy->n_cipher_suites = ARRAY_SIZE(mvm_ciphers);
hw->wiphy->cipher_suites = mvm->ciphers; hw->wiphy->cipher_suites = mvm->ciphers;
if (iwl_mvm_has_new_rx_api(mvm)) {
mvm->ciphers[hw->wiphy->n_cipher_suites] =
WLAN_CIPHER_SUITE_GCMP;
hw->wiphy->n_cipher_suites++;
mvm->ciphers[hw->wiphy->n_cipher_suites] =
WLAN_CIPHER_SUITE_GCMP_256;
hw->wiphy->n_cipher_suites++;
}
/* /*
* Enable 11w if advertised by firmware and software crypto * Enable 11w if advertised by firmware and software crypto
* is not enabled (as the firmware will interpret some mgmt * is not enabled (as the firmware will interpret some mgmt
...@@ -2721,6 +2730,8 @@ static int iwl_mvm_mac_set_key(struct ieee80211_hw *hw, ...@@ -2721,6 +2730,8 @@ static int iwl_mvm_mac_set_key(struct ieee80211_hw *hw,
key->flags |= IEEE80211_KEY_FLAG_PUT_IV_SPACE; key->flags |= IEEE80211_KEY_FLAG_PUT_IV_SPACE;
break; break;
case WLAN_CIPHER_SUITE_CCMP: case WLAN_CIPHER_SUITE_CCMP:
case WLAN_CIPHER_SUITE_GCMP:
case WLAN_CIPHER_SUITE_GCMP_256:
key->flags |= IEEE80211_KEY_FLAG_PUT_IV_SPACE; key->flags |= IEEE80211_KEY_FLAG_PUT_IV_SPACE;
break; break;
case WLAN_CIPHER_SUITE_AES_CMAC: case WLAN_CIPHER_SUITE_AES_CMAC:
...@@ -2782,7 +2793,8 @@ static int iwl_mvm_mac_set_key(struct ieee80211_hw *hw, ...@@ -2782,7 +2793,8 @@ static int iwl_mvm_mac_set_key(struct ieee80211_hw *hw,
sta && iwl_mvm_has_new_rx_api(mvm) && sta && iwl_mvm_has_new_rx_api(mvm) &&
key->flags & IEEE80211_KEY_FLAG_PAIRWISE && key->flags & IEEE80211_KEY_FLAG_PAIRWISE &&
(key->cipher == WLAN_CIPHER_SUITE_CCMP || (key->cipher == WLAN_CIPHER_SUITE_CCMP ||
key->cipher == WLAN_CIPHER_SUITE_GCMP)) { key->cipher == WLAN_CIPHER_SUITE_GCMP ||
key->cipher == WLAN_CIPHER_SUITE_GCMP_256)) {
struct ieee80211_key_seq seq; struct ieee80211_key_seq seq;
int tid, q; int tid, q;
...@@ -2836,7 +2848,8 @@ static int iwl_mvm_mac_set_key(struct ieee80211_hw *hw, ...@@ -2836,7 +2848,8 @@ static int iwl_mvm_mac_set_key(struct ieee80211_hw *hw,
if (sta && iwl_mvm_has_new_rx_api(mvm) && if (sta && iwl_mvm_has_new_rx_api(mvm) &&
key->flags & IEEE80211_KEY_FLAG_PAIRWISE && key->flags & IEEE80211_KEY_FLAG_PAIRWISE &&
(key->cipher == WLAN_CIPHER_SUITE_CCMP || (key->cipher == WLAN_CIPHER_SUITE_CCMP ||
key->cipher == WLAN_CIPHER_SUITE_GCMP)) { key->cipher == WLAN_CIPHER_SUITE_GCMP ||
key->cipher == WLAN_CIPHER_SUITE_GCMP_256)) {
mvmsta = iwl_mvm_sta_from_mac80211(sta); mvmsta = iwl_mvm_sta_from_mac80211(sta);
ptk_pn = rcu_dereference_protected( ptk_pn = rcu_dereference_protected(
mvmsta->ptk_pn[keyidx], mvmsta->ptk_pn[keyidx],
......
...@@ -707,6 +707,7 @@ enum iwl_mvm_queue_status { ...@@ -707,6 +707,7 @@ enum iwl_mvm_queue_status {
}; };
#define IWL_MVM_DQA_QUEUE_TIMEOUT (5 * HZ) #define IWL_MVM_DQA_QUEUE_TIMEOUT (5 * HZ)
#define IWL_MVM_NUM_CIPHERS 8
struct iwl_mvm { struct iwl_mvm {
/* for logger access */ /* for logger access */
...@@ -1015,7 +1016,7 @@ struct iwl_mvm { ...@@ -1015,7 +1016,7 @@ struct iwl_mvm {
struct iwl_mvm_shared_mem_cfg shared_mem_cfg; struct iwl_mvm_shared_mem_cfg shared_mem_cfg;
u32 ciphers[6]; u32 ciphers[IWL_MVM_NUM_CIPHERS];
struct iwl_mvm_tof_data tof_data; struct iwl_mvm_tof_data tof_data;
struct ieee80211_vif *nan_vif; struct ieee80211_vif *nan_vif;
......
...@@ -2243,6 +2243,13 @@ static int iwl_mvm_send_sta_key(struct iwl_mvm *mvm, ...@@ -2243,6 +2243,13 @@ static int iwl_mvm_send_sta_key(struct iwl_mvm *mvm,
key_flags |= cpu_to_le16(STA_KEY_FLG_WEP); key_flags |= cpu_to_le16(STA_KEY_FLG_WEP);
memcpy(cmd.key + 3, keyconf->key, keyconf->keylen); memcpy(cmd.key + 3, keyconf->key, keyconf->keylen);
break; break;
case WLAN_CIPHER_SUITE_GCMP_256:
key_flags |= cpu_to_le16(STA_KEY_FLG_KEY_32BYTES);
/* fall through */
case WLAN_CIPHER_SUITE_GCMP:
key_flags |= cpu_to_le16(STA_KEY_FLG_GCMP);
memcpy(cmd.key, keyconf->key, keyconf->keylen);
break;
default: default:
key_flags |= cpu_to_le16(STA_KEY_FLG_EXT); key_flags |= cpu_to_le16(STA_KEY_FLG_EXT);
memcpy(cmd.key, keyconf->key, keyconf->keylen); memcpy(cmd.key, keyconf->key, keyconf->keylen);
...@@ -2363,6 +2370,8 @@ static int __iwl_mvm_set_sta_key(struct iwl_mvm *mvm, ...@@ -2363,6 +2370,8 @@ static int __iwl_mvm_set_sta_key(struct iwl_mvm *mvm,
case WLAN_CIPHER_SUITE_CCMP: case WLAN_CIPHER_SUITE_CCMP:
case WLAN_CIPHER_SUITE_WEP40: case WLAN_CIPHER_SUITE_WEP40:
case WLAN_CIPHER_SUITE_WEP104: case WLAN_CIPHER_SUITE_WEP104:
case WLAN_CIPHER_SUITE_GCMP:
case WLAN_CIPHER_SUITE_GCMP_256:
ret = iwl_mvm_send_sta_key(mvm, mvm_sta, keyconf, mcast, ret = iwl_mvm_send_sta_key(mvm, mvm_sta, keyconf, mcast,
0, NULL, 0, key_offset); 0, NULL, 0, key_offset);
break; break;
......
...@@ -388,6 +388,23 @@ void iwl_mvm_set_tx_cmd_rate(struct iwl_mvm *mvm, struct iwl_tx_cmd *tx_cmd, ...@@ -388,6 +388,23 @@ void iwl_mvm_set_tx_cmd_rate(struct iwl_mvm *mvm, struct iwl_tx_cmd *tx_cmd,
tx_cmd->rate_n_flags = cpu_to_le32((u32)rate_plcp | rate_flags); tx_cmd->rate_n_flags = cpu_to_le32((u32)rate_plcp | rate_flags);
} }
static inline void iwl_mvm_set_tx_cmd_pn(struct ieee80211_tx_info *info,
u8 *crypto_hdr)
{
struct ieee80211_key_conf *keyconf = info->control.hw_key;
u64 pn;
pn = atomic64_inc_return(&keyconf->tx_pn);
crypto_hdr[0] = pn;
crypto_hdr[2] = 0;
crypto_hdr[3] = 0x20 | (keyconf->keyidx << 6);
crypto_hdr[1] = pn >> 8;
crypto_hdr[4] = pn >> 16;
crypto_hdr[5] = pn >> 24;
crypto_hdr[6] = pn >> 32;
crypto_hdr[7] = pn >> 40;
}
/* /*
* Sets the fields in the Tx cmd that are crypto related * Sets the fields in the Tx cmd that are crypto related
*/ */
...@@ -405,15 +422,7 @@ static void iwl_mvm_set_tx_cmd_crypto(struct iwl_mvm *mvm, ...@@ -405,15 +422,7 @@ static void iwl_mvm_set_tx_cmd_crypto(struct iwl_mvm *mvm,
case WLAN_CIPHER_SUITE_CCMP: case WLAN_CIPHER_SUITE_CCMP:
case WLAN_CIPHER_SUITE_CCMP_256: case WLAN_CIPHER_SUITE_CCMP_256:
iwl_mvm_set_tx_cmd_ccmp(info, tx_cmd); iwl_mvm_set_tx_cmd_ccmp(info, tx_cmd);
pn = atomic64_inc_return(&keyconf->tx_pn); iwl_mvm_set_tx_cmd_pn(info, crypto_hdr);
crypto_hdr[0] = pn;
crypto_hdr[2] = 0;
crypto_hdr[3] = 0x20 | (keyconf->keyidx << 6);
crypto_hdr[1] = pn >> 8;
crypto_hdr[4] = pn >> 16;
crypto_hdr[5] = pn >> 24;
crypto_hdr[6] = pn >> 32;
crypto_hdr[7] = pn >> 40;
break; break;
case WLAN_CIPHER_SUITE_TKIP: case WLAN_CIPHER_SUITE_TKIP:
...@@ -433,6 +442,18 @@ static void iwl_mvm_set_tx_cmd_crypto(struct iwl_mvm *mvm, ...@@ -433,6 +442,18 @@ static void iwl_mvm_set_tx_cmd_crypto(struct iwl_mvm *mvm,
memcpy(&tx_cmd->key[3], keyconf->key, keyconf->keylen); memcpy(&tx_cmd->key[3], keyconf->key, keyconf->keylen);
break; break;
case WLAN_CIPHER_SUITE_GCMP:
case WLAN_CIPHER_SUITE_GCMP_256:
/* TODO: Taking the key from the table might introduce a race
* when PTK rekeying is done, having an old packets with a PN
* based on the old key but the message encrypted with a new
* one.
* Need to handle this.
*/
tx_cmd->sec_ctl |= TX_CMD_SEC_GCMP | TC_CMD_SEC_KEY_FROM_TABLE;
tx_cmd->key[0] = keyconf->hw_key_idx;
iwl_mvm_set_tx_cmd_pn(info, crypto_hdr);
break;
default: default:
tx_cmd->sec_ctl |= TX_CMD_SEC_EXT; tx_cmd->sec_ctl |= TX_CMD_SEC_EXT;
} }
......
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