return 0;
 }
 
-static void adm8211_set_rx_mode(struct ieee80211_hw *dev,
-                               unsigned short flags, int mc_count)
-{
-       struct adm8211_priv *priv = dev->priv;
-       unsigned int bit_nr;
-       u32 mc_filter[2];
-       struct dev_mc_list *mclist;
-       void *tmp;
-
-       if (flags & IFF_PROMISC) {
-               priv->nar |= ADM8211_NAR_PR;
-               priv->nar &= ~ADM8211_NAR_MM;
-               mc_filter[1] = mc_filter[0] = ~0;
-       } else if ((flags & IFF_ALLMULTI) || (mc_count > -1)) {
-               priv->nar &= ~ADM8211_NAR_PR;
-               priv->nar |= ADM8211_NAR_MM;
-               mc_filter[1] = mc_filter[0] = ~0;
-       } else {
-               priv->nar &= ~(ADM8211_NAR_MM | ADM8211_NAR_PR);
-               mc_filter[1] = mc_filter[0] = 0;
-               mclist = NULL;
-               while ((mclist = ieee80211_get_mc_list_item(dev, mclist, &tmp))) {
-                       bit_nr = ether_crc(ETH_ALEN, mclist->dmi_addr) >> 26;
-
-                       bit_nr &= 0x3F;
-                       mc_filter[bit_nr >> 5] |= 1 << (bit_nr & 31);
-               }
-       }
-
-       ADM8211_IDLE_RX();
-
-       ADM8211_CSR_WRITE(MAR0, mc_filter[0]);
-       ADM8211_CSR_WRITE(MAR1, mc_filter[1]);
-       ADM8211_CSR_READ(NAR);
-
-       if (flags & IFF_PROMISC)
-               dev->flags |= IEEE80211_HW_RX_INCLUDES_FCS;
-       else
-               dev->flags &= ~IEEE80211_HW_RX_INCLUDES_FCS;
-
-       ADM8211_RESTORE();
-}
-
 static int adm8211_get_tx_stats(struct ieee80211_hw *dev,
                                struct ieee80211_tx_queue_stats *stats)
 {
 
        /* Clear the missed-packet counter. */
        ADM8211_CSR_READ(LPC);
-
-       if (!priv->mac_addr)
-               return;
-
-       /* set mac address */
-       ADM8211_CSR_WRITE(PAR0, *(u32 *)priv->mac_addr);
-       ADM8211_CSR_WRITE(PAR1, *(u16 *)&priv->mac_addr[4]);
 }
 
 static int adm8211_hw_reset(struct ieee80211_hw *dev)
        ADM8211_CSR_WRITE(BPLI, reg);
 }
 
-static void adm8211_set_bssid(struct ieee80211_hw *dev, u8 *bssid)
+static void adm8211_set_bssid(struct ieee80211_hw *dev, const u8 *bssid)
 {
        struct adm8211_priv *priv = dev->priv;
        u32 reg;
        return 0;
 }
 
+static void adm8211_configure_filter(struct ieee80211_hw *dev,
+                                    unsigned int changed_flags,
+                                    unsigned int *total_flags,
+                                    int mc_count, struct dev_mc_list *mclist)
+{
+       static const u8 bcast[ETH_ALEN] = { 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF };
+       struct adm8211_priv *priv = dev->priv;
+       unsigned int bit_nr, new_flags;
+       u32 mc_filter[2];
+       int i;
+
+       new_flags = 0;
+
+       if (*total_flags & FIF_PROMISC_IN_BSS) {
+               new_flags |= FIF_PROMISC_IN_BSS;
+               priv->nar |= ADM8211_NAR_PR;
+               priv->nar &= ~ADM8211_NAR_MM;
+               mc_filter[1] = mc_filter[0] = ~0;
+       } else if ((*total_flags & FIF_ALLMULTI) || (mc_count > 32)) {
+               new_flags |= FIF_ALLMULTI;
+               priv->nar &= ~ADM8211_NAR_PR;
+               priv->nar |= ADM8211_NAR_MM;
+               mc_filter[1] = mc_filter[0] = ~0;
+       } else {
+               priv->nar &= ~(ADM8211_NAR_MM | ADM8211_NAR_PR);
+               mc_filter[1] = mc_filter[0] = 0;
+               for (i = 0; i < mc_count; i++) {
+                       if (!mclist)
+                               break;
+                       bit_nr = ether_crc(ETH_ALEN, mclist->dmi_addr) >> 26;
+
+                       bit_nr &= 0x3F;
+                       mc_filter[bit_nr >> 5] |= 1 << (bit_nr & 31);
+                       mclist = mclist->next;
+               }
+       }
+
+       ADM8211_IDLE_RX();
+
+       ADM8211_CSR_WRITE(MAR0, mc_filter[0]);
+       ADM8211_CSR_WRITE(MAR1, mc_filter[1]);
+       ADM8211_CSR_READ(NAR);
+
+       if (priv->nar & ADM8211_NAR_PR)
+               dev->flags |= IEEE80211_HW_RX_INCLUDES_FCS;
+       else
+               dev->flags &= ~IEEE80211_HW_RX_INCLUDES_FCS;
+
+       if (*total_flags & FIF_BCN_PRBRESP_PROMISC)
+               adm8211_set_bssid(dev, bcast);
+       else
+               adm8211_set_bssid(dev, priv->bssid);
+
+       ADM8211_RESTORE();
+
+       *total_flags = new_flags;
+}
+
 static int adm8211_add_interface(struct ieee80211_hw *dev,
                                 struct ieee80211_if_init_conf *conf)
 {
        struct adm8211_priv *priv = dev->priv;
-       /* NOTE: using IEEE80211_IF_TYPE_MGMT to indicate no mode selected */
-       if (priv->mode != IEEE80211_IF_TYPE_MGMT)
-               return -1;
+       if (priv->mode != IEEE80211_IF_TYPE_MNTR)
+               return -EOPNOTSUPP;
 
        switch (conf->type) {
        case IEEE80211_IF_TYPE_STA:
-       case IEEE80211_IF_TYPE_MNTR:
                priv->mode = conf->type;
                break;
        default:
                return -EOPNOTSUPP;
        }
 
-       priv->mac_addr = conf->mac_addr;
+       ADM8211_IDLE();
+
+       ADM8211_CSR_WRITE(PAR0, *(u32 *)conf->mac_addr);
+       ADM8211_CSR_WRITE(PAR1, *(u16 *)(conf->mac_addr + 4));
+
+       adm8211_update_mode(dev);
+
+       ADM8211_RESTORE();
 
        return 0;
 }
                                     struct ieee80211_if_init_conf *conf)
 {
        struct adm8211_priv *priv = dev->priv;
-       priv->mode = IEEE80211_IF_TYPE_MGMT;
+       priv->mode = IEEE80211_IF_TYPE_MNTR;
 }
 
 static int adm8211_init_rings(struct ieee80211_hw *dev)
        }
 }
 
-static int adm8211_open(struct ieee80211_hw *dev)
+static int adm8211_start(struct ieee80211_hw *dev)
 {
        struct adm8211_priv *priv = dev->priv;
        int retval;
        return retval;
 }
 
