*     it can be sent out.
  * @IEEE80211_TX_INTFL_RETRIED: completely internal to mac80211,
  *     used to indicate that a frame was already retried due to PS
+ * @IEEE80211_TX_INTFL_DONT_ENCRYPT: completely internal to mac80211,
+ *     used to indicate frame should not be encrypted
  */
 enum mac80211_tx_control_flags {
        IEEE80211_TX_CTL_REQ_TX_STATUS          = BIT(0),
        IEEE80211_TX_INTFL_RCALGO               = BIT(13),
        IEEE80211_TX_INTFL_NEED_TXPROCESSING    = BIT(14),
        IEEE80211_TX_INTFL_RETRIED              = BIT(15),
+       IEEE80211_TX_INTFL_DONT_ENCRYPT         = BIT(16),
 };
 
 /**
 
 
        if (!skb_queue_empty(&sta->ampdu_mlme.tid_tx[tid]->pending)) {
                spin_lock_irqsave(&local->queue_stop_reason_lock, flags);
-               /* mark queue as pending, it is stopped already */
-               __set_bit(IEEE80211_QUEUE_STOP_REASON_PENDING,
-                         &local->queue_stop_reasons[queue]);
                /* copy over remaining packets */
                skb_queue_splice_tail_init(
                        &sta->ampdu_mlme.tid_tx[tid]->pending,
 
        for (q = 0; q < local->hw.queues; q++)
                res += sprintf(buf + res, "%02d: %#.8lx/%d\n", q,
                                local->queue_stop_reasons[q],
-                               __netif_subqueue_stopped(local->mdev, q));
+                               skb_queue_len(&local->pending[q]));
        spin_unlock_irqrestore(&local->queue_stop_reason_lock, flags);
 
        return simple_read_from_buffer(user_buf, count, ppos, buf, res);
 
        IEEE80211_QUEUE_STOP_REASON_CSA,
        IEEE80211_QUEUE_STOP_REASON_AGGREGATION,
        IEEE80211_QUEUE_STOP_REASON_SUSPEND,
-       IEEE80211_QUEUE_STOP_REASON_PENDING,
        IEEE80211_QUEUE_STOP_REASON_SKB_ADD,
 };
 
-struct ieee80211_master_priv {
-       struct ieee80211_local *local;
-};
-
 struct ieee80211_local {
        /* embed the driver visible part.
         * don't cast (use the static inlines below), but we keep
        /* also used to protect ampdu_ac_queue and amdpu_ac_stop_refcnt */
        spinlock_t queue_stop_reason_lock;
 
-       struct net_device *mdev; /* wmaster# - "master" 802.11 device */
        int open_count;
        int monitors, cooked_mntrs;
        /* number of interfaces with corresponding FIF_ flags */
        int fif_fcsfail, fif_plcpfail, fif_control, fif_other_bss;
        unsigned int filter_flags; /* FIF_* */
        struct iw_statistics wstats;
+
+       /* protects the aggregated multicast list and filter calls */
+       spinlock_t filter_lock;
+
+       /* aggregated multicast list */
+       struct dev_addr_list *mc_list;
+       int mc_count;
+
        bool tim_in_locked_section; /* see ieee80211_beacon_get() */
 
        /*
 static inline struct ieee80211_sub_if_data *
 IEEE80211_DEV_TO_SUB_IF(struct net_device *dev)
 {
-       struct ieee80211_local *local = wdev_priv(dev->ieee80211_ptr);
-
-       BUG_ON(!local || local->mdev == dev);
-
        return netdev_priv(dev);
 }
 
 /* tx handling */
 void ieee80211_clear_tx_pending(struct ieee80211_local *local);
 void ieee80211_tx_pending(unsigned long data);
-int ieee80211_master_start_xmit(struct sk_buff *skb, struct net_device *dev);
 int ieee80211_monitor_start_xmit(struct sk_buff *skb, struct net_device *dev);
 int ieee80211_subif_start_xmit(struct sk_buff *skb, struct net_device *dev);
 
 
                               ETH_ALEN);
        }
 
-       if (compare_ether_addr(null_addr, local->mdev->dev_addr) == 0)
-               memcpy(local->mdev->dev_addr, local->hw.wiphy->perm_addr,
-                      ETH_ALEN);
-
        /*
         * Validate the MAC address for this device.
         */
                if (sdata->u.mntr_flags & MONITOR_FLAG_OTHER_BSS)
                        local->fif_other_bss++;
 
-               netif_addr_lock_bh(local->mdev);
+               spin_lock_bh(&local->filter_lock);
                ieee80211_configure_filter(local);
-               netif_addr_unlock_bh(local->mdev);
+               spin_unlock_bh(&local->filter_lock);
                break;
        default:
                conf.vif = &sdata->vif;
 
                if (ieee80211_vif_is_mesh(&sdata->vif)) {
                        local->fif_other_bss++;
-                       netif_addr_lock_bh(local->mdev);
+                       spin_lock_bh(&local->filter_lock);
                        ieee80211_configure_filter(local);
-                       netif_addr_unlock_bh(local->mdev);
+                       spin_unlock_bh(&local->filter_lock);
 
                        ieee80211_start_mesh(sdata);
                }
        }
 
        if (local->open_count == 0) {
-               res = dev_open(local->mdev);
-               WARN_ON(res);
-               if (res)
-                       goto err_del_interface;
                tasklet_enable(&local->tx_pending_tasklet);
                tasklet_enable(&local->tasklet);
        }
        if (sdata->flags & IEEE80211_SDATA_PROMISC)
                atomic_dec(&local->iff_promiscs);
 
