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

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
...@@ -22,5 +22,5 @@ endif ...@@ -22,5 +22,5 @@ endif
obj-$(CONFIG_IWL4965) += iwl4965.o 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
...@@ -1112,6 +1112,9 @@ struct iwl_priv { ...@@ -1112,6 +1112,9 @@ struct iwl_priv {
spinlock_t sta_lock; spinlock_t sta_lock;
int num_stations; int num_stations;
struct iwl4965_station_entry stations[IWL_STATION_COUNT]; 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 */ /* Indication if ieee80211_ops->open has been called */
u8 is_open; u8 is_open;
......
/******************************************************************************
*
* 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;
}
/******************************************************************************
*
* 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__ */
...@@ -50,6 +50,7 @@ ...@@ -50,6 +50,7 @@
#include "iwl-core.h" #include "iwl-core.h"
#include "iwl-io.h" #include "iwl-io.h"
#include "iwl-helpers.h" #include "iwl-helpers.h"
#include "iwl-sta.h"
static int iwl4965_tx_queue_update_write_ptr(struct iwl_priv *priv, static int iwl4965_tx_queue_update_write_ptr(struct iwl_priv *priv,
struct iwl4965_tx_queue *txq); struct iwl4965_tx_queue *txq);
...@@ -941,6 +942,9 @@ static int iwl4965_commit_rxon(struct iwl_priv *priv) ...@@ -941,6 +942,9 @@ static int iwl4965_commit_rxon(struct iwl_priv *priv)
return -EIO; return -EIO;
} }
priv->assoc_station_added = 1; 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; return 0;
...@@ -1180,6 +1184,8 @@ static int iwl4965_clear_sta_key_info(struct iwl_priv *priv, u8 sta_id) ...@@ -1180,6 +1184,8 @@ static int iwl4965_clear_sta_key_info(struct iwl_priv *priv, u8 sta_id)
{ {
unsigned long flags; unsigned long flags;
priv->key_mapping_key = 0;
spin_lock_irqsave(&priv->sta_lock, flags); spin_lock_irqsave(&priv->sta_lock, flags);
memset(&priv->stations[sta_id].keyinfo, 0, sizeof(struct iwl4965_hw_key)); memset(&priv->stations[sta_id].keyinfo, 0, sizeof(struct iwl4965_hw_key));
memset(&priv->stations[sta_id].sta.key, 0, sizeof(struct iwl4965_keyinfo)); 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, ...@@ -1198,6 +1204,8 @@ static int iwl4965_set_dynamic_key(struct iwl_priv *priv,
{ {
int ret; int ret;
priv->key_mapping_key = 1;
switch (key->alg) { switch (key->alg) {
case ALG_CCMP: case ALG_CCMP:
ret = iwl4965_set_ccmp_dynamic_key_info(priv, key, sta_id); 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, ...@@ -1216,23 +1224,6 @@ static int iwl4965_set_dynamic_key(struct iwl_priv *priv,
return ret; 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) static void iwl4965_clear_free_frames(struct iwl_priv *priv)
{ {
struct list_head *element; struct list_head *element;
...@@ -2115,6 +2106,10 @@ static void iwl4965_build_tx_cmd_hwcrypto(struct iwl_priv *priv, ...@@ -2115,6 +2106,10 @@ static void iwl4965_build_tx_cmd_hwcrypto(struct iwl_priv *priv,
int sta_id) int sta_id)
{ {
struct iwl4965_hw_key *keyinfo = &priv->stations[sta_id].keyinfo; 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) { switch (keyinfo->alg) {
case ALG_CCMP: case ALG_CCMP:
...@@ -2133,16 +2128,24 @@ static void iwl4965_build_tx_cmd_hwcrypto(struct iwl_priv *priv, ...@@ -2133,16 +2128,24 @@ static void iwl4965_build_tx_cmd_hwcrypto(struct iwl_priv *priv,
break; break;
case ALG_WEP: case ALG_WEP:
cmd->cmd.tx.sec_ctl = TX_CMD_SEC_WEP | wepkey = &priv->wep_keys[ctl->key_idx];
(ctl->key_idx & TX_CMD_SEC_MSK) << TX_CMD_SEC_SHIFT; cmd->cmd.tx.sec_ctl = 0;
if (priv->default_wep_key) {
if (keyinfo->keylen == 13) /* the WEP key was sent as static */
cmd->cmd.tx.sec_ctl |= TX_CMD_SEC_KEY128; 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 " IWL_DEBUG_TX("Configuring packet for WEP encryption "
"with key %d\n", ctl->key_idx); "with key %d\n", keyidx);
break; break;
default: default:
...@@ -6989,7 +6992,7 @@ static int iwl4965_mac_set_key(struct ieee80211_hw *hw, enum set_key_cmd cmd, ...@@ -6989,7 +6992,7 @@ static int iwl4965_mac_set_key(struct ieee80211_hw *hw, enum set_key_cmd cmd,
DECLARE_MAC_BUF(mac); DECLARE_MAC_BUF(mac);
int ret = 0; int ret = 0;
u8 sta_id = IWL_INVALID_STATION; u8 sta_id = IWL_INVALID_STATION;
u8 static_key; u8 is_default_wep_key = 0;
IWL_DEBUG_MAC80211("enter\n"); IWL_DEBUG_MAC80211("enter\n");
...@@ -7002,33 +7005,42 @@ static int iwl4965_mac_set_key(struct ieee80211_hw *hw, enum set_key_cmd cmd, ...@@ -7002,33 +7005,42 @@ static int iwl4965_mac_set_key(struct ieee80211_hw *hw, enum set_key_cmd cmd,
/* only support pairwise keys */ /* only support pairwise keys */
return -EOPNOTSUPP; return -EOPNOTSUPP;
/* FIXME: need to differenciate between static and dynamic key sta_id = iwl4965_hw_find_station(priv, addr);
* in the level of mac80211 */ if (sta_id == IWL_INVALID_STATION) {
static_key = !iwl_is_associated(priv); 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); 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) { switch (cmd) {
case SET_KEY: case SET_KEY:
if (static_key) if (is_default_wep_key)
ret = iwl4965_set_static_key(priv, key); ret = iwl_set_default_wep_key(priv, key);
else else
ret = iwl4965_set_dynamic_key(priv, key, sta_id); ret = iwl4965_set_dynamic_key(priv, key, sta_id);
IWL_DEBUG_MAC80211("enable hwcrypto key\n"); IWL_DEBUG_MAC80211("enable hwcrypto key\n");
break; break;
case DISABLE_KEY: case DISABLE_KEY:
if (static_key) if (is_default_wep_key)
ret = iwl4965_remove_static_key(priv); ret = iwl_remove_default_wep_key(priv, key);
else else
ret = iwl4965_clear_sta_key_info(priv, sta_id); ret = iwl4965_clear_sta_key_info(priv, sta_id);
......
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