-static int adm8211_stop(struct ieee80211_hw *dev)
+static void adm8211_stop(struct ieee80211_hw *dev)
 {
        struct adm8211_priv *priv = dev->priv;
 
        free_irq(priv->pdev->irq, dev);
 
        adm8211_free_rings(dev);
-       return 0;
 }
 
 static void adm8211_calc_durations(int *dur, int *plcp, size_t payload_len, int len,
 
 static const struct ieee80211_ops adm8211_ops = {
        .tx                     = adm8211_tx,
-       .open                   = adm8211_open,
+       .start                  = adm8211_start,
        .stop                   = adm8211_stop,
        .add_interface          = adm8211_add_interface,
        .remove_interface       = adm8211_remove_interface,
        .config                 = adm8211_config,
        .config_interface       = adm8211_config_interface,
-       .set_multicast_list     = adm8211_set_rx_mode,
+       .configure_filter       = adm8211_configure_filter,
        .get_stats              = adm8211_get_stats,
        .get_tx_stats           = adm8211_get_tx_stats,
        .get_tsf                = adm8211_get_tsft
        priv->tx_power = 0x40;
        priv->lpf_cutoff = 0xFF;
        priv->lnags_threshold = 0xFF;
-       priv->mode = IEEE80211_IF_TYPE_MGMT;
+       priv->mode = IEEE80211_IF_TYPE_MNTR;
 
        /* Power-on issue. EEPROM won't read correctly without */
        if (priv->revid >= ADM8211_REV_BA) {
        struct ieee80211_hw *dev = pci_get_drvdata(pdev);
        struct adm8211_priv *priv = dev->priv;
 
-       if (priv->mode != IEEE80211_IF_TYPE_MGMT) {
+       if (priv->mode != IEEE80211_IF_TYPE_MNTR) {
                ieee80211_stop_queues(dev);
                adm8211_stop(dev);
        }
        pci_set_power_state(pdev, PCI_D0);
        pci_restore_state(pdev);
 
-       if (priv->mode != IEEE80211_IF_TYPE_MGMT) {
-               adm8211_open(dev);
+       if (priv->mode != IEEE80211_IF_TYPE_MNTR) {
+               adm8211_start(dev);
                ieee80211_start_queues(dev);
        }
 
 
        u8 bssid[ETH_ALEN];
        u8 ssid[32];
        size_t ssid_len;
-       u8 *mac_addr;
 
        u8 soft_rx_crc;
        u8 retry_limit;
 
         * at a time. General information about this interface follows.
         */
 
-       /* Opaque ID of the operating interface (!= monitor
-        * interface) from the ieee80211 subsystem.
-        * Do not modify.
+       /* Opaque ID of the operating interface from the ieee80211
+        * subsystem. Do not modify.
         */
        int if_id;
        /* The MAC address of the operating interface. */
        u8 bssid[ETH_ALEN];
        /* Interface type. (IEEE80211_IF_TYPE_XXX) */
        int if_type;
-       /* Counter of active monitor interfaces. */
-       int monitor;
        /* Is the card operating in AP, STA or IBSS mode? */
        bool operating;
-       /* Promisc mode active?
-        * Note that (monitor != 0) implies promisc.
-        */
-       bool promisc;
+       /* filter flags */
+       unsigned int filter_flags;
        /* Stats about the wireless interface */
        struct ieee80211_low_level_stats ieee_stats;
 
 /* Is the device operating in a specified mode (IEEE80211_IF_TYPE_XXX). */
 static inline int b43_is_mode(struct b43_wl *wl, int type)
 {
-       if (type == IEEE80211_IF_TYPE_MNTR)
-               return !!(wl->monitor);
        return (wl->operating && wl->if_type == type);
 }
 
 
 module_param_string(fwpostfix, modparam_fwpostfix, 16, 0444);
 MODULE_PARM_DESC(fwpostfix, "Postfix for the .fw files to load.");
 
-static int modparam_mon_keep_bad;
-module_param_named(mon_keep_bad, modparam_mon_keep_bad, int, 0444);
-MODULE_PARM_DESC(mon_keep_bad, "Keep bad frames in monitor mode");
-
-static int modparam_mon_keep_badplcp;
-module_param_named(mon_keep_badplcp, modparam_mon_keep_bad, int, 0444);
-MODULE_PARM_DESC(mon_keep_badplcp, "Keep frames with bad PLCP in monitor mode");
-
 static int modparam_hwpctl;
 module_param_named(hwpctl, modparam_hwpctl, int, 0444);
 MODULE_PARM_DESC(hwpctl, "Enable hardware-side power control (default off)");
        }
 }
 
-static void b43_upload_card_macaddress(struct b43_wldev *dev,
-                                      const u8 * mac_addr)
+static void b43_upload_card_macaddress(struct b43_wldev *dev)
 {
-       if (mac_addr)
-               memcpy(dev->wl->mac_addr, mac_addr, ETH_ALEN);
-       else
-               memset(dev->wl->mac_addr, 0, ETH_ALEN);
        b43_write_mac_bssid_templates(dev);
-       b43_macfilter_set(dev, B43_MACFILTER_SELF, mac_addr);
+       b43_macfilter_set(dev, B43_MACFILTER_SELF, dev->wl->mac_addr);
 }
 
 static void b43_set_slot_time(struct b43_wldev *dev, u16 slot_time)
        ctl &= ~B43_MACCTL_KEEP_BADPLCP;
        ctl &= ~B43_MACCTL_KEEP_BAD;
        ctl &= ~B43_MACCTL_PROMISC;
+       ctl &= ~B43_MACCTL_BEACPROMISC;
        ctl |= B43_MACCTL_INFRA;
 
-       if (wl->operating) {
-               switch (wl->if_type) {
-               case IEEE80211_IF_TYPE_AP:
-                       ctl |= B43_MACCTL_AP;
-                       break;
-               case IEEE80211_IF_TYPE_IBSS:
-                       ctl &= ~B43_MACCTL_INFRA;
-                       break;
-               case IEEE80211_IF_TYPE_STA:
-               case IEEE80211_IF_TYPE_MNTR:
-               case IEEE80211_IF_TYPE_WDS:
-                       break;
-               default:
-                       B43_WARN_ON(1);
-               }
-       }
-       if (wl->monitor) {
+       if (b43_is_mode(wl, IEEE80211_IF_TYPE_AP))
+               ctl |= B43_MACCTL_AP;
+       else if (b43_is_mode(wl, IEEE80211_IF_TYPE_IBSS))
+               ctl &= ~B43_MACCTL_INFRA;
+
+       if (wl->filter_flags & FIF_CONTROL)
                ctl |= B43_MACCTL_KEEP_CTL;
-               if (modparam_mon_keep_bad)
-                       ctl |= B43_MACCTL_KEEP_BAD;
-               if (modparam_mon_keep_badplcp)
-                       ctl |= B43_MACCTL_KEEP_BADPLCP;
-       }
-       if (wl->promisc)
+       if (wl->filter_flags & FIF_FCSFAIL)
+               ctl |= B43_MACCTL_KEEP_BAD;
+       if (wl->filter_flags & FIF_PLCPFAIL)
+               ctl |= B43_MACCTL_KEEP_BADPLCP;
+       if (wl->filter_flags & FIF_PROMISC_IN_BSS)
                ctl |= B43_MACCTL_PROMISC;
+       if (wl->filter_flags & FIF_BCN_PRBRESP_PROMISC)
+               ctl |= B43_MACCTL_BEACPROMISC;
+
        /* Workaround: On old hardware the HW-MAC-address-filter
         * doesn't work properly, so always run promisc in filter
         * it in software. */
                    & ~B43_MACCTL_INFRA);
        b43_write32(dev, B43_MMIO_MACCTL, b43_read32(dev, B43_MMIO_MACCTL)
                    | B43_MACCTL_INFRA);
-       /* Let beacons come through */
-       b43_write32(dev, B43_MMIO_MACCTL, b43_read32(dev, B43_MMIO_MACCTL)
-                   | B43_MACCTL_BEACPROMISC);
 
        if (b43_using_pio(dev)) {
                b43_write32(dev, 0x0210, 0x00000100);
        return err;
 }
 
-static int b43_dev_set_key(struct ieee80211_hw *hw,
-                          set_key_cmd cmd, const u8 *local_addr,
-                          const u8 *addr, struct ieee80211_key_conf *key)
+static int b43_dev_set_key(struct ieee80211_hw *hw, enum set_key_cmd cmd,
+                          const u8 *local_addr, const u8 *addr,
+                          struct ieee80211_key_conf *key)
 {
        struct b43_wl *wl = hw_to_b43_wl(hw);
        struct b43_wldev *dev = wl->current_dev;
        return err;
 }
 
-static void b43_set_multicast_list(struct ieee80211_hw *hw,
-                                  unsigned short netflags, int mc_count)
+static void b43_configure_filter(struct ieee80211_hw *hw,
+                                unsigned int changed, unsigned int *fflags,
+                                int mc_count, struct dev_addr_list *mc_list)
 {
        struct b43_wl *wl = hw_to_b43_wl(hw);
        struct b43_wldev *dev = wl->current_dev;
        unsigned long flags;
 
-       if (!dev)
+       if (!dev) {
+               *fflags = 0;
                return;
-       spin_lock_irqsave(&wl->irq_lock, flags);
-       if (wl->promisc != !!(netflags & IFF_PROMISC)) {
-               wl->promisc = !!(netflags & IFF_PROMISC);
-               if (b43_status(dev) >= B43_STAT_INITIALIZED)
-                       b43_adjust_opmode(dev);
        }
+
+       spin_lock_irqsave(&wl->irq_lock, flags);
+       *fflags &= FIF_PROMISC_IN_BSS |
+                 FIF_ALLMULTI |
+                 FIF_FCSFAIL |
+                 FIF_PLCPFAIL |
+                 FIF_CONTROL |
+                 FIF_OTHER_BSS |
+                 FIF_BCN_PRBRESP_PROMISC;
+
+       changed &= FIF_PROMISC_IN_BSS |
+                  FIF_ALLMULTI |
+                  FIF_FCSFAIL |
+                  FIF_PLCPFAIL |
+                  FIF_CONTROL |
+                  FIF_OTHER_BSS |
+                  FIF_BCN_PRBRESP_PROMISC;
+
+       wl->filter_flags = *fflags;
+
+       if (changed && b43_status(dev) >= B43_STAT_INITIALIZED)
+               b43_adjust_opmode(dev);
        spin_unlock_irqrestore(&wl->irq_lock, flags);
 }
 
                return -ENODEV;
        mutex_lock(&wl->mutex);
        spin_lock_irqsave(&wl->irq_lock, flags);
-       if (conf->type != IEEE80211_IF_TYPE_MNTR) {
-               B43_WARN_ON(wl->if_id != if_id);
-               if (conf->bssid)
-                       memcpy(wl->bssid, conf->bssid, ETH_ALEN);
-               else
-                       memset(wl->bssid, 0, ETH_ALEN);
-               if (b43_status(dev) >= B43_STAT_INITIALIZED) {
-                       if (b43_is_mode(wl, IEEE80211_IF_TYPE_AP)) {
-                               B43_WARN_ON(conf->type != IEEE80211_IF_TYPE_AP);
-                               b43_set_ssid(dev, conf->ssid, conf->ssid_len);
-                               if (conf->beacon)
-                                       b43_refresh_templates(dev, conf->beacon);
-                       }
-                       b43_write_mac_bssid_templates(dev);
+       B43_WARN_ON(wl->if_id != if_id);
+       if (conf->bssid)
+               memcpy(wl->bssid, conf->bssid, ETH_ALEN);
+       else
+               memset(wl->bssid, 0, ETH_ALEN);
+       if (b43_status(dev) >= B43_STAT_INITIALIZED) {
+               if (b43_is_mode(wl, IEEE80211_IF_TYPE_AP)) {
+                       B43_WARN_ON(conf->type != IEEE80211_IF_TYPE_AP);
+                       b43_set_ssid(dev, conf->ssid, conf->ssid_len);
+                       if (conf->beacon)
+                               b43_refresh_templates(dev, conf->beacon);
                }
+               b43_write_mac_bssid_templates(dev);
        }
        spin_unlock_irqrestore(&wl->irq_lock, flags);
        mutex_unlock(&wl->mutex);
 
        ssb_bus_powerup(bus, 1);        /* Enable dynamic PCTL */
        memset(wl->bssid, 0, ETH_ALEN);
-       b43_upload_card_macaddress(dev, NULL);
+       memset(wl->mac_addr, 0, ETH_ALEN);
+       b43_upload_card_macaddress(dev);
        b43_security_init(dev);
        b43_rng_init(wl);
 
        struct b43_wldev *dev;
        unsigned long flags;
        int err = -EOPNOTSUPP;
-       int did_init = 0;
+
+       /* TODO: allow WDS/AP devices to coexist */
+
+       if (conf->type != IEEE80211_IF_TYPE_AP &&
+           conf->type != IEEE80211_IF_TYPE_STA &&
+           conf->type != IEEE80211_IF_TYPE_WDS &&
+           conf->type != IEEE80211_IF_TYPE_IBSS)
+               return -EOPNOTSUPP;
 
        mutex_lock(&wl->mutex);
-       if ((conf->type != IEEE80211_IF_TYPE_MNTR) && wl->operating)
+       if (wl->operating)
                goto out_mutex_unlock;
 
        b43dbg(wl, "Adding Interface type %d\n", conf->type);
 
        dev = wl->current_dev;
+       wl->operating = 1;
+       wl->if_id = conf->if_id;
+       wl->if_type = conf->type;
+       memcpy(wl->mac_addr, conf->mac_addr, ETH_ALEN);
+
+       spin_lock_irqsave(&wl->irq_lock, flags);
+       b43_adjust_opmode(dev);
+       b43_upload_card_macaddress(dev);
+       spin_unlock_irqrestore(&wl->irq_lock, flags);
+
+       err = 0;
+ out_mutex_unlock:
+       mutex_unlock(&wl->mutex);
+
+       return err;
+}
+
+static void b43_remove_interface(struct ieee80211_hw *hw,
+                                struct ieee80211_if_init_conf *conf)
+{
+       struct b43_wl *wl = hw_to_b43_wl(hw);
+       struct b43_wldev *dev = wl->current_dev;
+       unsigned long flags;
+
+       b43dbg(wl, "Removing Interface type %d\n", conf->type);
+
+       mutex_lock(&wl->mutex);
+
+       B43_WARN_ON(!wl->operating);
+       B43_WARN_ON(wl->if_id != conf->if_id);
+
+       wl->operating = 0;
+
+       spin_lock_irqsave(&wl->irq_lock, flags);
+       b43_adjust_opmode(dev);
+       memset(wl->mac_addr, 0, ETH_ALEN);
+       b43_upload_card_macaddress(dev);
+       spin_unlock_irqrestore(&wl->irq_lock, flags);
+
+       mutex_unlock(&wl->mutex);
+}
+
+static int b43_start(struct ieee80211_hw *hw)
+{
+       struct b43_wl *wl = hw_to_b43_wl(hw);
+       struct b43_wldev *dev = wl->current_dev;
+       int did_init = 0;
+       int err;
+
+       mutex_lock(&wl->mutex);
+
        if (b43_status(dev) < B43_STAT_INITIALIZED) {
                err = b43_wireless_core_init(dev);
                if (err)
                        goto out_mutex_unlock;
                did_init = 1;
        }
+
        if (b43_status(dev) < B43_STAT_STARTED) {
                err = b43_wireless_core_start(dev);
                if (err) {
                }
        }
 
-       spin_lock_irqsave(&wl->irq_lock, flags);
-       switch (conf->type) {
-       case IEEE80211_IF_TYPE_MNTR:
-               wl->monitor++;
-               break;
-       default:
-               wl->operating = 1;
-               wl->if_id = conf->if_id;
-               wl->if_type = conf->type;
-               b43_upload_card_macaddress(dev, conf->mac_addr);
-       }
-       b43_adjust_opmode(dev);
-       spin_unlock_irqrestore(&wl->irq_lock, flags);
-
-       err = 0;
-      out_mutex_unlock:
+ out_mutex_unlock:
        mutex_unlock(&wl->mutex);
 
        return err;
 }
 
-static void b43_remove_interface(struct ieee80211_hw *hw,
-                                struct ieee80211_if_init_conf *conf)
+void b43_stop(struct ieee80211_hw *hw)
 {
        struct b43_wl *wl = hw_to_b43_wl(hw);
-       struct b43_wldev *dev;
-       unsigned long flags;
-
-       b43dbg(wl, "Removing Interface type %d\n", conf->type);
+       struct b43_wldev *dev = wl->current_dev;
 
        mutex_lock(&wl->mutex);
-       if (conf->type == IEEE80211_IF_TYPE_MNTR) {
-               wl->monitor--;
-               B43_WARN_ON(wl->monitor < 0);
-       } else {
-               B43_WARN_ON(!wl->operating);
-               wl->operating = 0;
-       }
-
-       dev = wl->current_dev;
-       if (!wl->operating && wl->monitor == 0) {
-               /* No interface left. */
-               if (b43_status(dev) >= B43_STAT_STARTED)
-                       b43_wireless_core_stop(dev);
-               b43_wireless_core_exit(dev);
-       } else {
-               /* Just monitor interfaces left. */
-               spin_lock_irqsave(&wl->irq_lock, flags);
-               b43_adjust_opmode(dev);
-               if (!wl->operating)
-                       b43_upload_card_macaddress(dev, NULL);
-               spin_unlock_irqrestore(&wl->irq_lock, flags);
-       }
+       if (b43_status(dev) >= B43_STAT_STARTED)
+               b43_wireless_core_stop(dev);
+       b43_wireless_core_exit(dev);
        mutex_unlock(&wl->mutex);
 }
 
        .remove_interface = b43_remove_interface,
        .config = b43_dev_config,
        .config_interface = b43_config_interface,
-       .set_multicast_list = b43_set_multicast_list,
+       .configure_filter = b43_configure_filter,
        .set_key = b43_dev_set_key,
        .get_stats = b43_get_stats,
        .get_tx_stats = b43_get_tx_stats,
+       .start = b43_start,
+       .stop = b43_stop,
 };
 
 /* Hard-reset the chip. Do not call this directly.
        }
 
        /* fill hw info */
-       hw->flags = IEEE80211_HW_HOST_GEN_BEACON_TEMPLATE |
-           IEEE80211_HW_MONITOR_DURING_OPER;
+       hw->flags = IEEE80211_HW_HOST_GEN_BEACON_TEMPLATE;
        hw->max_signal = 100;
        hw->max_rssi = -110;
        hw->max_noise = -110;
 
 #define B43legacy_MACCTL_IHR_ENABLED   0x00000400 /* IHR Region Enabled */
 #define B43legacy_MACCTL_INFRA         0x00020000 /* Infrastructure mode */
 #define B43legacy_MACCTL_AP            0x00040000 /* AccessPoint mode */
+#define B43legacy_MACCTL_BEACPROMISC   0x00100000 /* Beacon Promiscuous */
 #define B43legacy_MACCTL_KEEP_BADPLCP  0x00200000 /* Keep bad PLCP frames */
 #define B43legacy_MACCTL_KEEP_CTL      0x00400000 /* Keep control frames */
 #define B43legacy_MACCTL_KEEP_BAD      0x00800000 /* Keep bad frames (FCS) */
         * at a time. General information about this interface follows.
         */
 
-       /* Opaque ID of the operating interface (!= monitor
-        * interface) from the ieee80211 subsystem.
-        * Do not modify.
+       /* Opaque ID of the operating interface from the ieee80211
+        * subsystem. Do not modify.
         */
        int if_id;
        /* MAC address (can be NULL). */
-       const u8 *mac_addr;
+       u8 mac_addr[ETH_ALEN];
        /* Current BSSID (can be NULL). */
-       const u8 *bssid;
+       u8 bssid[ETH_ALEN];
        /* Interface type. (IEEE80211_IF_TYPE_XXX) */
        int if_type;
-       /* Counter of active monitor interfaces. */
-       int monitor;
        /* Is the card operating in AP, STA or IBSS mode? */
        bool operating;
-       /* Promisc mode active?
-        * Note that (monitor != 0) implies promisc.
-        */
-       bool promisc;
+       /* filter flags */
+       unsigned int filter_flags;
        /* Stats about the wireless interface */
        struct ieee80211_low_level_stats ieee_stats;
 
 static inline
 int b43legacy_is_mode(struct b43legacy_wl *wl, int type)
 {
-       if (type == IEEE80211_IF_TYPE_MNTR)
-               return !!(wl->monitor);
        return (wl->operating &&
                wl->if_type == type);
 }
 
 module_param_string(fwpostfix, modparam_fwpostfix, 16, 0444);
 MODULE_PARM_DESC(fwpostfix, "Postfix for the firmware files to load.");
 
-static int modparam_mon_keep_bad;
-module_param_named(mon_keep_bad, modparam_mon_keep_bad, int, 0444);
-MODULE_PARM_DESC(mon_keep_bad, "Keep bad frames in monitor mode");
-
-static int modparam_mon_keep_badplcp;
-module_param_named(mon_keep_badplcp, modparam_mon_keep_bad, int, 0444);
-MODULE_PARM_DESC(mon_keep_badplcp, "Keep frames with bad PLCP in monitor mode");
-
 /* The following table supports BCM4301, BCM4303 and BCM4306/2 devices. */
 static const struct ssb_device_id b43legacy_ssb_tbl[] = {
        SSB_DEVICE(SSB_VENDOR_BROADCOM, SSB_DEV_80211, 2),
        }
 }
 
-static void b43legacy_upload_card_macaddress(struct b43legacy_wldev *dev,
-                                            const u8 *mac_addr)
+static void b43legacy_upload_card_macaddress(struct b43legacy_wldev *dev)
 {
-       dev->wl->mac_addr = mac_addr;
        b43legacy_write_mac_bssid_templates(dev);
-       b43legacy_macfilter_set(dev, B43legacy_MACFILTER_SELF, mac_addr);
+       b43legacy_macfilter_set(dev, B43legacy_MACFILTER_SELF,
+                               dev->wl->mac_addr);
 }
 
 static void b43legacy_set_slot_time(struct b43legacy_wldev *dev,
        ctl &= ~B43legacy_MACCTL_KEEP_BADPLCP;
        ctl &= ~B43legacy_MACCTL_KEEP_BAD;
        ctl &= ~B43legacy_MACCTL_PROMISC;
+       ctl &= ~B43legacy_MACCTL_BEACPROMISC;
        ctl |= B43legacy_MACCTL_INFRA;
 
-       if (wl->operating) {
-               switch (wl->if_type) {
-               case IEEE80211_IF_TYPE_AP:
-                       ctl |= B43legacy_MACCTL_AP;
-                       break;
-               case IEEE80211_IF_TYPE_IBSS:
-                       ctl &= ~B43legacy_MACCTL_INFRA;
-                       break;
-               case IEEE80211_IF_TYPE_STA:
-               case IEEE80211_IF_TYPE_MNTR:
-               case IEEE80211_IF_TYPE_WDS:
-                       break;
-               default:
-                       b43legacyerr(wl, "Improper value of %d for"
-                                    " wl->if_type\n", wl->if_type);
-               }
-       }
-       if (wl->monitor) {
+       if (b43legacy_is_mode(wl, IEEE80211_IF_TYPE_AP))
+               ctl |= B43legacy_MACCTL_AP;
+       else if (b43legacy_is_mode(wl, IEEE80211_IF_TYPE_IBSS))
+               ctl &= ~B43legacy_MACCTL_INFRA;
+
+       if (wl->filter_flags & FIF_CONTROL)
                ctl |= B43legacy_MACCTL_KEEP_CTL;
-               if (modparam_mon_keep_bad)
-                       ctl |= B43legacy_MACCTL_KEEP_BAD;
-               if (modparam_mon_keep_badplcp)
-                       ctl |= B43legacy_MACCTL_KEEP_BADPLCP;
-       }
-       if (wl->promisc)
+       if (wl->filter_flags & FIF_FCSFAIL)
+               ctl |= B43legacy_MACCTL_KEEP_BAD;
+       if (wl->filter_flags & FIF_PLCPFAIL)
+               ctl |= B43legacy_MACCTL_KEEP_BADPLCP;
+       if (wl->filter_flags & FIF_PROMISC_IN_BSS)
                ctl |= B43legacy_MACCTL_PROMISC;
+       if (wl->filter_flags & FIF_BCN_PRBRESP_PROMISC)
+               ctl |= B43legacy_MACCTL_BEACPROMISC;
+
        /* Workaround: On old hardware the HW-MAC-address-filter
         * doesn't work properly, so always run promisc in filter
         * it in software. */
        value32 |= B43legacy_SBF_MODE_NOTADHOC;
        b43legacy_write32(dev, B43legacy_MMIO_STATUS_BITFIELD, value32);
 
-       value32 = b43legacy_read32(dev, B43legacy_MMIO_STATUS_BITFIELD);
-       value32 |= 0x100000;
-       b43legacy_write32(dev, B43legacy_MMIO_STATUS_BITFIELD, value32);
-
        if (b43legacy_using_pio(dev)) {
                b43legacy_write32(dev, 0x0210, 0x00000100);
                b43legacy_write32(dev, 0x0230, 0x00000100);
 }
 
 static int b43legacy_dev_set_key(struct ieee80211_hw *hw,
-                                set_key_cmd cmd,
+                                enum set_key_cmd cmd,
                                 const u8 *local_addr, const u8 *addr,
                                 struct ieee80211_key_conf *key)
 {
        return err;
 }
 
-static void b43legacy_set_multicast_list(struct ieee80211_hw *hw,
-                                        unsigned short netflags,
-                                        int mc_count)
+static void b43legacy_configure_filter(struct ieee80211_hw *hw,
+                                      unsigned int changed,
+                                      unsigned int *fflags,
+                                      int mc_count,
+                                      struct dev_addr_list *mc_list)
 {
        struct b43legacy_wl *wl = hw_to_b43legacy_wl(hw);
        struct b43legacy_wldev *dev = wl->current_dev;
        unsigned long flags;
 
-       if (!dev)
+       if (!dev) {
+               *fflags = 0;
                return;
-       spin_lock_irqsave(&wl->irq_lock, flags);
-       if (wl->promisc != !!(netflags & IFF_PROMISC)) {
-               wl->promisc = !!(netflags & IFF_PROMISC);
-               if (b43legacy_status(dev) >= B43legacy_STAT_INITIALIZED)
-                       b43legacy_adjust_opmode(dev);
        }
+
+       spin_lock_irqsave(&wl->irq_lock, flags);
+       *fflags &= FIF_PROMISC_IN_BSS |
+                 FIF_ALLMULTI |
+                 FIF_FCSFAIL |
+                 FIF_PLCPFAIL |
+                 FIF_CONTROL |
+                 FIF_OTHER_BSS |
+                 FIF_BCN_PRBRESP_PROMISC;
+
+       changed &= FIF_PROMISC_IN_BSS |
+                  FIF_ALLMULTI |
+                  FIF_FCSFAIL |
+                  FIF_PLCPFAIL |
+                  FIF_CONTROL |
+                  FIF_OTHER_BSS |
+                  FIF_BCN_PRBRESP_PROMISC;
+
+       wl->filter_flags = *fflags;
+
+       if (changed && b43legacy_status(dev) >= B43legacy_STAT_INITIALIZED)
+               b43legacy_adjust_opmode(dev);
        spin_unlock_irqrestore(&wl->irq_lock, flags);
 }
 
                return -ENODEV;
        mutex_lock(&wl->mutex);
        spin_lock_irqsave(&wl->irq_lock, flags);
-       if (conf->type != IEEE80211_IF_TYPE_MNTR) {
-               B43legacy_WARN_ON(wl->if_id != if_id);
-               wl->bssid = conf->bssid;
-               if (b43legacy_status(dev) >= B43legacy_STAT_INITIALIZED) {
-                       if (b43legacy_is_mode(wl, IEEE80211_IF_TYPE_AP)) {
-                               B43legacy_WARN_ON(conf->type !=
-                                                 IEEE80211_IF_TYPE_AP);
-                               b43legacy_set_ssid(dev, conf->ssid,
-                                                  conf->ssid_len);
-                               if (conf->beacon)
-                                       b43legacy_refresh_templates(dev,
-                                                                conf->beacon);
-                       }
-                       b43legacy_write_mac_bssid_templates(dev);
+       B43legacy_WARN_ON(wl->if_id != if_id);
+       if (conf->bssid)
+               memcpy(wl->bssid, conf->bssid, ETH_ALEN);
+       else
+               memset(wl->bssid, 0, ETH_ALEN);
+       if (b43legacy_status(dev) >= B43legacy_STAT_INITIALIZED) {
+               if (b43legacy_is_mode(wl, IEEE80211_IF_TYPE_AP)) {
+                       B43legacy_WARN_ON(conf->type != IEEE80211_IF_TYPE_AP);
+                       b43legacy_set_ssid(dev, conf->ssid, conf->ssid_len);
+                       if (conf->beacon)
+                               b43legacy_refresh_templates(dev, conf->beacon);
                }
+               b43legacy_write_mac_bssid_templates(dev);
        }
        spin_unlock_irqrestore(&wl->irq_lock, flags);
        mutex_unlock(&wl->mutex);
        b43legacy_shm_write16(dev, B43legacy_SHM_SHARED, 0x0414, 0x01F4);
 
        ssb_bus_powerup(bus, 1); /* Enable dynamic PCTL */
-       wl->bssid = NULL;
-       b43legacy_upload_card_macaddress(dev, NULL);
+       memset(wl->bssid, 0, ETH_ALEN);
+       memset(wl->mac_addr, 0, ETH_ALEN);
+       b43legacy_upload_card_macaddress(dev);
        b43legacy_security_init(dev);
        b43legacy_rng_init(wl);
 
        struct b43legacy_wldev *dev;
        unsigned long flags;
        int err = -EOPNOTSUPP;
-       int did_init = 0;
+
+       /* TODO: allow WDS/AP devices to coexist */
+
+       if (conf->type != IEEE80211_IF_TYPE_AP &&
+           conf->type != IEEE80211_IF_TYPE_STA &&
+           conf->type != IEEE80211_IF_TYPE_WDS &&
+           conf->type != IEEE80211_IF_TYPE_IBSS)
+               return -EOPNOTSUPP;
 
        mutex_lock(&wl->mutex);
-       if ((conf->type != IEEE80211_IF_TYPE_MNTR) &&
-           wl->operating)
+       if (wl->operating)
                goto out_mutex_unlock;
 
        b43legacydbg(wl, "Adding Interface type %d\n", conf->type);
 
        dev = wl->current_dev;
+       wl->operating = 1;
+       wl->if_id = conf->if_id;
+       wl->if_type = conf->type;
+       memcpy(wl->mac_addr, conf->mac_addr, ETH_ALEN);
+
+       spin_lock_irqsave(&wl->irq_lock, flags);
+       b43legacy_adjust_opmode(dev);
+       b43legacy_upload_card_macaddress(dev);
+       spin_unlock_irqrestore(&wl->irq_lock, flags);
+
+       err = 0;
+ out_mutex_unlock:
+       mutex_unlock(&wl->mutex);
+
+       return err;
+}
+
+static void b43legacy_remove_interface(struct ieee80211_hw *hw,
+                                      struct ieee80211_if_init_conf *conf)
+{
+       struct b43legacy_wl *wl = hw_to_b43legacy_wl(hw);
+       struct b43legacy_wldev *dev = wl->current_dev;
+       unsigned long flags;
+
+       b43legacydbg(wl, "Removing Interface type %d\n", conf->type);
+
+       mutex_lock(&wl->mutex);
+
+       B43legacy_WARN_ON(!wl->operating);
+       B43legacy_WARN_ON(wl->if_id != conf->if_id);
+
+       wl->operating = 0;
+
+       spin_lock_irqsave(&wl->irq_lock, flags);
+       b43legacy_adjust_opmode(dev);
+       memset(wl->mac_addr, 0, ETH_ALEN);
+       b43legacy_upload_card_macaddress(dev);
+       spin_unlock_irqrestore(&wl->irq_lock, flags);
+
+       mutex_unlock(&wl->mutex);
+}
+
+static int b43legacy_start(struct ieee80211_hw *hw)
+{
+       struct b43legacy_wl *wl = hw_to_b43legacy_wl(hw);
+       struct b43legacy_wldev *dev = wl->current_dev;
+       int did_init = 0;
+       int err;
+
+       mutex_lock(&wl->mutex);
+
        if (b43legacy_status(dev) < B43legacy_STAT_INITIALIZED) {
                err = b43legacy_wireless_core_init(dev);
                if (err)
                        goto out_mutex_unlock;
                did_init = 1;
        }
+
        if (b43legacy_status(dev) < B43legacy_STAT_STARTED) {
                err = b43legacy_wireless_core_start(dev);
                if (err) {
                }
        }
 
-       spin_lock_irqsave(&wl->irq_lock, flags);
-       switch (conf->type) {
-       case IEEE80211_IF_TYPE_MNTR:
-               wl->monitor++;
-               break;
-       default:
-               wl->operating = 1;
-               wl->if_id = conf->if_id;
-               wl->if_type = conf->type;
-               b43legacy_upload_card_macaddress(dev, conf->mac_addr);
-       }
-       b43legacy_adjust_opmode(dev);
-       spin_unlock_irqrestore(&wl->irq_lock, flags);
-
-       err = 0;
 out_mutex_unlock:
        mutex_unlock(&wl->mutex);
 
        return err;
 }
 
-static void b43legacy_remove_interface(struct ieee80211_hw *hw,
-                                      struct ieee80211_if_init_conf *conf)
+void b43legacy_stop(struct ieee80211_hw *hw)
 {
        struct b43legacy_wl *wl = hw_to_b43legacy_wl(hw);
-       struct b43legacy_wldev *dev;
-       unsigned long flags;
-
-       b43legacydbg(wl, "Removing Interface type %d\n", conf->type);
+       struct b43legacy_wldev *dev = wl->current_dev;
 
        mutex_lock(&wl->mutex);
-       if (conf->type == IEEE80211_IF_TYPE_MNTR) {
-               wl->monitor--;
-               B43legacy_WARN_ON(wl->monitor < 0);
-       } else {
-               B43legacy_WARN_ON(!wl->operating);
-               wl->operating = 0;
-       }
-
-       dev = wl->current_dev;
-       if (!wl->operating && wl->monitor == 0) {
-               /* No interface left. */
-               if (b43legacy_status(dev) >= B43legacy_STAT_STARTED)
-                       b43legacy_wireless_core_stop(dev);
-               b43legacy_wireless_core_exit(dev);
-       } else {
-               /* Just monitor interfaces left. */
-               spin_lock_irqsave(&wl->irq_lock, flags);
-               b43legacy_adjust_opmode(dev);
-               if (!wl->operating)
-                       b43legacy_upload_card_macaddress(dev, NULL);
-               spin_unlock_irqrestore(&wl->irq_lock, flags);
-       }
+       if (b43legacy_status(dev) >= B43legacy_STAT_STARTED)
+               b43legacy_wireless_core_stop(dev);
+       b43legacy_wireless_core_exit(dev);
        mutex_unlock(&wl->mutex);
 }
 
        .config = b43legacy_dev_config,
        .config_interface = b43legacy_config_interface,
        .set_key = b43legacy_dev_set_key,
-       .set_multicast_list = b43legacy_set_multicast_list,
+       .configure_filter = b43legacy_configure_filter,
        .get_stats = b43legacy_get_stats,
        .get_tx_stats = b43legacy_get_tx_stats,
+       .start = b43legacy_start,
+       .stop = b43legacy_stop,
 };
 
 /* Hard-reset the chip. Do not call this directly.
 
  *
  *****************************************************************************/
 
-static int iwl_mac_open(struct ieee80211_hw *hw)
+static int iwl_mac_start(struct ieee80211_hw *hw)
 {
        struct iwl_priv *priv = hw->priv;
 
        return 0;
 }
 
-static int iwl_mac_stop(struct ieee80211_hw *hw)
+static void iwl_mac_stop(struct ieee80211_hw *hw)
 {
        struct iwl_priv *priv = hw->priv;
 
        /*netif_stop_queue(dev); */
        flush_workqueue(priv->workqueue);
        IWL_DEBUG_MAC80211("leave\n");
-
-       return 0;
 }
 
 static int iwl_mac_tx(struct ieee80211_hw *hw, struct sk_buff *skb,
        if (conf == NULL)
                return -EIO;
 
+       /* XXX: this MUST use conf->mac_addr */
+
        if ((priv->iw_mode == IEEE80211_IF_TYPE_AP) &&
            (!conf->beacon || !conf->ssid_len)) {
                IWL_DEBUG_MAC80211
                IWL_DEBUG_MAC80211("bssid: %s\n",
                                   print_mac(mac, conf->bssid));
 
+/*
+ * very dubious code was here; the probe filtering flag is never set:
+ *
        if (unlikely(test_bit(STATUS_SCANNING, &priv->status)) &&
            !(priv->hw->flags & IEEE80211_HW_NO_PROBE_FILTERING)) {
+ */
+       if (unlikely(test_bit(STATUS_SCANNING, &priv->status))) {
                IWL_DEBUG_MAC80211("leave - scanning\n");
                mutex_unlock(&priv->mutex);
                return 0;
        return 0;
 }
 
+static void iwl_configure_filter(struct ieee80211_hw *hw,
+                                unsigned int changed_flags,
+                                unsigned int *total_flags,
+                                int mc_count, struct dev_addr_list *mc_list)
+{
+       /*
+        * XXX: dummy
+        * see also iwl_connection_init_rx_config
+        */
+       *total_flags = 0;
+}
+
 static void iwl_mac_remove_interface(struct ieee80211_hw *hw,
                                     struct ieee80211_if_init_conf *conf)
 {
 
 static struct ieee80211_ops iwl_hw_ops = {
        .tx = iwl_mac_tx,
-       .open = iwl_mac_open,
+       .start = iwl_mac_start,
        .stop = iwl_mac_stop,
        .add_interface = iwl_mac_add_interface,
        .remove_interface = iwl_mac_remove_interface,
        .config = iwl_mac_config,
        .config_interface = iwl_mac_config_interface,
+       .configure_filter = iwl_configure_filter,
        .set_key = iwl_mac_set_key,
        .get_stats = iwl_mac_get_stats,
        .get_tx_stats = iwl_mac_get_tx_stats,
 
  *
  *****************************************************************************/
 
-static int iwl_mac_open(struct ieee80211_hw *hw)
+static int iwl_mac_start(struct ieee80211_hw *hw)
 {
        struct iwl_priv *priv = hw->priv;
 
        return 0;
 }
 
-static int iwl_mac_stop(struct ieee80211_hw *hw)
+static void iwl_mac_stop(struct ieee80211_hw *hw)
 {
        struct iwl_priv *priv = hw->priv;
 
        /*netif_stop_queue(dev); */
        flush_workqueue(priv->workqueue);
        IWL_DEBUG_MAC80211("leave\n");
-
-       return 0;
 }
 
 static int iwl_mac_tx(struct ieee80211_hw *hw, struct sk_buff *skb,
                IWL_DEBUG_MAC80211("bssid: %s\n",
                                   print_mac(mac, conf->bssid));
 
+/*
+ * very dubious code was here; the probe filtering flag is never set:
+ *
        if (unlikely(test_bit(STATUS_SCANNING, &priv->status)) &&
            !(priv->hw->flags & IEEE80211_HW_NO_PROBE_FILTERING)) {
+ */
+       if (unlikely(test_bit(STATUS_SCANNING, &priv->status))) {
                IWL_DEBUG_MAC80211("leave - scanning\n");
                mutex_unlock(&priv->mutex);
                return 0;
        return 0;
 }
 
+static void iwl_configure_filter(struct ieee80211_hw *hw,
+                                unsigned int changed_flags,
+                                unsigned int *total_flags,
+                                int mc_count, struct dev_addr_list *mc_list)
+{
+       /*
+        * XXX: dummy
+        * see also iwl_connection_init_rx_config
+        */
+       *total_flags = 0;
+}
+
 static void iwl_mac_remove_interface(struct ieee80211_hw *hw,
                                     struct ieee80211_if_init_conf *conf)
 {
 
 static struct ieee80211_ops iwl_hw_ops = {
        .tx = iwl_mac_tx,
-       .open = iwl_mac_open,
+       .start = iwl_mac_start,
        .stop = iwl_mac_stop,
        .add_interface = iwl_mac_add_interface,
        .remove_interface = iwl_mac_remove_interface,
        .config = iwl_mac_config,
        .config_interface = iwl_mac_config_interface,
+       .configure_filter = iwl_configure_filter,
        .set_key = iwl_mac_set_key,
        .get_stats = iwl_mac_get_stats,
        .get_tx_stats = iwl_mac_get_tx_stats,
 
        int (*open)(struct ieee80211_hw *dev);
        void (*stop)(struct ieee80211_hw *dev);
        int mode;
-       u8 *mac_addr;
+       u8 mac_addr[ETH_ALEN];
+       u8 bssid[ETH_ALEN];
        struct pda_iq_autocal_entry *iq_autocal;
        unsigned int iq_autocal_len;
        struct pda_channel_output_limit *output_limit;
 
        priv->tx(dev, hdr, sizeof(*hdr) + sizeof(*vdcf), 0);
 }
 
+static int p54_start(struct ieee80211_hw *dev)
+{
+       struct p54_common *priv = dev->priv;
+       int err;
+
+       err = priv->open(dev);
+       if (!err)
+               priv->mode = IEEE80211_IF_TYPE_MNTR;
+
+       return err;
+}
+
+static void p54_stop(struct ieee80211_hw *dev)
+{
+       struct p54_common *priv = dev->priv;
+       struct sk_buff *skb;
+       while ((skb = skb_dequeue(&priv->tx_queue))) {
+               struct memrecord *range = (struct memrecord *)&skb->cb;
+               if (range->control)
+                       kfree(range->control);
+               kfree_skb(skb);
+       }
+       priv->stop(dev);
+       priv->mode = IEEE80211_IF_TYPE_MGMT;
+}
+
 static int p54_add_interface(struct ieee80211_hw *dev,
                             struct ieee80211_if_init_conf *conf)
 {
        struct p54_common *priv = dev->priv;
-       int err;
 
-       /* NOTE: using IEEE80211_IF_TYPE_MGMT to indicate no mode selected */
-       if (priv->mode != IEEE80211_IF_TYPE_MGMT)
-               return -1;
+       if (priv->mode != IEEE80211_IF_TYPE_MNTR)
+               return -EOPNOTSUPP;
 
        switch (conf->type) {
        case IEEE80211_IF_TYPE_STA:
                return -EOPNOTSUPP;
        }
 
-       priv->mac_addr = conf->mac_addr;
-
-       err = priv->open(dev);
-       if (err) {
-               priv->mode = IEEE80211_IF_TYPE_MGMT;
-               skb_queue_purge(&priv->tx_queue);
-               return err;
-       }
+       memcpy(priv->mac_addr, conf->mac_addr, ETH_ALEN);
 
        p54_set_filter(dev, 0, priv->mac_addr, NULL, 0, 1, 0, 0xF642);
        p54_set_filter(dev, 0, priv->mac_addr, NULL, 1, 0, 0, 0xF642);
-       p54_set_vdcf(dev);
 
        switch (conf->type) {
        case IEEE80211_IF_TYPE_STA:
                p54_set_filter(dev, 1, priv->mac_addr, NULL, 0, 0x15F, 0x1F4, 0);
                break;
+       default:
+               BUG();  /* impossible */
+               break;
        }
 
        p54_set_leds(dev, 1, 0, 0);
                                 struct ieee80211_if_init_conf *conf)
 {
        struct p54_common *priv = dev->priv;
-       struct sk_buff *skb;
-       while ((skb = skb_dequeue(&priv->tx_queue))) {
-               struct memrecord *range = (struct memrecord *)&skb->cb;
-               if (range->control)
-                       kfree(range->control);
-               kfree_skb(skb);
-       }
-       priv->mode = IEEE80211_IF_TYPE_MGMT;
-       priv->stop(dev);
+       priv->mode = IEEE80211_IF_TYPE_MNTR;
+       memset(priv->mac_addr, 0, ETH_ALEN);
+       p54_set_filter(dev, 0, priv->mac_addr, NULL, 2, 0, 0, 0);
 }
 
 static int p54_config(struct ieee80211_hw *dev, struct ieee80211_conf *conf)
        p54_set_filter(dev, 0, priv->mac_addr, conf->bssid, 0, 1, 0, 0xF642);
        p54_set_filter(dev, 0, priv->mac_addr, conf->bssid, 2, 0, 0, 0);
        p54_set_leds(dev, 1, !is_multicast_ether_addr(conf->bssid), 0);
+       memcpy(priv->bssid, conf->bssid, ETH_ALEN);
        return 0;
 }
 
+static void p54_configure_filter(struct ieee80211_hw *dev,
+                                unsigned int changed_flags,
+                                unsigned int *total_flags,
+                                int mc_count, struct dev_mc_list *mclist)
+{
+       struct p54_common *priv = dev->priv;
+
+       *total_flags &= FIF_BCN_PRBRESP_PROMISC;
+
+       if (changed_flags & FIF_BCN_PRBRESP_PROMISC) {
+               if (*total_flags & FIF_BCN_PRBRESP_PROMISC)
+                       p54_set_filter(dev, 0, priv->mac_addr,
+                                      NULL, 2, 0, 0, 0);
+               else
+                       p54_set_filter(dev, 0, priv->mac_addr,
+                                      priv->bssid, 2, 0, 0, 0);
+       }
+}
+
 static int p54_conf_tx(struct ieee80211_hw *dev, int queue,
                       const struct ieee80211_tx_queue_params *params)
 {
 
 static const struct ieee80211_ops p54_ops = {
        .tx                     = p54_tx,
+       .start                  = p54_start,
+       .stop                   = p54_stop,
        .add_interface          = p54_add_interface,
        .remove_interface       = p54_remove_interface,
        .config                 = p54_config,
        .config_interface       = p54_config_interface,
+       .configure_filter       = p54_configure_filter,
        .conf_tx                = p54_conf_tx,
        .get_stats              = p54_get_stats,
        .get_tx_stats           = p54_get_tx_stats
 
        rt2x00pci_register_multiwrite(rt2x00dev, CSR5, ®, sizeof(reg));
 }
 
-static void rt2400pci_config_packet_filter(struct rt2x00_dev *rt2x00dev,
-                                          const unsigned int filter)
-{
-       int promisc = !!(filter & IFF_PROMISC);
-       u32 reg;
-
-       rt2x00pci_register_read(rt2x00dev, RXCSR0, ®);
-       rt2x00_set_field32(®, RXCSR0_DROP_NOT_TO_ME, !promisc);
-       rt2x00pci_register_write(rt2x00dev, RXCSR0, reg);
-}
-
 static void rt2400pci_config_type(struct rt2x00_dev *rt2x00dev, int type)
 {
+       struct interface *intf = &rt2x00dev->interface;
        u32 reg;
 
        rt2x00pci_register_write(rt2x00dev, CSR14, 0);
 
-       /*
-        * Apply hardware packet filter.
-        */
-       rt2x00pci_register_read(rt2x00dev, RXCSR0, ®);
-
-       if (!is_monitor_present(&rt2x00dev->interface) &&
-           (type == IEEE80211_IF_TYPE_IBSS || type == IEEE80211_IF_TYPE_STA))
-               rt2x00_set_field32(®, RXCSR0_DROP_TODS, 1);
-       else
-               rt2x00_set_field32(®, RXCSR0_DROP_TODS, 0);
-
-       /*
-        * If there is a non-monitor interface present
-        * the packet should be strict (even if a monitor interface is present!).
-        * When there is only 1 interface present which is in monitor mode
-        * we should start accepting _all_ frames.
-        */
-       if (is_interface_present(&rt2x00dev->interface)) {
-               rt2x00_set_field32(®, RXCSR0_DROP_CRC, 1);
-               rt2x00_set_field32(®, RXCSR0_DROP_PHYSICAL, 1);
-               rt2x00_set_field32(®, RXCSR0_DROP_CONTROL, 1);
-               rt2x00_set_field32(®, RXCSR0_DROP_VERSION_ERROR, 1);
-       } else if (is_monitor_present(&rt2x00dev->interface)) {
-               rt2x00_set_field32(®, RXCSR0_DROP_CRC, 0);
-               rt2x00_set_field32(®, RXCSR0_DROP_PHYSICAL, 0);
-               rt2x00_set_field32(®, RXCSR0_DROP_CONTROL, 0);
-               rt2x00_set_field32(®, RXCSR0_DROP_VERSION_ERROR, 0);
-       }
-
-       rt2x00pci_register_write(rt2x00dev, RXCSR0, reg);
-
        /*
         * Enable beacon config
         */
         * Enable synchronisation.
         */
        rt2x00pci_register_read(rt2x00dev, CSR14, ®);
-       if (is_interface_present(&rt2x00dev->interface)) {
-               rt2x00_set_field32(®, CSR14_TSF_COUNT, 1);
-               rt2x00_set_field32(®, CSR14_TBCN, 1);
-       }
-
+       rt2x00_set_field32(®, CSR14_TSF_COUNT, 1);
+       rt2x00_set_field32(®, CSR14_TBCN, 1);
        rt2x00_set_field32(®, CSR14_BEACON_GEN, 0);
-       if (type == IEEE80211_IF_TYPE_IBSS || type == IEEE80211_IF_TYPE_AP)
+       if (is_interface_type(intf, IEEE80211_IF_TYPE_IBSS) ||
+           is_interface_type(intf, IEEE80211_IF_TYPE_AP))
                rt2x00_set_field32(®, CSR14_TSF_SYNC, 2);
-       else if (type == IEEE80211_IF_TYPE_STA)
+       else if (is_interface_type(intf, IEEE80211_IF_TYPE_STA))
                rt2x00_set_field32(®, CSR14_TSF_SYNC, 1);
-       else if (is_monitor_present(&rt2x00dev->interface) &&
-                !is_interface_present(&rt2x00dev->interface))
+       else
                rt2x00_set_field32(®, CSR14_TSF_SYNC, 0);
-
        rt2x00pci_register_write(rt2x00dev, CSR14, reg);
 }
 
  */
 static void rt2400pci_write_tx_desc(struct rt2x00_dev *rt2x00dev,
                                    struct data_desc *txd,
-                                   struct data_entry_desc *desc,
+                                   struct txdata_entry_desc *desc,
                                    struct ieee80211_hdr *ieee80211hdr,
                                    unsigned int length,
                                    struct ieee80211_tx_control *control)
 /*
  * RX control handlers
  */
-static int rt2400pci_fill_rxdone(struct data_entry *entry,
-                                int *signal, int *rssi, int *ofdm, int *size)
+static void rt2400pci_fill_rxdone(struct data_entry *entry,
+                                 struct rxdata_entry_desc *desc)
 {
        struct data_desc *rxd = entry->priv;
        u32 word0;
        rt2x00_desc_read(rxd, 0, &word0);
        rt2x00_desc_read(rxd, 2, &word2);
 
-       if (rt2x00_get_field32(word0, RXD_W0_CRC_ERROR) ||
-           rt2x00_get_field32(word0, RXD_W0_PHYSICAL_ERROR))
-               return -EINVAL;
+       desc->flags = 0;
+       if (rt2x00_get_field32(word0, RXD_W0_CRC_ERROR))
+               desc->flags |= RX_FLAG_FAILED_FCS_CRC;
+       if (rt2x00_get_field32(word0, RXD_W0_PHYSICAL_ERROR))
+               desc->flags |= RX_FLAG_FAILED_PLCP_CRC;
 
        /*
         * Obtain the status about this packet.
         */
-       *signal = rt2x00_get_field32(word2, RXD_W2_SIGNAL);
-       *rssi = rt2x00_get_field32(word2, RXD_W2_RSSI) -
+       desc->signal = rt2x00_get_field32(word2, RXD_W2_SIGNAL);
+       desc->rssi = rt2x00_get_field32(word2, RXD_W2_RSSI) -
            entry->ring->rt2x00dev->rssi_offset;
-       *ofdm = 0;
-       *size = rt2x00_get_field32(word0, RXD_W0_DATABYTE_COUNT);
-
-       return 0;
+       desc->ofdm = 0;
+       desc->size = rt2x00_get_field32(word0, RXD_W0_DATABYTE_COUNT);
 }
 
 /*
        /*
         * Initialize all hw fields.
         */
-       rt2x00dev->hw->flags =
-           IEEE80211_HW_HOST_BROADCAST_PS_BUFFERING |
-           IEEE80211_HW_MONITOR_DURING_OPER |
-           IEEE80211_HW_NO_PROBE_FILTERING;
+       rt2x00dev->hw->flags = IEEE80211_HW_HOST_BROADCAST_PS_BUFFERING;
        rt2x00dev->hw->extra_tx_headroom = 0;
        rt2x00dev->hw->max_signal = MAX_SIGNAL;
        rt2x00dev->hw->max_rssi = MAX_RX_SSI;
 /*
  * IEEE80211 stack callback functions.
  */
+static void rt2400pci_configure_filter(struct ieee80211_hw *hw,
+                                      unsigned int changed_flags,
+                                      unsigned int *total_flags,
+                                      int mc_count,
+                                      struct dev_addr_list *mc_list)
+{
+       struct rt2x00_dev *rt2x00dev = hw->priv;
+       struct interface *intf = &rt2x00dev->interface;
+       u32 reg;
+
+       /*
+        * Mask off any flags we are going to ignore from
+        * the total_flags field.
+        */
+       *total_flags &=
+           FIF_ALLMULTI |
+           FIF_FCSFAIL |
+           FIF_PLCPFAIL |
+           FIF_CONTROL |
+           FIF_OTHER_BSS |
+           FIF_PROMISC_IN_BSS;
+
+       /*
+        * Apply some rules to the filters:
+        * - Some filters imply different filters to be set.
+        * - Some things we can't filter out at all.
+        * - Some filters are set based on interface type.
+        */
+       *total_flags |= FIF_ALLMULTI;
+       if (changed_flags & FIF_OTHER_BSS ||
+           changed_flags & FIF_PROMISC_IN_BSS)
+               *total_flags |= FIF_PROMISC_IN_BSS | FIF_OTHER_BSS;
+       if (is_interface_type(intf, IEEE80211_IF_TYPE_AP))
+               *total_flags |= FIF_PROMISC_IN_BSS;
+
+       /*
+        * Check if there is any work left for us.
+        */
+       if (intf->filter == *total_flags)
+               return;
+       intf->filter = *total_flags;
+
+       /*
+        * Start configuration steps.
+        * Note that the version error will always be dropped
+        * since there is no filter for it at this time.
+        */
+       rt2x00pci_register_read(rt2x00dev, RXCSR0, ®);
+       rt2x00_set_field32(®, RXCSR0_DROP_CRC,
+                          !(*total_flags & FIF_FCSFAIL));
+       rt2x00_set_field32(®, RXCSR0_DROP_PHYSICAL,
+                          !(*total_flags & FIF_PLCPFAIL));
+       rt2x00_set_field32(®, RXCSR0_DROP_CONTROL,
+                          !(*total_flags & FIF_CONTROL));
+       rt2x00_set_field32(®, RXCSR0_DROP_NOT_TO_ME,
+                          !(*total_flags & FIF_PROMISC_IN_BSS));
+       rt2x00_set_field32(®, RXCSR0_DROP_TODS,
+                          !(*total_flags & FIF_PROMISC_IN_BSS));
+       rt2x00_set_field32(®, RXCSR0_DROP_VERSION_ERROR, 1);
+       rt2x00pci_register_write(rt2x00dev, RXCSR0, reg);
+}
+
 static int rt2400pci_set_retry_limit(struct ieee80211_hw *hw,
                                     u32 short_retry, u32 long_retry)
 {
 
 static const struct ieee80211_ops rt2400pci_mac80211_ops = {
        .tx                     = rt2x00mac_tx,
+       .start                  = rt2x00mac_start,
+       .stop                   = rt2x00mac_stop,
        .add_interface          = rt2x00mac_add_interface,
        .remove_interface       = rt2x00mac_remove_interface,
        .config                 = rt2x00mac_config,
        .config_interface       = rt2x00mac_config_interface,
-       .set_multicast_list     = rt2x00mac_set_multicast_list,
+       .configure_filter       = rt2400pci_configure_filter,
        .get_stats              = rt2x00mac_get_stats,
        .set_retry_limit        = rt2400pci_set_retry_limit,
        .conf_tx                = rt2400pci_conf_tx,
        .fill_rxdone            = rt2400pci_fill_rxdone,
        .config_mac_addr        = rt2400pci_config_mac_addr,
        .config_bssid           = rt2400pci_config_bssid,
-       .config_packet_filter   = rt2400pci_config_packet_filter,
        .config_type            = rt2400pci_config_type,
        .config                 = rt2400pci_config,
 };
 
        rt2x00pci_register_multiwrite(rt2x00dev, CSR5, ®, sizeof(reg));
 }
 
-static void rt2500pci_config_packet_filter(struct rt2x00_dev *rt2x00dev,
-                                          const unsigned int filter)
-{
-       int promisc = !!(filter & IFF_PROMISC);
-       int multicast = !!(filter & IFF_MULTICAST);
-       int broadcast = !!(filter & IFF_BROADCAST);
-       u32 reg;
-
-       rt2x00pci_register_read(rt2x00dev, RXCSR0, ®);
-       rt2x00_set_field32(®, RXCSR0_DROP_NOT_TO_ME, !promisc);
-       rt2x00_set_field32(®, RXCSR0_DROP_MCAST, !multicast);
-       rt2x00_set_field32(®, RXCSR0_DROP_BCAST, !broadcast);
-       rt2x00pci_register_write(rt2x00dev, RXCSR0, reg);
-}
-
 static void rt2500pci_config_type(struct rt2x00_dev *rt2x00dev, const int type)
 {
+       struct interface *intf = &rt2x00dev->interface;
        u32 reg;
 
        rt2x00pci_register_write(rt2x00dev, CSR14, 0);
 
-       /*
-        * Apply hardware packet filter.
-        */
-       rt2x00pci_register_read(rt2x00dev, RXCSR0, ®);
-
-       if (!is_monitor_present(&rt2x00dev->interface) &&
-           (type == IEEE80211_IF_TYPE_IBSS || type == IEEE80211_IF_TYPE_STA))
-               rt2x00_set_field32(®, RXCSR0_DROP_TODS, 1);
-       else
-               rt2x00_set_field32(®, RXCSR0_DROP_TODS, 0);
-
-       /*
-        * If there is a non-monitor interface present
-        * the packet should be strict (even if a monitor interface is present!).
-        * When there is only 1 interface present which is in monitor mode
-        * we should start accepting _all_ frames.
-        */
-       if (is_interface_present(&rt2x00dev->interface)) {
-               rt2x00_set_field32(®, RXCSR0_DROP_CRC, 1);
-               rt2x00_set_field32(®, RXCSR0_DROP_PHYSICAL, 1);
-               rt2x00_set_field32(®, RXCSR0_DROP_CONTROL, 1);
-               rt2x00_set_field32(®, RXCSR0_DROP_VERSION_ERROR, 1);
-       } else if (is_monitor_present(&rt2x00dev->interface)) {
-               rt2x00_set_field32(®, RXCSR0_DROP_CRC, 0);
-               rt2x00_set_field32(®, RXCSR0_DROP_PHYSICAL, 0);
-               rt2x00_set_field32(®, RXCSR0_DROP_CONTROL, 0);
-               rt2x00_set_field32(®, RXCSR0_DROP_VERSION_ERROR, 0);
-       }
-
-       rt2x00pci_register_write(rt2x00dev, RXCSR0, reg);
-
        /*
         * Enable beacon config
         */
         * Enable synchronisation.
         */
        rt2x00pci_register_read(rt2x00dev, CSR14, ®);
-       if (is_interface_present(&rt2x00dev->interface)) {
-               rt2x00_set_field32(®, CSR14_TSF_COUNT, 1);
-               rt2x00_set_field32(®, CSR14_TBCN, 1);
-       }
-
+       rt2x00_set_field32(®, CSR14_TSF_COUNT, 1);
+       rt2x00_set_field32(®, CSR14_TBCN, 1);
        rt2x00_set_field32(®, CSR14_BEACON_GEN, 0);
-       if (type == IEEE80211_IF_TYPE_IBSS || type == IEEE80211_IF_TYPE_AP)
+       if (is_interface_type(intf, IEEE80211_IF_TYPE_IBSS) ||
+           is_interface_type(intf, IEEE80211_IF_TYPE_AP))
                rt2x00_set_field32(®, CSR14_TSF_SYNC, 2);
-       else if (type == IEEE80211_IF_TYPE_STA)
+       else if (is_interface_type(intf, IEEE80211_IF_TYPE_STA))
                rt2x00_set_field32(®, CSR14_TSF_SYNC, 1);
-       else if (is_monitor_present(&rt2x00dev->interface) &&
-                !is_interface_present(&rt2x00dev->interface))
+       else
                rt2x00_set_field32(®, CSR14_TSF_SYNC, 0);
-
        rt2x00pci_register_write(rt2x00dev, CSR14, reg);
 }
 
  */
 static void rt2500pci_write_tx_desc(struct rt2x00_dev *rt2x00dev,
                                    struct data_desc *txd,
-                                   struct data_entry_desc *desc,
+                                   struct txdata_entry_desc *desc,
                                    struct ieee80211_hdr *ieee80211hdr,
                                    unsigned int length,
                                    struct ieee80211_tx_control *control)
 /*
  * RX control handlers
  */
-static int rt2500pci_fill_rxdone(struct data_entry *entry,
-                                int *signal, int *rssi, int *ofdm, int *size)
+static void rt2500pci_fill_rxdone(struct data_entry *entry,
+                                 struct rxdata_entry_desc *desc)
 {
        struct data_desc *rxd = entry->priv;
        u32 word0;
        rt2x00_desc_read(rxd, 0, &word0);
        rt2x00_desc_read(rxd, 2, &word2);
 
-       if (rt2x00_get_field32(word0, RXD_W0_CRC_ERROR) ||
-           rt2x00_get_field32(word0, RXD_W0_PHYSICAL_ERROR) ||
-           rt2x00_get_field32(word0, RXD_W0_ICV_ERROR))
-               return -EINVAL;
+       desc->flags = 0;
+       if (rt2x00_get_field32(word0, RXD_W0_CRC_ERROR))
+               desc->flags |= RX_FLAG_FAILED_FCS_CRC;
+       if (rt2x00_get_field32(word0, RXD_W0_PHYSICAL_ERROR))
+               desc->flags |= RX_FLAG_FAILED_PLCP_CRC;
 
-       *signal = rt2x00_get_field32(word2, RXD_W2_SIGNAL);
-       *rssi = rt2x00_get_field32(word2, RXD_W2_RSSI) -
+       desc->signal = rt2x00_get_field32(word2, RXD_W2_SIGNAL);
+       desc->rssi = rt2x00_get_field32(word2, RXD_W2_RSSI) -
            entry->ring->rt2x00dev->rssi_offset;
-       *ofdm = rt2x00_get_field32(word0, RXD_W0_OFDM);
-       *size = rt2x00_get_field32(word0, RXD_W0_DATABYTE_COUNT);
-
-       return 0;
+       desc->ofdm = rt2x00_get_field32(word0, RXD_W0_OFDM);
+       desc->size = rt2x00_get_field32(word0, RXD_W0_DATABYTE_COUNT);
 }
 
 /*
        /*
         * Initialize all hw fields.
         */
-       rt2x00dev->hw->flags =
-           IEEE80211_HW_HOST_BROADCAST_PS_BUFFERING |
-           IEEE80211_HW_MONITOR_DURING_OPER |
-           IEEE80211_HW_NO_PROBE_FILTERING;
+       rt2x00dev->hw->flags = IEEE80211_HW_HOST_BROADCAST_PS_BUFFERING;
        rt2x00dev->hw->extra_tx_headroom = 0;
        rt2x00dev->hw->max_signal = MAX_SIGNAL;
        rt2x00dev->hw->max_rssi = MAX_RX_SSI;
 /*
  * IEEE80211 stack callback functions.
  */
+static void rt2500pci_configure_filter(struct ieee80211_hw *hw,
+                                      unsigned int changed_flags,
+                                      unsigned int *total_flags,
+                                      int mc_count,
+                                      struct dev_addr_list *mc_list)
+{
+       struct rt2x00_dev *rt2x00dev = hw->priv;
+       struct interface *intf = &rt2x00dev->interface;
+       u32 reg;
+
+       /*
+        * Mask off any flags we are going to ignore from
+        * the total_flags field.
+        */
+       *total_flags &=
+           FIF_ALLMULTI |
+           FIF_FCSFAIL |
+           FIF_PLCPFAIL |
+           FIF_CONTROL |
+           FIF_OTHER_BSS |
+           FIF_PROMISC_IN_BSS;
+
+       /*
+        * Apply some rules to the filters:
+        * - Some filters imply different filters to be set.
+        * - Some things we can't filter out at all.
+        * - Some filters are set based on interface type.
+        */
+       if (mc_count)
+               *total_flags |= FIF_ALLMULTI;
+       if (changed_flags & FIF_OTHER_BSS ||
+           changed_flags & FIF_PROMISC_IN_BSS)
+               *total_flags |= FIF_PROMISC_IN_BSS | FIF_OTHER_BSS;
+       if (is_interface_type(intf, IEEE80211_IF_TYPE_AP))
+               *total_flags |= FIF_PROMISC_IN_BSS;
+
+       /*
+        * Check if there is any work left for us.
+        */
+       if (intf->filter == *total_flags)
+               return;
+       intf->filter = *total_flags;
+
+       /*
+        * Start configuration steps.
+        * Note that the version error will always be dropped
+        * and broadcast frames will always be accepted since
+        * there is no filter for it at this time.
+        */
+       rt2x00pci_register_read(rt2x00dev, RXCSR0, ®);
+       rt2x00_set_field32(®, RXCSR0_DROP_CRC,
+                          !(*total_flags & FIF_FCSFAIL));
+       rt2x00_set_field32(®, RXCSR0_DROP_PHYSICAL,
+                          !(*total_flags & FIF_PLCPFAIL));
+       rt2x00_set_field32(®, RXCSR0_DROP_CONTROL,
+                          !(*total_flags & FIF_CONTROL));
+       rt2x00_set_field32(®, RXCSR0_DROP_NOT_TO_ME,
+                          !(*total_flags & FIF_PROMISC_IN_BSS));
+       rt2x00_set_field32(®, RXCSR0_DROP_TODS,
+                          !(*total_flags & FIF_PROMISC_IN_BSS));
+       rt2x00_set_field32(®, RXCSR0_DROP_VERSION_ERROR, 1);
+       rt2x00_set_field32(®, RXCSR0_DROP_MCAST,
+                          !(*total_flags & FIF_ALLMULTI));
+       rt2x00_set_field32(®, RXCSR0_DROP_BCAST, 0);
+       rt2x00pci_register_write(rt2x00dev, RXCSR0, reg);
+}
+
 static int rt2500pci_set_retry_limit(struct ieee80211_hw *hw,
                                     u32 short_retry, u32 long_retry)
 {
 
 static const struct ieee80211_ops rt2500pci_mac80211_ops = {
        .tx                     = rt2x00mac_tx,
+       .start                  = rt2x00mac_start,
+       .stop                   = rt2x00mac_stop,
        .add_interface          = rt2x00mac_add_interface,
        .remove_interface       = rt2x00mac_remove_interface,
        .config                 = rt2x00mac_config,
        .config_interface       = rt2x00mac_config_interface,
-       .set_multicast_list     = rt2x00mac_set_multicast_list,
+       .configure_filter       = rt2500pci_configure_filter,
        .get_stats              = rt2x00mac_get_stats,
        .set_retry_limit        = rt2500pci_set_retry_limit,
        .conf_tx                = rt2x00mac_conf_tx,
        .fill_rxdone            = rt2500pci_fill_rxdone,
        .config_mac_addr        = rt2500pci_config_mac_addr,
        .config_bssid           = rt2500pci_config_bssid,
-       .config_packet_filter   = rt2500pci_config_packet_filter,
        .config_type            = rt2500pci_config_type,
        .config                 = rt2500pci_config,
 };
 
        rt2500usb_register_multiwrite(rt2x00dev, MAC_CSR5, ®, sizeof(reg));
 }
 
-static void rt2500usb_config_packet_filter(struct rt2x00_dev *rt2x00dev,
-                                          const unsigned int filter)
-{
-       int promisc = !!(filter & IFF_PROMISC);
-       int multicast = !!(filter & IFF_MULTICAST);
-       int broadcast = !!(filter & IFF_BROADCAST);
-       u16 reg;
-
-       rt2500usb_register_read(rt2x00dev, TXRX_CSR2, ®);
-       rt2x00_set_field16(®, TXRX_CSR2_DROP_NOT_TO_ME, !promisc);
-       rt2x00_set_field16(®, TXRX_CSR2_DROP_MULTICAST, !multicast);
-       rt2x00_set_field16(®, TXRX_CSR2_DROP_BROADCAST, !broadcast);
-       rt2500usb_register_write(rt2x00dev, TXRX_CSR2, reg);
-}
-
 static void rt2500usb_config_type(struct rt2x00_dev *rt2x00dev, const int type)
 {
+       struct interface *intf = &rt2x00dev->interface;
        u16 reg;
 
        rt2500usb_register_write(rt2x00dev, TXRX_CSR19, 0);
 
-       /*
-        * Apply hardware packet filter.
-        */
-       rt2500usb_register_read(rt2x00dev, TXRX_CSR2, ®);
-
-       if (!is_monitor_present(&rt2x00dev->interface) &&
-           (type == IEEE80211_IF_TYPE_IBSS || type == IEEE80211_IF_TYPE_STA))
-               rt2x00_set_field16(®, TXRX_CSR2_DROP_TODS, 1);
-       else
-               rt2x00_set_field16(®, TXRX_CSR2_DROP_TODS, 0);
-
-       /*
-        * If there is a non-monitor interface present
-        * the packet should be strict (even if a monitor interface is present!).
-        * When there is only 1 interface present which is in monitor mode
-        * we should start accepting _all_ frames.
-        */
-       if (is_interface_present(&rt2x00dev->interface)) {
-               rt2x00_set_field16(®, TXRX_CSR2_DROP_CRC, 1);
-               rt2x00_set_field16(®, TXRX_CSR2_DROP_PHYSICAL, 1);
-               rt2x00_set_field16(®, TXRX_CSR2_DROP_CONTROL, 1);
-               rt2x00_set_field16(®, TXRX_CSR2_DROP_VERSION_ERROR, 1);
-       } else if (is_monitor_present(&rt2x00dev->interface)) {
-               rt2x00_set_field16(®, TXRX_CSR2_DROP_CRC, 0);
-               rt2x00_set_field16(®, TXRX_CSR2_DROP_PHYSICAL, 0);
-               rt2x00_set_field16(®, TXRX_CSR2_DROP_CONTROL, 0);
-               rt2x00_set_field16(®, TXRX_CSR2_DROP_VERSION_ERROR, 0);
-       }
-
-       rt2500usb_register_write(rt2x00dev, TXRX_CSR2, reg);
-
        /*
         * Enable beacon config
         */
        rt2500usb_register_read(rt2x00dev, TXRX_CSR20, ®);
        rt2x00_set_field16(®, TXRX_CSR20_OFFSET,
                           (PREAMBLE + get_duration(IEEE80211_HEADER, 2)) >> 6);
-       if (type == IEEE80211_IF_TYPE_STA)
+       if (is_interface_type(intf, IEEE80211_IF_TYPE_STA))
                rt2x00_set_field16(®, TXRX_CSR20_BCN_EXPECT_WINDOW, 0);
        else
                rt2x00_set_field16(®, TXRX_CSR20_BCN_EXPECT_WINDOW, 2);
        rt2500usb_register_write(rt2x00dev, TXRX_CSR18, reg);
 
        rt2500usb_register_read(rt2x00dev, TXRX_CSR19, ®);
-       if (is_interface_present(&rt2x00dev->interface)) {
-               rt2x00_set_field16(®, TXRX_CSR19_TSF_COUNT, 1);
-               rt2x00_set_field16(®, TXRX_CSR19_TBCN, 1);
-       }
-
+       rt2x00_set_field16(®, TXRX_CSR19_TSF_COUNT, 1);
+       rt2x00_set_field16(®, TXRX_CSR19_TBCN, 1);
        rt2x00_set_field16(®, TXRX_CSR19_BEACON_GEN, 0);
-       if (type == IEEE80211_IF_TYPE_IBSS || type == IEEE80211_IF_TYPE_AP)
+       if (is_interface_type(intf, IEEE80211_IF_TYPE_IBSS) ||
+           is_interface_type(intf, IEEE80211_IF_TYPE_AP))
                rt2x00_set_field16(®, TXRX_CSR19_TSF_SYNC, 2);
-       else if (type == IEEE80211_IF_TYPE_STA)
+       else if (is_interface_type(intf, IEEE80211_IF_TYPE_STA))
                rt2x00_set_field16(®, TXRX_CSR19_TSF_SYNC, 1);
-       else if (is_monitor_present(&rt2x00dev->interface) &&
-                !is_interface_present(&rt2x00dev->interface))
+       else
                rt2x00_set_field16(®, TXRX_CSR19_TSF_SYNC, 0);
-
        rt2500usb_register_write(rt2x00dev, TXRX_CSR19, reg);
 }
 
  */
 static void rt2500usb_write_tx_desc(struct rt2x00_dev *rt2x00dev,
                                    struct data_desc *txd,
-                                   struct data_entry_desc *desc,
+                                   struct txdata_entry_desc *desc,
                                    struct ieee80211_hdr *ieee80211hdr,
                                    unsigned int length,
                                    struct ieee80211_tx_control *control)
 /*
  * RX control handlers
  */
-static int rt2500usb_fill_rxdone(struct data_entry *entry,
-                                int *signal, int *rssi, int *ofdm, int *size)
+static void rt2500usb_fill_rxdone(struct data_entry *entry,
+                                 struct rxdata_entry_desc *desc)
 {
        struct urb *urb = entry->priv;
        struct data_desc *rxd = (struct data_desc *)(entry->skb->data +
        rt2x00_desc_read(rxd, 0, &word0);
        rt2x00_desc_read(rxd, 1, &word1);
 
-       if (rt2x00_get_field32(word0, RXD_W0_CRC_ERROR) ||
-           rt2x00_get_field32(word0, RXD_W0_PHYSICAL_ERROR) ||
-           rt2x00_get_field32(word0, RXD_W0_CIPHER_ERROR))
-               return -EINVAL;
+       desc->flags = 0;
+       if (rt2x00_get_field32(word0, RXD_W0_CRC_ERROR))
+               desc->flags |= RX_FLAG_FAILED_FCS_CRC;
+       if (rt2x00_get_field32(word0, RXD_W0_PHYSICAL_ERROR))
+               desc->flags |= RX_FLAG_FAILED_PLCP_CRC;
 
        /*
         * Obtain the status about this packet.
         */
-       *signal = rt2x00_get_field32(word1, RXD_W1_SIGNAL);
-       *rssi = rt2x00_get_field32(word1, RXD_W1_RSSI) -
+       desc->signal = rt2x00_get_field32(word1, RXD_W1_SIGNAL);
+       desc->rssi = rt2x00_get_field32(word1, RXD_W1_RSSI) -
            entry->ring->rt2x00dev->rssi_offset;
-       *ofdm = rt2x00_get_field32(word0, RXD_W0_OFDM);
-       *size = rt2x00_get_field32(word0, RXD_W0_DATABYTE_COUNT);
+       desc->ofdm = rt2x00_get_field32(word0, RXD_W0_OFDM);
+       desc->size = rt2x00_get_field32(word0, RXD_W0_DATABYTE_COUNT);
 
-       return 0;
+       return;
 }
 
 /*
        rt2x00dev->hw->flags =
            IEEE80211_HW_HOST_GEN_BEACON_TEMPLATE |
            IEEE80211_HW_RX_INCLUDES_FCS |
-           IEEE80211_HW_HOST_BROADCAST_PS_BUFFERING |
-           IEEE80211_HW_MONITOR_DURING_OPER |
-           IEEE80211_HW_NO_PROBE_FILTERING;
+           IEEE80211_HW_HOST_BROADCAST_PS_BUFFERING;
        rt2x00dev->hw->extra_tx_headroom = TXD_DESC_SIZE;
        rt2x00dev->hw->max_signal = MAX_SIGNAL;
        rt2x00dev->hw->max_rssi = MAX_RX_SSI;
        rt2500usb_probe_hw_mode(rt2x00dev);
 
        /*
-        * USB devices require scheduled packet filter toggling
-        *This device requires the beacon ring
+        * This device requires the beacon ring
         */
-       __set_bit(PACKET_FILTER_SCHEDULED, &rt2x00dev->flags);
        __set_bit(REQUIRE_BEACON_RING, &rt2x00dev->flags);
 
        /*
 /*
  * IEEE80211 stack callback functions.
  */
+static void rt2500usb_configure_filter(struct ieee80211_hw *hw,
+                                      unsigned int changed_flags,
+                                      unsigned int *total_flags,
+                                      int mc_count,
+                                      struct dev_addr_list *mc_list)
+{
+       struct rt2x00_dev *rt2x00dev = hw->priv;
+       struct interface *intf = &rt2x00dev->interface;
+       u16 reg;
+
+       /*
+        * Mask off any flags we are going to ignore from
+        * the total_flags field.
+        */
+       *total_flags &=
+           FIF_ALLMULTI |
+           FIF_FCSFAIL |
+           FIF_PLCPFAIL |
+           FIF_CONTROL |
+           FIF_OTHER_BSS |
+           FIF_PROMISC_IN_BSS;
+
+       /*
+        * Apply some rules to the filters:
+        * - Some filters imply different filters to be set.
+        * - Some things we can't filter out at all.
+        * - Some filters are set based on interface type.
+        */
+       if (mc_count)
+               *total_flags |= FIF_ALLMULTI;
+       if (changed_flags & FIF_OTHER_BSS ||
+           changed_flags & FIF_PROMISC_IN_BSS)
+               *total_flags |= FIF_PROMISC_IN_BSS | FIF_OTHER_BSS;
+       if (is_interface_type(intf, IEEE80211_IF_TYPE_AP))
+               *total_flags |= FIF_PROMISC_IN_BSS;
+
+       /*
+        * Check if there is any work left for us.
+        */
+       if (intf->filter == *total_flags)
+               return;
+       intf->filter = *total_flags;
+
+       /*
+        * When in atomic context, reschedule and let rt2x00lib
+        * call this function again.
+        */
+       if (in_atomic()) {
+               queue_work(rt2x00dev->hw->workqueue, &rt2x00dev->filter_work);
+               return;
+       }
+
+       /*
+        * Start configuration steps.
+        * Note that the version error will always be dropped
+        * and broadcast frames will always be accepted since
+        * there is no filter for it at this time.
+        */
+       rt2500usb_register_read(rt2x00dev, TXRX_CSR2, ®);
+       rt2x00_set_field16(®, TXRX_CSR2_DROP_CRC,
+                          !(*total_flags & FIF_FCSFAIL));
+       rt2x00_set_field16(®, TXRX_CSR2_DROP_PHYSICAL,
+                          !(*total_flags & FIF_PLCPFAIL));
+       rt2x00_set_field16(®, TXRX_CSR2_DROP_CONTROL,
+                          !(*total_flags & FIF_CONTROL));
+       rt2x00_set_field16(®, TXRX_CSR2_DROP_NOT_TO_ME,
+                          !(*total_flags & FIF_PROMISC_IN_BSS));
+       rt2x00_set_field16(®, TXRX_CSR2_DROP_TODS,
+                          !(*total_flags & FIF_PROMISC_IN_BSS));
+       rt2x00_set_field16(®, TXRX_CSR2_DROP_VERSION_ERROR, 1);
+       rt2x00_set_field16(®, TXRX_CSR2_DROP_MULTICAST,
+                          !(*total_flags & FIF_ALLMULTI));
+       rt2x00_set_field16(®, TXRX_CSR2_DROP_BROADCAST, 0);
+       rt2500usb_register_write(rt2x00dev, TXRX_CSR2, reg);
+}
+
 static int rt2500usb_beacon_update(struct ieee80211_hw *hw,
                                   struct sk_buff *skb,
                                   struct ieee80211_tx_control *control)
 
 static const struct ieee80211_ops rt2500usb_mac80211_ops = {
        .tx                     = rt2x00mac_tx,
+       .start                  = rt2x00mac_start,
+       .stop                   = rt2x00mac_stop,
        .add_interface          = rt2x00mac_add_interface,
        .remove_interface       = rt2x00mac_remove_interface,
        .config                 = rt2x00mac_config,
        .config_interface       = rt2x00mac_config_interface,
-       .set_multicast_list     = rt2x00mac_set_multicast_list,
+       .configure_filter       = rt2500usb_configure_filter,
        .get_stats              = rt2x00mac_get_stats,
        .conf_tx                = rt2x00mac_conf_tx,
        .get_tx_stats           = rt2x00mac_get_tx_stats,
        .fill_rxdone            = rt2500usb_fill_rxdone,
        .config_mac_addr        = rt2500usb_config_mac_addr,
        .config_bssid           = rt2500usb_config_bssid,
-       .config_packet_filter   = rt2500usb_config_packet_filter,
        .config_type            = rt2500usb_config_type,
        .config                 = rt2500usb_config,
 };
 
 
        /*
         * Current working type (IEEE80211_IF_TYPE_*).
-        * This excludes the type IEEE80211_IF_TYPE_MNTR
-        * since that is counted seperately in the monitor_count
-        * field.
         * When set to INVALID_INTERFACE, no interface is configured.
         */
        int type;
 
        /*
         * Store the packet filter mode for the current interface.
-        * monitor mode always disabled filtering. But in such
-        * cases we still need to store the value here in case
-        * the monitor mode interfaces are removed, while a
-        * non-monitor mode interface remains.
         */
-       unsigned short filter;
-
-       /*
-        * Monitor mode count, the number of interfaces
-        * in monitor mode that that have been added.
-        */
-       unsigned short monitor_count;
+       unsigned int filter;
 };
 
 static inline int is_interface_present(struct interface *intf)
        return !!intf->id;
 }
 
-static inline int is_monitor_present(struct interface *intf)
+static inline int is_interface_type(struct interface *intf, int type)
 {
-       return !!intf->monitor_count;
+       return intf->type == type;
 }
 
 /*
         */
        void (*write_tx_desc) (struct rt2x00_dev *rt2x00dev,
                               struct data_desc *txd,
-                              struct data_entry_desc *desc,
+                              struct txdata_entry_desc *desc,
                               struct ieee80211_hdr *ieee80211hdr,
                               unsigned int length,
                               struct ieee80211_tx_control *control);
        /*
         * RX control handlers
         */
-       int (*fill_rxdone) (struct data_entry *entry,
-                           int *signal, int *rssi, int *ofdm, int *size);
+       void (*fill_rxdone) (struct data_entry *entry,
+                            struct rxdata_entry_desc *desc);
 
        /*
         * Configuration handlers.
 #define DEVICE_INITIALIZED             3
 #define DEVICE_INITIALIZED_HW          4
 #define REQUIRE_FIRMWARE               5
-#define PACKET_FILTER_SCHEDULED                6
-#define PACKET_FILTER_PENDING          7
+/* Hole: Add new Flag here */
 #define INTERFACE_RESUME               8
 #define INTERFACE_ENABLED              9
-#define INTERFACE_ENABLED_MONITOR      10
+/* Hole: Add new Flag here */
 #define REQUIRE_BEACON_RING            11
 #define DEVICE_SUPPORT_HW_BUTTON       12
 #define CONFIG_FRAME_TYPE              13
        struct ieee80211_rx_status rx_status;
 
        /*
-        * Beacon scheduled work.
+        * Scheduled work.
         */
        struct work_struct beacon_work;
+       struct work_struct filter_work;
 
        /*
         * Data ring arrays for RX, TX and Beacon.
 void rt2x00lib_txdone(struct data_entry *entry,
                      const int status, const int retry);
 void rt2x00lib_rxdone(struct data_entry *entry, struct sk_buff *skb,
-                     const int signal, const int rssi, const int ofdm);
+                     struct rxdata_entry_desc *desc);
 
 /*
  * TX descriptor initializer
 int rt2x00mac_config(struct ieee80211_hw *hw, struct ieee80211_conf *conf);
 int rt2x00mac_config_interface(struct ieee80211_hw *hw, int if_id,
                               struct ieee80211_if_conf *conf);
-void rt2x00mac_set_multicast_list(struct ieee80211_hw *hw,
-                                 unsigned short flags, int mc_count);
 int rt2x00mac_get_stats(struct ieee80211_hw *hw,
                        struct ieee80211_low_level_stats *stats);
 int rt2x00mac_get_tx_stats(struct ieee80211_hw *hw,
 
                rt2x00dev->ops->lib->config_bssid(rt2x00dev, bssid);
 }
 
-void rt2x00lib_config_packet_filter(struct rt2x00_dev *rt2x00dev, int filter)
-{
-       /*
-        * Only configure the device when something has changed,
-        * or if we are in RESUME state in which case all configuration
-        * will be forced upon the device.
-        */
-       if (!test_bit(INTERFACE_RESUME, &rt2x00dev->flags) &&
-           !test_bit(PACKET_FILTER_PENDING, &rt2x00dev->flags))
-               return;
-
-       /*
-        * Write configuration to device and clear the update flag.
-        */
-       rt2x00dev->ops->lib->config_packet_filter(rt2x00dev, filter);
-       __clear_bit(PACKET_FILTER_PENDING, &rt2x00dev->flags);
-}
-
 void rt2x00lib_config_type(struct rt2x00_dev *rt2x00dev, int type)
 {
        struct interface *intf = &rt2x00dev->interface;
 
-       /*
-        * Fallback when a invalid interface is attempted to
-        * be configured. If a monitor interface is present,
-        * we are going configure that, otherwise exit.
-        */
-       if (type == INVALID_INTERFACE) {
-               if (is_monitor_present(intf))
-                       type = IEEE80211_IF_TYPE_MNTR;
-               else
-                       return;
-       }
-
-       /*
-        * Only configure the device when something has changed,
-        * or if we are in RESUME state in which case all configuration
-        * will be forced upon the device.
-        */
        if (!test_bit(INTERFACE_RESUME, &rt2x00dev->flags) &&
-           (!(is_interface_present(intf) ^
-              test_bit(INTERFACE_ENABLED, &rt2x00dev->flags)) &&
-            !(is_monitor_present(intf) ^
-              test_bit(INTERFACE_ENABLED_MONITOR, &rt2x00dev->flags))))
+           (!!test_bit(INTERFACE_ENABLED, &rt2x00dev->flags) ==
+            !!is_interface_present(intf)))
                return;
 
-       /*
-        * Configure device.
-        */
        rt2x00dev->ops->lib->config_type(rt2x00dev, type);
 
        /*
         * Update the configuration flags.
         */
-       if (type != IEEE80211_IF_TYPE_MNTR) {
-               if (is_interface_present(intf))
-                       __set_bit(INTERFACE_ENABLED, &rt2x00dev->flags);
-               else
-                       __clear_bit(INTERFACE_ENABLED, &rt2x00dev->flags);
-       } else {
-               if (is_monitor_present(intf))
-                       __set_bit(INTERFACE_ENABLED_MONITOR, &rt2x00dev->flags);
-               else
-                       __clear_bit(INTERFACE_ENABLED_MONITOR,
-                                   &rt2x00dev->flags);
-       }
+       if (is_interface_present(intf))
+               __set_bit(INTERFACE_ENABLED, &rt2x00dev->flags);
+       else
+               __clear_bit(INTERFACE_ENABLED, &rt2x00dev->flags);
 }
 
 void rt2x00lib_config(struct rt2x00_dev *rt2x00dev, struct ieee80211_conf *conf)
 
                return;
 
        /*
-        * Stop beacon generation.
+        * Stop all scheduled work.
         */
        if (work_pending(&rt2x00dev->beacon_work))
                cancel_work_sync(&rt2x00dev->beacon_work);
+       if (work_pending(&rt2x00dev->filter_work))
+               cancel_work_sync(&rt2x00dev->filter_work);
 
        /*
         * Stop the TX queues.
                           LINK_TUNE_INTERVAL);
 }
 
+static void rt2x00lib_packetfilter_scheduled(struct work_struct *work)
+{
+       struct rt2x00_dev *rt2x00dev =
+           container_of(work, struct rt2x00_dev, filter_work);
+
+       rt2x00dev->ops->hw->configure_filter(rt2x00dev->hw,
+                                            rt2x00dev->interface.filter,
+                                            &rt2x00dev->interface.filter,
+                                            0, NULL);
+}
+
 /*
  * Interrupt context handlers.
  */
 EXPORT_SYMBOL_GPL(rt2x00lib_txdone);
 
 void rt2x00lib_rxdone(struct data_entry *entry, struct sk_buff *skb,
-                     const int signal, const int rssi, const int ofdm)
+                     struct rxdata_entry_desc *desc)
 {
        struct rt2x00_dev *rt2x00dev = entry->ring->rt2x00dev;
        struct ieee80211_rx_status *rx_status = &rt2x00dev->rx_status;
                 * the signal is the PLCP value. If it was received with
                 * a CCK bitrate the signal is the rate in 0.5kbit/s.
                 */
-               if (!ofdm)
+               if (!desc->ofdm)
                        val = DEVICE_GET_RATE_FIELD(rate->val, RATE);
                else
                        val = DEVICE_GET_RATE_FIELD(rate->val, PLCP);
 
-               if (val == signal) {
+               if (val == desc->signal) {
                        val = rate->val;
                        break;
                }
        }
 
-       rt2x00_update_link_rssi(&rt2x00dev->link, rssi);
+       rt2x00_update_link_rssi(&rt2x00dev->link, desc->rssi);
        rt2x00dev->link.rx_success++;
        rx_status->rate = val;
-       rx_status->signal = rt2x00lib_calculate_link_signal(rt2x00dev, rssi);
-       rx_status->ssi = rssi;
+       rx_status->signal =
+           rt2x00lib_calculate_link_signal(rt2x00dev, desc->rssi);
+       rx_status->ssi = desc->rssi;
+       rx_status->flag = desc->flags;
 
        /*
         * Send frame to mac80211
                             unsigned int length,
                             struct ieee80211_tx_control *control)
 {
-       struct data_entry_desc desc;
+       struct txdata_entry_desc desc;
        struct data_ring *ring;
        int tx_rate;
        int bitrate;
         * Initialize configuration work.
         */
        INIT_WORK(&rt2x00dev->beacon_work, rt2x00lib_beacondone_scheduled);
+       INIT_WORK(&rt2x00dev->filter_work, rt2x00lib_packetfilter_scheduled);
        INIT_DELAYED_WORK(&rt2x00dev->link.work, rt2x00lib_link_tuner);
 
        /*
        rt2x00lib_config_mac_addr(rt2x00dev, intf->mac);
        rt2x00lib_config_bssid(rt2x00dev, intf->bssid);
        rt2x00lib_config_type(rt2x00dev, intf->type);
-       rt2x00lib_config_packet_filter(rt2x00dev, intf->filter);
 
        /*
         * When in Master or Ad-hoc mode,
 
  */
 void rt2x00lib_config_mac_addr(struct rt2x00_dev *rt2x00dev, u8 *mac);
 void rt2x00lib_config_bssid(struct rt2x00_dev *rt2x00dev, u8 *bssid);
-void rt2x00lib_config_packet_filter(struct rt2x00_dev *rt2x00dev, int filter);
 void rt2x00lib_config_type(struct rt2x00_dev *rt2x00dev, int type);
 void rt2x00lib_config(struct rt2x00_dev *rt2x00dev, struct ieee80211_conf *conf);
 
 
 {
        struct rt2x00_dev *rt2x00dev = hw->priv;
        struct interface *intf = &rt2x00dev->interface;
-       int retval;
 
        /*
         * We only support 1 non-monitor interface.
         */
-       if (conf->type != IEEE80211_IF_TYPE_MNTR && is_interface_present(intf))
+       if (is_interface_present(intf))
                return -ENOBUFS;
 
-       /*
-        * HACK: Placeholder until start/stop handler has been
-        * added to the mac80211 callback functions structure.
-        */
-       retval = rt2x00mac_start(hw);
-       if (retval)
-               return retval;
-
-       /*
-        * We support muliple monitor mode interfaces.
-        * All we need to do is increase the monitor_count.
-        */
-       if (conf->type == IEEE80211_IF_TYPE_MNTR) {
-               intf->monitor_count++;
-       } else {
-               intf->id = conf->if_id;
-               intf->type = conf->type;
-               if (conf->type == IEEE80211_IF_TYPE_AP)
-                       memcpy(&intf->bssid, conf->mac_addr, ETH_ALEN);
-               memcpy(&intf->mac, conf->mac_addr, ETH_ALEN);
-               intf->filter = 0;
-       }
+       intf->id = conf->if_id;
+       intf->type = conf->type;
+       if (conf->type == IEEE80211_IF_TYPE_AP)
+               memcpy(&intf->bssid, conf->mac_addr, ETH_ALEN);
+       memcpy(&intf->mac, conf->mac_addr, ETH_ALEN);
 
        /*
-        * Configure interface.
         * The MAC adddress must be configured after the device
-        * has been initialized. Else the device can reset the
-        * MAC registers.
+        * has been initialized. Otherwise the device can reset
+        * the MAC registers.
         */
        rt2x00lib_config_mac_addr(rt2x00dev, intf->mac);
        rt2x00lib_config_type(rt2x00dev, conf->type);
-       rt2x00lib_config_packet_filter(rt2x00dev, intf->filter);
 
        return 0;
 }
        /*
         * We only support 1 non-monitor interface.
         */
-       if (conf->type != IEEE80211_IF_TYPE_MNTR && !is_interface_present(intf))
+       if (!is_interface_present(intf))
                return;
 
-       /*
-        * When removing an monitor interface, decrease monitor_count.
-        * For non-monitor interfaces, all interface data needs to be reset.
-        */
-       if (conf->type == IEEE80211_IF_TYPE_MNTR) {
-               intf->monitor_count--;
-       } else if (intf->type == conf->type) {
-               intf->id = 0;
-               intf->type = INVALID_INTERFACE;
-               memset(&intf->bssid, 0x00, ETH_ALEN);
-               memset(&intf->mac, 0x00, ETH_ALEN);
-               intf->filter = 0;
-       }
+       intf->id = 0;
+       intf->type = INVALID_INTERFACE;
+       memset(&intf->bssid, 0x00, ETH_ALEN);
+       memset(&intf->mac, 0x00, ETH_ALEN);
 
        /*
         * Make sure the bssid and mac address registers
        rt2x00lib_config_mac_addr(rt2x00dev, intf->mac);
        rt2x00lib_config_bssid(rt2x00dev, intf->bssid);
        rt2x00lib_config_type(rt2x00dev, intf->type);
-
-       /*
-        * HACK: Placeholder untill start/stop handler has been
-        * added to the mac80211 callback functions structure.
-        */
-       rt2x00mac_stop(hw);
 }
 EXPORT_SYMBOL_GPL(rt2x00mac_remove_interface);
 
 
        rt2x00lib_config(rt2x00dev, conf);
 
-       /*
-        * If promisc mode cannot be configured in irq context,
-        * then it is now the time to configure it.
-        */
-       if (test_bit(PACKET_FILTER_SCHEDULED, &rt2x00dev->flags))
-               rt2x00lib_config_packet_filter(rt2x00dev,
-                                              rt2x00dev->interface.filter);
-
        /*
         * Reenable RX only if the radio should be on.
         */
                return 0;
 
        /*
-        * Monitor mode does not need configuring.
         * If the given type does not match the configured type,
         * there has been a problem.
         */
-       if (conf->type == IEEE80211_IF_TYPE_MNTR)
-               return 0;
-       else if (conf->type != intf->type)
+       if (conf->type != intf->type)
                return -EINVAL;
 
        /*
 }
 EXPORT_SYMBOL_GPL(rt2x00mac_config_interface);
 
-void rt2x00mac_set_multicast_list(struct ieee80211_hw *hw,
-                                 unsigned short flags, int mc_count)
-{
-       struct rt2x00_dev *rt2x00dev = hw->priv;
-
-       /*
-        * Check if the new state is different then the old state.
-        */
-       if (rt2x00dev->interface.filter == flags)
-               return;
-
-       rt2x00dev->interface.filter = flags;
-
-       /*
-        * Raise the pending bit to indicate the
-        * packet filter should be updated.
-        */
-       __set_bit(PACKET_FILTER_PENDING, &rt2x00dev->flags);
-
-       /*
-        * Check if Packet filter actions are allowed in
-        * atomic context. If not, raise the pending flag and
-        * let it be.
-        */
-       if (!test_bit(PACKET_FILTER_SCHEDULED, &rt2x00dev->flags) ||
-           !in_atomic())
-               rt2x00lib_config_packet_filter(rt2x00dev, flags);
-}
-EXPORT_SYMBOL_GPL(rt2x00mac_set_multicast_list);
-
 int rt2x00mac_get_stats(struct ieee80211_hw *hw,
                        struct ieee80211_low_level_stats *stats)
 {
 
        struct data_entry *entry;
        struct data_desc *rxd;
        struct sk_buff *skb;
-       u32 desc;
-       int retval;
-       int signal;
-       int rssi;
-       int ofdm;
-       int size;
+       struct rxdata_entry_desc desc;
+       u32 word;
 
        while (1) {
                entry = rt2x00_get_data_entry(ring);
                rxd = entry->priv;
-               rt2x00_desc_read(rxd, 0, &desc);
+               rt2x00_desc_read(rxd, 0, &word);
 
-               if (rt2x00_get_field32(desc, RXD_ENTRY_OWNER_NIC))
+               if (rt2x00_get_field32(word, RXD_ENTRY_OWNER_NIC))
                        break;
 
-               retval = rt2x00dev->ops->lib->fill_rxdone(entry, &signal,
-                                                         &rssi, &ofdm, &size);
-               if (retval)
-                       goto skip_entry;
+               memset(&desc, 0x00, sizeof(desc));
+               rt2x00dev->ops->lib->fill_rxdone(entry, &desc);
 
                /*
                 * Allocate the sk_buffer, initialize it and copy
                 * all data into it.
                 */
-               skb = dev_alloc_skb(size + NET_IP_ALIGN);
+               skb = dev_alloc_skb(desc.size + NET_IP_ALIGN);
                if (!skb)
                        return;
 
                skb_reserve(skb, NET_IP_ALIGN);
-               skb_put(skb, size);
-               memcpy(skb->data, entry->data_addr, size);
+               skb_put(skb, desc.size);
+               memcpy(skb->data, entry->data_addr, desc.size);
 
                /*
                 * Send the frame to rt2x00lib for further processing.
                 */
-               rt2x00lib_rxdone(entry, skb, signal, rssi, ofdm);
+               rt2x00lib_rxdone(entry, skb, &desc);
 
-skip_entry:
                if (test_bit(DEVICE_ENABLED_RADIO, &ring->rt2x00dev->flags)) {
-                       rt2x00_set_field32(&desc, RXD_ENTRY_OWNER_NIC, 1);
-                       rt2x00_desc_write(rxd, 0, desc);
+                       rt2x00_set_field32(&word, RXD_ENTRY_OWNER_NIC, 1);
+                       rt2x00_desc_write(rxd, 0, word);
                }
 
                rt2x00_ring_index_inc(ring);
 
                return 0;
 
        /*
-        * Only continue if we have an active interface,
-        * either monitor or non-monitor should be present.
+        * Only continue if we have an active interface.
         */
-       if (!is_interface_present(&rt2x00dev->interface) &&
-           !is_monitor_present(&rt2x00dev->interface))
+       if (!is_interface_present(&rt2x00dev->interface))
                return 0;
 
        if (state == RFKILL_STATE_ON) {
 
 };
 
 /*
- * data_entry_desc
+ * rxdata_entry_desc
+ * Summary of information that has been read from the
+ * RX frame descriptor.
+ */
+struct rxdata_entry_desc {
+       int signal;
+       int rssi;
+       int ofdm;
+       int size;
+       int flags;
+};
+
+/*
+ * txdata_entry_desc
  * Summary of information that should be written into the
  * descriptor for sending a TX frame.
  */
-struct data_entry_desc {
+struct txdata_entry_desc {
        unsigned long flags;
 #define ENTRY_TXDONE           1
 #define ENTRY_TXD_RTS_FRAME    2
 
        struct data_ring *ring = entry->ring;
        struct rt2x00_dev *rt2x00dev = ring->rt2x00dev;
        struct sk_buff *skb;
-       int retval;
-       int signal;
-       int rssi;
-       int ofdm;
-       int size;
+       struct rxdata_entry_desc desc;
        int frame_size;
 
        if (!test_bit(DEVICE_ENABLED_RADIO, &rt2x00dev->flags) ||
        if (urb->actual_length < entry->ring->desc_size || urb->status)
                goto skip_entry;
 
-       retval = rt2x00dev->ops->lib->fill_rxdone(entry, &signal, &rssi,
-                                                 &ofdm, &size);
-       if (retval)
-               goto skip_entry;
+       memset(&desc, 0x00, sizeof(desc));
+       rt2x00dev->ops->lib->fill_rxdone(entry, &desc);
 
        /*
         * Allocate a new sk buffer to replace the current one.
         * Trim the skb_buffer to only contain the valid
         * frame data (so ignore the device's descriptor).
         */
-       skb_trim(entry->skb, size);
+       skb_trim(entry->skb, desc.size);
 
        /*
         * Send the frame to rt2x00lib for further processing.
         */
-       rt2x00lib_rxdone(entry, entry->skb, signal, rssi, ofdm);
+       rt2x00lib_rxdone(entry, entry->skb, &desc);
 
        /*
         * Replace current entry's skb with the newly allocated one,
 
        rt2x00pci_register_multiwrite(rt2x00dev, MAC_CSR4, ®, sizeof(reg));
 }
 
-static void rt61pci_config_packet_filter(struct rt2x00_dev *rt2x00dev,
-                                        const unsigned int filter)
-{
-       int promisc = !!(filter & IFF_PROMISC);
-       int multicast = !!(filter & IFF_MULTICAST);
-       int broadcast = !!(filter & IFF_BROADCAST);
-       u32 reg;
-
-       rt2x00pci_register_read(rt2x00dev, TXRX_CSR0, ®);
-       rt2x00_set_field32(®, TXRX_CSR0_DROP_NOT_TO_ME, !promisc);
-       rt2x00_set_field32(®, TXRX_CSR0_DROP_MULTICAST, !multicast);
-       rt2x00_set_field32(®, TXRX_CSR0_DROP_BORADCAST, !broadcast);
-       rt2x00pci_register_write(rt2x00dev, TXRX_CSR0, reg);
-}
-
 static void rt61pci_config_type(struct rt2x00_dev *rt2x00dev, const int type)
 {
+       struct interface *intf = &rt2x00dev->interface;
        u32 reg;
 
        /*
        rt2x00pci_register_write(rt2x00dev, HW_BEACON_BASE2, 0);
        rt2x00pci_register_write(rt2x00dev, HW_BEACON_BASE3, 0);
 
-       /*
-        * Apply hardware packet filter.
-        */
-       rt2x00pci_register_read(rt2x00dev, TXRX_CSR0, ®);
-
-       if (!is_monitor_present(&rt2x00dev->interface) &&
-           (type == IEEE80211_IF_TYPE_IBSS || type == IEEE80211_IF_TYPE_STA))
-               rt2x00_set_field32(®, TXRX_CSR0_DROP_TO_DS, 1);
-       else
-               rt2x00_set_field32(®, TXRX_CSR0_DROP_TO_DS, 0);
-
-       /*
-        * If there is a non-monitor interface present
-        * the packet should be strict (even if a monitor interface is present!).
-        * When there is only 1 interface present which is in monitor mode
-        * we should start accepting _all_ frames.
-        */
-       if (is_interface_present(&rt2x00dev->interface)) {
-               rt2x00_set_field32(®, TXRX_CSR0_DROP_CRC, 1);
-               rt2x00_set_field32(®, TXRX_CSR0_DROP_PHYSICAL, 1);
-               rt2x00_set_field32(®, TXRX_CSR0_DROP_CONTROL, 1);
-               rt2x00_set_field32(®, TXRX_CSR0_DROP_VERSION_ERROR, 1);
-               rt2x00_set_field32(®, TXRX_CSR0_DROP_ACK_CTS, 1);
-       } else if (is_monitor_present(&rt2x00dev->interface)) {
-               rt2x00_set_field32(®, TXRX_CSR0_DROP_CRC, 0);
-               rt2x00_set_field32(®, TXRX_CSR0_DROP_PHYSICAL, 0);
-               rt2x00_set_field32(®, TXRX_CSR0_DROP_CONTROL, 0);
-               rt2x00_set_field32(®, TXRX_CSR0_DROP_VERSION_ERROR, 0);
-               rt2x00_set_field32(®, TXRX_CSR0_DROP_ACK_CTS, 0);
-       }
-
-       rt2x00pci_register_write(rt2x00dev, TXRX_CSR0, reg);
-
        /*
         * Enable synchronisation.
         */
        rt2x00pci_register_read(rt2x00dev, TXRX_CSR9, ®);
-       if (is_interface_present(&rt2x00dev->interface)) {
-               rt2x00_set_field32(®, TXRX_CSR9_TSF_TICKING, 1);
-               rt2x00_set_field32(®, TXRX_CSR9_TBTT_ENABLE, 1);
-       }
-
+       rt2x00_set_field32(®, TXRX_CSR9_TSF_TICKING, 1);
+       rt2x00_set_field32(®, TXRX_CSR9_TBTT_ENABLE, 1);
        rt2x00_set_field32(®, TXRX_CSR9_BEACON_GEN, 0);
-       if (type == IEEE80211_IF_TYPE_IBSS || type == IEEE80211_IF_TYPE_AP)
+       if (is_interface_type(intf, IEEE80211_IF_TYPE_IBSS) ||
+           is_interface_type(intf, IEEE80211_IF_TYPE_AP))
                rt2x00_set_field32(®, TXRX_CSR9_TSF_SYNC, 2);
-       else if (type == IEEE80211_IF_TYPE_STA)
+       else if (is_interface_type(intf, IEEE80211_IF_TYPE_STA))
                rt2x00_set_field32(®, TXRX_CSR9_TSF_SYNC, 1);
-       else if (is_monitor_present(&rt2x00dev->interface) &&
-                !is_interface_present(&rt2x00dev->interface))
+       else
                rt2x00_set_field32(®, TXRX_CSR9_TSF_SYNC, 0);
-
        rt2x00pci_register_write(rt2x00dev, TXRX_CSR9, reg);
 }
 
  */
 static void rt61pci_write_tx_desc(struct rt2x00_dev *rt2x00dev,
                                  struct data_desc *txd,
-                                 struct data_entry_desc *desc,
+                                 struct txdata_entry_desc *desc,
                                  struct ieee80211_hdr *ieee80211hdr,
                                  unsigned int length,
                                  struct ieee80211_tx_control *control)
        return rt2x00_get_field32(rxd_w1, RXD_W1_RSSI_AGC) * 2 - offset;
 }
 
-static int rt61pci_fill_rxdone(struct data_entry *entry,
-                              int *signal, int *rssi, int *ofdm, int *size)
+static void rt61pci_fill_rxdone(struct data_entry *entry,
+                               struct rxdata_entry_desc *desc)
 {
        struct data_desc *rxd = entry->priv;
        u32 word0;
        rt2x00_desc_read(rxd, 0, &word0);
        rt2x00_desc_read(rxd, 1, &word1);
 
-       if (rt2x00_get_field32(word0, RXD_W0_CRC_ERROR) ||
-           rt2x00_get_field32(word0, RXD_W0_CIPHER_ERROR))
-               return -EINVAL;
+       desc->flags = 0;
+       if (rt2x00_get_field32(word0, RXD_W0_CRC_ERROR))
+               desc->flags |= RX_FLAG_FAILED_FCS_CRC;
 
        /*
         * Obtain the status about this packet.
         */
-       *signal = rt2x00_get_field32(word1, RXD_W1_SIGNAL);
-       *rssi = rt61pci_agc_to_rssi(entry->ring->rt2x00dev, word1);
-       *ofdm = rt2x00_get_field32(word0, RXD_W0_OFDM);
-       *size = rt2x00_get_field32(word0, RXD_W0_DATABYTE_COUNT);
+       desc->signal = rt2x00_get_field32(word1, RXD_W1_SIGNAL);
+       desc->rssi = rt61pci_agc_to_rssi(entry->ring->rt2x00dev, word1);
+       desc->ofdm = rt2x00_get_field32(word0, RXD_W0_OFDM);
+       desc->size = rt2x00_get_field32(word0, RXD_W0_DATABYTE_COUNT);
 
-       return 0;
+       return;
 }
 
 /*
         */
        rt2x00dev->hw->flags =
            IEEE80211_HW_HOST_GEN_BEACON_TEMPLATE |
-           IEEE80211_HW_HOST_BROADCAST_PS_BUFFERING |
-           IEEE80211_HW_MONITOR_DURING_OPER |
-           IEEE80211_HW_NO_PROBE_FILTERING;
+           IEEE80211_HW_HOST_BROADCAST_PS_BUFFERING;
        rt2x00dev->hw->extra_tx_headroom = 0;
        rt2x00dev->hw->max_signal = MAX_SIGNAL;
        rt2x00dev->hw->max_rssi = MAX_RX_SSI;
 /*
  * IEEE80211 stack callback functions.
  */
+static void rt61pci_configure_filter(struct ieee80211_hw *hw,
+                                    unsigned int changed_flags,
+                                    unsigned int *total_flags,
+                                    int mc_count,
+                                    struct dev_addr_list *mc_list)
+{
+       struct rt2x00_dev *rt2x00dev = hw->priv;
+       struct interface *intf = &rt2x00dev->interface;
+       u32 reg;
+
+       /*
+        * Mask off any flags we are going to ignore from
+        * the total_flags field.
+        */
+       *total_flags &=
+           FIF_ALLMULTI |
+           FIF_FCSFAIL |
+           FIF_PLCPFAIL |
+           FIF_CONTROL |
+           FIF_OTHER_BSS |
+           FIF_PROMISC_IN_BSS;
+
+       /*
+        * Apply some rules to the filters:
+        * - Some filters imply different filters to be set.
+        * - Some things we can't filter out at all.
+        * - Some filters are set based on interface type.
+        */
+       if (mc_count)
+               *total_flags |= FIF_ALLMULTI;
+       if (changed_flags & FIF_OTHER_BSS ||
+           changed_flags & FIF_PROMISC_IN_BSS)
+               *total_flags |= FIF_PROMISC_IN_BSS | FIF_OTHER_BSS;
+       if (is_interface_type(intf, IEEE80211_IF_TYPE_AP))
+               *total_flags |= FIF_PROMISC_IN_BSS;
+
+       /*
+        * Check if there is any work left for us.
+        */
+       if (intf->filter == *total_flags)
+               return;
+       intf->filter = *total_flags;
+
+       /*
+        * Start configuration steps.
+        * Note that the version error will always be dropped
+        * and broadcast frames will always be accepted since
+        * there is no filter for it at this time.
+        */
+       rt2x00pci_register_read(rt2x00dev, TXRX_CSR0, ®);
+       rt2x00_set_field32(®, TXRX_CSR0_DROP_CRC,
+                          !(*total_flags & FIF_FCSFAIL));
+       rt2x00_set_field32(®, TXRX_CSR0_DROP_PHYSICAL,
+                          !(*total_flags & FIF_PLCPFAIL));
+       rt2x00_set_field32(®, TXRX_CSR0_DROP_CONTROL,
+                          !(*total_flags & FIF_CONTROL));
+       rt2x00_set_field32(®, TXRX_CSR0_DROP_NOT_TO_ME,
+                          !(*total_flags & FIF_PROMISC_IN_BSS));
+       rt2x00_set_field32(®, TXRX_CSR0_DROP_TO_DS,
+                          !(*total_flags & FIF_PROMISC_IN_BSS));
+       rt2x00_set_field32(®, TXRX_CSR0_DROP_VERSION_ERROR, 1);
+       rt2x00_set_field32(®, TXRX_CSR0_DROP_MULTICAST,
+                          !(*total_flags & FIF_ALLMULTI));
+       rt2x00_set_field32(®, TXRX_CSR0_DROP_BORADCAST, 0);
+       rt2x00_set_field32(®, TXRX_CSR0_DROP_ACK_CTS, 1);
+       rt2x00pci_register_write(rt2x00dev, TXRX_CSR0, reg);
+}
+
 static int rt61pci_set_retry_limit(struct ieee80211_hw *hw,
                                   u32 short_retry, u32 long_retry)
 {
 
 static const struct ieee80211_ops rt61pci_mac80211_ops = {
        .tx                     = rt2x00mac_tx,
+       .start                  = rt2x00mac_start,
+       .stop                   = rt2x00mac_stop,
        .add_interface          = rt2x00mac_add_interface,
        .remove_interface       = rt2x00mac_remove_interface,
        .config                 = rt2x00mac_config,
        .config_interface       = rt2x00mac_config_interface,
-       .set_multicast_list     = rt2x00mac_set_multicast_list,
+       .configure_filter       = rt61pci_configure_filter,
        .get_stats              = rt2x00mac_get_stats,
        .set_retry_limit        = rt61pci_set_retry_limit,
        .conf_tx                = rt2x00mac_conf_tx,
        .fill_rxdone            = rt61pci_fill_rxdone,
        .config_mac_addr        = rt61pci_config_mac_addr,
        .config_bssid           = rt61pci_config_bssid,
-       .config_packet_filter   = rt61pci_config_packet_filter,
        .config_type            = rt61pci_config_type,
        .config                 = rt61pci_config,
 };
 
        rt73usb_register_multiwrite(rt2x00dev, MAC_CSR4, ®, sizeof(reg));
 }
 
-static void rt73usb_config_packet_filter(struct rt2x00_dev *rt2x00dev,
-                                        const unsigned int filter)
-{
-       int promisc = !!(filter & IFF_PROMISC);
-       int multicast = !!(filter & IFF_MULTICAST);
-       int broadcast = !!(filter & IFF_BROADCAST);
-       u32 reg;
-
-       rt73usb_register_read(rt2x00dev, TXRX_CSR0, ®);
-       rt2x00_set_field32(®, TXRX_CSR0_DROP_NOT_TO_ME, !promisc);
-       rt2x00_set_field32(®, TXRX_CSR0_DROP_MULTICAST, !multicast);
-       rt2x00_set_field32(®, TXRX_CSR0_DROP_BORADCAST, !broadcast);
-       rt73usb_register_write(rt2x00dev, TXRX_CSR0, reg);
-}
-
 static void rt73usb_config_type(struct rt2x00_dev *rt2x00dev, const int type)
 {
+       struct interface *intf = &rt2x00dev->interface;
        u32 reg;
 
        /*
        rt73usb_register_write(rt2x00dev, HW_BEACON_BASE2, 0);
        rt73usb_register_write(rt2x00dev, HW_BEACON_BASE3, 0);
 
-       /*
-        * Apply hardware packet filter.
-        */
-       rt73usb_register_read(rt2x00dev, TXRX_CSR0, ®);
-
-       if (!is_monitor_present(&rt2x00dev->interface) &&
-           (type == IEEE80211_IF_TYPE_IBSS || type == IEEE80211_IF_TYPE_STA))
-               rt2x00_set_field32(®, TXRX_CSR0_DROP_TO_DS, 1);
-       else
-               rt2x00_set_field32(®, TXRX_CSR0_DROP_TO_DS, 0);
-
-       /*
-        * If there is a non-monitor interface present
-        * the packet should be strict (even if a monitor interface is present!).
-        * When there is only 1 interface present which is in monitor mode
-        * we should start accepting _all_ frames.
-        */
-       if (is_interface_present(&rt2x00dev->interface)) {
-               rt2x00_set_field32(®, TXRX_CSR0_DROP_CRC, 1);
-               rt2x00_set_field32(®, TXRX_CSR0_DROP_PHYSICAL, 1);
-               rt2x00_set_field32(®, TXRX_CSR0_DROP_CONTROL, 1);
-               rt2x00_set_field32(®, TXRX_CSR0_DROP_VERSION_ERROR, 1);
-               rt2x00_set_field32(®, TXRX_CSR0_DROP_ACK_CTS, 1);
-       } else if (is_monitor_present(&rt2x00dev->interface)) {
-               rt2x00_set_field32(®, TXRX_CSR0_DROP_CRC, 0);
-               rt2x00_set_field32(®, TXRX_CSR0_DROP_PHYSICAL, 0);
-               rt2x00_set_field32(®, TXRX_CSR0_DROP_CONTROL, 0);
-               rt2x00_set_field32(®, TXRX_CSR0_DROP_VERSION_ERROR, 0);
-               rt2x00_set_field32(®, TXRX_CSR0_DROP_ACK_CTS, 0);
-       }
-
-       rt73usb_register_write(rt2x00dev, TXRX_CSR0, reg);
-
        /*
         * Enable synchronisation.
         */
        rt73usb_register_read(rt2x00dev, TXRX_CSR9, ®);
-       if (is_interface_present(&rt2x00dev->interface)) {
-               rt2x00_set_field32(®, TXRX_CSR9_TSF_TICKING, 1);
-               rt2x00_set_field32(®, TXRX_CSR9_TBTT_ENABLE, 1);
-       }
-
+       rt2x00_set_field32(®, TXRX_CSR9_TSF_TICKING, 1);
+       rt2x00_set_field32(®, TXRX_CSR9_TBTT_ENABLE, 1);
        rt2x00_set_field32(®, TXRX_CSR9_BEACON_GEN, 0);
-       if (type == IEEE80211_IF_TYPE_IBSS || type == IEEE80211_IF_TYPE_AP)
+       if (is_interface_type(intf, IEEE80211_IF_TYPE_IBSS) ||
+           is_interface_type(intf, IEEE80211_IF_TYPE_AP))
                rt2x00_set_field32(®, TXRX_CSR9_TSF_SYNC, 2);
-       else if (type == IEEE80211_IF_TYPE_STA)
+       else if (is_interface_type(intf, IEEE80211_IF_TYPE_STA))
                rt2x00_set_field32(®, TXRX_CSR9_TSF_SYNC, 1);
-       else if (is_monitor_present(&rt2x00dev->interface) &&
-                !is_interface_present(&rt2x00dev->interface))
+       else
                rt2x00_set_field32(®, TXRX_CSR9_TSF_SYNC, 0);
-
        rt73usb_register_write(rt2x00dev, TXRX_CSR9, reg);
 }
 
  */
 static void rt73usb_write_tx_desc(struct rt2x00_dev *rt2x00dev,
                                  struct data_desc *txd,
-                                 struct data_entry_desc *desc,
+                                 struct txdata_entry_desc *desc,
                                  struct ieee80211_hdr *ieee80211hdr,
                                  unsigned int length,
                                  struct ieee80211_tx_control *control)
        return rt2x00_get_field32(rxd_w1, RXD_W1_RSSI_AGC) * 2 - offset;
 }
 
-static int rt73usb_fill_rxdone(struct data_entry *entry,
-                              int *signal, int *rssi, int *ofdm, int *size)
+static void rt73usb_fill_rxdone(struct data_entry *entry,
+                               struct rxdata_entry_desc *desc)
 {
        struct data_desc *rxd = (struct data_desc *)entry->skb->data;
        u32 word0;
        rt2x00_desc_read(rxd, 0, &word0);
        rt2x00_desc_read(rxd, 1, &word1);
 
-       if (rt2x00_get_field32(word0, RXD_W0_CRC_ERROR) ||
-           rt2x00_get_field32(word0, RXD_W0_CIPHER_ERROR))
-               return -EINVAL;
+       desc->flags = 0;
+       if (rt2x00_get_field32(word0, RXD_W0_CRC_ERROR))
+               desc->flags |= RX_FLAG_FAILED_FCS_CRC;
 
        /*
         * Obtain the status about this packet.
         */
-       *signal = rt2x00_get_field32(word1, RXD_W1_SIGNAL);
-       *rssi = rt73usb_agc_to_rssi(entry->ring->rt2x00dev, word1);
-       *ofdm = rt2x00_get_field32(word0, RXD_W0_OFDM);
-       *size = rt2x00_get_field32(word0, RXD_W0_DATABYTE_COUNT);
+       desc->signal = rt2x00_get_field32(word1, RXD_W1_SIGNAL);
+       desc->rssi = rt73usb_agc_to_rssi(entry->ring->rt2x00dev, word1);
+       desc->ofdm = rt2x00_get_field32(word0, RXD_W0_OFDM);
+       desc->size = rt2x00_get_field32(word0, RXD_W0_DATABYTE_COUNT);
 
        /*
         * Pull the skb to clear the descriptor area.
         */
        skb_pull(entry->skb, entry->ring->desc_size);
 
-       return 0;
+       return;
 }
 
 /*
         */
        rt2x00dev->hw->flags =
            IEEE80211_HW_HOST_GEN_BEACON_TEMPLATE |
-           IEEE80211_HW_HOST_BROADCAST_PS_BUFFERING |
-           IEEE80211_HW_MONITOR_DURING_OPER |
-           IEEE80211_HW_NO_PROBE_FILTERING;
+           IEEE80211_HW_HOST_BROADCAST_PS_BUFFERING;
        rt2x00dev->hw->extra_tx_headroom = TXD_DESC_SIZE;
        rt2x00dev->hw->max_signal = MAX_SIGNAL;
        rt2x00dev->hw->max_rssi = MAX_RX_SSI;
        rt73usb_probe_hw_mode(rt2x00dev);
 
        /*
-        * USB devices require scheduled packet filter toggling
         * This device requires firmware
         */
        __set_bit(REQUIRE_FIRMWARE, &rt2x00dev->flags);
-       __set_bit(PACKET_FILTER_SCHEDULED, &rt2x00dev->flags);
 
        /*
         * Set the rssi offset.
 /*
  * IEEE80211 stack callback functions.
  */
+static void rt73usb_configure_filter(struct ieee80211_hw *hw,
+                                    unsigned int changed_flags,
+                                    unsigned int *total_flags,
+                                    int mc_count,
+                                    struct dev_addr_list *mc_list)
+{
+       struct rt2x00_dev *rt2x00dev = hw->priv;
+       struct interface *intf = &rt2x00dev->interface;
+       u32 reg;
+
+       /*
+        * Mask off any flags we are going to ignore from
+        * the total_flags field.
+        */
+       *total_flags &=
+           FIF_ALLMULTI |
+           FIF_FCSFAIL |
+           FIF_PLCPFAIL |
+           FIF_CONTROL |
+           FIF_OTHER_BSS |
+           FIF_PROMISC_IN_BSS;
+
+       /*
+        * Apply some rules to the filters:
+        * - Some filters imply different filters to be set.
+        * - Some things we can't filter out at all.
+        * - Some filters are set based on interface type.
+        */
+       if (mc_count)
+               *total_flags |= FIF_ALLMULTI;
+       if (changed_flags & FIF_OTHER_BSS ||
+           changed_flags & FIF_PROMISC_IN_BSS)
+               *total_flags |= FIF_PROMISC_IN_BSS | FIF_OTHER_BSS;
+       if (is_interface_type(intf, IEEE80211_IF_TYPE_AP))
+               *total_flags |= FIF_PROMISC_IN_BSS;
+
+       /*
+        * Check if there is any work left for us.
+        */
+       if (intf->filter == *total_flags)
+               return;
+       intf->filter = *total_flags;
+
+       /*
+        * When in atomic context, reschedule and let rt2x00lib
+        * call this function again.
+        */
+       if (in_atomic()) {
+               queue_work(rt2x00dev->hw->workqueue, &rt2x00dev->filter_work);
+               return;
+       }
+
+       /*
+        * Start configuration steps.
+        * Note that the version error will always be dropped
+        * and broadcast frames will always be accepted since
+        * there is no filter for it at this time.
+        */
+       rt73usb_register_read(rt2x00dev, TXRX_CSR0, ®);
+       rt2x00_set_field32(®, TXRX_CSR0_DROP_CRC,
+                          !(*total_flags & FIF_FCSFAIL));
+       rt2x00_set_field32(®, TXRX_CSR0_DROP_PHYSICAL,
+                          !(*total_flags & FIF_PLCPFAIL));
+       rt2x00_set_field32(®, TXRX_CSR0_DROP_CONTROL,
+                          !(*total_flags & FIF_CONTROL));
+       rt2x00_set_field32(®, TXRX_CSR0_DROP_NOT_TO_ME,
+                          !(*total_flags & FIF_PROMISC_IN_BSS));
+       rt2x00_set_field32(®, TXRX_CSR0_DROP_TO_DS,
+                          !(*total_flags & FIF_PROMISC_IN_BSS));
+       rt2x00_set_field32(®, TXRX_CSR0_DROP_VERSION_ERROR, 1);
+       rt2x00_set_field32(®, TXRX_CSR0_DROP_MULTICAST,
+                          !(*total_flags & FIF_ALLMULTI));
+       rt2x00_set_field32(®, TXRX_CSR0_DROP_BROADCAST, 0);
+       rt2x00_set_field32(®, TXRX_CSR0_DROP_ACK_CTS, 1);
+       rt73usb_register_write(rt2x00dev, TXRX_CSR0, reg);
+}
+
 static int rt73usb_set_retry_limit(struct ieee80211_hw *hw,
                                   u32 short_retry, u32 long_retry)
 {
 
 static const struct ieee80211_ops rt73usb_mac80211_ops = {
        .tx                     = rt2x00mac_tx,
+       .start                  = rt2x00mac_start,
+       .stop                   = rt2x00mac_stop,
        .add_interface          = rt2x00mac_add_interface,
        .remove_interface       = rt2x00mac_remove_interface,
        .config                 = rt2x00mac_config,
        .config_interface       = rt2x00mac_config_interface,
-       .set_multicast_list     = rt2x00mac_set_multicast_list,
+       .configure_filter       = rt73usb_configure_filter,
        .get_stats              = rt2x00mac_get_stats,
        .set_retry_limit        = rt73usb_set_retry_limit,
        .conf_tx                = rt2x00mac_conf_tx,
        .fill_rxdone            = rt73usb_fill_rxdone,
        .config_mac_addr        = rt73usb_config_mac_addr,
        .config_bssid           = rt73usb_config_bssid,
-       .config_packet_filter   = rt73usb_config_packet_filter,
        .config_type            = rt73usb_config_type,
        .config                 = rt73usb_config,
 };
 
 #define TXRX_CSR0_DROP_TO_DS           FIELD32(0x00200000)
 #define TXRX_CSR0_DROP_VERSION_ERROR   FIELD32(0x00400000)
 #define TXRX_CSR0_DROP_MULTICAST       FIELD32(0x00800000)
-#define TXRX_CSR0_DROP_BORADCAST       FIELD32(0x01000000)
+#define TXRX_CSR0_DROP_BROADCAST       FIELD32(0x01000000)
 #define TXRX_CSR0_DROP_ACK_CTS         FIELD32(0x02000000)
 #define TXRX_CSR0_TX_WITHOUT_WAITING   FIELD32(0x04000000)
 
 
 };
 
 struct rtl8187_rx_hdr {
-       __le16 len;
-       __le16 rate;
+       __le32 flags;
        u8 noise;
        u8 signal;
        u8 agc;
        struct ieee80211_rate rates[12];
        struct ieee80211_hw_mode modes[2];
        struct usb_device *udev;
-       u8 *hwaddr;
+       u32 rx_conf;
        u16 txpwr_base;
        u8 asic_rev;
        struct sk_buff_head rx_queue;
 
 
 MODULE_DEVICE_TABLE(usb, rtl8187_table);
 
+static void rtl8187_iowrite_async_cb(struct urb *urb)
+{
+       kfree(urb->context);
+       usb_free_urb(urb);
+}
+
+static void rtl8187_iowrite_async(struct rtl8187_priv *priv, __le16 addr,
+                                 void *data, u16 len)
+{
+       struct usb_ctrlrequest *dr;
+       struct urb *urb;
+       struct rtl8187_async_write_data {
+               u8 data[4];
+               struct usb_ctrlrequest dr;
+       } *buf;
+
+       buf = kmalloc(sizeof(*buf), GFP_ATOMIC);
+       if (!buf)
+               return;
+
+       urb = usb_alloc_urb(0, GFP_ATOMIC);
+       if (!urb) {
+               kfree(buf);
+               return;
+       }
+
+       dr = &buf->dr;
+
+       dr->bRequestType = RTL8187_REQT_WRITE;
+       dr->bRequest = RTL8187_REQ_SET_REG;
+       dr->wValue = addr;
+       dr->wIndex = 0;
+       dr->wLength = cpu_to_le16(len);
+
+       memcpy(buf, data, len);
+
+       usb_fill_control_urb(urb, priv->udev, usb_sndctrlpipe(priv->udev, 0),
+                            (unsigned char *)dr, buf, len,
+                            rtl8187_iowrite_async_cb, buf);
+       usb_submit_urb(urb, GFP_ATOMIC);
+}
+
+static inline void rtl818x_iowrite32_async(struct rtl8187_priv *priv,
+                                          __le32 *addr, u32 val)
+{
+       __le32 buf = cpu_to_le32(val);
+
+       rtl8187_iowrite_async(priv, cpu_to_le16((unsigned long)addr),
+                             &buf, sizeof(buf));
+}
+
 void rtl8187_write_phy(struct ieee80211_hw *dev, u8 addr, u32 data)
 {
        struct rtl8187_priv *priv = dev->priv;
        struct rtl8187_rx_hdr *hdr;
        struct ieee80211_rx_status rx_status = { 0 };
        int rate, signal;
+       u32 flags;
 
        spin_lock(&priv->rx_queue.lock);
        if (skb->next)
 
        skb_put(skb, urb->actual_length);
        hdr = (struct rtl8187_rx_hdr *)(skb_tail_pointer(skb) - sizeof(*hdr));
-       skb_trim(skb, le16_to_cpu(hdr->len) & 0x0FFF);
+       flags = le32_to_cpu(hdr->flags);
+       skb_trim(skb, flags & 0x0FFF);
 
        signal = hdr->agc >> 1;
-       rate = (le16_to_cpu(hdr->rate) >> 4) & 0xF;
+       rate = (flags >> 20) & 0xF;
        if (rate > 3) { /* OFDM rate */
                if (signal > 90)
                        signal = 90;
        rx_status.channel = dev->conf.channel;
        rx_status.phymode = dev->conf.phymode;
        rx_status.mactime = le64_to_cpu(hdr->mac_time);
+       if (flags & (1 << 13))
+               rx_status.flag |= RX_FLAG_FAILED_FCS_CRC;
        ieee80211_rx_irqsafe(dev, skb, &rx_status);
 
        skb = dev_alloc_skb(RTL8187_MAX_RX);
        rtl818x_iowrite8(priv, &priv->map->GP_ENABLE, 0);
 
        rtl818x_iowrite8(priv, &priv->map->EEPROM_CMD, RTL818X_EEPROM_CMD_CONFIG);
-       for (i = 0; i < ETH_ALEN; i++)
-               rtl818x_iowrite8(priv, &priv->map->MAC[i], priv->hwaddr[i]);
 
        rtl818x_iowrite16(priv, (__le16 *)0xFFF4, 0xFFFF);
        reg = rtl818x_ioread8(priv, &priv->map->CONFIG1);
        rtl818x_iowrite32(priv, &priv->map->TX_CONF, reg);
 }
 
-static int rtl8187_open(struct ieee80211_hw *dev)
+static int rtl8187_start(struct ieee80211_hw *dev)
 {
        struct rtl8187_priv *priv = dev->priv;
        u32 reg;
              RTL818X_RX_CONF_RX_AUTORESETPHY |
              RTL818X_RX_CONF_BSSID |
              RTL818X_RX_CONF_MGMT |
-             RTL818X_RX_CONF_CTRL |
              RTL818X_RX_CONF_DATA |
              (7 << 13 /* RX FIFO threshold NONE */) |
              (7 << 10 /* MAX RX DMA */) |
              RTL818X_RX_CONF_BROADCAST |
-             RTL818X_RX_CONF_MULTICAST |
              RTL818X_RX_CONF_NICMAC;
-       if (priv->mode == IEEE80211_IF_TYPE_MNTR)
-               reg |= RTL818X_RX_CONF_MONITOR;
 
+       priv->rx_conf = reg;
        rtl818x_iowrite32(priv, &priv->map->RX_CONF, reg);
 
        reg = rtl818x_ioread8(priv, &priv->map->CW_CONF);
        return 0;
 }
 
-static int rtl8187_stop(struct ieee80211_hw *dev)
+static void rtl8187_stop(struct ieee80211_hw *dev)
 {
        struct rtl8187_priv *priv = dev->priv;
        struct rtl8187_rx_info *info;
                usb_kill_urb(info->urb);
                kfree_skb(skb);
        }
-       return 0;
+       return;
 }
 
 static int rtl8187_add_interface(struct ieee80211_hw *dev,
                                 struct ieee80211_if_init_conf *conf)
 {
        struct rtl8187_priv *priv = dev->priv;
+       int i;
 
-       /* NOTE: using IEEE80211_IF_TYPE_MGMT to indicate no mode selected */
-       if (priv->mode != IEEE80211_IF_TYPE_MGMT)
-               return -1;
+       if (priv->mode != IEEE80211_IF_TYPE_MNTR)
+               return -EOPNOTSUPP;
 
        switch (conf->type) {
        case IEEE80211_IF_TYPE_STA:
-       case IEEE80211_IF_TYPE_MNTR:
                priv->mode = conf->type;
                break;
        default:
                return -EOPNOTSUPP;
        }
 
-       priv->hwaddr = conf->mac_addr ? conf->mac_addr : dev->wiphy->perm_addr;
+       rtl818x_iowrite8(priv, &priv->map->EEPROM_CMD, RTL818X_EEPROM_CMD_CONFIG);
+       for (i = 0; i < ETH_ALEN; i++)
+               rtl818x_iowrite8(priv, &priv->map->MAC[i],
+                                ((u8 *)conf->mac_addr)[i]);
+       rtl818x_iowrite8(priv, &priv->map->EEPROM_CMD, RTL818X_EEPROM_CMD_NORMAL);
 
        return 0;
 }
                                     struct ieee80211_if_init_conf *conf)
 {
        struct rtl8187_priv *priv = dev->priv;
-       priv->mode = IEEE80211_IF_TYPE_MGMT;
+       priv->mode = IEEE80211_IF_TYPE_MNTR;
 }
 
 static int rtl8187_config(struct ieee80211_hw *dev, struct ieee80211_conf *conf)
        return 0;
 }
 
+static void rtl8187_configure_filter(struct ieee80211_hw *dev,
+                                    unsigned int changed_flags,
+                                    unsigned int *total_flags,
+                                    int mc_count, struct dev_addr_list *mc_list)
+{
+       struct rtl8187_priv *priv = dev->priv;
+
+       *total_flags = 0;
+
+       if (changed_flags & FIF_PROMISC_IN_BSS)
+               priv->rx_conf ^= RTL818X_RX_CONF_NICMAC;
+       if (changed_flags & FIF_ALLMULTI)
+               priv->rx_conf ^= RTL818X_RX_CONF_MULTICAST;
+       if (changed_flags & FIF_FCSFAIL)
+               priv->rx_conf ^= RTL818X_RX_CONF_FCS;
+       if (changed_flags & FIF_CONTROL)
+               priv->rx_conf ^= RTL818X_RX_CONF_CTRL;
+       if (changed_flags & FIF_OTHER_BSS)
+               priv->rx_conf ^= RTL818X_RX_CONF_MONITOR;
+
+       if (mc_count > 0)
+               priv->rx_conf |= RTL818X_RX_CONF_MULTICAST;
+
+       if (priv->rx_conf & RTL818X_RX_CONF_NICMAC)
+               *total_flags |= FIF_PROMISC_IN_BSS;
+       if (priv->rx_conf & RTL818X_RX_CONF_MULTICAST)
+               *total_flags |= FIF_ALLMULTI;
+       if (priv->rx_conf & RTL818X_RX_CONF_FCS)
+               *total_flags |= FIF_FCSFAIL;
+       if (priv->rx_conf & RTL818X_RX_CONF_CTRL)
+               *total_flags |= FIF_CONTROL;
+       if (priv->rx_conf & RTL818X_RX_CONF_MONITOR)
+               *total_flags |= FIF_OTHER_BSS;
+
+       rtl818x_iowrite32_async(priv, &priv->map->RX_CONF, priv->rx_conf);
+}
+
 static const struct ieee80211_ops rtl8187_ops = {
        .tx                     = rtl8187_tx,
-       .open                   = rtl8187_open,
+       .start                  = rtl8187_start,
        .stop                   = rtl8187_stop,
        .add_interface          = rtl8187_add_interface,
        .remove_interface       = rtl8187_remove_interface,
        .config                 = rtl8187_config,
        .config_interface       = rtl8187_config_interface,
+       .configure_filter       = rtl8187_configure_filter,
 };
 
 static void rtl8187_eeprom_register_read(struct eeprom_93cx6 *eeprom)
        priv->modes[1].rates = priv->rates;
        priv->modes[1].num_channels = ARRAY_SIZE(rtl818x_channels);
        priv->modes[1].channels = priv->channels;
-       priv->mode = IEEE80211_IF_TYPE_MGMT;
+       priv->mode = IEEE80211_IF_TYPE_MNTR;
        dev->flags = IEEE80211_HW_HOST_BROADCAST_PS_BUFFERING |
                     IEEE80211_HW_RX_INCLUDES_FCS;
        dev->extra_tx_headroom = sizeof(struct rtl8187_tx_hdr);
 
 #define RTL818X_RX_CONF_NICMAC         (1 <<  1)
 #define RTL818X_RX_CONF_MULTICAST      (1 <<  2)
 #define RTL818X_RX_CONF_BROADCAST      (1 <<  3)
+#define RTL818X_RX_CONF_FCS            (1 <<  5)
 #define RTL818X_RX_CONF_DATA           (1 << 18)
 #define RTL818X_RX_CONF_CTRL           (1 << 19)
 #define RTL818X_RX_CONF_MGMT           (1 << 20)
 
  * @mac_addr: pointer to MAC address of the interface. This pointer is valid
  *     until the interface is removed (i.e. it cannot be used after
  *     remove_interface() callback was called for this interface).
- *     This pointer will be %NULL for monitor interfaces, be careful.
  *
  * This structure is used in add_interface() and remove_interface()
  * callbacks of &struct ieee80211_hw.
 
 /* hole at 8 */
 
-       /* Device is capable of performing full monitor mode even during
-        * normal operation. */
-#define IEEE80211_HW_MONITOR_DURING_OPER (1<<9)
+/* hole at 9 */
 
-       /* Device does not need BSSID filter set to broadcast in order to
-        * receive all probe responses while scanning */
-#define IEEE80211_HW_NO_PROBE_FILTERING (1<<10)
+/* hole at 10 */
 
        /* Channels are already configured to the default regulatory domain
         * specified in the device's EEPROM */
        memcpy(hw->wiphy->perm_addr, addr, ETH_ALEN);
 }
 
+/*
+ * flags for change_filter_flags()
+ *
+ * Note that e.g. if PROMISC_IN_BSS is unset then
+ * you should still do MAC address filtering if
+ * possible even if OTHER_BSS is set to indicate
+ * no BSSID filtering should be done.
+ */
+/*
+ * promiscuous mode within your BSS,
+ * think of the BSS as your network segment and then this corresponds
+ * to the regular ethernet device promiscuous mode
+ */
+#define FIF_PROMISC_IN_BSS     0x01
+/* show all multicast frames */
+#define FIF_ALLMULTI           0x02
+/* show frames with failed FCS, but set RX_FLAG_FAILED_FCS_CRC for them */
+#define FIF_FCSFAIL            0x04
+/* show frames with failed PLCP CRC, but set RX_FLAG_FAILED_PLCP_CRC for them */
+#define FIF_PLCPFAIL           0x08
+/*
+ * This flag is set during scanning to indicate to the hardware
+ * that it should not filter beacons or probe responses by BSSID.
+ */
+#define FIF_BCN_PRBRESP_PROMISC        0x10
+/*
+ * show control frames, if PROMISC_IN_BSS is not set then
+ * only those addressed to this station
+ */
+#define FIF_CONTROL            0x20
+/* show frames from other BSSes */
+#define FIF_OTHER_BSS          0x40
+
 /* Configuration block used by the low-level driver to tell the 802.11 code
  * about supported hardware features and to pass function pointers to callback
  * functions. */
        int (*tx)(struct ieee80211_hw *hw, struct sk_buff *skb,
                  struct ieee80211_tx_control *control);
 
-       /* Handler that is called when any netdevice attached to the hardware
-        * device is set UP for the first time. This can be used, e.g., to
-        * enable interrupts and beacon sending. */
-       int (*open)(struct ieee80211_hw *hw);
-
-       /* Handler that is called when the last netdevice attached to the
-        * hardware device is set DOWN. This can be used, e.g., to disable
-        * interrupts and beacon sending. */
-       int (*stop)(struct ieee80211_hw *hw);
-
-       /* Handler for asking a driver if a new interface can be added (or,
-        * more exactly, set UP). If the handler returns zero, the interface
-        * is added. Driver should perform any initialization it needs prior
-        * to returning zero. By returning non-zero addition of the interface
-        * is inhibited. Unless monitor_during_oper is set, it is guaranteed
-        * that monitor interfaces and normal interfaces are mutually
-        * exclusive. If assigned, the open() handler is called after
-        * add_interface() if this is the first device added. The
-        * add_interface() callback has to be assigned because it is the only
-        * way to obtain the requested MAC address for any interface.
+       /*
+        * Called before the first netdevice attached to the hardware
+        * is enabled. This should turn on the hardware and must turn on
+        * frame reception (for possibly enabled monitor interfaces.)
+        * Returns negative error codes, these may be seen in userspace,
+        * or zero.
+        * When the device is started it should not have a MAC address
+        * to avoid acknowledging frames before a non-monitor device
+        * is added.
+        *
+        * Must be implemented.
+        */
+       int (*start)(struct ieee80211_hw *hw);
+
+       /*
+        * Called after last netdevice attached to the hardware
+        * is disabled. This should turn off the hardware (at least
+        * it must turn off frame reception.)
+        * May be called right after add_interface if that rejects
+        * an interface.
+        *
+        * Must be implemented.
+        */
+       void (*stop)(struct ieee80211_hw *hw);
+
+       /*
+        * Called when a netdevice attached to the hardware is enabled.
+        * Because it is not called for monitor mode devices, open()
+        * and stop() must be implemented.
+        * The driver should perform any initialization it needs before
+        * the device can be enabled. The initial configuration for the
+        * interface is given in the conf parameter.
+        *
+        * Must be implemented.
         */
        int (*add_interface)(struct ieee80211_hw *hw,
                             struct ieee80211_if_init_conf *conf);
 
-       /* Notify a driver that an interface is going down. The stop() handler
-        * is called prior to this if this is a last interface. */
+       /*
+        * Notifies a driver that an interface is going down. The stop() handler
+        * is called after this if it is the last interface and no monitor
+        * interfaces are present.
+        * When all interfaces are removed, the MAC address in the hardware
+        * must be cleared so the device no longer acknowledges packets,
+        * the mac_addr member of the conf structure is, however, set to the
+        * MAC address of the device going away.
+        *
+        * Hence, this callback must be implemented.
+        */
        void (*remove_interface)(struct ieee80211_hw *hw,
                                 struct ieee80211_if_init_conf *conf);
 
        int (*config_interface)(struct ieee80211_hw *hw,
                                int if_id, struct ieee80211_if_conf *conf);
 
-       /* ieee80211 drivers do not have access to the &struct net_device
-        * that is (are) connected with their device. Hence (and because
-        * we need to combine the multicast lists and flags for multiple
-        * virtual interfaces), they cannot assign set_multicast_list.
-        * The parameters here replace dev->flags and dev->mc_count,
-        * dev->mc_list is replaced by calling ieee80211_get_mc_list_item.
-        * Must be atomic. */
-       void (*set_multicast_list)(struct ieee80211_hw *hw,
-                                  unsigned short flags, int mc_count);
+       /*
+        * Configure the device's RX filter.
+        *
+        * The multicast address filter must be changed if the hardware flags
+        * indicate that one is present.
+        *
+        * All unsupported flags in 'total_flags' must be cleared,
+        * clear all bits except those you honoured.
+        *
+        * The callback must be implemented and must be atomic.
+        */
+       void (*configure_filter)(struct ieee80211_hw *hw,
+                                unsigned int changed_flags,
+                                unsigned int *total_flags,
+                                int mc_count, struct dev_addr_list *mc_list);
 
        /* Set TIM bit handler. If the hardware/firmware takes care of beacon
         * generation, IEEE 802.11 code uses this function to tell the
  */
 void ieee80211_wake_queues(struct ieee80211_hw *hw);
 
-/**
- * ieee80211_get_mc_list_item - iteration over items in multicast list
- * @hw: pointer as obtained from ieee80211_alloc_hw().
- * @prev: value returned by previous call to ieee80211_get_mc_list_item() or
- *     NULL to start a new iteration.
- * @ptr: pointer to buffer of void * type for internal usage of
- *     ieee80211_get_mc_list_item().
- *
- * Iterates over items in multicast list of given device. To get the first
- * item, pass NULL in @prev and in *@ptr. In subsequent calls, pass the
- * value returned by previous call in @prev. Don't alter *@ptr during
- * iteration. When there are no more items, NULL is returned.
- */
-struct dev_mc_list *
-ieee80211_get_mc_list_item(struct ieee80211_hw *hw,
-                          struct dev_mc_list *prev,
-                          void **ptr);
-
 /* called by driver to notify scan status completed */
 void ieee80211_scan_completed(struct ieee80211_hw *hw);
 
 
 /* VLAN attributes */
 IEEE80211_IF_FILE(vlan_id, u.vlan.id, DEC);
 
-/* MONITOR attributes */
-static ssize_t ieee80211_if_fmt_mode(
-       const struct ieee80211_sub_if_data *sdata, char *buf, int buflen)
-{
-       struct ieee80211_local *local = sdata->local;
-
-       return scnprintf(buf, buflen, "%s\n",
-                        ((local->hw.flags & IEEE80211_HW_MONITOR_DURING_OPER) ||
-                         local->open_count == local->monitors) ?
-                        "hard" : "soft");
-}
-__IEEE80211_IF_FILE(mode);
-
-
 #define DEBUGFS_ADD(name, type)\
        sdata->debugfs.type.name = debugfs_create_file(#name, 0444,\
                sdata->debugfsdir, sdata, &name##_ops);
 
 static void add_monitor_files(struct ieee80211_sub_if_data *sdata)
 {
-       DEBUGFS_ADD(mode, monitor);
 }
 
 static void add_files(struct ieee80211_sub_if_data *sdata)
 
 static void del_monitor_files(struct ieee80211_sub_if_data *sdata)
 {
-       DEBUGFS_DEL(mode, monitor);
 }
 
 static void del_files(struct ieee80211_sub_if_data *sdata, int type)
 
        return ETH_ALEN;
 }
 
+/* must be called under mdev tx lock */
+static void ieee80211_configure_filter(struct ieee80211_local *local)
+{
+       unsigned int changed_flags;
+       unsigned int new_flags = 0;
+
+       if (local->iff_promiscs)
+               new_flags |= FIF_PROMISC_IN_BSS;
+
+       if (local->iff_allmultis)
+               new_flags |= FIF_ALLMULTI;
+
+       if (local->monitors)
+               new_flags |= FIF_CONTROL |
+                            FIF_OTHER_BSS |
+                            FIF_BCN_PRBRESP_PROMISC;
+
+       changed_flags = local->filter_flags ^ new_flags;
+
+       /* be a bit nasty */
+       new_flags |= (1<<31);
+
+       local->ops->configure_filter(local_to_hw(local),
+                                    changed_flags, &new_flags,
+                                    local->mdev->mc_count,
+                                    local->mdev->mc_list);
+
+       WARN_ON(new_flags & (1<<31));
+
+       local->filter_flags = new_flags & ~(1<<31);
+}
+
 /* master interface */
 
 static int ieee80211_master_open(struct net_device *dev)
        return 0;
 }
 
+static void ieee80211_master_set_multicast_list(struct net_device *dev)
+{
+       struct ieee80211_local *local = wdev_priv(dev->ieee80211_ptr);
+
+       ieee80211_configure_filter(local);
+}
+
 /* management interface */
 
 static void
                  type2 == IEEE80211_IF_TYPE_VLAN)));
 }
 
