BSS_LOSE_EVENT_ID                        = BIT(18),
        REGAINED_BSS_EVENT_ID                    = BIT(19),
        ROAMING_TRIGGER_MAX_TX_RETRY_EVENT_ID    = BIT(20),
-       STA_REMOVE_COMPLETE_EVENT_ID             = BIT(21), /* AP */
+       /* STA: dummy paket for dynamic mem blocks */
+       DUMMY_PACKET_EVENT_ID                    = BIT(21),
+       /* AP: STA remove complete */
+       STA_REMOVE_COMPLETE_EVENT_ID             = BIT(21),
        SOFT_GEMINI_SENSE_EVENT_ID               = BIT(22),
        SOFT_GEMINI_PREDICTION_EVENT_ID          = BIT(23),
        SOFT_GEMINI_AVALANCHE_EVENT_ID           = BIT(24),
 
        spin_unlock_irqrestore(&wl->wl_lock, flags);
 }
 
+#define TX_DUMMY_PACKET_SIZE 1400
+int wl1271_tx_dummy_packet(struct wl1271 *wl)
+{
+       struct sk_buff *skb = NULL;
+       struct ieee80211_hdr_3addr *hdr;
+       int ret = 0;
+
+       skb = dev_alloc_skb(
+               sizeof(struct wl1271_tx_hw_descr) + sizeof(*hdr) +
+               TX_DUMMY_PACKET_SIZE);
+       if (!skb) {
+               wl1271_warning("failed to allocate buffer for dummy packet");
+               ret = -ENOMEM;
+               goto out;
+       }
+
+       skb_reserve(skb, sizeof(struct wl1271_tx_hw_descr));
+
+       hdr = (struct ieee80211_hdr_3addr *) skb_put(skb, sizeof(*hdr));
+       memset(hdr, 0, sizeof(*hdr));
+       hdr->frame_control = cpu_to_le16(IEEE80211_FTYPE_DATA |
+                                        IEEE80211_FCTL_TODS  |
+                                        IEEE80211_STYPE_NULLFUNC);
+
+       memcpy(hdr->addr1, wl->bssid, ETH_ALEN);
+       memcpy(hdr->addr2, wl->mac_addr, ETH_ALEN);
+       memcpy(hdr->addr3, wl->bssid, ETH_ALEN);
+
+       skb_put(skb, TX_DUMMY_PACKET_SIZE);
+
+       memset(skb->data, 0, TX_DUMMY_PACKET_SIZE);
+
+       skb->pkt_type = TX_PKT_TYPE_DUMMY_REQ;
+       /* CONF_TX_AC_VO */
+       skb->queue_mapping = 0;
+
+       wl1271_op_tx(wl->hw, skb);
+
+out:
+       return ret;
+}
+
 static struct notifier_block wl1271_dev_notifier = {
        .notifier_call = wl1271_dev_notify,
 };
 
        else
                desc->life_time = cpu_to_le16(TX_HW_AP_MODE_PKT_LIFETIME_TU);
 
-       /* configure the tx attributes */
-       tx_attr = wl->session_counter << TX_HW_ATTR_OFST_SESSION_COUNTER;
-
        /* queue (we use same identifiers for tid's and ac's */
        ac = wl1271_tx_get_queue(skb_get_queue_mapping(skb));
        desc->tid = ac;
 
+       if (skb->pkt_type == TX_PKT_TYPE_DUMMY_REQ) {
+               /*
+                * FW expects the dummy packet to have an invalid session id -
+                * any session id that is different than the one set in the join
+                */
+               tx_attr = ((~wl->session_counter) <<
+                          TX_HW_ATTR_OFST_SESSION_COUNTER) &
+                          TX_HW_ATTR_SESSION_COUNTER;
+
+               tx_attr |= TX_HW_ATTR_TX_DUMMY_REQ;
+
+               /* Dummy packets require the TID to be management */
+               desc->tid = WL1271_TID_MGMT;
+       } else {
+               /* configure the tx attributes */
+               tx_attr =
+                       wl->session_counter << TX_HW_ATTR_OFST_SESSION_COUNTER;
+       }
+
        if (wl->bss_type != BSS_TYPE_AP_BSS) {
                desc->aid = hlid;
 
        skb = wl->tx_frames[id];
        info = IEEE80211_SKB_CB(skb);
 
+       if (skb->pkt_type == TX_PKT_TYPE_DUMMY_REQ) {
+               dev_kfree_skb(skb);
+               wl1271_free_tx_id(wl, id);
+               return;
+       }
+
        /* update the TX status info */
        if (result->status == TX_SUCCESS) {
                if (!(info->flags & IEEE80211_TX_CTL_NO_ACK))
                        while ((skb = skb_dequeue(&wl->tx_queue[i]))) {
                                wl1271_debug(DEBUG_TX, "freeing skb 0x%p",
                                             skb);
-                               info = IEEE80211_SKB_CB(skb);
-                               info->status.rates[0].idx = -1;
-                               info->status.rates[0].count = 0;
-                               ieee80211_tx_status(wl->hw, skb);
+
+                               if (skb->pkt_type == TX_PKT_TYPE_DUMMY_REQ) {
+                                       dev_kfree_skb(skb);
+                               } else {
+                                       info = IEEE80211_SKB_CB(skb);
+                                       info->status.rates[0].idx = -1;
+                                       info->status.rates[0].count = 0;
+                                       ieee80211_tx_status(wl->hw, skb);
+                               }
                        }
                }
        }
                wl1271_free_tx_id(wl, i);
                wl1271_debug(DEBUG_TX, "freeing skb 0x%p", skb);
 
-               /* Remove private headers before passing the skb to mac80211 */
-               info = IEEE80211_SKB_CB(skb);
-               skb_pull(skb, sizeof(struct wl1271_tx_hw_descr));
-               if (info->control.hw_key &&
-                   info->control.hw_key->cipher == WLAN_CIPHER_SUITE_TKIP) {
-                       int hdrlen = ieee80211_get_hdrlen_from_skb(skb);
-                       memmove(skb->data + WL1271_TKIP_IV_SPACE, skb->data,
-                               hdrlen);
-                       skb_pull(skb, WL1271_TKIP_IV_SPACE);
-               }
+               if (skb->pkt_type == TX_PKT_TYPE_DUMMY_REQ) {
+                       dev_kfree_skb(skb);
+               } else {
+                       /*
+                        * Remove private headers before passing the skb to
+                        * mac80211
+                        */
+                       info = IEEE80211_SKB_CB(skb);
+                       skb_pull(skb, sizeof(struct wl1271_tx_hw_descr));
+                       if (info->control.hw_key &&
+                           info->control.hw_key->cipher ==
+                           WLAN_CIPHER_SUITE_TKIP) {
+                               int hdrlen = ieee80211_get_hdrlen_from_skb(skb);
+                               memmove(skb->data + WL1271_TKIP_IV_SPACE,
+                                       skb->data, hdrlen);
+                               skb_pull(skb, WL1271_TKIP_IV_SPACE);
+                       }
 
-               info->status.rates[0].idx = -1;
-               info->status.rates[0].count = 0;
+                       info->status.rates[0].idx = -1;
+                       info->status.rates[0].count = 0;
 
-               ieee80211_tx_status(wl->hw, skb);
+                       ieee80211_tx_status(wl->hw, skb);
+               }
        }
 }