-       dev_mc_unsync(local->mdev, dev);
+       netif_addr_lock_bh(dev);
+       spin_lock_bh(&local->filter_lock);
+       __dev_addr_unsync(&local->mc_list, &local->mc_count,
+                         &dev->mc_list, &dev->mc_count);
+       ieee80211_configure_filter(local);
+       spin_unlock_bh(&local->filter_lock);
+       netif_addr_unlock_bh(dev);
+
        del_timer_sync(&local->dynamic_ps_timer);
        cancel_work_sync(&local->dynamic_ps_enable_work);
 
                if (sdata->u.mntr_flags & MONITOR_FLAG_OTHER_BSS)
                        local->fif_other_bss--;
 
-               netif_addr_lock_bh(local->mdev);
+               spin_lock_bh(&local->filter_lock);
                ieee80211_configure_filter(local);
-               netif_addr_unlock_bh(local->mdev);
+               spin_unlock_bh(&local->filter_lock);
                break;
        case NL80211_IFTYPE_STATION:
                del_timer_sync(&sdata->u.mgd.chswitch_timer);
                        local->fif_other_bss--;
                        atomic_dec(&local->iff_allmultis);
 
-                       netif_addr_lock_bh(local->mdev);
+                       spin_lock_bh(&local->filter_lock);
                        ieee80211_configure_filter(local);
-                       netif_addr_unlock_bh(local->mdev);
+                       spin_unlock_bh(&local->filter_lock);
 
                        ieee80211_stop_mesh(sdata);
                }
        ieee80211_recalc_ps(local, -1);
 
        if (local->open_count == 0) {
-               if (netif_running(local->mdev))
-                       dev_close(local->mdev);
-
                drv_stop(local);
 
                ieee80211_led_radio(local, false);
                        atomic_dec(&local->iff_promiscs);
                sdata->flags ^= IEEE80211_SDATA_PROMISC;
        }
-
-       dev_mc_sync(local->mdev, dev);
+       spin_lock_bh(&local->filter_lock);
+       __dev_addr_sync(&local->mc_list, &local->mc_count,
+                       &dev->mc_list, &dev->mc_count);
+       ieee80211_configure_filter(local);
+       spin_unlock_bh(&local->filter_lock);
 }
 
 /*
 
        new_flags |= (1<<31);
 
        drv_configure_filter(local, changed_flags, &new_flags,
-                            local->mdev->mc_count,
-                            local->mdev->mc_list);
+                            local->mc_count,
+                            local->mc_list);
 
        WARN_ON(new_flags & (1<<31));
 
        local->filter_flags = new_flags & ~(1<<31);
 }
 
-/* master interface */
-
-static int header_parse_80211(const struct sk_buff *skb, unsigned char *haddr)
-{
-       memcpy(haddr, skb_mac_header(skb) + 10, ETH_ALEN); /* addr2 */
-       return ETH_ALEN;
-}
-
-static const struct header_ops ieee80211_header_ops = {
-       .create         = eth_header,
-       .parse          = header_parse_80211,
-       .rebuild        = eth_rebuild_header,
-       .cache          = eth_header_cache,
-       .cache_update   = eth_header_cache_update,
-};
-
-static int ieee80211_master_open(struct net_device *dev)
-{
-       struct ieee80211_master_priv *mpriv = netdev_priv(dev);
-       struct ieee80211_local *local = mpriv->local;
-       struct ieee80211_sub_if_data *sdata;
-       int res = -EOPNOTSUPP;
-
-       /* we hold the RTNL here so can safely walk the list */
-       list_for_each_entry(sdata, &local->interfaces, list) {
-               if (netif_running(sdata->dev)) {
-                       res = 0;
-                       break;
-               }
-       }
-
-       if (res)
-               return res;
-
-       netif_tx_start_all_queues(local->mdev);
-
-       return 0;
-}
-
-static int ieee80211_master_stop(struct net_device *dev)
-{
-       struct ieee80211_master_priv *mpriv = netdev_priv(dev);
-       struct ieee80211_local *local = mpriv->local;
-       struct ieee80211_sub_if_data *sdata;
-
-       /* we hold the RTNL here so can safely walk the list */
-       list_for_each_entry(sdata, &local->interfaces, list)
-               if (netif_running(sdata->dev))
-                       dev_close(sdata->dev);
-
-       return 0;
-}
-
-static void ieee80211_master_set_multicast_list(struct net_device *dev)
-{
-       struct ieee80211_master_priv *mpriv = netdev_priv(dev);
-       struct ieee80211_local *local = mpriv->local;
-
-       ieee80211_configure_filter(local);
-}
-
 int ieee80211_hw_config(struct ieee80211_local *local, u32 changed)
 {
        struct ieee80211_channel *chan, *scan_chan;
        struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb);
        int tmp;
 
-       skb->dev = local->mdev;
        skb->pkt_type = IEEE80211_TX_STATUS_MSG;
        skb_queue_tail(info->flags & IEEE80211_TX_CTL_REQ_TX_STATUS ?
                       &local->skb_queue : &local->skb_queue_unreliable, skb);
        mutex_init(&local->scan_mtx);
 
        spin_lock_init(&local->key_lock);
-
+       spin_lock_init(&local->filter_lock);
        spin_lock_init(&local->queue_stop_reason_lock);
 
        INIT_DELAYED_WORK(&local->scan_work, ieee80211_scan_work);
 }
 EXPORT_SYMBOL(ieee80211_alloc_hw);
 
