Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit ccc038ab authored by Emmanuel Grumbach's avatar Emmanuel Grumbach Committed by John W. Linville
Browse files

iwlwifi: clean up and bug fix for security



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: default avatarEmmanuel Grumbach <emmanuel.grumbach@intel.com>
Signed-off-by: default avatarTomas Winkler <tomas.winkler@intel.com>
Signed-off-by: default avatarJohn W. Linville <linville@tuxdriver.com>
parent a9841013
Loading
Loading
Loading
Loading
+1 −1
Original line number Diff line number Diff line
@@ -2389,6 +2389,7 @@ 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
@@ -2396,7 +2397,6 @@ static int iwl4965_set_decrypted_flag(struct iwl_priv *priv,
			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) {
+0 −1
Original line number Diff line number Diff line
@@ -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];
};

+11 −14
Original line number Diff line number Diff line
@@ -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);
@@ -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);
@@ -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;
@@ -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)
@@ -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);
@@ -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;
	}

+3 −0
Original line number Diff line number Diff line
@@ -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,
+12 −29
Original line number Diff line number Diff line
@@ -639,16 +639,12 @@ 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");
@@ -656,39 +652,26 @@ static void iwl_tx_cmd_build_hwcrypto(struct iwl_priv *priv,

	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_WEP |
			(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;
		}

		tx_cmd->sec_ctl |= (TX_CMD_SEC_WEP |
			(keyidx & TX_CMD_SEC_MSK) << TX_CMD_SEC_SHIFT);
		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;
	}
}
Loading