-/* Check if running monitor interfaces should go to a "soft monitor" mode
- * and switch them if necessary. */
-static inline void ieee80211_start_soft_monitor(struct ieee80211_local *local)
-{
-       struct ieee80211_if_init_conf conf;
-
-       if (local->open_count && local->open_count == local->monitors &&
-           !(local->hw.flags & IEEE80211_HW_MONITOR_DURING_OPER) &&
-           local->ops->remove_interface) {
-               conf.if_id = -1;
-               conf.type = IEEE80211_IF_TYPE_MNTR;
-               conf.mac_addr = NULL;
-               local->ops->remove_interface(local_to_hw(local), &conf);
-       }
-}
-
-/* Check if running monitor interfaces should go to a "hard monitor" mode
- * and switch them if necessary. */
-static void ieee80211_start_hard_monitor(struct ieee80211_local *local)
-{
-       struct ieee80211_if_init_conf conf;
-
-       if (local->open_count && local->open_count == local->monitors &&
-           !(local->hw.flags & IEEE80211_HW_MONITOR_DURING_OPER)) {
-               conf.if_id = -1;
-               conf.type = IEEE80211_IF_TYPE_MNTR;
-               conf.mac_addr = NULL;
-               local->ops->add_interface(local_to_hw(local), &conf);
-       }
-}
-
-static void ieee80211_if_open(struct net_device *dev)
-{
-       struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev);
-
-       switch (sdata->type) {
-       case IEEE80211_IF_TYPE_STA:
-       case IEEE80211_IF_TYPE_IBSS:
-               sdata->u.sta.flags &= ~IEEE80211_STA_PREV_BSSID_SET;
-               break;
-       }
-}
-
 static int ieee80211_open(struct net_device *dev)
 {
        struct ieee80211_sub_if_data *sdata, *nsdata;
            is_zero_ether_addr(sdata->u.wds.remote_addr))
                return -ENOLINK;
 