-static const struct net_device_ops ieee80211_master_ops = {
-       .ndo_start_xmit = ieee80211_master_start_xmit,
-       .ndo_open = ieee80211_master_open,
-       .ndo_stop = ieee80211_master_stop,
-       .ndo_set_multicast_list = ieee80211_master_set_multicast_list,
-       .ndo_select_queue = ieee80211_select_queue,
-};
-
-static void ieee80211_master_setup(struct net_device *mdev)
-{
-       mdev->type = ARPHRD_IEEE80211;
-       mdev->netdev_ops = &ieee80211_master_ops;
-       mdev->header_ops = &ieee80211_header_ops;
-       mdev->tx_queue_len = 1000;
-       mdev->addr_len = ETH_ALEN;
-}
-
 int ieee80211_register_hw(struct ieee80211_hw *hw)
 {
        struct ieee80211_local *local = hw_to_local(hw);
        int result;
        enum ieee80211_band band;
-       struct net_device *mdev;
-       struct ieee80211_master_priv *mpriv;
        int channels, i, j, max_bitrates;
        bool supp_ht;
        static const u32 cipher_suites[] = {
        if (hw->queues > IEEE80211_MAX_QUEUES)
                hw->queues = IEEE80211_MAX_QUEUES;
 
-       mdev = alloc_netdev_mq(sizeof(struct ieee80211_master_priv),
-                              "wmaster%d", ieee80211_master_setup,
-                              hw->queues);
-       if (!mdev)
-               goto fail_mdev_alloc;
-
-       mpriv = netdev_priv(mdev);
-       mpriv->local = local;
-       local->mdev = mdev;
-
        local->hw.workqueue =
                create_singlethread_workqueue(wiphy_name(local->hw.wiphy));
        if (!local->hw.workqueue) {
        }
 
        rtnl_lock();
-       result = dev_alloc_name(local->mdev, local->mdev->name);
-       if (result < 0)
-               goto fail_dev;
-
-       memcpy(local->mdev->dev_addr, local->hw.wiphy->perm_addr, ETH_ALEN);
-       SET_NETDEV_DEV(local->mdev, wiphy_dev(local->hw.wiphy));
-       local->mdev->features |= NETIF_F_NETNS_LOCAL;
-
-       result = register_netdevice(local->mdev);
-       if (result < 0)
-               goto fail_dev;
 
        result = ieee80211_init_rate_ctrl_alg(local,
                                              hw->rate_control_algorithm);
        ieee80211_led_exit(local);
        ieee80211_remove_interfaces(local);
  fail_rate:
-       unregister_netdevice(local->mdev);
-       local->mdev = NULL;
- fail_dev:
        rtnl_unlock();
        ieee80211_wep_free(local);
  fail_wep:
        debugfs_hw_del(local);
        destroy_workqueue(local->hw.workqueue);
  fail_workqueue:
-       if (local->mdev)
-               free_netdev(local->mdev);
- fail_mdev_alloc:
        wiphy_unregister(local->hw.wiphy);
  fail_wiphy_register:
        kfree(local->int_scan_req.channels);
         * because the driver cannot be handing us frames any
         * more and the tasklet is killed.
         */
-
-       /* First, we remove all virtual interfaces. */
        ieee80211_remove_interfaces(local);
 
-       /* then, finally, remove the master interface */
-       unregister_netdevice(local->mdev);
-
        rtnl_unlock();
 
        ieee80211_clear_tx_pending(local);
        wiphy_unregister(local->hw.wiphy);
        ieee80211_wep_free(local);
        ieee80211_led_exit(local);
-       free_netdev(local->mdev);
        kfree(local->int_scan_req.channels);
 }
 EXPORT_SYMBOL(ieee80211_unregister_hw);
 
        struct rate_control_ref *ref, *old;
 
        ASSERT_RTNL();
-       if (local->open_count || netif_running(local->mdev))
+       if (local->open_count)
                return -EBUSY;
 
        ref = rate_control_alloc(name, local);
 
        struct ieee80211s_hdr *mesh_hdr;
        unsigned int hdrlen;
        struct sk_buff *skb = rx->skb, *fwd_skb;
+       struct ieee80211_local *local = rx->local;
 
        hdr = (struct ieee80211_hdr *) skb->data;
        hdrlen = ieee80211_hdrlen(hdr->frame_control);
                                                     dropped_frames_ttl);
                else {
                        struct ieee80211_hdr *fwd_hdr;
+                       struct ieee80211_tx_info *info;
+
                        fwd_skb = skb_copy(skb, GFP_ATOMIC);
 
                        if (!fwd_skb && net_ratelimit())
                         */
                        memcpy(fwd_hdr->addr1, fwd_hdr->addr2, ETH_ALEN);
                        memcpy(fwd_hdr->addr2, rx->dev->dev_addr, ETH_ALEN);
-                       fwd_skb->dev = rx->local->mdev;
+                       info = IEEE80211_SKB_CB(fwd_skb);
+                       memset(info, 0, sizeof(*info));
+                       info->flags |= IEEE80211_TX_INTFL_NEED_TXPROCESSING;
                        fwd_skb->iif = rx->dev->ifindex;
-                       dev_queue_xmit(fwd_skb);
+                       ieee80211_select_queue(local, fwd_skb);
+                       ieee80211_add_pending_skb(local, fwd_skb);
                }
        }
 
        return RX_DROP_MONITOR;
 }
 
-static void ieee80211_rx_michael_mic_report(struct net_device *dev,
-                                           struct ieee80211_hdr *hdr,
+static void ieee80211_rx_michael_mic_report(struct ieee80211_hdr *hdr,
                                            struct ieee80211_rx_data *rx)
 {
        int keyidx;
        }
 
        if ((status->flag & RX_FLAG_MMIC_ERROR)) {
-               ieee80211_rx_michael_mic_report(local->mdev, hdr, &rx);
+               ieee80211_rx_michael_mic_report(hdr, &rx);
                return;
        }
 
 
        BUILD_BUG_ON(sizeof(struct ieee80211_rx_status) > sizeof(skb->cb));
 
-       skb->dev = local->mdev;
        skb->pkt_type = IEEE80211_RX_MSG;
        skb_queue_tail(&local->skb_queue, skb);
        tasklet_schedule(&local->tasklet);
 
        if (was_hw_scan)
                goto done;
 
-       netif_tx_lock_bh(local->mdev);
-       netif_addr_lock(local->mdev);
+       spin_lock_bh(&local->filter_lock);
        local->filter_flags &= ~FIF_BCN_PRBRESP_PROMISC;
        drv_configure_filter(local, FIF_BCN_PRBRESP_PROMISC,
                             &local->filter_flags,
-                            local->mdev->mc_count,
-                            local->mdev->mc_list);
-
-       netif_addr_unlock(local->mdev);
-       netif_tx_unlock_bh(local->mdev);
+                            local->mc_count,
+                            local->mc_list);
+       spin_unlock_bh(&local->filter_lock);
 
        drv_sw_scan_complete(local);
 
        local->scan_state = SCAN_SET_CHANNEL;
        local->scan_channel_idx = 0;
 
