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

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

iwlwifi: default WEP HW encryption



This patch adds HW encryption support in default WEP mode.
When no key mapping key/pairwise key is used. The key is broadcast key
is used as default/global/static key.
This code assumes that group cast key is added after pairwise key.

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 0a0bed1d
Loading
Loading
Loading
Loading
+1 −1
Original line number Diff line number Diff line
@@ -22,5 +22,5 @@ endif


obj-$(CONFIG_IWL4965)	+= iwl4965.o
iwl4965-objs		= iwl4965-base.o iwl-4965.o iwl-4965-rs.o
iwl4965-objs		= iwl4965-base.o iwl-4965.o iwl-4965-rs.o iwl-sta.o
+3 −0
Original line number Diff line number Diff line
@@ -1112,6 +1112,9 @@ struct iwl_priv {
	spinlock_t sta_lock;
	int num_stations;
	struct iwl4965_station_entry stations[IWL_STATION_COUNT];
	struct iwl_wep_key wep_keys[WEP_KEYS_MAX];
	u8 default_wep_key;
	u8 key_mapping_key;

	/* Indication if ieee80211_ops->open has been called */
	u8 is_open;
+119 −0
Original line number Diff line number Diff line
/******************************************************************************
 *
 * Copyright(c) 2003 - 2008 Intel Corporation. All rights reserved.
 *
 * Portions of this file are derived from the ipw3945 project, as well
 * as portions of the ieee80211 subsystem header files.
 *
 * This program is free software; you can redistribute it and/or modify it
 * under the terms of version 2 of the GNU General Public License as
 * published by the Free Software Foundation.
 *
 * This program is distributed in the hope that it will be useful, but WITHOUT
 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
 * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for
 * more details.
 *
 * You should have received a copy of the GNU General Public License along with
 * this program; if not, write to the Free Software Foundation, Inc.,
 * 51 Franklin Street, Fifth Floor, Boston, MA 02110, USA
 *
 * The full GNU General Public License is included in this distribution in the
 * file called LICENSE.
 *
 * Contact Information:
 * James P. Ketrenos <ipw2100-admin@linux.intel.com>
 * Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497
 *
 *****************************************************************************/

#include <net/mac80211.h>

#include "iwl-eeprom.h"
#include "iwl-4965.h"
#include "iwl-core.h"
#include "iwl-sta.h"
#include "iwl-io.h"
#include "iwl-helpers.h"

int iwl_send_static_wepkey_cmd(struct iwl_priv *priv, u8 send_if_empty)
{
	int i, not_empty = 0;
	u8 buff[sizeof(struct iwl_wep_cmd) +
		sizeof(struct iwl_wep_key) * WEP_KEYS_MAX];
	struct iwl_wep_cmd *wep_cmd = (struct iwl_wep_cmd *)buff;
	size_t cmd_size  = sizeof(struct iwl_wep_cmd);
	struct iwl_host_cmd cmd = {
		.id = REPLY_WEPKEY,
		.data = wep_cmd,
		.meta.flags = CMD_ASYNC,
	};

	memset(wep_cmd, 0, cmd_size +
			(sizeof(struct iwl_wep_key) * WEP_KEYS_MAX));

	for (i = 0; i < WEP_KEYS_MAX ; i++) {
		wep_cmd->key[i].key_index = i;
		if (priv->wep_keys[i].key_size) {
			wep_cmd->key[i].key_offset = i;
			not_empty = 1;
		} else {
			wep_cmd->key[i].key_offset = WEP_INVALID_OFFSET;
		}

		wep_cmd->key[i].key_size = priv->wep_keys[i].key_size;
		memcpy(&wep_cmd->key[i].key[3], priv->wep_keys[i].key,
				priv->wep_keys[i].key_size);
	}

	wep_cmd->global_key_type = WEP_KEY_WEP_TYPE;
	wep_cmd->num_keys = WEP_KEYS_MAX;

	cmd_size += sizeof(struct iwl_wep_key) * WEP_KEYS_MAX;

	cmd.len = cmd_size;

	if (not_empty || send_if_empty)
		return iwl_send_cmd(priv, &cmd);
	else
		return 0;
}

int iwl_remove_default_wep_key(struct iwl_priv *priv,
			       struct ieee80211_key_conf *key)
{
	int ret;
	unsigned long flags;

	spin_lock_irqsave(&priv->sta_lock, flags);
	priv->default_wep_key--;
	memset(&priv->wep_keys[key->keyidx], 0, sizeof(priv->wep_keys[0]));
	ret = iwl_send_static_wepkey_cmd(priv, 1);
	spin_unlock_irqrestore(&priv->sta_lock, flags);

	return ret;
}

int iwl_set_default_wep_key(struct iwl_priv *priv,
			    struct ieee80211_key_conf *keyconf)
{
	int ret;
	unsigned long flags;

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

	spin_lock_irqsave(&priv->sta_lock, flags);
	priv->default_wep_key++;

	priv->wep_keys[keyconf->keyidx].key_size = keyconf->keylen;
	memcpy(&priv->wep_keys[keyconf->keyidx].key, &keyconf->key,
							keyconf->keylen);

	ret = iwl_send_static_wepkey_cmd(priv, 0);
	spin_unlock_irqrestore(&priv->sta_lock, flags);

	return ret;
}
+46 −0
Original line number Diff line number Diff line
/******************************************************************************
 *
 * Copyright(c) 2003 - 2008 Intel Corporation. All rights reserved.
 *
 * Portions of this file are derived from the ipw3945 project, as well
 * as portions of the ieee80211 subsystem header files.
 *
 * This program is free software; you can redistribute it and/or modify it
 * under the terms of version 2 of the GNU General Public License as
 * published by the Free Software Foundation.
 *
 * This program is distributed in the hope that it will be useful, but WITHOUT
 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
 * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for
 * more details.
 *
 * You should have received a copy of the GNU General Public License along with
 * this program; if not, write to the Free Software Foundation, Inc.,
 * 51 Franklin Street, Fifth Floor, Boston, MA 02110, USA
 *
 * The full GNU General Public License is included in this distribution in the
 * file called LICENSE.
 *
 * Contact Information:
 * James P. Ketrenos <ipw2100-admin@linux.intel.com>
 * Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497
 *
 *****************************************************************************/
#ifndef __iwl_sta_h__
#define __iwl_sta_h__

#include <net/mac80211.h>

#include "iwl-eeprom.h"
#include "iwl-core.h"
#include "iwl-4965.h"
#include "iwl-io.h"
#include "iwl-helpers.h"

int iwl_send_static_wepkey_cmd(struct iwl_priv *priv, u8 send_if_empty);
int iwl_remove_default_wep_key(struct iwl_priv *priv,
				struct ieee80211_key_conf *key);
int iwl_set_default_wep_key(struct iwl_priv *priv,
				struct ieee80211_key_conf *key);

#endif /* __iwl_sta_h__ */
+51 −39
Original line number Diff line number Diff line
@@ -50,6 +50,7 @@
#include "iwl-core.h"
#include "iwl-io.h"
#include "iwl-helpers.h"
#include "iwl-sta.h"

static int iwl4965_tx_queue_update_write_ptr(struct iwl_priv *priv,
				  struct iwl4965_tx_queue *txq);
@@ -941,6 +942,9 @@ static int iwl4965_commit_rxon(struct iwl_priv *priv)
			return -EIO;
		}
		priv->assoc_station_added = 1;
		if (priv->default_wep_key &&
		    iwl_send_static_wepkey_cmd(priv, 0))
			IWL_ERROR("Could not send WEP static key.\n");
	}

	return 0;