-       if (sdata->type == IEEE80211_IF_TYPE_MNTR && local->open_count &&
-           !(local->hw.flags & IEEE80211_HW_MONITOR_DURING_OPER)) {
-               /* run the interface in a "soft monitor" mode */
-               local->monitors++;
-               local->open_count++;
-               local->hw.conf.flags |= IEEE80211_CONF_RADIOTAP;
-               return 0;
-       }
-       ieee80211_if_open(dev);
-       ieee80211_start_soft_monitor(local);
-
-       conf.if_id = dev->ifindex;
-       conf.type = sdata->type;
-       if (sdata->type == IEEE80211_IF_TYPE_MNTR)
-               conf.mac_addr = NULL;
-       else
-               conf.mac_addr = dev->dev_addr;
-       res = local->ops->add_interface(local_to_hw(local), &conf);
-       if (res) {
-               if (sdata->type == IEEE80211_IF_TYPE_MNTR)
-                       ieee80211_start_hard_monitor(local);
-               return res;
-       }
-
        if (local->open_count == 0) {
                res = 0;
-               tasklet_enable(&local->tx_pending_tasklet);
-               tasklet_enable(&local->tasklet);
-               if (local->ops->open)
-                       res = local->ops->open(local_to_hw(local));
-               if (res == 0) {
-                       res = dev_open(local->mdev);
-                       if (res) {
-                               if (local->ops->stop)
-                                       local->ops->stop(local_to_hw(local));
-                       } else {
-                               res = ieee80211_hw_config(local);
-                               if (res && local->ops->stop)
-                                       local->ops->stop(local_to_hw(local));
-                               else if (!res && local->apdev)
-                                       dev_open(local->apdev);
-                       }
-               }
-               if (res) {
-                       if (local->ops->remove_interface)
-                               local->ops->remove_interface(local_to_hw(local),
-                                                           &conf);
+               if (local->ops->start)
+                       res = local->ops->start(local_to_hw(local));
+               if (res)
                        return res;
-               }
        }
