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

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

[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
Loading
Loading
Loading
Loading
+14 −0
Original line number Original line Diff line number Diff line
@@ -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 {
	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,
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)
{
{
+230 −8
Original line number Original line Diff line number Diff line
@@ -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,
		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,
	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);