iwlwifi: mvm: add support for GCMP encryption
authorAyala Beker <ayala.beker@intel.com>
Thu, 7 Apr 2016 13:21:57 +0000 (16:21 +0300)
committerLuca Coelho <luciano.coelho@intel.com>
Tue, 5 Jul 2016 23:07:49 +0000 (02:07 +0300)
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: Ayala Beker <ayala.beker@intel.com>
Signed-off-by: Luca Coelho <luciano.coelho@intel.com>
drivers/net/wireless/intel/iwlwifi/mvm/fw-api-sta.h
drivers/net/wireless/intel/iwlwifi/mvm/fw-api-tx.h
drivers/net/wireless/intel/iwlwifi/mvm/mac80211.c
drivers/net/wireless/intel/iwlwifi/mvm/mvm.h
drivers/net/wireless/intel/iwlwifi/mvm/sta.c
drivers/net/wireless/intel/iwlwifi/mvm/tx.c

index 38b1d045be8ec130680e203a01975b41f0f15dbe..d1c4fb84911123cb828a94c680ac801329809cb5 100644 (file)
@@ -141,6 +141,7 @@ enum iwl_sta_flags {
  * @STA_KEY_FLG_CCM: CCMP encryption algorithm
  * @STA_KEY_FLG_TKIP: TKIP encryption algorithm
  * @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_ENC_UNKNOWN: unknown encryption algorithm
  * @STA_KEY_FLG_EN_MSK: mask for encryption algorithmi value
@@ -149,6 +150,7 @@ enum iwl_sta_flags {
  * @STA_KEY_FLG_KEYID_MSK: the index of the key
  * @STA_KEY_NOT_VALID: key is invalid
  * @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_MFP: key is used for Management Frame Protection
  */
@@ -158,6 +160,7 @@ enum iwl_sta_key_flag {
        STA_KEY_FLG_CCM                 = (2 << 0),
        STA_KEY_FLG_TKIP                = (3 << 0),
        STA_KEY_FLG_EXT                 = (4 << 0),
+       STA_KEY_FLG_GCMP                = (5 << 0),
        STA_KEY_FLG_CMAC                = (6 << 0),
        STA_KEY_FLG_ENC_UNKNOWN         = (7 << 0),
        STA_KEY_FLG_EN_MSK              = (7 << 0),
@@ -167,6 +170,7 @@ enum iwl_sta_key_flag {
        STA_KEY_FLG_KEYID_MSK           = (3 << STA_KEY_FLG_KEYID_POS),
        STA_KEY_NOT_VALID               = BIT(11),
        STA_KEY_FLG_WEP_13BYTES         = BIT(12),
+       STA_KEY_FLG_KEY_32BYTES         = BIT(12),
        STA_KEY_MULTICAST               = BIT(14),
        STA_KEY_MFP                     = BIT(15),
 };
@@ -388,7 +392,6 @@ struct iwl_mvm_add_sta_cmd {
  * @key_offset: key offset in key storage
  * @key_flags: type %iwl_sta_key_flag
  * @key: key material data
- * @key2: key material data
  * @rx_secur_seq_cnt: RX security sequence counter for the key
  * @tkip_rx_tsc_byte2: TSC[2] for key mix ph1 detection
  * @tkip_rx_ttak: 10-byte unicast TKIP TTAK for Rx
@@ -397,8 +400,7 @@ struct iwl_mvm_add_sta_key_cmd {
        u8 sta_id;
        u8 key_offset;
        __le16 key_flags;
-       u8 key[16];
-       u8 key2[16];
+       u8 key[32];
        u8 rx_secur_seq_cnt[16];
        u8 tkip_rx_tsc_byte2;
        u8 reserved;
index ee59511323c1ff71c0bb289dbbd7870208f59b1c..4144623e16168ebf90972d201aa55db07bf0b246 100644 (file)
@@ -137,17 +137,32 @@ enum iwl_tx_pm_timeouts {
        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_WEP_KEY_IDX_POS     6
 #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??? */
 /*
index af1d266d6fe8581b00d10612d16a86e4be6619dc..6b158f0de39d395fc9252cb1c9fb8dbabfa63e85 100644 (file)
@@ -465,11 +465,20 @@ int iwl_mvm_mac_setup_register(struct iwl_mvm *mvm)
        hw->uapsd_queues = IWL_MVM_UAPSD_QUEUES;
        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));
        hw->wiphy->n_cipher_suites = ARRAY_SIZE(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
         * 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,
                key->flags |= IEEE80211_KEY_FLAG_PUT_IV_SPACE;
                break;
        case WLAN_CIPHER_SUITE_CCMP:
+       case WLAN_CIPHER_SUITE_GCMP:
+       case WLAN_CIPHER_SUITE_GCMP_256:
                key->flags |= IEEE80211_KEY_FLAG_PUT_IV_SPACE;
                break;
        case WLAN_CIPHER_SUITE_AES_CMAC:
@@ -2782,7 +2793,8 @@ static int iwl_mvm_mac_set_key(struct ieee80211_hw *hw,
                    sta && iwl_mvm_has_new_rx_api(mvm) &&
                    key->flags & IEEE80211_KEY_FLAG_PAIRWISE &&
                    (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;
                        int tid, q;
 
@@ -2836,7 +2848,8 @@ static int iwl_mvm_mac_set_key(struct ieee80211_hw *hw,
                if (sta && iwl_mvm_has_new_rx_api(mvm) &&
                    key->flags & IEEE80211_KEY_FLAG_PAIRWISE &&
                    (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);
                        ptk_pn = rcu_dereference_protected(
                                                mvmsta->ptk_pn[keyidx],
index 6092af23969f0288bcb5bff16b60ed27d76983d3..e240f198e001293b2d19fc589cb88fb69414ce55 100644 (file)
@@ -707,6 +707,7 @@ enum iwl_mvm_queue_status {
 };
 
 #define IWL_MVM_DQA_QUEUE_TIMEOUT      (5 * HZ)
+#define IWL_MVM_NUM_CIPHERS             8
 
 struct iwl_mvm {
        /* for logger access */
@@ -1015,7 +1016,7 @@ struct iwl_mvm {
 
        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 ieee80211_vif *nan_vif;
index cf0681765ec4e4dfe5c041ba3cb0a9913c8b976d..7321bb6b8d6754a911dbacd270d33fe8effd7c8e 100644 (file)
@@ -2243,6 +2243,13 @@ static int iwl_mvm_send_sta_key(struct iwl_mvm *mvm,
                key_flags |= cpu_to_le16(STA_KEY_FLG_WEP);
                memcpy(cmd.key + 3, keyconf->key, keyconf->keylen);
                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:
                key_flags |= cpu_to_le16(STA_KEY_FLG_EXT);
                memcpy(cmd.key, keyconf->key, keyconf->keylen);
@@ -2363,6 +2370,8 @@ static int __iwl_mvm_set_sta_key(struct iwl_mvm *mvm,
        case WLAN_CIPHER_SUITE_CCMP:
        case WLAN_CIPHER_SUITE_WEP40:
        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,
                                           0, NULL, 0, key_offset);
                break;
index 1f23ceeb2350d3ee44cbd679925752868e1593a1..2373142b0f432ca9e53e4375d93177fcf28269ca 100644 (file)
@@ -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);
 }
 
+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
  */
@@ -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_256:
                iwl_mvm_set_tx_cmd_ccmp(info, tx_cmd);
-               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;
+               iwl_mvm_set_tx_cmd_pn(info, crypto_hdr);
                break;
 
        case WLAN_CIPHER_SUITE_TKIP:
@@ -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);
                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:
                tx_cmd->sec_ctl |= TX_CMD_SEC_EXT;
        }