-       local->open_count++;
 
-       if (sdata->type == IEEE80211_IF_TYPE_MNTR) {
+       switch (sdata->type) {
+       case IEEE80211_IF_TYPE_MNTR:
+               /* must be before the call to ieee80211_configure_filter */
                local->monitors++;
-               local->hw.conf.flags |= IEEE80211_CONF_RADIOTAP;
-       } else {
+               if (local->monitors == 1) {
+                       netif_tx_lock_bh(local->mdev);
+                       ieee80211_configure_filter(local);
+                       netif_tx_unlock_bh(local->mdev);
+
+                       local->hw.conf.flags |= IEEE80211_CONF_RADIOTAP;
+                       ieee80211_hw_config(local);
+               }
+               break;
+       case IEEE80211_IF_TYPE_STA:
+       case IEEE80211_IF_TYPE_IBSS:
+               sdata->u.sta.flags &= ~IEEE80211_STA_PREV_BSSID_SET;
+               /* fall through */
+       default:
+               conf.if_id = dev->ifindex;
+               conf.type = sdata->type;
+               conf.mac_addr = dev->dev_addr;
+               res = local->ops->add_interface(local_to_hw(local), &conf);
+               if (res && !local->open_count && local->ops->stop)
+                       local->ops->stop(local_to_hw(local));
+               if (res)
+                       return res;
+
                ieee80211_if_config(dev);
                ieee80211_reset_erp_info(dev);
                ieee80211_enable_keys(sdata);
+
+               if (sdata->type == IEEE80211_IF_TYPE_STA &&
+                   !local->user_space_mlme)
+                       netif_carrier_off(dev);
+               else
+                       netif_carrier_on(dev);
        }
 
-       if (sdata->type == IEEE80211_IF_TYPE_STA &&
-           !local->user_space_mlme)
-               netif_carrier_off(dev);
-       else
-               netif_carrier_on(dev);
+       if (local->open_count == 0) {
+               res = dev_open(local->mdev);
+               WARN_ON(res);
+               if (local->apdev) {
+                       res = dev_open(local->apdev);
+                       WARN_ON(res);
+               }
+               tasklet_enable(&local->tx_pending_tasklet);
+               tasklet_enable(&local->tasklet);
+       }
+
+       local->open_count++;
 
        netif_start_queue(dev);
+
        return 0;
 }
 