@@ -1180,6 +1184,8 @@ static int iwl4965_clear_sta_key_info(struct iwl_priv *priv, u8 sta_id)
{
	unsigned long flags;

	priv->key_mapping_key = 0;

	spin_lock_irqsave(&priv->sta_lock, flags);
	memset(&priv->stations[sta_id].keyinfo, 0, sizeof(struct iwl4965_hw_key));
	memset(&priv->stations[sta_id].sta.key, 0, sizeof(struct iwl4965_keyinfo));
@@ -1198,6 +1204,8 @@ static int iwl4965_set_dynamic_key(struct iwl_priv *priv,
{
	int ret;

	priv->key_mapping_key = 1;

	switch (key->alg) {
	case ALG_CCMP:
		ret = iwl4965_set_ccmp_dynamic_key_info(priv, key, sta_id);
@@ -1216,23 +1224,6 @@ static int iwl4965_set_dynamic_key(struct iwl_priv *priv,
	return ret;
}

static int iwl4965_remove_static_key(struct iwl_priv *priv)
{
	int ret = -EOPNOTSUPP;

	return ret;
}

static int iwl4965_set_static_key(struct iwl_priv *priv,
				struct ieee80211_key_conf *key)
{
	if (key->alg == ALG_WEP)
		return -EOPNOTSUPP;

	IWL_ERROR("Static key invalid: alg %d\n", key->alg);
	return -EINVAL;
}

static void iwl4965_clear_free_frames(struct iwl_priv *priv)
{
	struct list_head *element;
@@ -2115,6 +2106,10 @@ static void iwl4965_build_tx_cmd_hwcrypto(struct iwl_priv *priv,
				      int sta_id)
{
	struct iwl4965_hw_key *keyinfo = &priv->stations[sta_id].keyinfo;
	struct iwl_wep_key *wepkey;
	int keyidx = 0;

	BUG_ON(ctl->key_idx > 3);

	switch (keyinfo->alg) {
	case ALG_CCMP:
@@ -2133,16 +2128,24 @@ static void iwl4965_build_tx_cmd_hwcrypto(struct iwl_priv *priv,
		break;

	case ALG_WEP:
		cmd->cmd.tx.sec_ctl = TX_CMD_SEC_WEP |
			(ctl->key_idx & TX_CMD_SEC_MSK) << TX_CMD_SEC_SHIFT;

		if (keyinfo->keylen == 13)
		wepkey = &priv->wep_keys[ctl->key_idx];
		cmd->cmd.tx.sec_ctl = 0;
		if (priv->default_wep_key) {
			/* the WEP key was sent as static */
			keyidx = ctl->key_idx;
			memcpy(&cmd->cmd.tx.key[3], wepkey->key,
							wepkey->key_size);
			if (wepkey->key_size == WEP_KEY_LEN_128)
				cmd->cmd.tx.sec_ctl |= TX_CMD_SEC_KEY128;
		} else {
			IWL_ERROR("No support for WEP key mappings key\n");
		}

		memcpy(&cmd->cmd.tx.key[3], keyinfo->key, keyinfo->keylen);
		cmd->cmd.tx.sec_ctl |= (TX_CMD_SEC_WEP |
			(keyidx & TX_CMD_SEC_MSK) << TX_CMD_SEC_SHIFT);

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

	default:
@@ -6989,7 +6992,7 @@ static int iwl4965_mac_set_key(struct ieee80211_hw *hw, enum set_key_cmd cmd,
	DECLARE_MAC_BUF(mac);
	int ret = 0;
	u8 sta_id = IWL_INVALID_STATION;
	u8 static_key;
	u8 is_default_wep_key = 0;

	IWL_DEBUG_MAC80211("enter\n");

@@ -7002,33 +7005,42 @@ static int iwl4965_mac_set_key(struct ieee80211_hw *hw, enum set_key_cmd cmd,
		/* only support pairwise keys */
		return -EOPNOTSUPP;

	/* FIXME: need to differenciate between static and dynamic key
	 * in the level of mac80211 */
	static_key = !iwl_is_associated(priv);

	if (!static_key) {
	sta_id = iwl4965_hw_find_station(priv, addr);
	if (sta_id == IWL_INVALID_STATION) {
		IWL_DEBUG_MAC80211("leave - %s not in station map.\n",
				   print_mac(mac, addr));
		return -EINVAL;
		}

	}

	mutex_lock(&priv->mutex);
	iwl4965_scan_cancel_timeout(priv, 100);
	mutex_unlock(&priv->mutex);

	/* 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
	 * in 1X mode.
	 * In legacy wep mode, we use another host command to the uCode */
	if (key->alg == ALG_WEP && sta_id == priv->hw_setting.bcast_sta_id &&
		priv->iw_mode != IEEE80211_IF_TYPE_AP) {
		if (cmd == SET_KEY)
			is_default_wep_key = !priv->key_mapping_key;
		else
			is_default_wep_key = priv->default_wep_key;
	}

	switch (cmd) {
	case SET_KEY:
		if (static_key)
			ret = iwl4965_set_static_key(priv, key);
		if (is_default_wep_key)
			ret = iwl_set_default_wep_key(priv, key);
		else
			ret = iwl4965_set_dynamic_key(priv, key, sta_id);

		IWL_DEBUG_MAC80211("enable hwcrypto key\n");
		break;
	case DISABLE_KEY:
		if (static_key)
			ret = iwl4965_remove_static_key(priv);
		if (is_default_wep_key)
			ret = iwl_remove_default_wep_key(priv, key);
		else
			ret = iwl4965_clear_sta_key_info(priv, sta_id);