aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/net
diff options
context:
space:
mode:
authorAyala Beker <ayala.beker@intel.com>2016-04-11 04:37:38 -0400
committerLuca Coelho <luciano.coelho@intel.com>2016-08-29 16:35:06 -0400
commit8e160ab83a32a16cd45d82778aca1ec3e51b802b (patch)
tree7aee84ed70ba917efa2fffdd4c7b4a1461fac208 /drivers/net
parentf1ae02b186d9b37ee621c7e922ecf5db96f5fb5c (diff)
iwlwifi: mvm: support GMAC protocol
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>
Diffstat (limited to 'drivers/net')
-rw-r--r--drivers/net/wireless/intel/iwlwifi/mvm/fw-api-sta.h31
-rw-r--r--drivers/net/wireless/intel/iwlwifi/mvm/mac80211.c18
-rw-r--r--drivers/net/wireless/intel/iwlwifi/mvm/mvm.h2
-rw-r--r--drivers/net/wireless/intel/iwlwifi/mvm/sta.c42
4 files changed, 76 insertions, 17 deletions
diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/fw-api-sta.h b/drivers/net/wireless/intel/iwlwifi/mvm/fw-api-sta.h
index d1c4fb849111..6c8e3ca79323 100644
--- a/drivers/net/wireless/intel/iwlwifi/mvm/fw-api-sta.h
+++ b/drivers/net/wireless/intel/iwlwifi/mvm/fw-api-sta.h
@@ -433,25 +433,42 @@ struct iwl_mvm_rm_sta_cmd {
433} __packed; /* REMOVE_STA_CMD_API_S_VER_2 */ 433} __packed; /* REMOVE_STA_CMD_API_S_VER_2 */
434 434
435/** 435/**
436 * struct iwl_mvm_mgmt_mcast_key_cmd_v1
437 * ( MGMT_MCAST_KEY = 0x1f )
438 * @ctrl_flags: %iwl_sta_key_flag
439 * @igtk:
440 * @k1: unused
441 * @k2: unused
442 * @sta_id: station ID that support IGTK
443 * @key_id:
444 * @receive_seq_cnt: initial RSC/PN needed for replay check
445 */
446struct iwl_mvm_mgmt_mcast_key_cmd_v1 {
447 __le32 ctrl_flags;
448 u8 igtk[16];
449 u8 k1[16];
450 u8 k2[16];
451 __le32 key_id;
452 __le32 sta_id;
453 __le64 receive_seq_cnt;
454} __packed; /* SEC_MGMT_MULTICAST_KEY_CMD_API_S_VER_1 */
455
456/**
436 * struct iwl_mvm_mgmt_mcast_key_cmd 457 * struct iwl_mvm_mgmt_mcast_key_cmd
437 * ( MGMT_MCAST_KEY = 0x1f ) 458 * ( MGMT_MCAST_KEY = 0x1f )
438 * @ctrl_flags: %iwl_sta_key_flag 459 * @ctrl_flags: %iwl_sta_key_flag
439 * @IGTK: 460 * @igtk: IGTK master key
440 * @K1: unused
441 * @K2: unused
442 * @sta_id: station ID that support IGTK 461 * @sta_id: station ID that support IGTK
443 * @key_id: 462 * @key_id:
444 * @receive_seq_cnt: initial RSC/PN needed for replay check 463 * @receive_seq_cnt: initial RSC/PN needed for replay check
445 */ 464 */
446struct iwl_mvm_mgmt_mcast_key_cmd { 465struct iwl_mvm_mgmt_mcast_key_cmd {
447 __le32 ctrl_flags; 466 __le32 ctrl_flags;
448 u8 IGTK[16]; 467 u8 igtk[32];
449 u8 K1[16];
450 u8 K2[16];
451 __le32 key_id; 468 __le32 key_id;
452 __le32 sta_id; 469 __le32 sta_id;
453 __le64 receive_seq_cnt; 470 __le64 receive_seq_cnt;
454} __packed; /* SEC_MGMT_MULTICAST_KEY_CMD_API_S_VER_1 */ 471} __packed; /* SEC_MGMT_MULTICAST_KEY_CMD_API_S_VER_2 */
455 472
456struct iwl_mvm_wep_key { 473struct iwl_mvm_wep_key {
457 u8 key_index; 474 u8 key_index;
diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/mac80211.c b/drivers/net/wireless/intel/iwlwifi/mvm/mac80211.c
index 6d6064534d59..f5290c4568ad 100644
--- a/drivers/net/wireless/intel/iwlwifi/mvm/mac80211.c
+++ b/drivers/net/wireless/intel/iwlwifi/mvm/mac80211.c
@@ -465,7 +465,7 @@ int iwl_mvm_mac_setup_register(struct iwl_mvm *mvm)
465 hw->uapsd_queues = IWL_MVM_UAPSD_QUEUES; 465 hw->uapsd_queues = IWL_MVM_UAPSD_QUEUES;
466 hw->uapsd_max_sp_len = IWL_UAPSD_MAX_SP; 466 hw->uapsd_max_sp_len = IWL_UAPSD_MAX_SP;
467 467
468 BUILD_BUG_ON(ARRAY_SIZE(mvm->ciphers) < ARRAY_SIZE(mvm_ciphers) + 4); 468 BUILD_BUG_ON(ARRAY_SIZE(mvm->ciphers) < ARRAY_SIZE(mvm_ciphers) + 6);
469 memcpy(mvm->ciphers, mvm_ciphers, sizeof(mvm_ciphers)); 469 memcpy(mvm->ciphers, mvm_ciphers, sizeof(mvm_ciphers));
470 hw->wiphy->n_cipher_suites = ARRAY_SIZE(mvm_ciphers); 470 hw->wiphy->n_cipher_suites = ARRAY_SIZE(mvm_ciphers);
471 hw->wiphy->cipher_suites = mvm->ciphers; 471 hw->wiphy->cipher_suites = mvm->ciphers;
@@ -490,6 +490,14 @@ int iwl_mvm_mac_setup_register(struct iwl_mvm *mvm)
490 mvm->ciphers[hw->wiphy->n_cipher_suites] = 490 mvm->ciphers[hw->wiphy->n_cipher_suites] =
491 WLAN_CIPHER_SUITE_AES_CMAC; 491 WLAN_CIPHER_SUITE_AES_CMAC;
492 hw->wiphy->n_cipher_suites++; 492 hw->wiphy->n_cipher_suites++;
493 if (iwl_mvm_has_new_rx_api(mvm)) {
494 mvm->ciphers[hw->wiphy->n_cipher_suites] =
495 WLAN_CIPHER_SUITE_BIP_GMAC_128;
496 hw->wiphy->n_cipher_suites++;
497 mvm->ciphers[hw->wiphy->n_cipher_suites] =
498 WLAN_CIPHER_SUITE_BIP_GMAC_256;
499 hw->wiphy->n_cipher_suites++;
500 }
493 } 501 }
494 502
495 /* currently FW API supports only one optional cipher scheme */ 503 /* currently FW API supports only one optional cipher scheme */
@@ -2746,6 +2754,8 @@ static int iwl_mvm_mac_set_key(struct ieee80211_hw *hw,
2746 key->flags |= IEEE80211_KEY_FLAG_PUT_IV_SPACE; 2754 key->flags |= IEEE80211_KEY_FLAG_PUT_IV_SPACE;
2747 break; 2755 break;
2748 case WLAN_CIPHER_SUITE_AES_CMAC: 2756 case WLAN_CIPHER_SUITE_AES_CMAC:
2757 case WLAN_CIPHER_SUITE_BIP_GMAC_128:
2758 case WLAN_CIPHER_SUITE_BIP_GMAC_256:
2749 WARN_ON_ONCE(!ieee80211_hw_check(hw, MFP_CAPABLE)); 2759 WARN_ON_ONCE(!ieee80211_hw_check(hw, MFP_CAPABLE));
2750 break; 2760 break;
2751 case WLAN_CIPHER_SUITE_WEP40: 2761 case WLAN_CIPHER_SUITE_WEP40:
@@ -2779,9 +2789,11 @@ static int iwl_mvm_mac_set_key(struct ieee80211_hw *hw,
2779 * GTK on AP interface is a TX-only key, return 0; 2789 * GTK on AP interface is a TX-only key, return 0;
2780 * on IBSS they're per-station and because we're lazy 2790 * on IBSS they're per-station and because we're lazy
2781 * we don't support them for RX, so do the same. 2791 * we don't support them for RX, so do the same.
2782 * CMAC in AP/IBSS modes must be done in software. 2792 * CMAC/GMAC in AP/IBSS modes must be done in software.
2783 */ 2793 */
2784 if (key->cipher == WLAN_CIPHER_SUITE_AES_CMAC) 2794 if (key->cipher == WLAN_CIPHER_SUITE_AES_CMAC ||
2795 key->cipher == WLAN_CIPHER_SUITE_BIP_GMAC_128 ||
2796 key->cipher == WLAN_CIPHER_SUITE_BIP_GMAC_256)
2785 ret = -EOPNOTSUPP; 2797 ret = -EOPNOTSUPP;
2786 else 2798 else
2787 ret = 0; 2799 ret = 0;
diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/mvm.h b/drivers/net/wireless/intel/iwlwifi/mvm/mvm.h
index b4fc86d5d7ef..0b0855ae092e 100644
--- a/drivers/net/wireless/intel/iwlwifi/mvm/mvm.h
+++ b/drivers/net/wireless/intel/iwlwifi/mvm/mvm.h
@@ -707,7 +707,7 @@ enum iwl_mvm_queue_status {
707}; 707};
708 708
709#define IWL_MVM_DQA_QUEUE_TIMEOUT (5 * HZ) 709#define IWL_MVM_DQA_QUEUE_TIMEOUT (5 * HZ)
710#define IWL_MVM_NUM_CIPHERS 8 710#define IWL_MVM_NUM_CIPHERS 10
711 711
712struct iwl_mvm { 712struct iwl_mvm {
713 /* for logger access */ 713 /* for logger access */
diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/sta.c b/drivers/net/wireless/intel/iwlwifi/mvm/sta.c
index 3130b9c68a74..5960eb4fdf1f 100644
--- a/drivers/net/wireless/intel/iwlwifi/mvm/sta.c
+++ b/drivers/net/wireless/intel/iwlwifi/mvm/sta.c
@@ -2412,9 +2412,15 @@ static int iwl_mvm_send_sta_igtk(struct iwl_mvm *mvm,
2412 struct iwl_mvm_mgmt_mcast_key_cmd igtk_cmd = {}; 2412 struct iwl_mvm_mgmt_mcast_key_cmd igtk_cmd = {};
2413 2413
2414 /* verify the key details match the required command's expectations */ 2414 /* verify the key details match the required command's expectations */
2415 if (WARN_ON((keyconf->cipher != WLAN_CIPHER_SUITE_AES_CMAC) || 2415 if (WARN_ON((keyconf->flags & IEEE80211_KEY_FLAG_PAIRWISE) ||
2416 (keyconf->flags & IEEE80211_KEY_FLAG_PAIRWISE) || 2416 (keyconf->keyidx != 4 && keyconf->keyidx != 5) ||
2417 (keyconf->keyidx != 4 && keyconf->keyidx != 5))) 2417 (keyconf->cipher != WLAN_CIPHER_SUITE_AES_CMAC &&
2418 keyconf->cipher != WLAN_CIPHER_SUITE_BIP_GMAC_128 &&
2419 keyconf->cipher != WLAN_CIPHER_SUITE_BIP_GMAC_256)))
2420 return -EINVAL;
2421
2422 if (WARN_ON(!iwl_mvm_has_new_rx_api(mvm) &&
2423 keyconf->cipher != WLAN_CIPHER_SUITE_AES_CMAC))
2418 return -EINVAL; 2424 return -EINVAL;
2419 2425
2420 igtk_cmd.key_id = cpu_to_le32(keyconf->keyidx); 2426 igtk_cmd.key_id = cpu_to_le32(keyconf->keyidx);
@@ -2430,11 +2436,18 @@ static int iwl_mvm_send_sta_igtk(struct iwl_mvm *mvm,
2430 case WLAN_CIPHER_SUITE_AES_CMAC: 2436 case WLAN_CIPHER_SUITE_AES_CMAC:
2431 igtk_cmd.ctrl_flags |= cpu_to_le32(STA_KEY_FLG_CCM); 2437 igtk_cmd.ctrl_flags |= cpu_to_le32(STA_KEY_FLG_CCM);
2432 break; 2438 break;
2439 case WLAN_CIPHER_SUITE_BIP_GMAC_128:
2440 case WLAN_CIPHER_SUITE_BIP_GMAC_256:
2441 igtk_cmd.ctrl_flags |= cpu_to_le32(STA_KEY_FLG_GCMP);
2442 break;
2433 default: 2443 default:
2434 return -EINVAL; 2444 return -EINVAL;
2435 } 2445 }
2436 2446
2437 memcpy(igtk_cmd.IGTK, keyconf->key, keyconf->keylen); 2447 memcpy(igtk_cmd.igtk, keyconf->key, keyconf->keylen);
2448 if (keyconf->cipher == WLAN_CIPHER_SUITE_BIP_GMAC_256)
2449 igtk_cmd.ctrl_flags |=
2450 cpu_to_le32(STA_KEY_FLG_KEY_32BYTES);
2438 ieee80211_get_key_rx_seq(keyconf, 0, &seq); 2451 ieee80211_get_key_rx_seq(keyconf, 0, &seq);
2439 pn = seq.aes_cmac.pn; 2452 pn = seq.aes_cmac.pn;
2440 igtk_cmd.receive_seq_cnt = cpu_to_le64(((u64) pn[5] << 0) | 2453 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,
2449 remove_key ? "removing" : "installing", 2462 remove_key ? "removing" : "installing",
2450 igtk_cmd.sta_id); 2463 igtk_cmd.sta_id);
2451 2464
2465 if (!iwl_mvm_has_new_rx_api(mvm)) {
2466 struct iwl_mvm_mgmt_mcast_key_cmd_v1 igtk_cmd_v1 = {
2467 .ctrl_flags = igtk_cmd.ctrl_flags,
2468 .key_id = igtk_cmd.key_id,
2469 .sta_id = igtk_cmd.sta_id,
2470 .receive_seq_cnt = igtk_cmd.receive_seq_cnt
2471 };
2472
2473 memcpy(igtk_cmd_v1.igtk, igtk_cmd.igtk,
2474 ARRAY_SIZE(igtk_cmd_v1.igtk));
2475 return iwl_mvm_send_cmd_pdu(mvm, MGMT_MCAST_KEY, 0,
2476 sizeof(igtk_cmd_v1), &igtk_cmd_v1);
2477 }
2452 return iwl_mvm_send_cmd_pdu(mvm, MGMT_MCAST_KEY, 0, 2478 return iwl_mvm_send_cmd_pdu(mvm, MGMT_MCAST_KEY, 0,
2453 sizeof(igtk_cmd), &igtk_cmd); 2479 sizeof(igtk_cmd), &igtk_cmd);
2454} 2480}
@@ -2573,7 +2599,9 @@ int iwl_mvm_set_sta_key(struct iwl_mvm *mvm,
2573 } 2599 }
2574 sta_id = mvm_sta->sta_id; 2600 sta_id = mvm_sta->sta_id;
2575 2601
2576 if (keyconf->cipher == WLAN_CIPHER_SUITE_AES_CMAC) { 2602 if (keyconf->cipher == WLAN_CIPHER_SUITE_AES_CMAC ||
2603 keyconf->cipher == WLAN_CIPHER_SUITE_BIP_GMAC_128 ||
2604 keyconf->cipher == WLAN_CIPHER_SUITE_BIP_GMAC_256) {
2577 ret = iwl_mvm_send_sta_igtk(mvm, keyconf, sta_id, false); 2605 ret = iwl_mvm_send_sta_igtk(mvm, keyconf, sta_id, false);
2578 goto end; 2606 goto end;
2579 } 2607 }
@@ -2659,7 +2687,9 @@ int iwl_mvm_remove_sta_key(struct iwl_mvm *mvm,
2659 IWL_DEBUG_WEP(mvm, "mvm remove dynamic key: idx=%d sta=%d\n", 2687 IWL_DEBUG_WEP(mvm, "mvm remove dynamic key: idx=%d sta=%d\n",
2660 keyconf->keyidx, sta_id); 2688 keyconf->keyidx, sta_id);
2661 2689
2662 if (keyconf->cipher == WLAN_CIPHER_SUITE_AES_CMAC) 2690 if (keyconf->cipher == WLAN_CIPHER_SUITE_AES_CMAC ||
2691 keyconf->cipher == WLAN_CIPHER_SUITE_BIP_GMAC_128 ||
2692 keyconf->cipher == WLAN_CIPHER_SUITE_BIP_GMAC_256)
2663 return iwl_mvm_send_sta_igtk(mvm, keyconf, sta_id, true); 2693 return iwl_mvm_send_sta_igtk(mvm, keyconf, sta_id, true);
2664 2694
2665 if (!__test_and_clear_bit(keyconf->hw_key_idx, mvm->fw_key_table)) { 2695 if (!__test_and_clear_bit(keyconf->hw_key_idx, mvm->fw_key_table)) {