-static void ieee80211_if_shutdown(struct net_device *dev)
+static int ieee80211_stop(struct net_device *dev)
 {
+       struct ieee80211_sub_if_data *sdata;
        struct ieee80211_local *local = wdev_priv(dev->ieee80211_ptr);
-       struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev);
+       struct ieee80211_if_init_conf conf;
+
+       sdata = IEEE80211_DEV_TO_SUB_IF(dev);
+
+       netif_stop_queue(dev);
+
+       dev_mc_unsync(local->mdev, dev);
+
+       local->open_count--;
 
-       ASSERT_RTNL();
        switch (sdata->type) {
+       case IEEE80211_IF_TYPE_MNTR:
+               local->monitors--;
+               if (local->monitors == 0) {
+                       netif_tx_lock_bh(local->mdev);
+                       ieee80211_configure_filter(local);
+                       netif_tx_unlock_bh(local->mdev);
+
+                       local->hw.conf.flags |= IEEE80211_CONF_RADIOTAP;
+                       ieee80211_hw_config(local);
+               }
+               break;
        case IEEE80211_IF_TYPE_STA:
        case IEEE80211_IF_TYPE_IBSS:
                sdata->u.sta.state = IEEE80211_DISABLED;
                        cancel_delayed_work(&local->scan_work);
                }
                flush_workqueue(local->hw.workqueue);
