Commit e0d369d1 authored by James Ketrenos's avatar James Ketrenos Committed by Jeff Garzik

[PATCH] ieee82011: Added WE-18 support to default wireless extension handler

tree 1536f39c18756698d033da72c49300a561be1289
parent 07172d7c9f10ee3d05d6f6489ba6d6ee2628da06
author Liu Hong <hong.liu@intel.com> 1124436225 -0500
committer James Ketrenos <jketreno@linux.intel.com> 1127312664 -0500

Added WE-18 support to default wireless extension handler in ieee80211
subsystem.

Updated patch since last send to account for ieee80211_device parameter
being added to the crypto init method.
Signed-off-by: default avatarJames Ketrenos <jketreno@linux.intel.com>
Signed-off-by: default avatarJeff Garzik <jgarzik@pobox.com>
parent 259bf1fd
...@@ -447,6 +447,11 @@ struct ieee80211_device; ...@@ -447,6 +447,11 @@ struct ieee80211_device;
#define SEC_LEVEL_2_CKIP 3 /* Level 1 + CKIP */ #define SEC_LEVEL_2_CKIP 3 /* Level 1 + CKIP */
#define SEC_LEVEL_3 4 /* Level 2 + CCMP */ #define SEC_LEVEL_3 4 /* Level 2 + CCMP */
#define SEC_ALG_NONE 0
#define SEC_ALG_WEP 1
#define SEC_ALG_TKIP 2
#define SEC_ALG_CCMP 3
#define WEP_KEYS 4 #define WEP_KEYS 4
#define WEP_KEY_LEN 13 #define WEP_KEY_LEN 13
#define SCM_KEY_LEN 32 #define SCM_KEY_LEN 32
...@@ -456,6 +461,7 @@ struct ieee80211_security { ...@@ -456,6 +461,7 @@ struct ieee80211_security {
u16 active_key:2, u16 active_key:2,
enabled:1, enabled:1,
auth_mode:2, auth_algo:4, unicast_uses_group:1, encrypt:1; auth_mode:2, auth_algo:4, unicast_uses_group:1, encrypt:1;
u8 encode_alg[WEP_KEYS];
u8 key_sizes[WEP_KEYS]; u8 key_sizes[WEP_KEYS];
u8 keys[WEP_KEYS][SCM_KEY_LEN]; u8 keys[WEP_KEYS][SCM_KEY_LEN];
u8 level; u8 level;
...@@ -824,6 +830,14 @@ extern int ieee80211_wx_set_encode(struct ieee80211_device *ieee, ...@@ -824,6 +830,14 @@ extern int ieee80211_wx_set_encode(struct ieee80211_device *ieee,
extern int ieee80211_wx_get_encode(struct ieee80211_device *ieee, extern int ieee80211_wx_get_encode(struct ieee80211_device *ieee,
struct iw_request_info *info, struct iw_request_info *info,
union iwreq_data *wrqu, char *key); union iwreq_data *wrqu, char *key);
#if WIRELESS_EXT > 17
extern int ieee80211_wx_set_encodeext(struct ieee80211_device *ieee,
struct iw_request_info *info,
union iwreq_data *wrqu, char *extra);
extern int ieee80211_wx_get_encodeext(struct ieee80211_device *ieee,
struct iw_request_info *info,
union iwreq_data *wrqu, char *extra);
#endif
extern inline void ieee80211_increment_scans(struct ieee80211_device *ieee) extern inline void ieee80211_increment_scans(struct ieee80211_device *ieee)
{ {
......
...@@ -422,6 +422,7 @@ int ieee80211_wx_set_encode(struct ieee80211_device *ieee, ...@@ -422,6 +422,7 @@ int ieee80211_wx_set_encode(struct ieee80211_device *ieee,
* TODO: When WPA is added this is one place that needs to change */ * TODO: When WPA is added this is one place that needs to change */
sec.flags |= SEC_LEVEL; sec.flags |= SEC_LEVEL;
sec.level = SEC_LEVEL_1; /* 40 and 104 bit WEP */ sec.level = SEC_LEVEL_1; /* 40 and 104 bit WEP */
sec.encode_alg[key] = SEC_ALG_WEP;
done: done:
if (ieee->set_security) if (ieee->set_security)
...@@ -469,14 +470,6 @@ int ieee80211_wx_get_encode(struct ieee80211_device *ieee, ...@@ -469,14 +470,6 @@ int ieee80211_wx_get_encode(struct ieee80211_device *ieee,
return 0; return 0;
} }
if (sec->level != SEC_LEVEL_1) {
/* only WEP is supported with wireless extensions, so just
* report that encryption is used */
erq->length = 0;
erq->flags |= IW_ENCODE_ENABLED;
return 0;
}
len = sec->key_sizes[key]; len = sec->key_sizes[key];
memcpy(keybuf, sec->keys[key], len); memcpy(keybuf, sec->keys[key], len);
...@@ -491,6 +484,235 @@ int ieee80211_wx_get_encode(struct ieee80211_device *ieee, ...@@ -491,6 +484,235 @@ int ieee80211_wx_get_encode(struct ieee80211_device *ieee,
return 0; return 0;
} }
#if WIRELESS_EXT > 17
int ieee80211_wx_set_encodeext(struct ieee80211_device *ieee,
struct iw_request_info *info,
union iwreq_data *wrqu, char *extra)
{
struct net_device *dev = ieee->dev;
struct iw_point *encoding = &wrqu->encoding;
struct iw_encode_ext *ext = (struct iw_encode_ext *)extra;
int i, idx, ret = 0;
const char *alg, *module;
struct ieee80211_crypto_ops *ops;
struct ieee80211_crypt_data **crypt;
struct ieee80211_security sec = {
.flags = 0,
};
idx = encoding->flags & IW_ENCODE_INDEX;
if (idx) {
if (idx < 1 || idx > WEP_KEYS)
return -EINVAL;
idx--;
} else
idx = ieee->tx_keyidx;
if (ext->ext_flags & IW_ENCODE_EXT_GROUP_KEY)
crypt = &ieee->crypt[idx];
else {
if (idx != 0)
return -EINVAL;
if (ieee->iw_mode == IW_MODE_INFRA)
crypt = &ieee->crypt[idx];
else
return -EINVAL;
}
sec.flags |= SEC_ENABLED | SEC_ENCRYPT;
if ((encoding->flags & IW_ENCODE_DISABLED) ||
ext->alg == IW_ENCODE_ALG_NONE) {
if (*crypt)
ieee80211_crypt_delayed_deinit(ieee, crypt);
for (i = 0; i < WEP_KEYS; i++)
if (ieee->crypt[i] != NULL)
break;
if (i == WEP_KEYS) {
sec.enabled = 0;
sec.encrypt = 0;
sec.level = SEC_LEVEL_0;
sec.flags |= SEC_LEVEL;
}
goto done;
}
sec.enabled = 1;
sec.encrypt = 1;
if (!(ieee->host_encrypt || ieee->host_decrypt))
goto skip_host_crypt;
switch (ext->alg) {
case IW_ENCODE_ALG_WEP:
alg = "WEP";
module = "ieee80211_crypt_wep";
break;
case IW_ENCODE_ALG_TKIP:
alg = "TKIP";
module = "ieee80211_crypt_tkip";
break;
case IW_ENCODE_ALG_CCMP:
alg = "CCMP";
module = "ieee80211_crypt_ccmp";
break;
default:
IEEE80211_DEBUG_WX("%s: unknown crypto alg %d\n",
dev->name, ext->alg);
ret = -EINVAL;
goto done;
}
ops = ieee80211_get_crypto_ops(alg);
if (ops == NULL) {
request_module(module);
ops = ieee80211_get_crypto_ops(alg);
}
if (ops == NULL) {
IEEE80211_DEBUG_WX("%s: unknown crypto alg %d\n",
dev->name, ext->alg);
ret = -EINVAL;
goto done;
}
if (*crypt == NULL || (*crypt)->ops != ops) {
struct ieee80211_crypt_data *new_crypt;
ieee80211_crypt_delayed_deinit(ieee, crypt);
new_crypt = (struct ieee80211_crypt_data *)
kmalloc(sizeof(*new_crypt), GFP_KERNEL);
if (new_crypt == NULL) {
ret = -ENOMEM;
goto done;
}
memset(new_crypt, 0, sizeof(struct ieee80211_crypt_data));
new_crypt->ops = ops;
if (new_crypt->ops && try_module_get(new_crypt->ops->owner))
new_crypt->priv = new_crypt->ops->init(ieee, idx);
if (new_crypt->priv == NULL) {
kfree(new_crypt);
ret = -EINVAL;
goto done;
}
*crypt = new_crypt;
}
if (ext->key_len > 0 && (*crypt)->ops->set_key &&
(*crypt)->ops->set_key(ext->key, ext->key_len, ext->rx_seq,
(*crypt)->priv) < 0) {
IEEE80211_DEBUG_WX("%s: key setting failed\n", dev->name);
ret = -EINVAL;
goto done;
}
skip_host_crypt:
if (ext->ext_flags & IW_ENCODE_EXT_SET_TX_KEY) {
ieee->tx_keyidx = idx;
sec.active_key = idx;
sec.flags |= SEC_ACTIVE_KEY;
}
if (ext->alg != IW_ENCODE_ALG_NONE) {
memcpy(sec.keys[idx], ext->key, ext->key_len);
sec.key_sizes[idx] = ext->key_len;
sec.flags |= (1 << idx);
if (ext->alg == IW_ENCODE_ALG_WEP) {
sec.encode_alg[idx] = SEC_ALG_WEP;
sec.flags |= SEC_LEVEL;
sec.level = SEC_LEVEL_1;
} else if (ext->alg == IW_ENCODE_ALG_TKIP) {
sec.encode_alg[idx] = SEC_ALG_TKIP;
sec.flags |= SEC_LEVEL;
sec.level = SEC_LEVEL_2;
} else if (ext->alg == IW_ENCODE_ALG_CCMP) {
sec.encode_alg[idx] = SEC_ALG_CCMP;
sec.flags |= SEC_LEVEL;
sec.level = SEC_LEVEL_3;
}
}
done:
if (ieee->set_security)
ieee->set_security(ieee->dev, &sec);
/*
* Do not reset port if card is in Managed mode since resetting will
* generate new IEEE 802.11 authentication which may end up in looping
* with IEEE 802.1X. If your hardware requires a reset after WEP
* configuration (for example... Prism2), implement the reset_port in
* the callbacks structures used to initialize the 802.11 stack.
*/
if (ieee->reset_on_keychange &&
ieee->iw_mode != IW_MODE_INFRA &&
ieee->reset_port && ieee->reset_port(dev)) {
IEEE80211_DEBUG_WX("%s: reset_port failed\n", dev->name);
return -EINVAL;
}
return ret;
}
int ieee80211_wx_get_encodeext(struct ieee80211_device *ieee,
struct iw_request_info *info,
union iwreq_data *wrqu, char *extra)
{
struct iw_point *encoding = &wrqu->encoding;
struct iw_encode_ext *ext = (struct iw_encode_ext *)extra;
struct ieee80211_security *sec = &ieee->sec;
int idx, max_key_len;
max_key_len = encoding->length - sizeof(*ext);
if (max_key_len < 0)
return -EINVAL;
idx = encoding->flags & IW_ENCODE_INDEX;
if (idx) {
if (idx < 1 || idx > WEP_KEYS)
return -EINVAL;
idx--;
} else
idx = ieee->tx_keyidx;
if (!ext->ext_flags & IW_ENCODE_EXT_GROUP_KEY)
if (idx != 0 || ieee->iw_mode != IW_MODE_INFRA)
return -EINVAL;
encoding->flags = idx + 1;
memset(ext, 0, sizeof(*ext));
if (!sec->enabled) {
ext->alg = IW_ENCODE_ALG_NONE;
ext->key_len = 0;
encoding->flags |= IW_ENCODE_DISABLED;
} else {
if (sec->encode_alg[idx] == SEC_ALG_WEP)
ext->alg = IW_ENCODE_ALG_WEP;
else if (sec->encode_alg[idx] == SEC_ALG_TKIP)
ext->alg = IW_ENCODE_ALG_TKIP;
else if (sec->encode_alg[idx] == SEC_ALG_CCMP)
ext->alg = IW_ENCODE_ALG_CCMP;
else
return -EINVAL;
ext->key_len = sec->key_sizes[idx];
memcpy(ext->key, sec->keys[idx], ext->key_len);
encoding->flags |= IW_ENCODE_ENABLED;
if (ext->key_len &&
(ext->alg == IW_ENCODE_ALG_TKIP ||
ext->alg == IW_ENCODE_ALG_CCMP))
ext->ext_flags |= IW_ENCODE_EXT_TX_SEQ_VALID;
}
return 0;
}
EXPORT_SYMBOL(ieee80211_wx_set_encodeext);
EXPORT_SYMBOL(ieee80211_wx_get_encodeext);
#endif
EXPORT_SYMBOL(ieee80211_wx_get_scan); EXPORT_SYMBOL(ieee80211_wx_get_scan);
EXPORT_SYMBOL(ieee80211_wx_set_encode); EXPORT_SYMBOL(ieee80211_wx_set_encode);
EXPORT_SYMBOL(ieee80211_wx_get_encode); EXPORT_SYMBOL(ieee80211_wx_get_encode);
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