iwlwifi: mvm: support GMAC protocol
authorAyala Beker <ayala.beker@intel.com>
Mon, 11 Apr 2016 08:37:38 +0000 (11:37 +0300)
committerLuca Coelho <luciano.coelho@intel.com>
Mon, 29 Aug 2016 20:35:06 +0000 (23:35 +0300)
Add support for installing and removing GMAC key
for newer FW versions that support GCM and MFP.
GMAC provides authentication and integrity for multicast management
frames.

Firmware API was changed, update the driver accordingly.

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/mac80211.c
drivers/net/wireless/intel/iwlwifi/mvm/mvm.h
drivers/net/wireless/intel/iwlwifi/mvm/sta.c

index d1c4fb84911123cb828a94c680ac801329809cb5..6c8e3ca79323944cfd5960ee759291fe7f93ad3d 100644 (file)
@@ -432,26 +432,43 @@ struct iwl_mvm_rm_sta_cmd {
        u8 reserved[3];
 } __packed; /* REMOVE_STA_CMD_API_S_VER_2 */
 
+/**
+ * struct iwl_mvm_mgmt_mcast_key_cmd_v1
+ * ( MGMT_MCAST_KEY = 0x1f )
+ * @ctrl_flags: %iwl_sta_key_flag
+ * @igtk:
+ * @k1: unused
+ * @k2: unused
+ * @sta_id: station ID that support IGTK
+ * @key_id:
+ * @receive_seq_cnt: initial RSC/PN needed for replay check
+ */
+struct iwl_mvm_mgmt_mcast_key_cmd_v1 {
+       __le32 ctrl_flags;
+       u8 igtk[16];
+       u8 k1[16];
+       u8 k2[16];
+       __le32 key_id;
+       __le32 sta_id;
+       __le64 receive_seq_cnt;
+} __packed; /* SEC_MGMT_MULTICAST_KEY_CMD_API_S_VER_1 */
+
 /**
  * struct iwl_mvm_mgmt_mcast_key_cmd
  * ( MGMT_MCAST_KEY = 0x1f )
  * @ctrl_flags: %iwl_sta_key_flag
- * @IGTK:
- * @K1: unused
- * @K2: unused
+ * @igtk: IGTK master key
  * @sta_id: station ID that support IGTK
  * @key_id:
  * @receive_seq_cnt: initial RSC/PN needed for replay check
  */
 struct iwl_mvm_mgmt_mcast_key_cmd {
        __le32 ctrl_flags;
-       u8 IGTK[16];
-       u8 K1[16];
-       u8 K2[16];
+       u8 igtk[32];
        __le32 key_id;
        __le32 sta_id;
        __le64 receive_seq_cnt;
-} __packed; /* SEC_MGMT_MULTICAST_KEY_CMD_API_S_VER_1 */
+} __packed; /* SEC_MGMT_MULTICAST_KEY_CMD_API_S_VER_2 */
 
 struct iwl_mvm_wep_key {
        u8 key_index;
index 6d6064534d590c76f71444bfa7f3b0c9163ad003..f5290c4568ad8273c443c36d0568a0fd8856cf7a 100644 (file)
@@ -465,7 +465,7 @@ 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) + 4);
+       BUILD_BUG_ON(ARRAY_SIZE(mvm->ciphers) < ARRAY_SIZE(mvm_ciphers) + 6);
        memcpy(mvm->ciphers, mvm_ciphers, sizeof(mvm_ciphers));
        hw->wiphy->n_cipher_suites = ARRAY_SIZE(mvm_ciphers);
        hw->wiphy->cipher_suites = mvm->ciphers;
@@ -490,6 +490,14 @@ int iwl_mvm_mac_setup_register(struct iwl_mvm *mvm)
                mvm->ciphers[hw->wiphy->n_cipher_suites] =
                        WLAN_CIPHER_SUITE_AES_CMAC;
                hw->wiphy->n_cipher_suites++;
