diff options
Diffstat (limited to 'net/mac80211/tkip.c')
| -rw-r--r-- | net/mac80211/tkip.c | 164 | 
1 files changed, 68 insertions, 96 deletions
diff --git a/net/mac80211/tkip.c b/net/mac80211/tkip.c index e840c9cd46d..0ae207771a5 100644 --- a/net/mac80211/tkip.c +++ b/net/mac80211/tkip.c @@ -10,6 +10,7 @@  #include <linux/bitops.h>  #include <linux/types.h>  #include <linux/netdevice.h> +#include <linux/export.h>  #include <asm/unaligned.h>  #include <net/mac80211.h> @@ -101,6 +102,7 @@ static void tkip_mixing_phase1(const u8 *tk, struct tkip_ctx *ctx,  		p1k[4] += tkipS(p1k[3] ^ get_unaligned_le16(tk + 0 + j)) + i;  	}  	ctx->state = TKIP_STATE_PHASE1_DONE; +	ctx->p1k_iv32 = tsc_IV32;  }  static void tkip_mixing_phase2(const u8 *tk, struct tkip_ctx *ctx, @@ -140,60 +142,78 @@ static void tkip_mixing_phase2(const u8 *tk, struct tkip_ctx *ctx,  /* Add TKIP IV and Ext. IV at @pos. @iv0, @iv1, and @iv2 are the first octets   * of the IV. Returns pointer to the octet following IVs (i.e., beginning of   * the packet payload). */ -u8 *ieee80211_tkip_add_iv(u8 *pos, struct ieee80211_key *key, u16 iv16) +u8 *ieee80211_tkip_add_iv(u8 *pos, struct ieee80211_key *key)  { -	pos = write_tkip_iv(pos, iv16); +	lockdep_assert_held(&key->u.tkip.txlock); + +	pos = write_tkip_iv(pos, key->u.tkip.tx.iv16);  	*pos++ = (key->conf.keyidx << 6) | (1 << 5) /* Ext IV */;  	put_unaligned_le32(key->u.tkip.tx.iv32, pos);  	return pos + 4;  } -void ieee80211_get_tkip_key(struct ieee80211_key_conf *keyconf, -			struct sk_buff *skb, enum ieee80211_tkip_key_type type, -			u8 *outkey) +static void ieee80211_compute_tkip_p1k(struct ieee80211_key *key, u32 iv32)  { -	struct ieee80211_key *key = (struct ieee80211_key *) -			container_of(keyconf, struct ieee80211_key, conf); -	struct ieee80211_hdr *hdr = (struct ieee80211_hdr *)skb->data; -	u8 *data; -	const u8 *tk; -	struct tkip_ctx *ctx; -	u16 iv16; -	u32 iv32; - -	data = (u8 *)hdr + ieee80211_hdrlen(hdr->frame_control); -	iv16 = data[2] | (data[0] << 8); -	iv32 = get_unaligned_le32(&data[4]); +	struct ieee80211_sub_if_data *sdata = key->sdata; +	struct tkip_ctx *ctx = &key->u.tkip.tx; +	const u8 *tk = &key->conf.key[NL80211_TKIP_DATA_OFFSET_ENCR_KEY]; -	tk = &key->conf.key[NL80211_TKIP_DATA_OFFSET_ENCR_KEY]; -	ctx = &key->u.tkip.tx; +	lockdep_assert_held(&key->u.tkip.txlock); + +	/* +	 * Update the P1K when the IV32 is different from the value it +	 * had when we last computed it (or when not initialised yet). +	 * This might flip-flop back and forth if packets are processed +	 * out-of-order due to the different ACs, but then we have to +	 * just compute the P1K more often. +	 */ +	if (ctx->p1k_iv32 != iv32 || ctx->state == TKIP_STATE_NOT_INIT) +		tkip_mixing_phase1(tk, ctx, sdata->vif.addr, iv32); +} -#ifdef CONFIG_MAC80211_TKIP_DEBUG -	printk(KERN_DEBUG "TKIP encrypt: iv16 = 0x%04x, iv32 = 0x%08x\n", -			iv16, iv32); +void ieee80211_get_tkip_p1k_iv(struct ieee80211_key_conf *keyconf, +			       u32 iv32, u16 *p1k) +{ +	struct ieee80211_key *key = (struct ieee80211_key *) +			container_of(keyconf, struct ieee80211_key, conf); +	struct tkip_ctx *ctx = &key->u.tkip.tx; -	if (iv32 != ctx->iv32) { -		printk(KERN_DEBUG "skb: iv32 = 0x%08x key: iv32 = 0x%08x\n", -			iv32, ctx->iv32); -		printk(KERN_DEBUG "Wrap around of iv16 in the middle of a " -			"fragmented packet\n"); -	} -#endif +	spin_lock_bh(&key->u.tkip.txlock); +	ieee80211_compute_tkip_p1k(key, iv32); +	memcpy(p1k, ctx->p1k, sizeof(ctx->p1k)); +	spin_unlock_bh(&key->u.tkip.txlock); +} +EXPORT_SYMBOL(ieee80211_get_tkip_p1k_iv); -	/* Update the p1k only when the iv16 in the packet wraps around, this -	 * might occur after the wrap around of iv16 in the key in case of -	 * fragmented packets. */ -	if (iv16 == 0 || ctx->state == TKIP_STATE_NOT_INIT) -		tkip_mixing_phase1(tk, ctx, hdr->addr2, iv32); +void ieee80211_get_tkip_rx_p1k(struct ieee80211_key_conf *keyconf, +			       const u8 *ta, u32 iv32, u16 *p1k) +{ +	const u8 *tk = &keyconf->key[NL80211_TKIP_DATA_OFFSET_ENCR_KEY]; +	struct tkip_ctx ctx; -	if (type == IEEE80211_TKIP_P1_KEY) { -		memcpy(outkey, ctx->p1k, sizeof(u16) * 5); -		return; -	} +	tkip_mixing_phase1(tk, &ctx, ta, iv32); +	memcpy(p1k, ctx.p1k, sizeof(ctx.p1k)); +} +EXPORT_SYMBOL(ieee80211_get_tkip_rx_p1k); -	tkip_mixing_phase2(tk, ctx, iv16, outkey); +void ieee80211_get_tkip_p2k(struct ieee80211_key_conf *keyconf, +			    struct sk_buff *skb, u8 *p2k) +{ +	struct ieee80211_key *key = (struct ieee80211_key *) +			container_of(keyconf, struct ieee80211_key, conf); +	const u8 *tk = &key->conf.key[NL80211_TKIP_DATA_OFFSET_ENCR_KEY]; +	struct tkip_ctx *ctx = &key->u.tkip.tx; +	struct ieee80211_hdr *hdr = (struct ieee80211_hdr *)skb->data; +	const u8 *data = (u8 *)hdr + ieee80211_hdrlen(hdr->frame_control); +	u32 iv32 = get_unaligned_le32(&data[4]); +	u16 iv16 = data[2] | (data[0] << 8); + +	spin_lock(&key->u.tkip.txlock); +	ieee80211_compute_tkip_p1k(key, iv32); +	tkip_mixing_phase2(tk, ctx, iv16, p2k); +	spin_unlock(&key->u.tkip.txlock);  } -EXPORT_SYMBOL(ieee80211_get_tkip_key); +EXPORT_SYMBOL(ieee80211_get_tkip_p2k);  /*   * Encrypt packet payload with TKIP using @key. @pos is a pointer to the @@ -202,28 +222,24 @@ EXPORT_SYMBOL(ieee80211_get_tkip_key);   * @payload_len is the length of payload (_not_ including IV/ICV length).   * @ta is the transmitter addresses.   */ -int ieee80211_tkip_encrypt_data(struct crypto_blkcipher *tfm, +int ieee80211_tkip_encrypt_data(struct crypto_cipher *tfm,  				struct ieee80211_key *key, -				u8 *pos, size_t payload_len, u8 *ta) +				struct sk_buff *skb, +				u8 *payload, size_t payload_len)  {  	u8 rc4key[16]; -	struct tkip_ctx *ctx = &key->u.tkip.tx; -	const u8 *tk = &key->conf.key[NL80211_TKIP_DATA_OFFSET_ENCR_KEY]; - -	/* Calculate per-packet key */ -	if (ctx->iv16 == 0 || ctx->state == TKIP_STATE_NOT_INIT) -		tkip_mixing_phase1(tk, ctx, ta, ctx->iv32); -	tkip_mixing_phase2(tk, ctx, ctx->iv16, rc4key); +	ieee80211_get_tkip_p2k(&key->conf, skb, rc4key); -	return ieee80211_wep_encrypt_data(tfm, rc4key, 16, pos, payload_len); +	return ieee80211_wep_encrypt_data(tfm, rc4key, 16, +					  payload, payload_len);  }  /* Decrypt packet payload with TKIP using @key. @pos is a pointer to the   * beginning of the buffer containing IEEE 802.11 header payload, i.e.,   * including IV, Ext. IV, real data, Michael MIC, ICV. @payload_len is the   * length of payload, including IV, Ext. IV, MIC, ICV.  */ -int ieee80211_tkip_decrypt_data(struct crypto_blkcipher *tfm, +int ieee80211_tkip_decrypt_data(struct crypto_cipher *tfm,  				struct ieee80211_key *key,  				u8 *payload, size_t payload_len, u8 *ta,  				u8 *ra, int only_iv, int queue, @@ -242,17 +258,6 @@ int ieee80211_tkip_decrypt_data(struct crypto_blkcipher *tfm,  	keyid = pos[3];  	iv32 = get_unaligned_le32(pos + 4);  	pos += 8; -#ifdef CONFIG_MAC80211_TKIP_DEBUG -	{ -		int i; -		printk(KERN_DEBUG "TKIP decrypt: data(len=%zd)", payload_len); -		for (i = 0; i < payload_len; i++) -			printk(" %02x", payload[i]); -		printk("\n"); -		printk(KERN_DEBUG "TKIP decrypt: iv16=%04x iv32=%08x\n", -		       iv16, iv32); -	} -#endif  	if (!(keyid & (1 << 5)))  		return TKIP_DECRYPT_NO_EXT_IV; @@ -263,16 +268,8 @@ int ieee80211_tkip_decrypt_data(struct crypto_blkcipher *tfm,  	if (key->u.tkip.rx[queue].state != TKIP_STATE_NOT_INIT &&  	    (iv32 < key->u.tkip.rx[queue].iv32 ||  	     (iv32 == key->u.tkip.rx[queue].iv32 && -	      iv16 <= key->u.tkip.rx[queue].iv16))) { -#ifdef CONFIG_MAC80211_TKIP_DEBUG -		printk(KERN_DEBUG "TKIP replay detected for RX frame from " -		       "%pM (RX IV (%04x,%02x) <= prev. IV (%04x,%02x)\n", -		       ta, -		       iv32, iv16, key->u.tkip.rx[queue].iv32, -		       key->u.tkip.rx[queue].iv16); -#endif +	      iv16 <= key->u.tkip.rx[queue].iv16)))  		return TKIP_DECRYPT_REPLAY; -	}  	if (only_iv) {  		res = TKIP_DECRYPT_OK; @@ -284,22 +281,6 @@ int ieee80211_tkip_decrypt_data(struct crypto_blkcipher *tfm,  	    key->u.tkip.rx[queue].iv32 != iv32) {  		/* IV16 wrapped around - perform TKIP phase 1 */  		tkip_mixing_phase1(tk, &key->u.tkip.rx[queue], ta, iv32); -#ifdef CONFIG_MAC80211_TKIP_DEBUG -		{ -			int i; -			u8 key_offset = NL80211_TKIP_DATA_OFFSET_ENCR_KEY; -			printk(KERN_DEBUG "TKIP decrypt: Phase1 TA=%pM" -			       " TK=", ta); -			for (i = 0; i < 16; i++) -				printk("%02x ", -				       key->conf.key[key_offset + i]); -			printk("\n"); -			printk(KERN_DEBUG "TKIP decrypt: P1K="); -			for (i = 0; i < 5; i++) -				printk("%04x ", key->u.tkip.rx[queue].p1k[i]); -			printk("\n"); -		} -#endif  	}  	if (key->local->ops->update_tkip_key &&  	    key->flags & KEY_FLAG_UPLOADED_TO_HARDWARE && @@ -315,15 +296,6 @@ int ieee80211_tkip_decrypt_data(struct crypto_blkcipher *tfm,  	}  	tkip_mixing_phase2(tk, &key->u.tkip.rx[queue], iv16, rc4key); -#ifdef CONFIG_MAC80211_TKIP_DEBUG -	{ -		int i; -		printk(KERN_DEBUG "TKIP decrypt: Phase2 rc4key="); -		for (i = 0; i < 16; i++) -			printk("%02x ", rc4key[i]); -		printk("\n"); -	} -#endif  	res = ieee80211_wep_decrypt_data(tfm, rc4key, 16, pos, payload_len - 12);   done:  | 
