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

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

[PATCH] ieee80211: Hardware crypto and fragmentation offload support



tree 5322d496af90d03ffbec27292dc1a6268a746ede
parent 6c9364386ccb786e4a84427ab3ad712f0b7b8904
author James Ketrenos <jketreno@linux.intel.com> 1124432367 -0500
committer James Ketrenos <jketreno@linux.intel.com> 1127311810 -0500

Hardware crypto and fragmentation offload support added (Zhu Yi)

Signed-off-by: default avatarJames Ketrenos <jketreno@linux.intel.com>
Signed-off-by: default avatarJeff Garzik <jgarzik@pobox.com>
parent 20d64713
Loading
Loading
Loading
Loading
+25 −21
Original line number Diff line number Diff line
@@ -434,12 +434,12 @@ struct ieee80211_device;
#define SEC_KEY_2		(1<<1)
#define SEC_KEY_3		(1<<2)
#define SEC_KEY_4		(1<<3)
#define SEC_KEY_MASK      (SEC_KEY_1 | SEC_KEY_2 | SEC_KEY_3 | SEC_KEY_4)
#define SEC_ACTIVE_KEY		(1<<4)
#define SEC_AUTH_MODE		(1<<5)
#define SEC_UNICAST_GROUP	(1<<6)
#define SEC_LEVEL		(1<<7)
#define SEC_ENABLED		(1<<8)
#define SEC_TGI_KEY_RESET	(1<<9)

#define SEC_LEVEL_0		0	/* None */
#define SEC_LEVEL_1		1	/* WEP 40 and 104 bit */
@@ -449,12 +449,15 @@ struct ieee80211_device;

#define WEP_KEYS		4
#define WEP_KEY_LEN		13
#define SCM_KEY_LEN		32
#define SCM_TEMPORAL_KEY_LENGTH	16

