ieee80211_tx_skb(sdata, skb);
 }
 
+void ieee80211_assign_tid_tx(struct sta_info *sta, int tid,
+                            struct tid_ampdu_tx *tid_tx)
+{
+       lockdep_assert_held(&sta->ampdu_mlme.mtx);
+       lockdep_assert_held(&sta->lock);
+       rcu_assign_pointer(sta->ampdu_mlme.tid_tx[tid], tid_tx);
+}
+
 static void kfree_tid_tx(struct rcu_head *rcu_head)
 {
        struct tid_ampdu_tx *tid_tx =
 
        if (test_bit(HT_AGG_STATE_WANT_START, &tid_tx->state)) {
                /* not even started yet! */
-               rcu_assign_pointer(sta->ampdu_mlme.tid_tx[tid], NULL);
+               ieee80211_assign_tid_tx(sta, tid, NULL);
                spin_unlock_bh(&sta->lock);
                call_rcu(&tid_tx->rcu_head, kfree_tid_tx);
                return 0;
                                        " tid %d\n", tid);
 #endif
                spin_lock_bh(&sta->lock);
-               rcu_assign_pointer(sta->ampdu_mlme.tid_tx[tid], NULL);
+               ieee80211_assign_tid_tx(sta, tid, NULL);
                spin_unlock_bh(&sta->lock);
 
                ieee80211_wake_queue_agg(local, tid);
 
        tid_tx = sta->ampdu_mlme.tid_tx[tid];
        /* check if the TID is not in aggregation flow already */
-       if (tid_tx) {
+       if (tid_tx || sta->ampdu_mlme.tid_start_tx[tid]) {
 #ifdef CONFIG_MAC80211_HT_DEBUG
                printk(KERN_DEBUG "BA request denied - session is not "
                                 "idle on tid %u\n", tid);
        sta->ampdu_mlme.dialog_token_allocator++;
        tid_tx->dialog_token = sta->ampdu_mlme.dialog_token_allocator;
 
-       /* finally, assign it to the array */
-       rcu_assign_pointer(sta->ampdu_mlme.tid_tx[tid], tid_tx);
+       /*
+        * Finally, assign it to the start array; the work item will
+        * collect it and move it to the normal array.
+        */
+       sta->ampdu_mlme.tid_start_tx[tid] = tid_tx;
 
        ieee80211_queue_work(&local->hw, &sta->ampdu_mlme.work);
 
        ieee80211_agg_splice_packets(local, tid_tx, tid);
 
        /* future packets must not find the tid_tx struct any more */
-       rcu_assign_pointer(sta->ampdu_mlme.tid_tx[tid], NULL);
+       ieee80211_assign_tid_tx(sta, tid, NULL);
 
        ieee80211_agg_splice_finish(local, tid);
 
 
                                sta, tid, WLAN_BACK_RECIPIENT,
                                WLAN_REASON_QSTA_TIMEOUT, true);
 
-               tid_tx = sta->ampdu_mlme.tid_tx[tid];
-               if (!tid_tx)
-                       continue;
+               tid_tx = sta->ampdu_mlme.tid_start_tx[tid];
+               if (tid_tx) {
+                       /*
+                        * Assign it over to the normal tid_tx array
+                        * where it "goes live".
+                        */
+                       spin_lock_bh(&sta->lock);
+
+                       sta->ampdu_mlme.tid_start_tx[tid] = NULL;
+                       /* could there be a race? */
+                       if (sta->ampdu_mlme.tid_tx[tid])
+                               kfree(tid_tx);
+                       else
+                               ieee80211_assign_tid_tx(sta, tid, tid_tx);
+                       spin_unlock_bh(&sta->lock);
 
-               if (test_bit(HT_AGG_STATE_WANT_START, &tid_tx->state))
                        ieee80211_tx_ba_session_handle_start(sta, tid);
-               else if (test_and_clear_bit(HT_AGG_STATE_WANT_STOP,
-                                           &tid_tx->state))
+                       continue;
+               }
+
+               tid_tx = sta->ampdu_mlme.tid_tx[tid];
+               if (tid_tx && test_and_clear_bit(HT_AGG_STATE_WANT_STOP,
+                                                &tid_tx->state))
                        ___ieee80211_stop_tx_ba_session(sta, tid,
                                                        WLAN_BACK_INITIATOR,
                                                        true);
 
  *
  * @tid_rx: aggregation info for Rx per TID -- RCU protected
  * @tid_tx: aggregation info for Tx per TID
+ * @tid_start_tx: sessions where start was requested
  * @addba_req_num: number of times addBA request has been sent.
  * @dialog_token_allocator: dialog token enumerator for each new session;
  * @work: work struct for starting/stopping aggregation
        /* tx */
        struct work_struct work;
        struct tid_ampdu_tx *tid_tx[STA_TID_NUM];
+       struct tid_ampdu_tx *tid_start_tx[STA_TID_NUM];
        u8 addba_req_num[STA_TID_NUM];
        u8 dialog_token_allocator;
 };
        return ret;
 }
 
+void ieee80211_assign_tid_tx(struct sta_info *sta, int tid,
+                            struct tid_ampdu_tx *tid_tx);
 
 
 #define STA_HASH_SIZE 256