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: Emmanuel Grumbach <emmanuel.grumbach@intel.com>
Signed-off-by: Tomas Winkler <tomas.winkler@intel.com>
Signed-off-by: John W. Linville <linville@tuxdriver.com>
This commit is contained in:
Emmanuel Grumbach 2008-04-14 21:16:06 -07:00 committed by John W. Linville
parent 0a0bed1d10
commit 6974e36356
5 changed files with 220 additions and 40 deletions

View File

@ -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

View File

@ -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;

View File

@ -0,0 +1,119 @@
/******************************************************************************
*
* 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;
}

View File

@ -0,0 +1,46 @@
/******************************************************************************
*
* 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__ */

View File

@ -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;
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");
}
if (keyinfo->keylen == 13)
cmd->cmd.tx.sec_ctl |= TX_CMD_SEC_KEY128;
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);
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;
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);