+-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]);
+-
+- tk = &key->conf.key[NL80211_TKIP_DATA_OFFSET_ENCR_KEY];
+- ctx = &key->u.tkip.tx;
+-
+-#ifdef CONFIG_MAC80211_TKIP_DEBUG
+- printk(KERN_DEBUG "TKIP encrypt: iv16 = 0x%04x, iv32 = 0x%08x\n",
+- iv16, iv32);
++ 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];
+
+- 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
++ lockdep_assert_held(&key->u.tkip.txlock);
+
+- /* 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);
++ /*
++ * 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);
++}
+
+- if (type == IEEE80211_TKIP_P1_KEY) {
+- memcpy(outkey, ctx->p1k, sizeof(u16) * 5);
+- return;
+- }
++void ieee80211_get_tkip_p1k(struct ieee80211_key_conf *keyconf,
++ struct sk_buff *skb, u16 *p1k)
++{
++ struct ieee80211_key *key = (struct ieee80211_key *)
++ container_of(keyconf, struct ieee80211_key, conf);
++ 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]);
++ unsigned long flags;
++
++ spin_lock_irqsave(&key->u.tkip.txlock, flags);
++ ieee80211_compute_tkip_p1k(key, iv32);
++ memcpy(p1k, ctx->p1k, sizeof(ctx->p1k));
++ spin_unlock_irqrestore(&key->u.tkip.txlock, flags);
++}
++EXPORT_SYMBOL(ieee80211_get_tkip_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);
++ unsigned long flags;
++
++ spin_lock_irqsave(&key->u.tkip.txlock, flags);
++ ieee80211_compute_tkip_p1k(key, iv32);
++ tkip_mixing_phase2(tk, ctx, iv16, p2k);
++ spin_unlock_irqrestore(&key->u.tkip.txlock, flags);
+ }
+-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
+@@ -204,19 +217,15 @@ EXPORT_SYMBOL(ieee80211_get_tkip_key);
+ */
+ 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
+--- a/net/mac80211/tkip.h
++++ b/net/mac80211/tkip.h
+@@ -13,11 +13,13 @@
+ #include <linux/crypto.h>
+ #include "key.h"
+
+-u8 *ieee80211_tkip_add_iv(u8 *pos, struct ieee80211_key *key, u16 iv16);
++u8 *ieee80211_tkip_add_iv(u8 *pos, struct ieee80211_key *key);
+
+ int ieee80211_tkip_encrypt_data(struct crypto_cipher *tfm,
+- struct ieee80211_key *key,
+- u8 *pos, size_t payload_len, u8 *ta);
++ struct ieee80211_key *key,
++ struct sk_buff *skb,
++ u8 *payload, size_t payload_len);
++
+ enum {
+ TKIP_DECRYPT_OK = 0,
+ TKIP_DECRYPT_NO_EXT_IV = -1,
+--- a/net/mac80211/cfg.c
++++ b/net/mac80211/cfg.c
+@@ -209,6 +209,7 @@ static int ieee80211_get_key(struct wiph
+ u8 seq[6] = {0};
+ struct key_params params;
+ struct ieee80211_key *key = NULL;
++ u64 pn64;
+ u32 iv32;
+ u16 iv16;
+ int err = -ENOENT;
+@@ -256,12 +257,13 @@ static int ieee80211_get_key(struct wiph
+ params.seq_len = 6;
+ break;
+ case WLAN_CIPHER_SUITE_CCMP:
+- seq[0] = key->u.ccmp.tx_pn[5];
+- seq[1] = key->u.ccmp.tx_pn[4];
+- seq[2] = key->u.ccmp.tx_pn[3];
+- seq[3] = key->u.ccmp.tx_pn[2];
+- seq[4] = key->u.ccmp.tx_pn[1];
+- seq[5] = key->u.ccmp.tx_pn[0];
++ pn64 = atomic64_read(&key->u.ccmp.tx_pn);
++ seq[0] = pn64;
++ seq[1] = pn64 >> 8;
++ seq[2] = pn64 >> 16;
++ seq[3] = pn64 >> 24;
++ seq[4] = pn64 >> 32;
++ seq[5] = pn64 >> 40;
+ params.seq = seq;
+ params.seq_len = 6;
+ break;
+--- a/net/mac80211/debugfs_key.c
++++ b/net/mac80211/debugfs_key.c
+@@ -79,6 +79,7 @@ static ssize_t key_tx_spec_read(struct f
+ size_t count, loff_t *ppos)
+ {
+ const u8 *tpn;
++ u64 pn;
+ char buf[20];
+ int len;
+ struct ieee80211_key *key = file->private_data;
+@@ -94,9 +95,10 @@ static ssize_t key_tx_spec_read(struct f
+ key->u.tkip.tx.iv16);
+ break;
+ case WLAN_CIPHER_SUITE_CCMP:
+- tpn = key->u.ccmp.tx_pn;
++ pn = atomic64_read(&key->u.ccmp.tx_pn);
+ len = scnprintf(buf, sizeof(buf), "%02x%02x%02x%02x%02x%02x\n",
+- tpn[0], tpn[1], tpn[2], tpn[3], tpn[4], tpn[5]);
++ (u8)(pn >> 40), (u8)(pn >> 32), (u8)(pn >> 24),
++ (u8)(pn >> 16), (u8)(pn >> 8), (u8)pn);
+ break;
+ case WLAN_CIPHER_SUITE_AES_CMAC:
+ tpn = key->u.aes_cmac.tx_pn;