*     wants to be given when a frame is transmitted and needs to be
  *     encrypted in hardware.
  * @cipher: The key's cipher suite selector.
- * @tx_pn: PN used for TX on non-TKIP keys, may be used by the driver
- *     as well if it needs to do software PN assignment by itself
- *     (e.g. due to TSO)
+ * @tx_pn: PN used for TX keys, may be used by the driver as well if it
+ *     needs to do software PN assignment by itself (e.g. due to TSO)
  * @flags: key flags, see &enum ieee80211_key_flags.
  * @keyidx: the key index (0-3)
  * @keylen: key material length
 
 #define IEEE80211_MAX_PN_LEN   16
 
+#define TKIP_PN_TO_IV16(pn) ((u16)(pn & 0xffff))
+#define TKIP_PN_TO_IV32(pn) ((u32)((pn >> 16) & 0xffffffff))
+
 /**
  * struct ieee80211_key_seq - key sequence counter
  *
 void ieee80211_get_tkip_p2k(struct ieee80211_key_conf *keyconf,
                            struct sk_buff *skb, u8 *p2k);
 
+/**
+ * ieee80211_tkip_add_iv - write TKIP IV and Ext. IV to pos
+ *
+ * @pos: start of crypto header
+ * @keyconf: the parameter passed with the set key
+ * @pn: PN to add
+ *
+ * Returns: pointer to the octet following IVs (i.e. beginning of
+ * the packet payload)
+ *
+ * This function writes the tkip IV value to pos (which should
+ * point to the crypto header)
+ */
+u8 *ieee80211_tkip_add_iv(u8 *pos, struct ieee80211_key_conf *keyconf, u64 pn);
+
 /**
  * ieee80211_get_key_tx_seq - get key TX sequence counter
  *
 
 
        switch (key->conf.cipher) {
        case WLAN_CIPHER_SUITE_TKIP:
-               iv32 = key->u.tkip.tx.iv32;
-               iv16 = key->u.tkip.tx.iv16;
+               pn64 = atomic64_read(&key->conf.tx_pn);
+               iv32 = TKIP_PN_TO_IV32(pn64);
+               iv16 = TKIP_PN_TO_IV16(pn64);
 
                if (key->flags & KEY_FLAG_UPLOADED_TO_HARDWARE &&
                    !(key->conf.flags & IEEE80211_KEY_FLAG_GENERATE_IV)) {
 
                len = scnprintf(buf, sizeof(buf), "\n");
                break;
        case WLAN_CIPHER_SUITE_TKIP:
+               pn = atomic64_read(&key->conf.tx_pn);
                len = scnprintf(buf, sizeof(buf), "%08x %04x\n",
-                               key->u.tkip.tx.iv32,
-                               key->u.tkip.tx.iv16);
+                               TKIP_PN_TO_IV32(pn),
+                               TKIP_PN_TO_IV16(pn));
                break;
        case WLAN_CIPHER_SUITE_CCMP:
        case WLAN_CIPHER_SUITE_CCMP_256:
 
 
        switch (key->conf.cipher) {
        case WLAN_CIPHER_SUITE_TKIP:
-               seq->tkip.iv32 = key->u.tkip.tx.iv32;
-               seq->tkip.iv16 = key->u.tkip.tx.iv16;
+               pn64 = atomic64_read(&key->conf.tx_pn);
+               seq->tkip.iv32 = TKIP_PN_TO_IV32(pn64);
+               seq->tkip.iv16 = TKIP_PN_TO_IV16(pn64);
                break;
        case WLAN_CIPHER_SUITE_CCMP:
        case WLAN_CIPHER_SUITE_CCMP_256:
 
        switch (key->conf.cipher) {
        case WLAN_CIPHER_SUITE_TKIP:
-               key->u.tkip.tx.iv32 = seq->tkip.iv32;
-               key->u.tkip.tx.iv16 = seq->tkip.iv16;
+               pn64 = (u64)seq->tkip.iv16 | ((u64)seq->tkip.iv32 << 16);
+               atomic64_set(&key->conf.tx_pn, pn64);
                break;
        case WLAN_CIPHER_SUITE_CCMP:
        case WLAN_CIPHER_SUITE_CCMP_256:
 
 };
 
 struct tkip_ctx {
-       u32 iv32;       /* current iv32 */
-       u16 iv16;       /* current iv16 */
        u16 p1k[5];     /* p1k cache */
        u32 p1k_iv32;   /* iv32 for which p1k computed */
        enum ieee80211_internal_tkip_state state;
 };
 
+struct tkip_ctx_rx {
+       struct tkip_ctx ctx;
+       u32 iv32;       /* current iv32 */
+       u16 iv16;       /* current iv16 */
+};
+
 struct ieee80211_key {
        struct ieee80211_local *local;
        struct ieee80211_sub_if_data *sdata;
                        struct tkip_ctx tx;
 
                        /* last received RSC */
-                       struct tkip_ctx rx[IEEE80211_NUM_TIDS];
+                       struct tkip_ctx_rx rx[IEEE80211_NUM_TIDS];
 
                        /* number of mic failures */
                        u32 mic_failures;
 
 /*
  * Copyright 2002-2004, Instant802 Networks, Inc.
  * Copyright 2005, Devicescape Software, Inc.
+ * Copyright (C) 2016 Intel Deutschland GmbH
  *
  * This program is free software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License version 2 as
 /* 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)
+u8 *ieee80211_tkip_add_iv(u8 *pos, struct ieee80211_key_conf *keyconf, u64 pn)
 {
-       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);
+       pos = write_tkip_iv(pos, TKIP_PN_TO_IV16(pn));
+       *pos++ = (keyconf->keyidx << 6) | (1 << 5) /* Ext IV */;
+       put_unaligned_le32(TKIP_PN_TO_IV32(pn), pos);
        return pos + 4;
 }