-       netif_addr_lock_bh(local->mdev);
+       spin_lock_bh(&local->filter_lock);
        local->filter_flags |= FIF_BCN_PRBRESP_PROMISC;
        drv_configure_filter(local, FIF_BCN_PRBRESP_PROMISC,
                             &local->filter_flags,
-                            local->mdev->mc_count,
-                            local->mdev->mc_list);
-       netif_addr_unlock_bh(local->mdev);
+                            local->mc_count,
+                            local->mc_list);
+       spin_unlock_bh(&local->filter_lock);
 
        /* TODO: start scan as soon as all nullfunc frames are ACKed */
        queue_delayed_work(local->hw.workqueue, &local->scan_work,
 
        struct ieee80211_tx_info *info = IEEE80211_SKB_CB(tx->skb);
        struct ieee80211_hdr *hdr = (struct ieee80211_hdr *)tx->skb->data;
 
-       if (unlikely(tx->skb->do_not_encrypt))
+       if (unlikely(info->flags & IEEE80211_TX_INTFL_DONT_ENCRYPT))
                tx->key = NULL;
        else if (tx->sta && (key = rcu_dereference(tx->sta->key)))
                tx->key = key;
        }
 
        if (!tx->key || !(tx->key->flags & KEY_FLAG_UPLOADED_TO_HARDWARE))
-               tx->skb->do_not_encrypt = 1;
+               info->flags |= IEEE80211_TX_INTFL_DONT_ENCRYPT;
 
        return TX_CONTINUE;
 }
                memcpy(tmp->cb, skb->cb, sizeof(tmp->cb));
                skb_copy_queue_mapping(tmp, skb);
                tmp->priority = skb->priority;
-               tmp->do_not_encrypt = skb->do_not_encrypt;
                tmp->dev = skb->dev;
-               tmp->iif = skb->iif;
 
                /* copy header and data */
                memcpy(skb_put(tmp, hdrlen), skb->data, hdrlen);
 
        /*
         * Warn when submitting a fragmented A-MPDU frame and drop it.
-        * This scenario is handled in __ieee80211_tx_prepare but extra
+        * This scenario is handled in ieee80211_tx_prepare but extra
         * caution taken here as fragmented ampdu may cause Tx stop.
         */
        if (WARN_ON(info->flags & IEEE80211_TX_CTL_AMPDU))
        struct ieee80211_radiotap_header *rthdr =
                (struct ieee80211_radiotap_header *) skb->data;
        struct ieee80211_supported_band *sband;
+       struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb);
        int ret = ieee80211_radiotap_iterator_init(&iterator, rthdr, skb->len);
 
        sband = tx->local->hw.wiphy->bands[tx->channel->band];
 
-       skb->do_not_encrypt = 1;
+       info->flags |= IEEE80211_TX_INTFL_DONT_ENCRYPT;
        tx->flags &= ~IEEE80211_TX_FRAGMENTED;
 
        /*
                                skb_trim(skb, skb->len - FCS_LEN);
                        }
                        if (*iterator.this_arg & IEEE80211_RADIOTAP_F_WEP)
-                               tx->skb->do_not_encrypt = 0;
+                               info->flags &= ~IEEE80211_TX_INTFL_DONT_ENCRYPT;
                        if (*iterator.this_arg & IEEE80211_RADIOTAP_F_FRAG)
                                tx->flags |= IEEE80211_TX_FRAGMENTED;
                        break;
  * initialises @tx
  */
 static ieee80211_tx_result
-__ieee80211_tx_prepare(struct ieee80211_tx_data *tx,
-                      struct sk_buff *skb,
-                      struct net_device *dev)
+ieee80211_tx_prepare(struct ieee80211_sub_if_data *sdata,
+                    struct ieee80211_tx_data *tx,
+                    struct sk_buff *skb)
 {
-       struct ieee80211_local *local = wdev_priv(dev->ieee80211_ptr);
+       struct ieee80211_local *local = sdata->local;
        struct ieee80211_hdr *hdr;
-       struct ieee80211_sub_if_data *sdata;
        struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb);
        int hdrlen, tid;
        u8 *qc, *state;
 
        memset(tx, 0, sizeof(*tx));
        tx->skb = skb;
-       tx->dev = dev; /* use original interface */
+       tx->dev = sdata->dev; /* use original interface */
        tx->local = local;
-       tx->sdata = IEEE80211_DEV_TO_SUB_IF(dev);
+       tx->sdata = sdata;
        tx->channel = local->hw.conf.channel;
        /*
         * Set this flag (used below to indicate "automatic fragmentation"),
        tx->flags |= IEEE80211_TX_FRAGMENTED;
 
        /* process and remove the injection radiotap header */
-       sdata = IEEE80211_DEV_TO_SUB_IF(dev);
        if (unlikely(info->flags & IEEE80211_TX_CTL_INJECTED)) {
                if (!__ieee80211_parse_tx_radiotap(tx, skb))
                        return TX_DROP;
        return TX_CONTINUE;
 }
 
