Commit 5a3d9882 authored by Johannes Berg's avatar Johannes Berg Committed by Wey-Yi Guy

iwlagn: rewrite HW crypto

As I just discovered while doing WoWLAN, HW crypto
is done wrong for GTKs: they should be programmed
for the AP station ID (in the managed mode case)
and the HW can actually deal with multiple group
keys per station as well (which is useful in IBSS
RSN but that I've chosen not to use this).

To fix all this, modify the way keys are sent to
the device and key offsets are allocated. After
these changes, key offsets are stored into the
hw_key_idx which we can then track for the key
lifetime, not relying on our sta_cmd array. WEP
default keys get special treatment, of course.

Additionally, since I had the API for it, we can
now pre-fill TKIP phase 1 keys for RX now that we
can obtain the P1K from mac80211, a capability I
had added for WoWLAN initially.

Finally, some keys simply don't need to be added
into the device's key cache -- a key that won't
be used for RX is only needed in the TX header,
so "pretend" to have accepted any key without
adding it into the device -- no need to use up
key space there for it.
Signed-off-by: default avatarJohannes Berg <johannes.berg@intel.com>
Signed-off-by: default avatarWey-Yi Guy <wey-yi.w.guy@intel.com>
parent 0bfe9895
This diff is collapsed.
...@@ -2259,14 +2259,8 @@ static void iwlagn_mac_update_tkip_key(struct ieee80211_hw *hw, ...@@ -2259,14 +2259,8 @@ static void iwlagn_mac_update_tkip_key(struct ieee80211_hw *hw,
u32 iv32, u16 *phase1key) u32 iv32, u16 *phase1key)
{ {
struct iwl_priv *priv = hw->priv; struct iwl_priv *priv = hw->priv;
struct iwl_vif_priv *vif_priv = (void *)vif->drv_priv;
IWL_DEBUG_MAC80211(priv, "enter\n");
iwl_update_tkip_key(priv, vif_priv->ctx, keyconf, sta, iwl_update_tkip_key(priv, vif, keyconf, sta, iv32, phase1key);
iv32, phase1key);
IWL_DEBUG_MAC80211(priv, "leave\n");
} }
static int iwlagn_mac_set_key(struct ieee80211_hw *hw, enum set_key_cmd cmd, static int iwlagn_mac_set_key(struct ieee80211_hw *hw, enum set_key_cmd cmd,
...@@ -2278,7 +2272,6 @@ static int iwlagn_mac_set_key(struct ieee80211_hw *hw, enum set_key_cmd cmd, ...@@ -2278,7 +2272,6 @@ static int iwlagn_mac_set_key(struct ieee80211_hw *hw, enum set_key_cmd cmd,
struct iwl_vif_priv *vif_priv = (void *)vif->drv_priv; struct iwl_vif_priv *vif_priv = (void *)vif->drv_priv;
struct iwl_rxon_context *ctx = vif_priv->ctx; struct iwl_rxon_context *ctx = vif_priv->ctx;
int ret; int ret;
u8 sta_id;
bool is_default_wep_key = false; bool is_default_wep_key = false;
IWL_DEBUG_MAC80211(priv, "enter\n"); IWL_DEBUG_MAC80211(priv, "enter\n");
...@@ -2289,20 +2282,27 @@ static int iwlagn_mac_set_key(struct ieee80211_hw *hw, enum set_key_cmd cmd, ...@@ -2289,20 +2282,27 @@ static int iwlagn_mac_set_key(struct ieee80211_hw *hw, enum set_key_cmd cmd,
} }
/* /*
* To support IBSS RSN, don't program group keys in IBSS, the * We could program these keys into the hardware as well, but we
* hardware will then not attempt to decrypt the frames. * don't expect much multicast traffic in IBSS and having keys
* for more stations is probably more useful.
*
* Mark key TX-only and return 0.
*/ */
if (vif->type == NL80211_IFTYPE_ADHOC && if (vif->type == NL80211_IFTYPE_ADHOC &&
!(key->flags & IEEE80211_KEY_FLAG_PAIRWISE)) !(key->flags & IEEE80211_KEY_FLAG_PAIRWISE)) {
return -EOPNOTSUPP; key->hw_key_idx = WEP_INVALID_OFFSET;
return 0;
}
sta_id = iwl_sta_id_or_broadcast(priv, vif_priv->ctx, sta); /* If they key was TX-only, accept deletion */
if (sta_id == IWL_INVALID_STATION) if (cmd == DISABLE_KEY && key->hw_key_idx == WEP_INVALID_OFFSET)
return -EINVAL; return 0;
mutex_lock(&priv->mutex); mutex_lock(&priv->mutex);
iwl_scan_cancel_timeout(priv, 100); iwl_scan_cancel_timeout(priv, 100);
BUILD_BUG_ON(WEP_INVALID_OFFSET == IWLAGN_HW_KEY_DEFAULT);
/* /*
* If we are getting WEP group key and we didn't receive any key mapping * If we are getting WEP group key and we didn't receive any key mapping
* so far, we are in legacy wep mode (group key only), otherwise we are * so far, we are in legacy wep mode (group key only), otherwise we are
...@@ -2310,22 +2310,30 @@ static int iwlagn_mac_set_key(struct ieee80211_hw *hw, enum set_key_cmd cmd, ...@@ -2310,22 +2310,30 @@ static int iwlagn_mac_set_key(struct ieee80211_hw *hw, enum set_key_cmd cmd,
* In legacy wep mode, we use another host command to the uCode. * In legacy wep mode, we use another host command to the uCode.
*/ */
if ((key->cipher == WLAN_CIPHER_SUITE_WEP40 || if ((key->cipher == WLAN_CIPHER_SUITE_WEP40 ||
key->cipher == WLAN_CIPHER_SUITE_WEP104) && key->cipher == WLAN_CIPHER_SUITE_WEP104) && !sta) {
!sta) {
if (cmd == SET_KEY) if (cmd == SET_KEY)
is_default_wep_key = !ctx->key_mapping_keys; is_default_wep_key = !ctx->key_mapping_keys;
else else
is_default_wep_key = is_default_wep_key =
(key->hw_key_idx == HW_KEY_DEFAULT); key->hw_key_idx == IWLAGN_HW_KEY_DEFAULT;
} }
switch (cmd) { switch (cmd) {
case SET_KEY: case SET_KEY:
if (is_default_wep_key) if (is_default_wep_key) {
ret = iwl_set_default_wep_key(priv, vif_priv->ctx, key); ret = iwl_set_default_wep_key(priv, vif_priv->ctx, key);
else break;
ret = iwl_set_dynamic_key(priv, vif_priv->ctx, }
key, sta_id); ret = iwl_set_dynamic_key(priv, vif_priv->ctx, key, sta);
if (ret) {
/*
* can't add key for RX, but we don't need it
* in the device for TX so still return 0
*/
ret = 0;
key->hw_key_idx = WEP_INVALID_OFFSET;
}
IWL_DEBUG_MAC80211(priv, "enable hwcrypto key\n"); IWL_DEBUG_MAC80211(priv, "enable hwcrypto key\n");
break; break;
...@@ -2333,7 +2341,7 @@ static int iwlagn_mac_set_key(struct ieee80211_hw *hw, enum set_key_cmd cmd, ...@@ -2333,7 +2341,7 @@ static int iwlagn_mac_set_key(struct ieee80211_hw *hw, enum set_key_cmd cmd,
if (is_default_wep_key) if (is_default_wep_key)
ret = iwl_remove_default_wep_key(priv, ctx, key); ret = iwl_remove_default_wep_key(priv, ctx, key);
else else
ret = iwl_remove_dynamic_key(priv, ctx, key, sta_id); ret = iwl_remove_dynamic_key(priv, ctx, key, sta);
IWL_DEBUG_MAC80211(priv, "disable hwcrypto key\n"); IWL_DEBUG_MAC80211(priv, "disable hwcrypto key\n");
break; break;
......
...@@ -246,11 +246,13 @@ int iwl_set_default_wep_key(struct iwl_priv *priv, ...@@ -246,11 +246,13 @@ int iwl_set_default_wep_key(struct iwl_priv *priv,
int iwl_restore_default_wep_keys(struct iwl_priv *priv, int iwl_restore_default_wep_keys(struct iwl_priv *priv,
struct iwl_rxon_context *ctx); struct iwl_rxon_context *ctx);
int iwl_set_dynamic_key(struct iwl_priv *priv, struct iwl_rxon_context *ctx, int iwl_set_dynamic_key(struct iwl_priv *priv, struct iwl_rxon_context *ctx,
struct ieee80211_key_conf *key, u8 sta_id); struct ieee80211_key_conf *key,
struct ieee80211_sta *sta);
int iwl_remove_dynamic_key(struct iwl_priv *priv, struct iwl_rxon_context *ctx, int iwl_remove_dynamic_key(struct iwl_priv *priv, struct iwl_rxon_context *ctx,
struct ieee80211_key_conf *key, u8 sta_id); struct ieee80211_key_conf *key,
struct ieee80211_sta *sta);
void iwl_update_tkip_key(struct iwl_priv *priv, void iwl_update_tkip_key(struct iwl_priv *priv,
struct iwl_rxon_context *ctx, struct ieee80211_vif *vif,
struct ieee80211_key_conf *keyconf, struct ieee80211_key_conf *keyconf,
struct ieee80211_sta *sta, u32 iv32, u16 *phase1key); struct ieee80211_sta *sta, u32 iv32, u16 *phase1key);
int iwl_sta_tx_modify_enable_tid(struct iwl_priv *priv, int sta_id, int tid); int iwl_sta_tx_modify_enable_tid(struct iwl_priv *priv, int sta_id, int tid);
......
...@@ -832,6 +832,8 @@ struct iwl_qosparam_cmd { ...@@ -832,6 +832,8 @@ struct iwl_qosparam_cmd {
#define STA_KEY_MULTICAST_MSK cpu_to_le16(0x4000) #define STA_KEY_MULTICAST_MSK cpu_to_le16(0x4000)
#define STA_KEY_MAX_NUM 8 #define STA_KEY_MAX_NUM 8
#define STA_KEY_MAX_NUM_PAN 16 #define STA_KEY_MAX_NUM_PAN 16
/* must not match WEP_INVALID_OFFSET */
#define IWLAGN_HW_KEY_DEFAULT 0xfe
/* Flags indicate whether to modify vs. don't change various station params */ /* Flags indicate whether to modify vs. don't change various station params */
#define STA_MODIFY_KEY_MASK 0x01 #define STA_MODIFY_KEY_MASK 0x01
......
...@@ -669,7 +669,7 @@ void iwl_reprogram_ap_sta(struct iwl_priv *priv, struct iwl_rxon_context *ctx) ...@@ -669,7 +669,7 @@ void iwl_reprogram_ap_sta(struct iwl_priv *priv, struct iwl_rxon_context *ctx)
iwl_send_lq_cmd(priv, ctx, &lq, CMD_SYNC, true); iwl_send_lq_cmd(priv, ctx, &lq, CMD_SYNC, true);
} }
int iwl_get_free_ucode_key_index(struct iwl_priv *priv) int iwl_get_free_ucode_key_offset(struct iwl_priv *priv)
{ {
int i; int i;
......
...@@ -31,9 +31,6 @@ ...@@ -31,9 +31,6 @@
#include "iwl-dev.h" #include "iwl-dev.h"
#define HW_KEY_DYNAMIC 0
#define HW_KEY_DEFAULT 1
#define IWL_STA_DRIVER_ACTIVE BIT(0) /* driver entry is active */ #define IWL_STA_DRIVER_ACTIVE BIT(0) /* driver entry is active */
#define IWL_STA_UCODE_ACTIVE BIT(1) /* ucode entry is active */ #define IWL_STA_UCODE_ACTIVE BIT(1) /* ucode entry is active */
#define IWL_STA_UCODE_INPROGRESS BIT(2) /* ucode entry is in process of #define IWL_STA_UCODE_INPROGRESS BIT(2) /* ucode entry is in process of
...@@ -47,7 +44,7 @@ void iwl_restore_stations(struct iwl_priv *priv, struct iwl_rxon_context *ctx); ...@@ -47,7 +44,7 @@ void iwl_restore_stations(struct iwl_priv *priv, struct iwl_rxon_context *ctx);
void iwl_clear_ucode_stations(struct iwl_priv *priv, void iwl_clear_ucode_stations(struct iwl_priv *priv,
struct iwl_rxon_context *ctx); struct iwl_rxon_context *ctx);
void iwl_dealloc_bcast_stations(struct iwl_priv *priv); void iwl_dealloc_bcast_stations(struct iwl_priv *priv);
int iwl_get_free_ucode_key_index(struct iwl_priv *priv); int iwl_get_free_ucode_key_offset(struct iwl_priv *priv);
int iwl_send_add_sta(struct iwl_priv *priv, int iwl_send_add_sta(struct iwl_priv *priv,
struct iwl_addsta_cmd *sta, u8 flags); struct iwl_addsta_cmd *sta, u8 flags);
int iwl_add_station_common(struct iwl_priv *priv, struct iwl_rxon_context *ctx, int iwl_add_station_common(struct iwl_priv *priv, struct iwl_rxon_context *ctx,
......
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