return NULL;
 }
 
+static void increment_tailroom_need_count(struct ieee80211_sub_if_data *sdata)
+{
+       /*
+        * When this count is zero, SKB resizing for allocating tailroom
+        * for IV or MMIC is skipped. But, this check has created two race
+        * cases in xmit path while transiting from zero count to one:
+        *
+        * 1. SKB resize was skipped because no key was added but just before
+        * the xmit key is added and SW encryption kicks off.
+        *
+        * 2. SKB resize was skipped because all the keys were hw planted but
+        * just before xmit one of the key is deleted and SW encryption kicks
+        * off.
+        *
+        * In both the above case SW encryption will find not enough space for
+        * tailroom and exits with WARN_ON. (See WARN_ONs at wpa.c)
+        *
+        * Solution has been explained at
+        * http://mid.gmane.org/1308590980.4322.19.camel@jlt3.sipsolutions.net
+        */
+
+       if (!sdata->crypto_tx_tailroom_needed_cnt++) {
+               /*
+                * Flush all XMIT packets currently using HW encryption or no
+                * encryption at all if the count transition is from 0 -> 1.
+                */
+               synchronize_net();
+       }
+}
+
 static int ieee80211_key_enable_hw_accel(struct ieee80211_key *key)
 {
        struct ieee80211_sub_if_data *sdata;
 
        if (!ret) {
                key->flags |= KEY_FLAG_UPLOADED_TO_HARDWARE;
+
+               if (!((key->conf.flags & IEEE80211_KEY_FLAG_GENERATE_MMIC) ||
+                     (key->conf.flags & IEEE80211_KEY_FLAG_GENERATE_IV)))
+                       sdata->crypto_tx_tailroom_needed_cnt--;
+
                return 0;
        }
 
        sta = get_sta_for_key(key);
        sdata = key->sdata;
 
+       if (!((key->conf.flags & IEEE80211_KEY_FLAG_GENERATE_MMIC) ||
+             (key->conf.flags & IEEE80211_KEY_FLAG_GENERATE_IV)))
+               increment_tailroom_need_count(sdata);
+
        if (sdata->vif.type == NL80211_IFTYPE_AP_VLAN)
                sdata = container_of(sdata->bss,
                                     struct ieee80211_sub_if_data,
                ieee80211_aes_key_free(key->u.ccmp.tfm);
        if (key->conf.cipher == WLAN_CIPHER_SUITE_AES_CMAC)
                ieee80211_aes_cmac_key_free(key->u.aes_cmac.tfm);
-       if (key->local)
+       if (key->local) {
                ieee80211_debugfs_key_remove(key);
+               key->sdata->crypto_tx_tailroom_needed_cnt--;
+       }
 
        kfree(key);
 }
        else
                old_key = key_mtx_dereference(sdata->local, sdata->keys[idx]);
 
+       increment_tailroom_need_count(sdata);
+
        __ieee80211_key_replace(sdata, sta, pairwise, old_key, key);
        __ieee80211_key_destroy(old_key);
 
 
        mutex_lock(&sdata->local->key_mtx);
 
-       list_for_each_entry(key, &sdata->key_list, list)
+       sdata->crypto_tx_tailroom_needed_cnt = 0;
+
+       list_for_each_entry(key, &sdata->key_list, list) {
+               increment_tailroom_need_count(sdata);
                ieee80211_key_enable_hw_accel(key);
+       }
 
        mutex_unlock(&sdata->local->key_mtx);
 }
 
 
 /* device xmit handlers */
 
-static int ieee80211_skb_resize(struct ieee80211_local *local,
+static int ieee80211_skb_resize(struct ieee80211_sub_if_data *sdata,
                                struct sk_buff *skb,
                                int head_need, bool may_encrypt)
 {
+       struct ieee80211_local *local = sdata->local;
        int tail_need = 0;
 
-       /*
-        * This could be optimised, devices that do full hardware
-        * crypto (including TKIP MMIC) need no tailroom... But we
-        * have no drivers for such devices currently.
-        */
-       if (may_encrypt) {
+       if (may_encrypt && sdata->crypto_tx_tailroom_needed_cnt) {
                tail_need = IEEE80211_ENCRYPT_TAILROOM;
                tail_need -= skb_tailroom(skb);
                tail_need = max_t(int, tail_need, 0);
        headroom -= skb_headroom(skb);
        headroom = max_t(int, 0, headroom);
 
-       if (ieee80211_skb_resize(local, skb, headroom, may_encrypt)) {
+       if (ieee80211_skb_resize(sdata, skb, headroom, may_encrypt)) {
                dev_kfree_skb(skb);
                rcu_read_unlock();
                return;
                head_need += IEEE80211_ENCRYPT_HEADROOM;
                head_need += local->tx_headroom;
                head_need = max_t(int, 0, head_need);
-               if (ieee80211_skb_resize(local, skb, head_need, true))
+               if (ieee80211_skb_resize(sdata, skb, head_need, true))
                        goto fail;
        }