-/*
- * NB: @tx is uninitialised when passed in here
- */
-static int ieee80211_tx_prepare(struct ieee80211_local *local,
-                               struct ieee80211_tx_data *tx,
-                               struct sk_buff *skb)
-{
-       struct net_device *dev;
-
-       dev = dev_get_by_index(&init_net, skb->iif);
-       if (unlikely(dev && !is_ieee80211_device(local, dev))) {
-               dev_put(dev);
-               dev = NULL;
-       }
-       if (unlikely(!dev))
-               return -ENODEV;
-       /*
-        * initialises tx with control
-        *
-        * return value is safe to ignore here because this function
-        * can only be invoked for multicast frames
-        *
-        * XXX: clean up
-        */
-       __ieee80211_tx_prepare(tx, skb, dev);
-       dev_put(dev);
-       return 0;
-}
-
 static int __ieee80211_tx(struct ieee80211_local *local,
                          struct sk_buff **skbp,
-                         struct sta_info *sta)
+                         struct sta_info *sta,
+                         bool txpending)
 {
        struct sk_buff *skb = *skbp, *next;
        struct ieee80211_tx_info *info;
+       unsigned long flags;
        int ret, len;
        bool fragm = false;
 
-       local->mdev->trans_start = jiffies;
-
        while (skb) {
-               if (ieee80211_queue_stopped(&local->hw,
-                                           skb_get_queue_mapping(skb)))
-                       return IEEE80211_TX_PENDING;
+               int q = skb_get_queue_mapping(skb);
+
+               spin_lock_irqsave(&local->queue_stop_reason_lock, flags);
+               ret = IEEE80211_TX_OK;
+               if (local->queue_stop_reasons[q] ||
+                   (!txpending && !skb_queue_empty(&local->pending[q])))
+                       ret = IEEE80211_TX_PENDING;
+               spin_unlock_irqrestore(&local->queue_stop_reason_lock, flags);
+               if (ret != IEEE80211_TX_OK)
+                       return ret;
 
                info = IEEE80211_SKB_CB(skb);
 
        return 0;
 }
 
-static void ieee80211_tx(struct net_device *dev, struct sk_buff *skb,
-                        bool txpending)
+static void ieee80211_tx(struct ieee80211_sub_if_data *sdata,
+                        struct sk_buff *skb, bool txpending)
 {
-       struct ieee80211_local *local = wdev_priv(dev->ieee80211_ptr);
+       struct ieee80211_local *local = sdata->local;
        struct ieee80211_tx_data tx;
        ieee80211_tx_result res_prepare;
        struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb);
 
        queue = skb_get_queue_mapping(skb);
 
-       WARN_ON(!txpending && !skb_queue_empty(&local->pending[queue]));
-
        if (unlikely(skb->len < 10)) {
                dev_kfree_skb(skb);
                return;
        rcu_read_lock();
 
        /* initialises tx */
-       res_prepare = __ieee80211_tx_prepare(&tx, skb, dev);
+       res_prepare = ieee80211_tx_prepare(sdata, &tx, skb);
 
        if (unlikely(res_prepare == TX_DROP)) {
                dev_kfree_skb(skb);
 
        retries = 0;
  retry:
-       ret = __ieee80211_tx(local, &tx.skb, tx.sta);
+       ret = __ieee80211_tx(local, &tx.skb, tx.sta, txpending);
        switch (ret) {
        case IEEE80211_TX_OK:
                break;
 
                spin_lock_irqsave(&local->queue_stop_reason_lock, flags);
 
-               if (__netif_subqueue_stopped(local->mdev, queue)) {
+               if (local->queue_stop_reasons[queue] ||
+                   !skb_queue_empty(&local->pending[queue])) {
+                       /*
+                        * if queue is stopped, queue up frames for later
+                        * transmission from the tasklet
+                        */
                        do {
                                next = skb->next;
                                skb->next = NULL;
                                if (unlikely(txpending))
-                                       skb_queue_head(&local->pending[queue],
-                                                      skb);
+                                       __skb_queue_head(&local->pending[queue],
+                                                        skb);
                                else
-                                       skb_queue_tail(&local->pending[queue],
-                                                      skb);
+                                       __skb_queue_tail(&local->pending[queue],
+                                                        skb);
                        } while ((skb = next));
 
-                       /*
-                        * Make sure nobody will enable the queue on us
-                        * (without going through the tasklet) nor disable the
-                        * netdev queue underneath the pending handling code.
-                        */
-                       __set_bit(IEEE80211_QUEUE_STOP_REASON_PENDING,
-                                 &local->queue_stop_reasons[queue]);
-
                        spin_unlock_irqrestore(&local->queue_stop_reason_lock,
                                               flags);
                } else {
+                       /*
+                        * otherwise retry, but this is a race condition or
+                        * a driver bug (which we warn about if it persists)
+                        */
                        spin_unlock_irqrestore(&local->queue_stop_reason_lock,
                                               flags);
 
                        retries++;
-                       if (WARN(retries > 10, "tx refused but queue active"))
+                       if (WARN(retries > 10, "tx refused but queue active\n"))
                                goto drop;
                        goto retry;
                }
        return 0;
 }
 
-int ieee80211_master_start_xmit(struct sk_buff *skb, struct net_device *dev)
+static void ieee80211_xmit(struct ieee80211_sub_if_data *sdata,
+                          struct sk_buff *skb)
 {
-       struct ieee80211_master_priv *mpriv = netdev_priv(dev);
-       struct ieee80211_local *local = mpriv->local;
+       struct ieee80211_local *local = sdata->local;
        struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb);
        struct ieee80211_hdr *hdr = (struct ieee80211_hdr *) skb->data;
-       struct net_device *odev = NULL;
-       struct ieee80211_sub_if_data *osdata;
+       struct ieee80211_sub_if_data *tmp_sdata;
        int headroom;
        bool may_encrypt;
        enum {
                UNKNOWN_ADDRESS,
        } monitor_iface = NOT_MONITOR;
 
-       if (skb->iif)
-               odev = dev_get_by_index(&init_net, skb->iif);
-       if (unlikely(odev && !is_ieee80211_device(local, odev))) {
-               dev_put(odev);
-               odev = NULL;
-       }
-       if (unlikely(!odev)) {
-#ifdef CONFIG_MAC80211_VERBOSE_DEBUG
-               printk(KERN_DEBUG "%s: Discarded packet with nonexistent "
-                      "originating device\n", dev->name);
-#endif
-               dev_kfree_skb(skb);
-               return NETDEV_TX_OK;
-       }
+       dev_hold(sdata->dev);
 
        if ((local->hw.flags & IEEE80211_HW_PS_NULLFUNC_STACK) &&
            local->hw.conf.dynamic_ps_timeout > 0 &&
                        msecs_to_jiffies(local->hw.conf.dynamic_ps_timeout));
        }
 
-       memset(info, 0, sizeof(*info));
-
        info->flags |= IEEE80211_TX_CTL_REQ_TX_STATUS;
 
-       osdata = IEEE80211_DEV_TO_SUB_IF(odev);
-
-       if (ieee80211_vif_is_mesh(&osdata->vif) &&
+       if (ieee80211_vif_is_mesh(&sdata->vif) &&
            ieee80211_is_data(hdr->frame_control)) {
                if (is_multicast_ether_addr(hdr->addr3))
                        memcpy(hdr->addr1, hdr->addr3, ETH_ALEN);
                else
-                       if (mesh_nexthop_lookup(skb, osdata)) {
-                               dev_put(odev);
-                               return NETDEV_TX_OK;
+                       if (mesh_nexthop_lookup(skb, sdata)) {
+                               dev_put(sdata->dev);
+                               return;
                        }
-               if (memcmp(odev->dev_addr, hdr->addr4, ETH_ALEN) != 0)
-                       IEEE80211_IFSTA_MESH_CTR_INC(&osdata->u.mesh,
-                                                           fwded_frames);
-       } else if (unlikely(osdata->vif.type == NL80211_IFTYPE_MONITOR)) {
-               struct ieee80211_sub_if_data *sdata;
+               if (memcmp(sdata->dev->dev_addr, hdr->addr4, ETH_ALEN) != 0)
+                       IEEE80211_IFSTA_MESH_CTR_INC(&sdata->u.mesh,
+                                                    fwded_frames);
+       } else if (unlikely(sdata->vif.type == NL80211_IFTYPE_MONITOR)) {
                int hdrlen;
                u16 len_rthdr;
 
                         */
 
                        rcu_read_lock();
-                       list_for_each_entry_rcu(sdata, &local->interfaces,
+                       list_for_each_entry_rcu(tmp_sdata, &local->interfaces,
                                                list) {
-                               if (!netif_running(sdata->dev))
+                               if (!netif_running(tmp_sdata->dev))
                                        continue;
-                               if (sdata->vif.type != NL80211_IFTYPE_AP)
+                               if (tmp_sdata->vif.type != NL80211_IFTYPE_AP)
                                        continue;
-                               if (compare_ether_addr(sdata->dev->dev_addr,
+                               if (compare_ether_addr(tmp_sdata->dev->dev_addr,
                                                       hdr->addr2)) {
-                                       dev_hold(sdata->dev);
-                                       dev_put(odev);
-                                       osdata = sdata;
-                                       odev = osdata->dev;
-                                       skb->iif = sdata->dev->ifindex;
+                                       dev_hold(tmp_sdata->dev);
+                                       dev_put(sdata->dev);
+                                       sdata = tmp_sdata;
                                        monitor_iface = FOUND_SDATA;
                                        break;
                                }
                }
        }
 
-       may_encrypt = !skb->do_not_encrypt;
+       may_encrypt = !(info->flags & IEEE80211_TX_INTFL_DONT_ENCRYPT);
 
-       headroom = osdata->local->tx_headroom;
+       headroom = local->tx_headroom;
        if (may_encrypt)
                headroom += IEEE80211_ENCRYPT_HEADROOM;
        headroom -= skb_headroom(skb);
        headroom = max_t(int, 0, headroom);
 
-       if (ieee80211_skb_resize(osdata->local, skb, headroom, may_encrypt)) {
+       if (ieee80211_skb_resize(local, skb, headroom, may_encrypt)) {
                dev_kfree_skb(skb);
-               dev_put(odev);
-               return NETDEV_TX_OK;
+               dev_put(sdata->dev);
+               return;
        }
 
-       if (osdata->vif.type == NL80211_IFTYPE_AP_VLAN)
-               osdata = container_of(osdata->bss,
-                                     struct ieee80211_sub_if_data,
-                                     u.ap);
+       tmp_sdata = sdata;
+       if (sdata->vif.type == NL80211_IFTYPE_AP_VLAN)
+               tmp_sdata = container_of(sdata->bss,
+                                        struct ieee80211_sub_if_data,
+                                        u.ap);
        if (likely(monitor_iface != UNKNOWN_ADDRESS))
-               info->control.vif = &osdata->vif;
-
-       ieee80211_tx(odev, skb, false);
-       dev_put(odev);
+               info->control.vif = &tmp_sdata->vif;
 
-       return NETDEV_TX_OK;
+       ieee80211_select_queue(local, skb);
+       ieee80211_tx(sdata, skb, false);
+       dev_put(sdata->dev);
 }
 
 int ieee80211_monitor_start_xmit(struct sk_buff *skb,
        struct ieee80211_channel *chan = local->hw.conf.channel;
        struct ieee80211_radiotap_header *prthdr =
                (struct ieee80211_radiotap_header *)skb->data;
+       struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb);
        u16 len_rthdr;
 
        /*
        if (unlikely(skb->len < len_rthdr))
                goto fail; /* skb too short for claimed rt header extent */
 
-       skb->dev = local->mdev;
-
        /* needed because we set skb device to master */
        skb->iif = dev->ifindex;
 
-       /* sometimes we do encrypt injected frames, will be fixed
-        * up in radiotap parser if not wanted */
-       skb->do_not_encrypt = 0;
-
        /*
         * fix up the pointers accounting for the radiotap
         * header still being in there.  We are being given
        skb_set_network_header(skb, len_rthdr);
        skb_set_transport_header(skb, len_rthdr);
 
-       /* pass the radiotap header up to the next stage intact */
-       dev_queue_xmit(skb);
+       memset(info, 0, sizeof(*info));
+
+       /* pass the radiotap header up to xmit */
+       ieee80211_xmit(IEEE80211_DEV_TO_SUB_IF(dev), skb);
        return NETDEV_TX_OK;
 
 fail:
 {
        struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev);
        struct ieee80211_local *local = sdata->local;
+       struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb);
        int ret = NETDEV_TX_BUSY, head_need;
        u16 ethertype, hdrlen,  meshhdrlen = 0;
        __le16 fc;
 
        skb->iif = dev->ifindex;
 
-       skb->dev = local->mdev;
        dev->stats.tx_packets++;
        dev->stats.tx_bytes += skb->len;
 
        skb_set_network_header(skb, nh_pos);
        skb_set_transport_header(skb, h_pos);
 
+       memset(info, 0, sizeof(*info));
+
        dev->trans_start = jiffies;
-       dev_queue_xmit(skb);
+       ieee80211_xmit(sdata, skb);
 
        return NETDEV_TX_OK;
 
                return true;
        }
 
-       /* validate info->control.vif against skb->iif */
        sdata = IEEE80211_DEV_TO_SUB_IF(dev);
        if (sdata->vif.type == NL80211_IFTYPE_AP_VLAN)
                sdata = container_of(sdata->bss,
        }
 
        if (info->flags & IEEE80211_TX_INTFL_NEED_TXPROCESSING) {
-               ieee80211_tx(dev, skb, true);
+               /* do not use sdata, it may have been changed above */
+               ieee80211_tx(IEEE80211_DEV_TO_SUB_IF(dev), skb, true);
        } else {
                hdr = (struct ieee80211_hdr *)skb->data;
                sta = sta_info_get(local, hdr->addr1);
 
-               ret = __ieee80211_tx(local, &skb, sta);
+               ret = __ieee80211_tx(local, &skb, sta, true);
                if (ret != IEEE80211_TX_OK)
                        result = false;
        }
 }
 
 /*
- * Transmit all pending packets. Called from tasklet, locks master device
- * TX lock so that no new packets can come in.
+ * Transmit all pending packets. Called from tasklet.
  */
 void ieee80211_tx_pending(unsigned long data)
 {
        struct ieee80211_local *local = (struct ieee80211_local *)data;
-       struct net_device *dev = local->mdev;
        unsigned long flags;
        int i;
-       bool next;
+       bool txok;
 
        rcu_read_lock();
-       netif_tx_lock_bh(dev);
 
+       spin_lock_irqsave(&local->queue_stop_reason_lock, flags);
        for (i = 0; i < local->hw.queues; i++) {
                /*
                 * If queue is stopped by something other than due to pending
                 * frames, or we have no pending frames, proceed to next queue.
                 */
-               spin_lock_irqsave(&local->queue_stop_reason_lock, flags);
-               next = false;
-               if (local->queue_stop_reasons[i] !=
-                       BIT(IEEE80211_QUEUE_STOP_REASON_PENDING) ||
+               if (local->queue_stop_reasons[i] ||
                    skb_queue_empty(&local->pending[i]))
-                       next = true;
-               spin_unlock_irqrestore(&local->queue_stop_reason_lock, flags);
-
-               if (next)
                        continue;
 
-               /*
-                * start the queue now to allow processing our packets,
-                * we're under the tx lock here anyway so nothing will
-                * happen as a result of this
-                */
-               netif_start_subqueue(local->mdev, i);
-
                while (!skb_queue_empty(&local->pending[i])) {
-                       struct sk_buff *skb = skb_dequeue(&local->pending[i]);
-
-                       if (!ieee80211_tx_pending_skb(local, skb)) {
-                               skb_queue_head(&local->pending[i], skb);
+                       struct sk_buff *skb = __skb_dequeue(&local->pending[i]);
+                       spin_unlock_irqrestore(&local->queue_stop_reason_lock,
+                                               flags);
+
+                       txok = ieee80211_tx_pending_skb(local, skb);
+                       if (!txok)
+                               __skb_queue_head(&local->pending[i], skb);
+                       spin_lock_irqsave(&local->queue_stop_reason_lock,
+                                         flags);
+                       if (!txok)
                                break;
-                       }
                }
-
-               /* Start regular packet processing again. */
-               if (skb_queue_empty(&local->pending[i]))
-                       ieee80211_wake_queue_by_reason(&local->hw, i,
-                                       IEEE80211_QUEUE_STOP_REASON_PENDING);
        }
+       spin_unlock_irqrestore(&local->queue_stop_reason_lock, flags);
 
-       netif_tx_unlock_bh(dev);
        rcu_read_unlock();
 }
 
 
        info = IEEE80211_SKB_CB(skb);
 
-       skb->do_not_encrypt = 1;
-
+       info->flags |= IEEE80211_TX_INTFL_DONT_ENCRYPT;
        info->band = band;
        /*
         * XXX: For now, always use the lowest rate
        sdata = vif_to_sdata(vif);
        bss = &sdata->u.ap;
 
-       if (!bss)
-               return NULL;
-
        rcu_read_lock();
        beacon = rcu_dereference(bss->beacon);
 
                                cpu_to_le16(IEEE80211_FCTL_MOREDATA);
                }
 
-               if (!ieee80211_tx_prepare(local, &tx, skb))
+               if (!ieee80211_tx_prepare(sdata, &tx, skb))
                        break;
                dev_kfree_skb_any(skb);
        }
        return skb;
 }
 EXPORT_SYMBOL(ieee80211_get_buffered_bc);
+
+void ieee80211_tx_skb(struct ieee80211_sub_if_data *sdata, struct sk_buff *skb,
+                     int encrypt)
+{
+       struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb);
+       skb_set_mac_header(skb, 0);
+       skb_set_network_header(skb, 0);
+       skb_set_transport_header(skb, 0);
+
+       skb->iif = sdata->dev->ifindex;
+       if (!encrypt)
+               info->flags |= IEEE80211_TX_INTFL_DONT_ENCRYPT;
+
+       ieee80211_xmit(sdata, skb);
+}
 
 
        __clear_bit(reason, &local->queue_stop_reasons[queue]);
 
-       if (!skb_queue_empty(&local->pending[queue]) &&
-           local->queue_stop_reasons[queue] ==
-                               BIT(IEEE80211_QUEUE_STOP_REASON_PENDING))
-               tasklet_schedule(&local->tx_pending_tasklet);
-
        if (local->queue_stop_reasons[queue] != 0)
                /* someone still has this queue stopped */
                return;
 
-       netif_wake_subqueue(local->mdev, queue);
+       if (!skb_queue_empty(&local->pending[queue]))
+               tasklet_schedule(&local->tx_pending_tasklet);
 }
 
 void ieee80211_wake_queue_by_reason(struct ieee80211_hw *hw, int queue,
        if (WARN_ON(queue >= hw->queues))
                return;
 
-       /*
-        * Only stop if it was previously running, this is necessary
-        * for correct pending packets handling because there we may
-        * start (but not wake) the queue and rely on that.
-        */
-       if (!local->queue_stop_reasons[queue])
-               netif_stop_subqueue(local->mdev, queue);
-
        __set_bit(reason, &local->queue_stop_reasons[queue]);
 }
 
 
        spin_lock_irqsave(&local->queue_stop_reason_lock, flags);
        __ieee80211_stop_queue(hw, queue, IEEE80211_QUEUE_STOP_REASON_SKB_ADD);
-       __ieee80211_stop_queue(hw, queue, IEEE80211_QUEUE_STOP_REASON_PENDING);
-       skb_queue_tail(&local->pending[queue], skb);
+       __skb_queue_tail(&local->pending[queue], skb);
        __ieee80211_wake_queue(hw, queue, IEEE80211_QUEUE_STOP_REASON_SKB_ADD);
        spin_unlock_irqrestore(&local->queue_stop_reason_lock, flags);
 }
        while ((skb = skb_dequeue(skbs))) {
                ret++;
                queue = skb_get_queue_mapping(skb);
-               skb_queue_tail(&local->pending[queue], skb);
+               __skb_queue_tail(&local->pending[queue], skb);
        }
 
-       for (i = 0; i < hw->queues; i++) {
-               if (ret)
-                       __ieee80211_stop_queue(hw, i,
-                               IEEE80211_QUEUE_STOP_REASON_PENDING);
+       for (i = 0; i < hw->queues; i++)
                __ieee80211_wake_queue(hw, i,
                        IEEE80211_QUEUE_STOP_REASON_SKB_ADD);
-       }
        spin_unlock_irqrestore(&local->queue_stop_reason_lock, flags);
 
        return ret;
 int ieee80211_queue_stopped(struct ieee80211_hw *hw, int queue)
 {
        struct ieee80211_local *local = hw_to_local(hw);
+       unsigned long flags;
+       int ret;
 
        if (WARN_ON(queue >= hw->queues))
                return true;
 
-       return __netif_subqueue_stopped(local->mdev, queue);
+       spin_lock_irqsave(&local->queue_stop_reason_lock, flags);
+       ret = !!local->queue_stop_reasons[queue];
+       spin_unlock_irqrestore(&local->queue_stop_reason_lock, flags);
+       return ret;
 }
 EXPORT_SYMBOL(ieee80211_queue_stopped);
 
        ieee80211_set_wmm_default(sdata);
 }
 
-void ieee80211_tx_skb(struct ieee80211_sub_if_data *sdata, struct sk_buff *skb,
-                     int encrypt)
-{
-       skb->dev = sdata->local->mdev;
-       skb_set_mac_header(skb, 0);
-       skb_set_network_header(skb, 0);
-       skb_set_transport_header(skb, 0);
-
-       skb->iif = sdata->dev->ifindex;
-       skb->do_not_encrypt = !encrypt;
-
-       dev_queue_xmit(skb);
-}
-
 u32 ieee80211_mandatory_rates(struct ieee80211_local *local,
                              enum ieee80211_band band)
 {
        /* reconfigure hardware */
        ieee80211_hw_config(local, ~0);
 
-       netif_addr_lock_bh(local->mdev);
+       spin_lock_bh(&local->filter_lock);
        ieee80211_configure_filter(local);
-       netif_addr_unlock_bh(local->mdev);
+       spin_unlock_bh(&local->filter_lock);
 
        /* Finally also reconfigure all the BSS information */
        list_for_each_entry(sdata, &local->interfaces, list) {
 
        return ieee802_1d_to_ac[skb->priority];
 }
 
-u16 ieee80211_select_queue(struct net_device *dev, struct sk_buff *skb)
+void ieee80211_select_queue(struct ieee80211_local *local, struct sk_buff *skb)
 {
-       struct ieee80211_master_priv *mpriv = netdev_priv(dev);
-       struct ieee80211_local *local = mpriv->local;
        struct ieee80211_hdr *hdr = (struct ieee80211_hdr *) skb->data;
        u16 queue;
        u8 tid;
                *p = 0;
        }
 
-       return queue;
+       skb_set_queue_mapping(skb, queue);
 }
 
 
 extern const int ieee802_1d_to_ac[8];
 
-u16 ieee80211_select_queue(struct net_device *dev, struct sk_buff *skb);
+void ieee80211_select_queue(struct ieee80211_local *local,
+                           struct sk_buff *skb);
 
 #endif /* _WME_H */