Skip to content

Commit

Permalink
iwlwifi: clean up and bug fix for security
Browse files Browse the repository at this point in the history
This patch cleans up code in security.

1) uses the new pointer to ieee80211_key_conf passed with the tx_control.
2) resolves bug reported by Mirco Tischler (sends ADD_STA in ASYNC mode)
3) resolves bug reported by Volker Braun regarding dynamic WEP
4) drops a WEP packet which has been garbaged by firmware. This can
happen upon rekeying.

Signed-off-by: Emmanuel Grumbach <emmanuel.grumbach@intel.com>
Signed-off-by: Tomas Winkler <tomas.winkler@intel.com>
Signed-off-by: John W. Linville <linville@tuxdriver.com>
  • Loading branch information
Emmanuel Grumbach authored and John W. Linville committed May 22, 2008
1 parent a984101 commit ccc038a
Show file tree
Hide file tree
Showing 6 changed files with 29 additions and 46 deletions.
2 changes: 1 addition & 1 deletion drivers/net/wireless/iwlwifi/iwl-4965.c
Original file line number Diff line number Diff line change
Expand Up @@ -2389,14 +2389,14 @@ static int iwl4965_set_decrypted_flag(struct iwl_priv *priv,
RX_RES_STATUS_BAD_KEY_TTAK)
break;