-               break;
-       }
-}
-
-static int ieee80211_stop(struct net_device *dev)
-{
-       struct ieee80211_sub_if_data *sdata;
-       struct ieee80211_local *local = wdev_priv(dev->ieee80211_ptr);
-
-       sdata = IEEE80211_DEV_TO_SUB_IF(dev);
-
-       if (sdata->type == IEEE80211_IF_TYPE_MNTR &&
-           local->open_count > 1 &&
-           !(local->hw.flags & IEEE80211_HW_MONITOR_DURING_OPER)) {
-               /* remove "soft monitor" interface */
-               local->open_count--;
-               local->monitors--;
-               if (!local->monitors)
-                       local->hw.conf.flags &= ~IEEE80211_CONF_RADIOTAP;
-               return 0;
-       }
-
-       netif_stop_queue(dev);
-       ieee80211_if_shutdown(dev);
-
-       if (sdata->type == IEEE80211_IF_TYPE_MNTR) {
-               local->monitors--;
-               if (!local->monitors)
-                       local->hw.conf.flags &= ~IEEE80211_CONF_RADIOTAP;
-       } else {
+               /* fall through */
+       default:
+               conf.if_id = dev->ifindex;
+               conf.type = sdata->type;
+               conf.mac_addr = dev->dev_addr;
                /* disable all keys for as long as this netdev is down */
                ieee80211_disable_keys(sdata);
+               local->ops->remove_interface(local_to_hw(local), &conf);
        }
 
-       local->open_count--;
        if (local->open_count == 0) {
                if (netif_running(local->mdev))
                        dev_close(local->mdev);
+
                if (local->apdev)
                        dev_close(local->apdev);
+
                if (local->ops->stop)
                        local->ops->stop(local_to_hw(local));
+
                tasklet_disable(&local->tx_pending_tasklet);
                tasklet_disable(&local->tasklet);
        }
-       if (local->ops->remove_interface) {
-               struct ieee80211_if_init_conf conf;
-
-               conf.if_id = dev->ifindex;
-               conf.type = sdata->type;
-               conf.mac_addr = dev->dev_addr;
-               local->ops->remove_interface(local_to_hw(local), &conf);
-       }
-
-       ieee80211_start_hard_monitor(local);
 
        return 0;
 }
 
