unsigned long jiffies;
                        };
                        /* NB: vif can be NULL for injected frames */
-                       union {
-                               /* NB: vif can be NULL for injected frames */
-                               struct ieee80211_vif *vif;
-
-                               /* When packets are enqueued on txq it's easy
-                                * to re-construct the vif pointer. There's no
-                                * more space in tx_info so it can be used to
-                                * store the necessary enqueue time for packet
-                                * sojourn time computation.
-                                */
-                               codel_time_t enqueue_time;
-                       };
+                       struct ieee80211_vif *vif;
                        struct ieee80211_key_conf *hw_key;
                        u32 flags;
-                       /* 4 bytes free */
+                       codel_time_t enqueue_time;
                } control;
                struct {
                        u64 cookie;
 
 static void ieee80211_do_stop(struct ieee80211_sub_if_data *sdata,
                              bool going_down)
 {
+       struct ieee80211_sub_if_data *txq_sdata = sdata;
        struct ieee80211_local *local = sdata->local;
        struct fq *fq = &local->fq;
        unsigned long flags;
 
        switch (sdata->vif.type) {
        case NL80211_IFTYPE_AP_VLAN:
+               txq_sdata = container_of(sdata->bss,
+                                        struct ieee80211_sub_if_data, u.ap);
+
                mutex_lock(&local->mtx);
                list_del(&sdata->u.vlan.list);
                mutex_unlock(&local->mtx);
        }
        spin_unlock_irqrestore(&local->queue_stop_reason_lock, flags);
 
-       if (sdata->vif.txq) {
-               struct txq_info *txqi = to_txq_info(sdata->vif.txq);
+       if (txq_sdata->vif.txq) {
+               struct txq_info *txqi = to_txq_info(txq_sdata->vif.txq);
+
+               /*
+                * FIXME FIXME
+                *
+                * We really shouldn't purge the *entire* txqi since that
+                * contains frames for the other AP_VLANs (and possibly
+                * the AP itself) as well, but there's no API in FQ now
+                * to be able to filter.
+                */
 
                spin_lock_bh(&fq->lock);
                ieee80211_txq_purge(local, txqi);
 
        IEEE80211_SKB_CB(skb)->control.enqueue_time = codel_get_time();
 }
 
-static void ieee80211_set_skb_vif(struct sk_buff *skb, struct txq_info *txqi)
-{
-       IEEE80211_SKB_CB(skb)->control.vif = txqi->txq.vif;
-}
-
 static u32 codel_skb_len_func(const struct sk_buff *skb)
 {
        return skb->len;
        struct ieee80211_tx_info *info;
        struct ieee80211_tx_data tx;
        ieee80211_tx_result r;
+       struct ieee80211_vif *vif;
 
        spin_lock_bh(&fq->lock);
 
        if (!skb)
                goto out;
 
-       ieee80211_set_skb_vif(skb, txqi);
-
        hdr = (struct ieee80211_hdr *)skb->data;
        info = IEEE80211_SKB_CB(skb);
 
                }
        }
 
+       switch (tx.sdata->vif.type) {
+       case NL80211_IFTYPE_MONITOR:
+               if (tx.sdata->u.mntr.flags & MONITOR_FLAG_ACTIVE) {
+                       vif = &tx.sdata->vif;
+                       break;
+               }
+               tx.sdata = rcu_dereference(local->monitor_sdata);
+               if (tx.sdata) {
+                       vif = &tx.sdata->vif;
+                       info->hw_queue =
+                               vif->hw_queue[skb_get_queue_mapping(skb)];
+               } else if (ieee80211_hw_check(&local->hw, QUEUE_CONTROL)) {
+                       ieee80211_free_txskb(&local->hw, skb);
+                       goto begin;
+               } else {
+                       vif = NULL;
+               }
+               break;
+       case NL80211_IFTYPE_AP_VLAN:
+               tx.sdata = container_of(tx.sdata->bss,
+                                       struct ieee80211_sub_if_data, u.ap);
+               /* fall through */
+       default:
+               vif = &tx.sdata->vif;
+               break;
+       }
+
+       IEEE80211_SKB_CB(skb)->control.vif = vif;
 out:
        spin_unlock_bh(&fq->lock);