+EXPORT_SYMBOL_GPL(ieee80211_tkip_add_iv);
 
 static void ieee80211_compute_tkip_p1k(struct ieee80211_key *key, u32 iv32)
 {
        u8 rc4key[16], keyid, *pos = payload;
        int res;
        const u8 *tk = &key->conf.key[NL80211_TKIP_DATA_OFFSET_ENCR_KEY];
+       struct tkip_ctx_rx *rx_ctx = &key->u.tkip.rx[queue];
 
        if (payload_len < 12)
                return -1;
        if ((keyid >> 6) != key->conf.keyidx)
                return TKIP_DECRYPT_INVALID_KEYIDX;
 
-       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)))
+       if (rx_ctx->ctx.state != TKIP_STATE_NOT_INIT &&
+           (iv32 < rx_ctx->iv32 ||
+            (iv32 == rx_ctx->iv32 && iv16 <= rx_ctx->iv16)))
                return TKIP_DECRYPT_REPLAY;
 
        if (only_iv) {
                res = TKIP_DECRYPT_OK;
-               key->u.tkip.rx[queue].state = TKIP_STATE_PHASE1_HW_UPLOADED;
+               rx_ctx->ctx.state = TKIP_STATE_PHASE1_HW_UPLOADED;
                goto done;
        }
 
-       if (key->u.tkip.rx[queue].state == TKIP_STATE_NOT_INIT ||
-           key->u.tkip.rx[queue].iv32 != iv32) {
+       if (rx_ctx->ctx.state == TKIP_STATE_NOT_INIT ||
+           rx_ctx->iv32 != iv32) {
                /* IV16 wrapped around - perform TKIP phase 1 */
-               tkip_mixing_phase1(tk, &key->u.tkip.rx[queue], ta, iv32);
+               tkip_mixing_phase1(tk, &rx_ctx->ctx, ta, iv32);
        }
        if (key->local->ops->update_tkip_key &&
            key->flags & KEY_FLAG_UPLOADED_TO_HARDWARE &&
-           key->u.tkip.rx[queue].state != TKIP_STATE_PHASE1_HW_UPLOADED) {
+           rx_ctx->ctx.state != TKIP_STATE_PHASE1_HW_UPLOADED) {
                struct ieee80211_sub_if_data *sdata = key->sdata;
 
                if (sdata->vif.type == NL80211_IFTYPE_AP_VLAN)
                        sdata = container_of(key->sdata->bss,
                                        struct ieee80211_sub_if_data, u.ap);
                drv_update_tkip_key(key->local, sdata, &key->conf, key->sta,
-                               iv32, key->u.tkip.rx[queue].p1k);
-               key->u.tkip.rx[queue].state = TKIP_STATE_PHASE1_HW_UPLOADED;
+                               iv32, rx_ctx->ctx.p1k);
+               rx_ctx->ctx.state = TKIP_STATE_PHASE1_HW_UPLOADED;
        }
 
-       tkip_mixing_phase2(tk, &key->u.tkip.rx[queue], iv16, rc4key);
+       tkip_mixing_phase2(tk, &rx_ctx->ctx, iv16, rc4key);
 
        res = ieee80211_wep_decrypt_data(tfm, rc4key, 16, pos, payload_len - 12);
  done:
 
 #include <linux/crypto.h>
 #include "key.h"
 
-u8 *ieee80211_tkip_add_iv(u8 *pos, struct ieee80211_key *key);
-
 int ieee80211_tkip_encrypt_data(struct crypto_cipher *tfm,
                                struct ieee80211_key *key,
                                struct sk_buff *skb,
 
 /*
  * Copyright 2002-2004, Instant802 Networks, Inc.
  * Copyright 2008, Jouni Malinen <j@w1.fi>
+ * Copyright (C) 2016 Intel Deutschland GmbH
  *
  * This program is free software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License version 2 as
        return RX_DROP_UNUSABLE;
 }
 
-
 static int tkip_encrypt_skb(struct ieee80211_tx_data *tx, struct sk_buff *skb)
 {
        struct ieee80211_hdr *hdr = (struct ieee80211_hdr *) skb->data;
        struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb);
        unsigned int hdrlen;
        int len, tail;
+       u64 pn;
        u8 *pos;
 
        if (info->control.hw_key &&
                return 0;
 
        /* Increase IV for the frame */
-       spin_lock(&key->u.tkip.txlock);
-       key->u.tkip.tx.iv16++;
-       if (key->u.tkip.tx.iv16 == 0)
-               key->u.tkip.tx.iv32++;
-       pos = ieee80211_tkip_add_iv(pos, key);
-       spin_unlock(&key->u.tkip.txlock);
+       pn = atomic64_inc_return(&key->conf.tx_pn);
+       pos = ieee80211_tkip_add_iv(pos, &key->conf, pn);
 
        /* hwaccel - with software IV */
        if (info->control.hw_key)