case RX_RES_STATUS_SEC_TYPE_WEP:
if ((decrypt_res & RX_RES_STATUS_DECRYPT_TYPE_MSK) ==
RX_RES_STATUS_BAD_ICV_MIC) {
/* bad ICV, the packet is destroyed since the
* decryption is inplace, drop it */
IWL_DEBUG_RX("Packet destroyed\n");
return -1;
}
case RX_RES_STATUS_SEC_TYPE_WEP:
case RX_RES_STATUS_SEC_TYPE_CCMP:
if ((decrypt_res & RX_RES_STATUS_DECRYPT_TYPE_MSK) ==
RX_RES_STATUS_DECRYPT_OK) {
Expand Down
1 change: 0 additions & 1 deletion drivers/net/wireless/iwlwifi/iwl-dev.h
Original file line number Diff line number Diff line change
Expand Up @@ -442,7 +442,6 @@ struct iwl_hw_key {
enum ieee80211_key_alg alg;
int keylen;
u8 keyidx;
struct ieee80211_key_conf *conf;
u8 key[32];
};

Expand Down
25 changes: 11 additions & 14 deletions drivers/net/wireless/iwlwifi/iwl-sta.c
Original file line number Diff line number Diff line change
Expand Up @@ -324,7 +324,7 @@ int iwl_set_default_wep_key(struct iwl_priv *priv,
unsigned long flags;

keyconf->flags &= ~IEEE80211_KEY_FLAG_GENERATE_IV;
keyconf->hw_key_idx = keyconf->keyidx;
keyconf->hw_key_idx = HW_KEY_DEFAULT;
priv->stations[IWL_AP_ID].keyinfo.alg = ALG_WEP;

spin_lock_irqsave(&priv->sta_lock, flags);
Expand Down Expand Up @@ -354,7 +354,6 @@ static int iwl_set_wep_dynamic_key_info(struct iwl_priv *priv,
int ret;

keyconf->flags &= ~IEEE80211_KEY_FLAG_GENERATE_IV;
keyconf->hw_key_idx = keyconf->keyidx;

key_flags |= (STA_KEY_FLG_WEP | STA_KEY_FLG_MAP_KEY_MSK);
key_flags |= cpu_to_le16(keyconf->keyidx << STA_KEY_FLG_KEYID_POS);
Expand Down Expand Up @@ -411,7 +410,6 @@ static int iwl_set_ccmp_dynamic_key_info(struct iwl_priv *priv,
key_flags |= STA_KEY_MULTICAST_MSK;

keyconf->flags |= IEEE80211_KEY_FLAG_GENERATE_IV;
keyconf->hw_key_idx = keyconf->keyidx;

spin_lock_irqsave(&priv->sta_lock, flags);
priv->stations[sta_id].keyinfo.alg = keyconf->alg;
Expand Down Expand Up @@ -449,12 +447,10 @@ static int iwl_set_tkip_dynamic_key_info(struct iwl_priv *priv,

keyconf->flags |= IEEE80211_KEY_FLAG_GENERATE_IV;
keyconf->flags |= IEEE80211_KEY_FLAG_GENERATE_MMIC;
keyconf->hw_key_idx = keyconf->keyidx;

spin_lock_irqsave(&priv->sta_lock, flags);

priv->stations[sta_id].keyinfo.alg = keyconf->alg;
priv->stations[sta_id].keyinfo.conf = keyconf;
priv->stations[sta_id].keyinfo.keylen = 16;

if ((priv->stations[sta_id].sta.key.key_flags & STA_KEY_FLG_ENCRYPT_MSK)
Expand Down Expand Up @@ -483,7 +479,7 @@ int iwl_remove_dynamic_key(struct iwl_priv *priv,
u16 key_flags;
u8 keyidx;

priv->key_mapping_key = 0;
priv->key_mapping_key--;

spin_lock_irqsave(&priv->sta_lock, flags);
key_flags = le16_to_cpu(priv->stations[sta_id].sta.key.key_flags);
Expand Down Expand Up @@ -514,31 +510,32 @@ int iwl_remove_dynamic_key(struct iwl_priv *priv,
priv->stations[sta_id].sta.mode = STA_CONTROL_MODIFY_MSK;

IWL_DEBUG_INFO("hwcrypto: clear ucode station key info\n");
ret = iwl_send_add_sta(priv, &priv->stations[sta_id].sta, 0);
ret = iwl_send_add_sta(priv, &priv->stations[sta_id].sta, CMD_ASYNC);
spin_unlock_irqrestore(&priv->sta_lock, flags);
return ret;
}
EXPORT_SYMBOL(iwl_remove_dynamic_key);

int iwl_set_dynamic_key(struct iwl_priv *priv,
struct ieee80211_key_conf *key, u8 sta_id)
struct ieee80211_key_conf *keyconf, u8 sta_id)
{
int ret;

priv->key_mapping_key = 1;
priv->key_mapping_key++;
keyconf->hw_key_idx = HW_KEY_DYNAMIC;

switch (key->alg) {
switch (keyconf->alg) {
case ALG_CCMP:
ret = iwl_set_ccmp_dynamic_key_info(priv, key, sta_id);
ret = iwl_set_ccmp_dynamic_key_info(priv, keyconf, sta_id);
break;
case ALG_TKIP:
ret = iwl_set_tkip_dynamic_key_info(priv, key, sta_id);
ret = iwl_set_tkip_dynamic_key_info(priv, keyconf, sta_id);
break;
case ALG_WEP:
ret = iwl_set_wep_dynamic_key_info(priv, key, sta_id);
ret = iwl_set_wep_dynamic_key_info(priv, keyconf, sta_id);
break;
default:
IWL_ERROR("Unknown alg: %s alg = %d\n", __func__, key->alg);
IWL_ERROR("Unknown alg: %s alg = %d\n", __func__, keyconf->alg);
ret = -EINVAL;
}

Expand Down
3 changes: 3 additions & 0 deletions drivers/net/wireless/iwlwifi/iwl-sta.h
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,9 @@
#ifndef __iwl_sta_h__
#define __iwl_sta_h__

#define HW_KEY_DYNAMIC 0
#define HW_KEY_DEFAULT 1

int iwl_get_free_ucode_key_index(struct iwl_priv *priv);
int iwl_send_static_wepkey_cmd(struct iwl_priv *priv, u8 send_if_empty);
int iwl_remove_default_wep_key(struct iwl_priv *priv,
Expand Down
41 changes: 12 additions & 29 deletions drivers/net/wireless/iwlwifi/iwl-tx.c
Original file line number Diff line number Diff line change
Expand Up @@ -639,56 +639,39 @@ static void iwl_tx_cmd_build_hwcrypto(struct iwl_priv *priv,
struct sk_buff *skb_frag,
int sta_id)
{
struct iwl_hw_key *keyinfo = &priv->stations[sta_id].keyinfo;
struct iwl_wep_key *wepkey;
int keyidx = 0;
struct ieee80211_key_conf *keyconf = ctl->hw_key;

BUG_ON(ctl->hw_key->hw_key_idx > 3);

switch (keyinfo->alg) {
switch (keyconf->alg) {
case ALG_CCMP:
tx_cmd->sec_ctl = TX_CMD_SEC_CCM;
memcpy(tx_cmd->key, keyinfo->key, keyinfo->keylen);
memcpy(tx_cmd->key, keyconf->key, keyconf->keylen);
if (ctl->flags & IEEE80211_TXCTL_AMPDU)
tx_cmd->tx_flags |= TX_CMD_FLG_AGG_CCMP_MSK;
IWL_DEBUG_TX("tx_cmd with aes hwcrypto\n");
break;

case ALG_TKIP:
tx_cmd->sec_ctl = TX_CMD_SEC_TKIP;
ieee80211_get_tkip_key(keyinfo->conf, skb_frag,
ieee80211_get_tkip_key(keyconf, skb_frag,
IEEE80211_TKIP_P2_KEY, tx_cmd->key);
IWL_DEBUG_TX("tx_cmd with tkip hwcrypto\n");
break;

case ALG_WEP:
wepkey = &priv->wep_keys[ctl->hw_key->hw_key_idx];
tx_cmd->sec_ctl = 0;
if (priv->default_wep_key) {
/* the WEP key was sent as static */
keyidx = ctl->hw_key->hw_key_idx;
memcpy(&tx_cmd->key[3], wepkey->key,
wepkey->key_size);
if (wepkey->key_size == WEP_KEY_LEN_128)
tx_cmd->sec_ctl |= TX_CMD_SEC_KEY128;
} else {
/* the WEP key was sent as dynamic */
keyidx = keyinfo->keyidx;
memcpy(&tx_cmd->key[3], keyinfo->key,
keyinfo->keylen);
if (keyinfo->keylen == WEP_KEY_LEN_128)
tx_cmd->sec_ctl |= TX_CMD_SEC_KEY128;
}

tx_cmd->sec_ctl |= (TX_CMD_SEC_WEP |
(keyidx & TX_CMD_SEC_MSK) << TX_CMD_SEC_SHIFT);
(keyconf->keyidx & TX_CMD_SEC_MSK) << TX_CMD_SEC_SHIFT);

if (keyconf->keylen == WEP_KEY_LEN_128)
tx_cmd->sec_ctl |= TX_CMD_SEC_KEY128;

memcpy(&tx_cmd->key[3], keyconf->key, keyconf->keylen);

IWL_DEBUG_TX("Configuring packet for WEP encryption "
"with key %d\n", keyidx);
"with key %d\n", keyconf->keyidx);
break;

default:
printk(KERN_ERR "Unknown encode alg %d\n", keyinfo->alg);
printk(KERN_ERR "Unknown encode alg %d\n", keyconf->alg);
break;
}
}
Expand Down
3 changes: 2 additions & 1 deletion drivers/net/wireless/iwlwifi/iwl4965-base.c
Original file line number Diff line number Diff line change
Expand Up @@ -4951,7 +4951,8 @@ static int iwl4965_mac_set_key(struct ieee80211_hw *hw, enum set_key_cmd cmd,
if (cmd == SET_KEY)
is_default_wep_key = !priv->key_mapping_key;
else
is_default_wep_key = priv->default_wep_key;
is_default_wep_key =
(key->hw_key_idx == HW_KEY_DEFAULT);
}

switch (cmd) {
Expand Down

0 comments on commit ccc038a

Please sign in to comment.