struct ieee80211_security {
	u16 active_key:2,
	    enabled:1, auth_mode:2, auth_algo:4, unicast_uses_group:1;
	    enabled:1,
	    auth_mode:2, auth_algo:4, unicast_uses_group:1, encrypt:1;
	u8 key_sizes[WEP_KEYS];
	u8 keys[WEP_KEYS][WEP_KEY_LEN];
	u8 keys[WEP_KEYS][SCM_KEY_LEN];
	u8 level;
	u16 flags;
} __attribute__ ((packed));
@@ -636,6 +639,7 @@ enum ieee80211_state {

struct ieee80211_device {
	struct net_device *dev;
	struct ieee80211_security sec;

	/* Bookkeeping structures */
	struct net_device_stats stats;
+21 −6
Original line number Diff line number Diff line
@@ -231,7 +231,7 @@ int ieee80211_xmit(struct sk_buff *skb, struct net_device *dev)
	int i, bytes_per_frag, nr_frags, bytes_last_frag, frag_size;
	unsigned long flags;
	struct net_device_stats *stats = &ieee->stats;
	int ether_type, encrypt;
	int ether_type, encrypt, host_encrypt;
	int bytes, fc, hdr_len;
	struct sk_buff *skb_frag;
	struct ieee80211_hdr header = {	/* Ensure zero initialized */
@@ -262,7 +262,8 @@ int ieee80211_xmit(struct sk_buff *skb, struct net_device *dev)
	crypt = ieee->crypt[ieee->tx_keyidx];

	encrypt = !(ether_type == ETH_P_PAE && ieee->ieee802_1x) &&
	    ieee->host_encrypt && crypt && crypt->ops;
	    ieee->sec.encrypt;
	host_encrypt = ieee->host_encrypt && encrypt;

	if (!encrypt && ieee->ieee802_1x &&
	    ieee->drop_unencrypted && ether_type != ETH_P_PAE) {
@@ -280,7 +281,7 @@ int ieee80211_xmit(struct sk_buff *skb, struct net_device *dev)
	/* Determine total amount of storage required for TXB packets */
	bytes = skb->len + SNAP_SIZE + sizeof(u16);

	if (encrypt)
	if (host_encrypt)
		fc = IEEE80211_FTYPE_DATA | IEEE80211_STYPE_DATA |
		    IEEE80211_FCTL_PROTECTED;
	else
@@ -320,7 +321,7 @@ int ieee80211_xmit(struct sk_buff *skb, struct net_device *dev)
		bytes_per_frag -= IEEE80211_FCS_LEN;

	/* Each fragment may need to have room for encryptiong pre/postfix */
	if (encrypt)
	if (host_encrypt)
		bytes_per_frag -= crypt->ops->extra_prefix_len +
		    crypt->ops->extra_postfix_len;

@@ -348,7 +349,7 @@ int ieee80211_xmit(struct sk_buff *skb, struct net_device *dev)
	for (i = 0; i < nr_frags; i++) {
		skb_frag = txb->fragments[i];

		if (encrypt)
		if (host_encrypt)
			skb_reserve(skb_frag, crypt->ops->extra_prefix_len);

		frag_hdr = (struct ieee80211_hdr *)skb_put(skb_frag, hdr_len);
@@ -380,8 +381,22 @@ int ieee80211_xmit(struct sk_buff *skb, struct net_device *dev)

		/* Encryption routine will move the header forward in order
		 * to insert the IV between the header and the payload */
		if (encrypt)
		if (host_encrypt)
			ieee80211_encrypt_fragment(ieee, skb_frag, hdr_len);

		/* ipw2200/2915 Hardware encryption doesn't support TKIP MIC */
		if (!ieee->host_encrypt && encrypt &&
		    (ieee->sec.level == SEC_LEVEL_2) &&
		    crypt && crypt->ops && crypt->ops->encrypt_msdu) {
			int res = 0;
			res = crypt->ops->encrypt_msdu(skb_frag, hdr_len,
						       crypt->priv);
			if (res < 0) {
				IEEE80211_ERROR("TKIP MIC encryption failed\n");
				goto failed;
			}
		}

		if (ieee->config &
		    (CFG_IEEE80211_COMPUTE_FCS | CFG_IEEE80211_RESERVE_FCS))
			skb_put(skb_frag, 4);
+29 −21
Original line number Diff line number Diff line
@@ -278,6 +278,7 @@ int ieee80211_wx_set_encode(struct ieee80211_device *ieee,
	};
	int i, key, key_provided, len;
	struct ieee80211_crypt_data **crypt;
	int host_crypto = ieee->host_encrypt || ieee->host_decrypt;

	IEEE80211_DEBUG_WX("SET_ENCODE\n");

@@ -318,6 +319,7 @@ int ieee80211_wx_set_encode(struct ieee80211_device *ieee,

		if (i == WEP_KEYS) {
			sec.enabled = 0;
			sec.encrypt = 0;
			sec.level = SEC_LEVEL_0;
			sec.flags |= SEC_ENABLED | SEC_LEVEL;
		}
@@ -326,6 +328,7 @@ int ieee80211_wx_set_encode(struct ieee80211_device *ieee,
	}

	sec.enabled = 1;
	sec.encrypt = 1;
	sec.flags |= SEC_ENABLED;

	if (*crypt != NULL && (*crypt)->ops != NULL &&
@@ -335,7 +338,7 @@ int ieee80211_wx_set_encode(struct ieee80211_device *ieee,
		ieee80211_crypt_delayed_deinit(ieee, crypt);
	}

	if (*crypt == NULL) {
	if (*crypt == NULL && host_crypto) {
		struct ieee80211_crypt_data *new_crypt;

		/* take WEP into use */
@@ -375,6 +378,7 @@ int ieee80211_wx_set_encode(struct ieee80211_device *ieee,
				   key, escape_essid(sec.keys[key], len),
				   erq->length, len);
		sec.key_sizes[key] = len;
		if (*crypt)
			(*crypt)->ops->set_key(sec.keys[key], len, NULL,
					       (*crypt)->priv);
		sec.flags |= (1 << key);
@@ -382,24 +386,26 @@ int ieee80211_wx_set_encode(struct ieee80211_device *ieee,
		 * explicitely set */
		if (key == sec.active_key)
			sec.flags |= SEC_ACTIVE_KEY;

	} else {
		if (host_crypto) {
			len = (*crypt)->ops->get_key(sec.keys[key], WEP_KEY_LEN,
						     NULL, (*crypt)->priv);
			if (len == 0) {
				/* Set a default key of all 0 */
			IEEE80211_DEBUG_WX("Setting key %d to all zero.\n",
					   key);
				IEEE80211_DEBUG_WX("Setting key %d to all "
						   "zero.\n", key);
				memset(sec.keys[key], 0, 13);
				(*crypt)->ops->set_key(sec.keys[key], 13, NULL,
						       (*crypt)->priv);
				sec.key_sizes[key] = 13;
				sec.flags |= (1 << key);
			}

		}
		/* No key data - just set the default TX key index */
		if (key_provided) {
			IEEE80211_DEBUG_WX
			    ("Setting key %d to default Tx key.\n", key);
			IEEE80211_DEBUG_WX("Setting key %d to default Tx "
					   "key.\n", key);
			ieee->tx_keyidx = key;
			sec.active_key = key;
			sec.flags |= SEC_ACTIVE_KEY;
@@ -442,6 +448,7 @@ int ieee80211_wx_get_encode(struct ieee80211_device *ieee,
	struct iw_point *erq = &(wrqu->encoding);
	int len, key;
	struct ieee80211_crypt_data *crypt;
	struct ieee80211_security *sec = &ieee->sec;

	IEEE80211_DEBUG_WX("GET_ENCODE\n");

@@ -456,13 +463,13 @@ int ieee80211_wx_get_encode(struct ieee80211_device *ieee,
	crypt = ieee->crypt[key];
	erq->flags = key + 1;

	if (crypt == NULL || crypt->ops == NULL) {
	if (!sec->enabled) {
		erq->length = 0;
		erq->flags |= IW_ENCODE_DISABLED;
		return 0;
	}

	if (strcmp(crypt->ops->name, "WEP") != 0) {
	if (sec->level != SEC_LEVEL_1) {
		/* only WEP is supported with wireless extensions, so just
		 * report that encryption is used */
		erq->length = 0;
@@ -470,9 +477,10 @@ int ieee80211_wx_get_encode(struct ieee80211_device *ieee,
		return 0;
	}

	len = crypt->ops->get_key(keybuf, WEP_KEY_LEN, NULL, crypt->priv);
	erq->length = (len >= 0 ? len : 0);
	len = sec->key_sizes[key];
	memcpy(keybuf, sec->keys[key], len);

	erq->length = (len >= 0 ? len : 0);
	erq->flags |= IW_ENCODE_ENABLED;

	if (ieee->open_wep)