-enum netif_tx_lock_class {
-       TX_LOCK_NORMAL,
-       TX_LOCK_MASTER,
-};
-
-static inline void netif_tx_lock_nested(struct net_device *dev, int subclass)
-{
-       spin_lock_nested(&dev->_xmit_lock, subclass);
-       dev->xmit_lock_owner = smp_processor_id();
-}
-
 static void ieee80211_set_multicast_list(struct net_device *dev)
 {
        struct ieee80211_local *local = wdev_priv(dev->ieee80211_ptr);
        struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev);
-       unsigned short flags;
+       int allmulti, promisc, sdata_allmulti, sdata_promisc;
 
-       netif_tx_lock_nested(local->mdev, TX_LOCK_MASTER);
-       if (((dev->flags & IFF_ALLMULTI) != 0) ^
-           ((sdata->flags & IEEE80211_SDATA_ALLMULTI) != 0)) {
-               if (sdata->flags & IEEE80211_SDATA_ALLMULTI)
-                       local->iff_allmultis--;
-               else
+       allmulti = !!(dev->flags & IFF_ALLMULTI);
+       promisc = !!(dev->flags & IFF_PROMISC);
+       sdata_allmulti = sdata->flags & IEEE80211_SDATA_ALLMULTI;
+       sdata_promisc = sdata->flags & IEEE80211_SDATA_PROMISC;
+
+       if (allmulti != sdata_allmulti) {
+               if (dev->flags & IFF_ALLMULTI)
                        local->iff_allmultis++;
+               else
+                       local->iff_allmultis--;
                sdata->flags ^= IEEE80211_SDATA_ALLMULTI;
        }
-       if (((dev->flags & IFF_PROMISC) != 0) ^
-           ((sdata->flags & IEEE80211_SDATA_PROMISC) != 0)) {
-               if (sdata->flags & IEEE80211_SDATA_PROMISC)
-                       local->iff_promiscs--;
-               else
+
+       if (promisc != sdata_promisc) {
+               if (dev->flags & IFF_PROMISC)
                        local->iff_promiscs++;
+               else
+                       local->iff_promiscs--;
                sdata->flags ^= IEEE80211_SDATA_PROMISC;
        }
-       if (dev->mc_count != sdata->mc_count) {
-               local->mc_count = local->mc_count - sdata->mc_count +
-                                 dev->mc_count;
-               sdata->mc_count = dev->mc_count;
-       }
-       if (local->ops->set_multicast_list) {
-               flags = local->mdev->flags;
-               if (local->iff_allmultis)
-                       flags |= IFF_ALLMULTI;
-               if (local->iff_promiscs)
-                       flags |= IFF_PROMISC;
-               read_lock(&local->sub_if_lock);
-               local->ops->set_multicast_list(local_to_hw(local), flags,
-                                             local->mc_count);
-               read_unlock(&local->sub_if_lock);
-       }
-       netif_tx_unlock(local->mdev);
+
+       dev_mc_sync(local->mdev, dev);
 }
 
 static const struct header_ops ieee80211_header_ops = {
        struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev);
        struct ieee80211_local *local = wdev_priv(dev->ieee80211_ptr);
        struct ieee80211_if_conf conf;
-       static u8 scan_bssid[] = { 0xff, 0xff, 0xff, 0xff, 0xff, 0xff };
 
        if (!local->ops->config_interface || !netif_running(dev))
                return 0;
        conf.type = sdata->type;
        if (sdata->type == IEEE80211_IF_TYPE_STA ||
            sdata->type == IEEE80211_IF_TYPE_IBSS) {
-               if (local->sta_scanning &&
-                   local->scan_dev == dev)
-                       conf.bssid = scan_bssid;
-               else
-                       conf.bssid = sdata->u.sta.bssid;
+               conf.bssid = sdata->u.sta.bssid;
                conf.ssid = sdata->u.sta.ssid;
                conf.ssid_len = sdata->u.sta.ssid_len;
                conf.generic_elem = sdata->u.sta.extra_ie;
                                         IEEE80211_ERP_CHANGE_PREAMBLE);
 }
 
-struct dev_mc_list *ieee80211_get_mc_list_item(struct ieee80211_hw *hw,
-                                              struct dev_mc_list *prev,
-                                              void **ptr)
-{
-       struct ieee80211_local *local = hw_to_local(hw);
-       struct ieee80211_sub_if_data *sdata = *ptr;
-       struct dev_mc_list *mc;
-
-       if (!prev) {
-               WARN_ON(sdata);
-               sdata = NULL;
-       }
-       if (!prev || !prev->next) {
-               if (sdata)
-                       sdata = list_entry(sdata->list.next,
-                                          struct ieee80211_sub_if_data, list);
-               else
-                       sdata = list_entry(local->sub_if_list.next,
-                                          struct ieee80211_sub_if_data, list);
-               if (&sdata->list != &local->sub_if_list)
-                       mc = sdata->dev->mc_list;
-               else
-                       mc = NULL;
-       } else
-               mc = prev->next;
-
-       *ptr = sdata;
-       return mc;
-}
-EXPORT_SYMBOL(ieee80211_get_mc_list_item);
-
 void ieee80211_tx_status_irqsafe(struct ieee80211_hw *hw,
                                 struct sk_buff *skb,
                                 struct ieee80211_tx_status *status)
                           NETDEV_ALIGN_CONST) & ~NETDEV_ALIGN_CONST);
 
        BUG_ON(!ops->tx);
+       BUG_ON(!ops->start);
+       BUG_ON(!ops->stop);
        BUG_ON(!ops->config);
        BUG_ON(!ops->add_interface);
+       BUG_ON(!ops->remove_interface);
+       BUG_ON(!ops->configure_filter);
        local->ops = ops;
 
        /* for now, mdev needs sub_if_data :/ */
        mdev->stop = ieee80211_master_stop;
        mdev->type = ARPHRD_IEEE80211;
        mdev->header_ops = &ieee80211_header_ops;
+       mdev->set_multicast_list = ieee80211_master_set_multicast_list;
 
        sdata->type = IEEE80211_IF_TYPE_AP;
        sdata->dev = mdev;
 
        struct net_device *dev;
        struct ieee80211_local *local;
 
-       int mc_count;
-
        unsigned int flags;
 
        int drop_unencrypted;
        struct net_device *apdev; /* wlan#ap - management frames (hostapd) */
        int open_count;
        int monitors;
+       unsigned int filter_flags; /* FIF_* */
        struct iw_statistics wstats;
        u8 wstats_flags;
        int tx_headroom; /* required headroom for hardware/radiotap */
 
                printk(KERN_DEBUG "%s: failed to restore operational"
                       "channel after scan\n", dev->name);
 
-       if (!(local->hw.flags & IEEE80211_HW_NO_PROBE_FILTERING) &&
-           ieee80211_if_config(dev))
-               printk(KERN_DEBUG "%s: failed to restore operational"
-                      "BSSID after scan\n", dev->name);
+
+       netif_tx_lock_bh(local->mdev);
+       local->filter_flags &= ~FIF_BCN_PRBRESP_PROMISC;
+       local->ops->configure_filter(local_to_hw(local),
+                                    FIF_BCN_PRBRESP_PROMISC,
+                                    &local->filter_flags,
+                                    local->mdev->mc_count,
+                                    local->mdev->mc_list);
+
+       netif_tx_unlock_bh(local->mdev);
 
        memset(&wrqu, 0, sizeof(wrqu));
        wireless_send_event(dev, SIOCGIWSCAN, &wrqu, NULL);
        local->scan_channel_idx = 0;
        local->scan_dev = dev;
 
-       if (!(local->hw.flags & IEEE80211_HW_NO_PROBE_FILTERING) &&
-           ieee80211_if_config(dev))
-               printk(KERN_DEBUG "%s: failed to set BSSID for scan\n",
-                      dev->name);
+       netif_tx_lock_bh(local->mdev);
+       local->filter_flags |= FIF_BCN_PRBRESP_PROMISC;
+       local->ops->configure_filter(local_to_hw(local),
+                                    FIF_BCN_PRBRESP_PROMISC,
+                                    &local->filter_flags,
+                                    local->mdev->mc_count,
+                                    local->mdev->mc_list);
+       netif_tx_unlock_bh(local->mdev);
 
        /* TODO: start scan as soon as all nullfunc frames are ACKed */
        queue_delayed_work(local->hw.workqueue, &local->scan_work,
 
                } else if (!multicast &&
                           compare_ether_addr(sdata->dev->dev_addr,
                                              hdr->addr1) != 0) {
-                       if (!(sdata->flags & IEEE80211_SDATA_PROMISC))
+                       if (!(sdata->dev->flags & IFF_PROMISC))
                                return 0;
                        rx->flags &= ~IEEE80211_TXRXD_RXRA_MATCH;
                }
                } else if (!multicast &&
                           compare_ether_addr(sdata->dev->dev_addr,
                                              hdr->addr1) != 0) {
-                       if (!(sdata->flags & IEEE80211_SDATA_PROMISC))
+                       if (!(sdata->dev->flags & IFF_PROMISC))
                                return 0;
                        rx->flags &= ~IEEE80211_TXRXD_RXRA_MATCH;
                } else if (!rx->sta)