+               if (iwl_mvm_has_new_rx_api(mvm)) {
+                       mvm->ciphers[hw->wiphy->n_cipher_suites] =
+                               WLAN_CIPHER_SUITE_BIP_GMAC_128;
+                       hw->wiphy->n_cipher_suites++;
+                       mvm->ciphers[hw->wiphy->n_cipher_suites] =
+                               WLAN_CIPHER_SUITE_BIP_GMAC_256;
+                       hw->wiphy->n_cipher_suites++;
+               }
        }
 
        /* currently FW API supports only one optional cipher scheme */
@@ -2746,6 +2754,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_AES_CMAC:
+       case WLAN_CIPHER_SUITE_BIP_GMAC_128:
+       case WLAN_CIPHER_SUITE_BIP_GMAC_256:
                WARN_ON_ONCE(!ieee80211_hw_check(hw, MFP_CAPABLE));
                break;
        case WLAN_CIPHER_SUITE_WEP40:
@@ -2779,9 +2789,11 @@ static int iwl_mvm_mac_set_key(struct ieee80211_hw *hw,
                         * GTK on AP interface is a TX-only key, return 0;
                         * on IBSS they're per-station and because we're lazy
                         * we don't support them for RX, so do the same.
-                        * CMAC in AP/IBSS modes must be done in software.
+                        * CMAC/GMAC in AP/IBSS modes must be done in software.
                         */
-                       if (key->cipher == WLAN_CIPHER_SUITE_AES_CMAC)
+                       if (key->cipher == WLAN_CIPHER_SUITE_AES_CMAC ||
+                           key->cipher == WLAN_CIPHER_SUITE_BIP_GMAC_128 ||
+                           key->cipher == WLAN_CIPHER_SUITE_BIP_GMAC_256)
                                ret = -EOPNOTSUPP;
                        else
                                ret = 0;
index b4fc86d5d7ef1252cde57cfb872c390d698b7d16..0b0855ae092e3b219fd0ad0a3a587a0f6fe0fb02 100644 (file)
@@ -707,7 +707,7 @@ enum iwl_mvm_queue_status {
 };
 
 #define IWL_MVM_DQA_QUEUE_TIMEOUT      (5 * HZ)
-#define IWL_MVM_NUM_CIPHERS             8
+#define IWL_MVM_NUM_CIPHERS             10
 
 struct iwl_mvm {
        /* for logger access */
index 3130b9c68a7419624f354f8e0656d88326ad8300..5960eb4fdf1f7c0d3747aa798f6a89e3963cebf1 100644 (file)
@@ -2412,9 +2412,15 @@ static int iwl_mvm_send_sta_igtk(struct iwl_mvm *mvm,
        struct iwl_mvm_mgmt_mcast_key_cmd igtk_cmd = {};
 
        /* verify the key details match the required command's expectations */
-       if (WARN_ON((keyconf->cipher != WLAN_CIPHER_SUITE_AES_CMAC) ||
-                   (keyconf->flags & IEEE80211_KEY_FLAG_PAIRWISE) ||
-                   (keyconf->keyidx != 4 && keyconf->keyidx != 5)))
+       if (WARN_ON((keyconf->flags & IEEE80211_KEY_FLAG_PAIRWISE) ||
+                   (keyconf->keyidx != 4 && keyconf->keyidx != 5) ||
+                   (keyconf->cipher != WLAN_CIPHER_SUITE_AES_CMAC &&
+                    keyconf->cipher != WLAN_CIPHER_SUITE_BIP_GMAC_128 &&
+                    keyconf->cipher != WLAN_CIPHER_SUITE_BIP_GMAC_256)))
+               return -EINVAL;
+
+       if (WARN_ON(!iwl_mvm_has_new_rx_api(mvm) &&
+                   keyconf->cipher != WLAN_CIPHER_SUITE_AES_CMAC))
                return -EINVAL;
 
        igtk_cmd.key_id = cpu_to_le32(keyconf->keyidx);
@@ -2430,11 +2436,18 @@ static int iwl_mvm_send_sta_igtk(struct iwl_mvm *mvm,
                case WLAN_CIPHER_SUITE_AES_CMAC:
                        igtk_cmd.ctrl_flags |= cpu_to_le32(STA_KEY_FLG_CCM);
                        break;
+               case WLAN_CIPHER_SUITE_BIP_GMAC_128:
+               case WLAN_CIPHER_SUITE_BIP_GMAC_256:
+                       igtk_cmd.ctrl_flags |= cpu_to_le32(STA_KEY_FLG_GCMP);
+                       break;
                default:
                        return -EINVAL;
                }
 
-               memcpy(igtk_cmd.IGTK, keyconf->key, keyconf->keylen);
+               memcpy(igtk_cmd.igtk, keyconf->key, keyconf->keylen);
+               if (keyconf->cipher == WLAN_CIPHER_SUITE_BIP_GMAC_256)
+                       igtk_cmd.ctrl_flags |=
+                               cpu_to_le32(STA_KEY_FLG_KEY_32BYTES);
                ieee80211_get_key_rx_seq(keyconf, 0, &seq);
                pn = seq.aes_cmac.pn;
                igtk_cmd.receive_seq_cnt = cpu_to_le64(((u64) pn[5] << 0) |
@@ -2449,6 +2462,19 @@ static int iwl_mvm_send_sta_igtk(struct iwl_mvm *mvm,
                       remove_key ? "removing" : "installing",
                       igtk_cmd.sta_id);
 
+       if (!iwl_mvm_has_new_rx_api(mvm)) {
+               struct iwl_mvm_mgmt_mcast_key_cmd_v1 igtk_cmd_v1 = {
+                       .ctrl_flags = igtk_cmd.ctrl_flags,
+                       .key_id = igtk_cmd.key_id,
+                       .sta_id = igtk_cmd.sta_id,
+                       .receive_seq_cnt = igtk_cmd.receive_seq_cnt
+               };
+
+               memcpy(igtk_cmd_v1.igtk, igtk_cmd.igtk,
+                      ARRAY_SIZE(igtk_cmd_v1.igtk));
+               return iwl_mvm_send_cmd_pdu(mvm, MGMT_MCAST_KEY, 0,
+                                           sizeof(igtk_cmd_v1), &igtk_cmd_v1);
+       }
        return iwl_mvm_send_cmd_pdu(mvm, MGMT_MCAST_KEY, 0,
                                    sizeof(igtk_cmd), &igtk_cmd);
 }
@@ -2573,7 +2599,9 @@ int iwl_mvm_set_sta_key(struct iwl_mvm *mvm,
        }
        sta_id = mvm_sta->sta_id;
 
-       if (keyconf->cipher == WLAN_CIPHER_SUITE_AES_CMAC) {
+       if (keyconf->cipher == WLAN_CIPHER_SUITE_AES_CMAC ||
+           keyconf->cipher == WLAN_CIPHER_SUITE_BIP_GMAC_128 ||
+           keyconf->cipher == WLAN_CIPHER_SUITE_BIP_GMAC_256) {
                ret = iwl_mvm_send_sta_igtk(mvm, keyconf, sta_id, false);
                goto end;
        }
@@ -2659,7 +2687,9 @@ int iwl_mvm_remove_sta_key(struct iwl_mvm *mvm,
        IWL_DEBUG_WEP(mvm, "mvm remove dynamic key: idx=%d sta=%d\n",
                      keyconf->keyidx, sta_id);
 
-       if (keyconf->cipher == WLAN_CIPHER_SUITE_AES_CMAC)
+       if (keyconf->cipher == WLAN_CIPHER_SUITE_AES_CMAC ||
+           keyconf->cipher == WLAN_CIPHER_SUITE_BIP_GMAC_128 ||
+           keyconf->cipher == WLAN_CIPHER_SUITE_BIP_GMAC_256)
                return iwl_mvm_send_sta_igtk(mvm, keyconf, sta_id, true);
 
        if (!__test_and_clear_bit(keyconf->hw_key_idx, mvm->fw_key_table)) {