mirror of https://gitee.com/openkylin/linux.git
[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: James Ketrenos <jketreno@linux.intel.com> Signed-off-by: Jeff Garzik <jgarzik@pobox.com>
This commit is contained in:
parent
259bf1fd8a
commit
e0d369d1d9
|
@ -447,6 +447,11 @@ struct ieee80211_device;
|
|||
#define SEC_LEVEL_2_CKIP 3 /* Level 1 + CKIP */
|
||||
#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_KEY_LEN 13
|
||||
#define SCM_KEY_LEN 32
|
||||
|
@ -456,6 +461,7 @@ struct ieee80211_security {
|
|||
u16 active_key:2,
|
||||
enabled:1,
|
||||
auth_mode:2, auth_algo:4, unicast_uses_group:1, encrypt:1;
|
||||
u8 encode_alg[WEP_KEYS];
|
||||
u8 key_sizes[WEP_KEYS];
|
||||
u8 keys[WEP_KEYS][SCM_KEY_LEN];
|
||||
u8 level;
|
||||
|
@ -824,6 +830,14 @@ extern int ieee80211_wx_set_encode(struct ieee80211_device *ieee,
|
|||
extern int ieee80211_wx_get_encode(struct ieee80211_device *ieee,
|
||||
struct iw_request_info *info,
|
||||
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)
|
||||
{
|
||||
|
|
|
@ -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 */
|
||||
sec.flags |= SEC_LEVEL;
|
||||
sec.level = SEC_LEVEL_1; /* 40 and 104 bit WEP */
|
||||
sec.encode_alg[key] = SEC_ALG_WEP;
|
||||
|
||||
done:
|
||||
if (ieee->set_security)
|
||||
|
@ -469,14 +470,6 @@ int ieee80211_wx_get_encode(struct ieee80211_device *ieee,
|
|||
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];
|
||||
memcpy(keybuf, sec->keys[key], len);
|
||||
|
||||
|
@ -491,6 +484,235 @@ int ieee80211_wx_get_encode(struct ieee80211_device *ieee,
|
|||
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_set_encode);
|
||||
EXPORT_SYMBOL(ieee80211_wx_get_encode);
|
||||
|
|
Loading…
Reference in New Issue