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 d1c4fb8..6c8e3ca 100644 (file)
@@ -433,25 +433,42 @@ struct iwl_mvm_rm_sta_cmd {
 } __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 6d60645..f5290c4 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 b4fc86d..0b0855a 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 3130b9c..5960eb4 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)) {