[PATCH] mac80211: revamp interface and filter configuration

Drivers are currently supposed to keep track of monitor
interfaces if they allow so-called "hard" monitor, and
they are also supposed to keep track of multicast etc.

This patch changes that, replaces the set_multicast_list()
callback with a new configure_filter() callback that takes
filter flags (FIF_*) instead of interface flags (IFF_*).
For a driver, this means it should open the filter as much
as necessary to get all frames requested by the filter flags.
Accordingly, the filter flags are named "positively", e.g.
FIF_ALLMULTI.

Multicast filtering is a bit special in that drivers that
have no multicast address filters need to allow multicast
frames through when either the FIF_ALLMULTI flag is set or
when the mc_count value is positive.

At the same time, drivers are no longer notified about
monitor interfaces at all, this means they now need to
implement the start() and stop() callbacks and the new
change_filter_flags() callback. Also, the start()/stop()
ordering changed, start() is now called *before* any
add_interface() as it really should be, and stop() after
any remove_interface().

The patch also changes the behaviour of setting the bssid
to multicast for scanning when IEEE80211_HW_NO_PROBE_FILTERING
is set; the IEEE80211_HW_NO_PROBE_FILTERING flag is removed
and the filter flag FIF_BCN_PRBRESP_PROMISC introduced.
This is a lot more efficient for hardware like b43 that
supports it and other hardware can still set the BSSID
to all-ones.

Driver modifications by Johannes Berg (b43 & iwlwifi), Michael Wu
(rtl8187, adm8211, and p54), Larry Finger (b43legacy), and
Ivo van Doorn (rt2x00).

Signed-off-by: Johannes Berg <johannes@sipsolutions.net>
Signed-off-by: Michael Wu <flamingice@sourmilk.net>
Signed-off-by: Larry Finger <Larry.Finger@lwfinger.net>
Signed-off-by: Ivo van Doorn <IvDoorn@gmail.com>
Signed-off-by: John W. Linville <linville@tuxdriver.com>
diff --git a/drivers/net/wireless/adm8211.c b/drivers/net/wireless/adm8211.c
index ac2ea23..49a6b9e 100644
--- a/drivers/net/wireless/adm8211.c
+++ b/drivers/net/wireless/adm8211.c
@@ -281,49 +281,6 @@
 	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)
 {
@@ -1254,13 +1211,6 @@
 
 	/* 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)
@@ -1334,7 +1284,7 @@
 	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;
@@ -1395,24 +1345,87 @@
 	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;
 }
@@ -1421,7 +1434,7 @@
 				     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)
@@ -1505,7 +1518,7 @@
 	}
 }
 
-static int adm8211_open(struct ieee80211_hw *dev)
+static int adm8211_start(struct ieee80211_hw *dev)
 {
 	struct adm8211_priv *priv = dev->priv;
 	int retval;
@@ -1550,7 +1563,7 @@
 	return retval;
 }
 
-static int adm8211_stop(struct ieee80211_hw *dev)
+static void adm8211_stop(struct ieee80211_hw *dev)
 {
 	struct adm8211_priv *priv = dev->priv;
 
@@ -1562,7 +1575,6 @@
 	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,
@@ -1765,13 +1777,13 @@
 
 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
@@ -1905,7 +1917,7 @@
 	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) {
@@ -2000,7 +2012,7 @@
 	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);
 	}
@@ -2018,8 +2030,8 @@
 	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);
 	}
 
diff --git a/drivers/net/wireless/adm8211.h b/drivers/net/wireless/adm8211.h
index 795d895..5991b17 100644
--- a/drivers/net/wireless/adm8211.h
+++ b/drivers/net/wireless/adm8211.h
@@ -612,7 +612,6 @@
 	u8 bssid[ETH_ALEN];
 	u8 ssid[32];
 	size_t ssid_len;
-	u8 *mac_addr;
 
 	u8 soft_rx_crc;
 	u8 retry_limit;
diff --git a/drivers/net/wireless/b43/b43.h b/drivers/net/wireless/b43/b43.h
index a22435a..2c8fa1c 100644
--- a/drivers/net/wireless/b43/b43.h
+++ b/drivers/net/wireless/b43/b43.h
@@ -604,9 +604,8 @@
 	 * 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. */
@@ -615,14 +614,10 @@
 	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;
 
@@ -779,8 +774,6 @@
 /* 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);
 }
 
diff --git a/drivers/net/wireless/b43/main.c b/drivers/net/wireless/b43/main.c
index b44c9f9..72467c8 100644
--- a/drivers/net/wireless/b43/main.c
+++ b/drivers/net/wireless/b43/main.c
@@ -92,14 +92,6 @@
 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)");
@@ -561,15 +553,10 @@
 	}
 }
 
-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)
@@ -2052,33 +2039,25 @@
 	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. */
@@ -2254,9 +2233,6 @@
 		    & ~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);
@@ -2899,9 +2875,9 @@
 	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;
@@ -3003,21 +2979,40 @@
 	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);
 }
 
@@ -3032,21 +3027,19 @@
 		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);
@@ -3472,7 +3465,8 @@
 
 	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);
 
@@ -3502,46 +3496,34 @@
 	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;
-	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) {
-			if (did_init)
-				b43_wireless_core_exit(dev);
-			goto out_mutex_unlock;
-		}
-	}
+	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);
-	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);
+	b43_upload_card_macaddress(dev);
 	spin_unlock_irqrestore(&wl->irq_lock, flags);
 
 	err = 0;
-      out_mutex_unlock:
+ out_mutex_unlock:
 	mutex_unlock(&wl->mutex);
 
 	return err;
@@ -3551,34 +3533,67 @@
 				 struct ieee80211_if_init_conf *conf)
 {
 	struct b43_wl *wl = hw_to_b43_wl(hw);
-	struct b43_wldev *dev;
+	struct b43_wldev *dev = wl->current_dev;
 	unsigned long flags;
 
 	b43dbg(wl, "Removing Interface type %d\n", conf->type);
 
 	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;
+
+	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;
 	}
 
-	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) {
+		err = b43_wireless_core_start(dev);
+		if (err) {
+			if (did_init)
+				b43_wireless_core_exit(dev);
+			goto out_mutex_unlock;
+		}
 	}
+
+ out_mutex_unlock:
+	mutex_unlock(&wl->mutex);
+
+	return err;
+}
+
+void b43_stop(struct ieee80211_hw *hw)
+{
+	struct b43_wl *wl = hw_to_b43_wl(hw);
+	struct b43_wldev *dev = wl->current_dev;
+
+	mutex_lock(&wl->mutex);
+	if (b43_status(dev) >= B43_STAT_STARTED)
+		b43_wireless_core_stop(dev);
+	b43_wireless_core_exit(dev);
 	mutex_unlock(&wl->mutex);
 }
 
@@ -3589,10 +3604,12 @@
 	.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.
@@ -3930,8 +3947,7 @@
 	}
 
 	/* 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;
diff --git a/drivers/net/wireless/b43legacy/b43legacy.h b/drivers/net/wireless/b43legacy/b43legacy.h
index 746de2f..afe145c 100644
--- a/drivers/net/wireless/b43legacy/b43legacy.h
+++ b/drivers/net/wireless/b43legacy/b43legacy.h
@@ -179,6 +179,7 @@
 #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) */
@@ -570,25 +571,20 @@
 	 * 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;
 
@@ -753,8 +749,6 @@
 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);
 }
diff --git a/drivers/net/wireless/b43legacy/main.c b/drivers/net/wireless/b43legacy/main.c
index a793f18..f074951 100644
--- a/drivers/net/wireless/b43legacy/main.c
+++ b/drivers/net/wireless/b43legacy/main.c
@@ -91,14 +91,6 @@
 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),
@@ -566,12 +558,11 @@
 	}
 }
 
-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,
@@ -1874,34 +1865,25 @@
 	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. */
@@ -2091,10 +2073,6 @@
 	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);
@@ -2699,7 +2677,7 @@
 }
 
 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)
 {
@@ -2724,22 +2702,42 @@
 	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);
 }
 
@@ -2755,21 +2753,19 @@
 		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);
@@ -3216,8 +3212,9 @@
 	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);
 
@@ -3246,47 +3243,34 @@
 	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;
-	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) {
-			if (did_init)
-				b43legacy_wireless_core_exit(dev);
-			goto out_mutex_unlock;
-		}
-	}
+	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);
-	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);
+	b43legacy_upload_card_macaddress(dev);
 	spin_unlock_irqrestore(&wl->irq_lock, flags);
 
 	err = 0;
-out_mutex_unlock:
+ out_mutex_unlock:
 	mutex_unlock(&wl->mutex);
 
 	return err;
@@ -3296,34 +3280,67 @@
 				       struct ieee80211_if_init_conf *conf)
 {
 	struct b43legacy_wl *wl = hw_to_b43legacy_wl(hw);
-	struct b43legacy_wldev *dev;
+	struct b43legacy_wldev *dev = wl->current_dev;
 	unsigned long flags;
 
 	b43legacydbg(wl, "Removing Interface type %d\n", conf->type);
 
 	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;
+
+	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;
 	}
 
-	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) {
+		err = b43legacy_wireless_core_start(dev);
+		if (err) {
+			if (did_init)
+				b43legacy_wireless_core_exit(dev);
+			goto out_mutex_unlock;
+		}
 	}
+
+out_mutex_unlock:
+	mutex_unlock(&wl->mutex);
+
+	return err;
+}
+
+void b43legacy_stop(struct ieee80211_hw *hw)
+{
+	struct b43legacy_wl *wl = hw_to_b43legacy_wl(hw);
+	struct b43legacy_wldev *dev = wl->current_dev;
+
+	mutex_lock(&wl->mutex);
+	if (b43legacy_status(dev) >= B43legacy_STAT_STARTED)
+		b43legacy_wireless_core_stop(dev);
+	b43legacy_wireless_core_exit(dev);
 	mutex_unlock(&wl->mutex);
 }
 
@@ -3336,9 +3353,11 @@
 	.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.
diff --git a/drivers/net/wireless/iwlwifi/iwl3945-base.c b/drivers/net/wireless/iwlwifi/iwl3945-base.c
index 44f983b..8acda64 100644
--- a/drivers/net/wireless/iwlwifi/iwl3945-base.c
+++ b/drivers/net/wireless/iwlwifi/iwl3945-base.c
@@ -6870,7 +6870,7 @@
  *
  *****************************************************************************/
 
-static int iwl_mac_open(struct ieee80211_hw *hw)
+static int iwl_mac_start(struct ieee80211_hw *hw)
 {
 	struct iwl_priv *priv = hw->priv;
 
@@ -6889,7 +6889,7 @@
 	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;
 
@@ -6898,8 +6898,6 @@
 	/*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,
@@ -7115,6 +7113,8 @@
 	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
@@ -7129,8 +7129,13 @@
 		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;
@@ -7205,6 +7210,18 @@
 	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)
 {
@@ -8265,12 +8282,13 @@
 
 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,
diff --git a/drivers/net/wireless/iwlwifi/iwl4965-base.c b/drivers/net/wireless/iwlwifi/iwl4965-base.c
index 61500a2..7b9227c 100644
--- a/drivers/net/wireless/iwlwifi/iwl4965-base.c
+++ b/drivers/net/wireless/iwlwifi/iwl4965-base.c
@@ -7252,7 +7252,7 @@
  *
  *****************************************************************************/
 
-static int iwl_mac_open(struct ieee80211_hw *hw)
+static int iwl_mac_start(struct ieee80211_hw *hw)
 {
 	struct iwl_priv *priv = hw->priv;
 
@@ -7271,7 +7271,7 @@
 	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;
 
@@ -7280,8 +7280,6 @@
 	/*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,
@@ -7528,8 +7526,13 @@
 		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;
@@ -7604,6 +7607,18 @@
 	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)
 {
@@ -8852,12 +8867,13 @@
 
 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,
diff --git a/drivers/net/wireless/p54.h b/drivers/net/wireless/p54.h
index e558d69..744c866 100644
--- a/drivers/net/wireless/p54.h
+++ b/drivers/net/wireless/p54.h
@@ -52,7 +52,8 @@
 	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;
diff --git a/drivers/net/wireless/p54common.c b/drivers/net/wireless/p54common.c
index b05b5c5..9befd6c 100644
--- a/drivers/net/wireless/p54common.c
+++ b/drivers/net/wireless/p54common.c
@@ -774,15 +774,39 @@
 	priv->tx(dev, hdr, sizeof(*hdr) + sizeof(*vdcf), 0);
 }
 
-static int p54_add_interface(struct ieee80211_hw *dev,
-			     struct ieee80211_if_init_conf *conf)
+static int p54_start(struct ieee80211_hw *dev)
 {
 	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;
+	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;
+
+	if (priv->mode != IEEE80211_IF_TYPE_MNTR)
+		return -EOPNOTSUPP;
 
 	switch (conf->type) {
 	case IEEE80211_IF_TYPE_STA:
@@ -792,23 +816,18 @@
 		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);
@@ -820,15 +839,9 @@
 				 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)
@@ -848,9 +861,29 @@
 	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)
 {
@@ -893,10 +926,13 @@
 
 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
diff --git a/drivers/net/wireless/rt2x00/rt2400pci.c b/drivers/net/wireless/rt2x00/rt2400pci.c
index 398c201..03a94a3 100644
--- a/drivers/net/wireless/rt2x00/rt2400pci.c
+++ b/drivers/net/wireless/rt2x00/rt2400pci.c
@@ -277,55 +277,14 @@
 	rt2x00pci_register_multiwrite(rt2x00dev, CSR5, &reg, 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, &reg);
-	rt2x00_set_field32(&reg, 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, &reg);
-
-	if (!is_monitor_present(&rt2x00dev->interface) &&
-	    (type == IEEE80211_IF_TYPE_IBSS || type == IEEE80211_IF_TYPE_STA))
-		rt2x00_set_field32(&reg, RXCSR0_DROP_TODS, 1);
-	else
-		rt2x00_set_field32(&reg, 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(&reg, RXCSR0_DROP_CRC, 1);
-		rt2x00_set_field32(&reg, RXCSR0_DROP_PHYSICAL, 1);
-		rt2x00_set_field32(&reg, RXCSR0_DROP_CONTROL, 1);
-		rt2x00_set_field32(&reg, RXCSR0_DROP_VERSION_ERROR, 1);
-	} else if (is_monitor_present(&rt2x00dev->interface)) {
-		rt2x00_set_field32(&reg, RXCSR0_DROP_CRC, 0);
-		rt2x00_set_field32(&reg, RXCSR0_DROP_PHYSICAL, 0);
-		rt2x00_set_field32(&reg, RXCSR0_DROP_CONTROL, 0);
-		rt2x00_set_field32(&reg, RXCSR0_DROP_VERSION_ERROR, 0);
-	}
-
-	rt2x00pci_register_write(rt2x00dev, RXCSR0, reg);
-
-	/*
 	 * Enable beacon config
 	 */
 	rt2x00pci_register_read(rt2x00dev, BCNCSR1, &reg);
@@ -337,20 +296,16 @@
 	 * Enable synchronisation.
 	 */
 	rt2x00pci_register_read(rt2x00dev, CSR14, &reg);
-	if (is_interface_present(&rt2x00dev->interface)) {
-		rt2x00_set_field32(&reg, CSR14_TSF_COUNT, 1);
-		rt2x00_set_field32(&reg, CSR14_TBCN, 1);
-	}
-
+	rt2x00_set_field32(&reg, CSR14_TSF_COUNT, 1);
+	rt2x00_set_field32(&reg, CSR14_TBCN, 1);
 	rt2x00_set_field32(&reg, 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(&reg, CSR14_TSF_SYNC, 2);
-	else if (type == IEEE80211_IF_TYPE_STA)
+	else if (is_interface_type(intf, IEEE80211_IF_TYPE_STA))
 		rt2x00_set_field32(&reg, CSR14_TSF_SYNC, 1);
-	else if (is_monitor_present(&rt2x00dev->interface) &&
-		 !is_interface_present(&rt2x00dev->interface))
+	else
 		rt2x00_set_field32(&reg, CSR14_TSF_SYNC, 0);
-
 	rt2x00pci_register_write(rt2x00dev, CSR14, reg);
 }
 
@@ -1104,7 +1059,7 @@
  */
 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)
@@ -1200,8 +1155,8 @@
 /*
  * 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;
@@ -1210,20 +1165,20 @@
 	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);
 }
 
 /*
@@ -1460,10 +1415,7 @@
 	/*
 	 * 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;
@@ -1530,6 +1482,68 @@
 /*
  * 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, &reg);
+	rt2x00_set_field32(&reg, RXCSR0_DROP_CRC,
+			   !(*total_flags & FIF_FCSFAIL));
+	rt2x00_set_field32(&reg, RXCSR0_DROP_PHYSICAL,
+			   !(*total_flags & FIF_PLCPFAIL));
+	rt2x00_set_field32(&reg, RXCSR0_DROP_CONTROL,
+			   !(*total_flags & FIF_CONTROL));
+	rt2x00_set_field32(&reg, RXCSR0_DROP_NOT_TO_ME,
+			   !(*total_flags & FIF_PROMISC_IN_BSS));
+	rt2x00_set_field32(&reg, RXCSR0_DROP_TODS,
+			   !(*total_flags & FIF_PROMISC_IN_BSS));
+	rt2x00_set_field32(&reg, 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)
 {
@@ -1602,11 +1616,13 @@
 
 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,
@@ -1635,7 +1651,6 @@
 	.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,
 };
diff --git a/drivers/net/wireless/rt2x00/rt2500pci.c b/drivers/net/wireless/rt2x00/rt2500pci.c
index e8d63aa..892baa9 100644
--- a/drivers/net/wireless/rt2x00/rt2500pci.c
+++ b/drivers/net/wireless/rt2x00/rt2500pci.c
@@ -277,59 +277,14 @@
 	rt2x00pci_register_multiwrite(rt2x00dev, CSR5, &reg, 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, &reg);
-	rt2x00_set_field32(&reg, RXCSR0_DROP_NOT_TO_ME, !promisc);
-	rt2x00_set_field32(&reg, RXCSR0_DROP_MCAST, !multicast);
-	rt2x00_set_field32(&reg, 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, &reg);
-
-	if (!is_monitor_present(&rt2x00dev->interface) &&
-	    (type == IEEE80211_IF_TYPE_IBSS || type == IEEE80211_IF_TYPE_STA))
-		rt2x00_set_field32(&reg, RXCSR0_DROP_TODS, 1);
-	else
-		rt2x00_set_field32(&reg, 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(&reg, RXCSR0_DROP_CRC, 1);
-		rt2x00_set_field32(&reg, RXCSR0_DROP_PHYSICAL, 1);
-		rt2x00_set_field32(&reg, RXCSR0_DROP_CONTROL, 1);
-		rt2x00_set_field32(&reg, RXCSR0_DROP_VERSION_ERROR, 1);
-	} else if (is_monitor_present(&rt2x00dev->interface)) {
-		rt2x00_set_field32(&reg, RXCSR0_DROP_CRC, 0);
-		rt2x00_set_field32(&reg, RXCSR0_DROP_PHYSICAL, 0);
-		rt2x00_set_field32(&reg, RXCSR0_DROP_CONTROL, 0);
-		rt2x00_set_field32(&reg, RXCSR0_DROP_VERSION_ERROR, 0);
-	}
-
-	rt2x00pci_register_write(rt2x00dev, RXCSR0, reg);
-
-	/*
 	 * Enable beacon config
 	 */
 	rt2x00pci_register_read(rt2x00dev, BCNCSR1, &reg);
@@ -345,20 +300,16 @@
 	 * Enable synchronisation.
 	 */
 	rt2x00pci_register_read(rt2x00dev, CSR14, &reg);
-	if (is_interface_present(&rt2x00dev->interface)) {
-		rt2x00_set_field32(&reg, CSR14_TSF_COUNT, 1);
-		rt2x00_set_field32(&reg, CSR14_TBCN, 1);
-	}
-
+	rt2x00_set_field32(&reg, CSR14_TSF_COUNT, 1);
+	rt2x00_set_field32(&reg, CSR14_TBCN, 1);
 	rt2x00_set_field32(&reg, 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(&reg, CSR14_TSF_SYNC, 2);
-	else if (type == IEEE80211_IF_TYPE_STA)
+	else if (is_interface_type(intf, IEEE80211_IF_TYPE_STA))
 		rt2x00_set_field32(&reg, CSR14_TSF_SYNC, 1);
-	else if (is_monitor_present(&rt2x00dev->interface) &&
-		 !is_interface_present(&rt2x00dev->interface))
+	else
 		rt2x00_set_field32(&reg, CSR14_TSF_SYNC, 0);
-
 	rt2x00pci_register_write(rt2x00dev, CSR14, reg);
 }
 
@@ -1269,7 +1220,7 @@
  */
 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)
@@ -1349,8 +1300,8 @@
 /*
  * 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;
@@ -1359,18 +1310,17 @@
 	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);
 }
 
 /*
@@ -1779,10 +1729,7 @@
 	/*
 	 * 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;
@@ -1867,6 +1814,73 @@
 /*
  * 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, &reg);
+	rt2x00_set_field32(&reg, RXCSR0_DROP_CRC,
+			   !(*total_flags & FIF_FCSFAIL));
+	rt2x00_set_field32(&reg, RXCSR0_DROP_PHYSICAL,
+			   !(*total_flags & FIF_PLCPFAIL));
+	rt2x00_set_field32(&reg, RXCSR0_DROP_CONTROL,
+			   !(*total_flags & FIF_CONTROL));
+	rt2x00_set_field32(&reg, RXCSR0_DROP_NOT_TO_ME,
+			   !(*total_flags & FIF_PROMISC_IN_BSS));
+	rt2x00_set_field32(&reg, RXCSR0_DROP_TODS,
+			   !(*total_flags & FIF_PROMISC_IN_BSS));
+	rt2x00_set_field32(&reg, RXCSR0_DROP_VERSION_ERROR, 1);
+	rt2x00_set_field32(&reg, RXCSR0_DROP_MCAST,
+			   !(*total_flags & FIF_ALLMULTI));
+	rt2x00_set_field32(&reg, 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)
 {
@@ -1914,11 +1928,13 @@
 
 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,
@@ -1947,7 +1963,6 @@
 	.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,
 };
diff --git a/drivers/net/wireless/rt2x00/rt2500usb.c b/drivers/net/wireless/rt2x00/rt2500usb.c
index 614600c..f4e6f6e 100644
--- a/drivers/net/wireless/rt2x00/rt2500usb.c
+++ b/drivers/net/wireless/rt2x00/rt2500usb.c
@@ -282,65 +282,20 @@
 	rt2500usb_register_multiwrite(rt2x00dev, MAC_CSR5, &reg, 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, &reg);
-	rt2x00_set_field16(&reg, TXRX_CSR2_DROP_NOT_TO_ME, !promisc);
-	rt2x00_set_field16(&reg, TXRX_CSR2_DROP_MULTICAST, !multicast);
-	rt2x00_set_field16(&reg, 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, &reg);
-
-	if (!is_monitor_present(&rt2x00dev->interface) &&
-	    (type == IEEE80211_IF_TYPE_IBSS || type == IEEE80211_IF_TYPE_STA))
-		rt2x00_set_field16(&reg, TXRX_CSR2_DROP_TODS, 1);
-	else
-		rt2x00_set_field16(&reg, 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(&reg, TXRX_CSR2_DROP_CRC, 1);
-		rt2x00_set_field16(&reg, TXRX_CSR2_DROP_PHYSICAL, 1);
-		rt2x00_set_field16(&reg, TXRX_CSR2_DROP_CONTROL, 1);
-		rt2x00_set_field16(&reg, TXRX_CSR2_DROP_VERSION_ERROR, 1);
-	} else if (is_monitor_present(&rt2x00dev->interface)) {
-		rt2x00_set_field16(&reg, TXRX_CSR2_DROP_CRC, 0);
-		rt2x00_set_field16(&reg, TXRX_CSR2_DROP_PHYSICAL, 0);
-		rt2x00_set_field16(&reg, TXRX_CSR2_DROP_CONTROL, 0);
-		rt2x00_set_field16(&reg, TXRX_CSR2_DROP_VERSION_ERROR, 0);
-	}
-
-	rt2500usb_register_write(rt2x00dev, TXRX_CSR2, reg);
-
-	/*
 	 * Enable beacon config
 	 */
 	rt2500usb_register_read(rt2x00dev, TXRX_CSR20, &reg);
 	rt2x00_set_field16(&reg, 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(&reg, TXRX_CSR20_BCN_EXPECT_WINDOW, 0);
 	else
 		rt2x00_set_field16(&reg, TXRX_CSR20_BCN_EXPECT_WINDOW, 2);
@@ -354,20 +309,16 @@
 	rt2500usb_register_write(rt2x00dev, TXRX_CSR18, reg);
 
 	rt2500usb_register_read(rt2x00dev, TXRX_CSR19, &reg);
-	if (is_interface_present(&rt2x00dev->interface)) {
-		rt2x00_set_field16(&reg, TXRX_CSR19_TSF_COUNT, 1);
-		rt2x00_set_field16(&reg, TXRX_CSR19_TBCN, 1);
-	}
-
+	rt2x00_set_field16(&reg, TXRX_CSR19_TSF_COUNT, 1);
+	rt2x00_set_field16(&reg, TXRX_CSR19_TBCN, 1);
 	rt2x00_set_field16(&reg, 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(&reg, 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(&reg, TXRX_CSR19_TSF_SYNC, 1);
-	else if (is_monitor_present(&rt2x00dev->interface) &&
-		 !is_interface_present(&rt2x00dev->interface))
+	else
 		rt2x00_set_field16(&reg, TXRX_CSR19_TSF_SYNC, 0);
-
 	rt2500usb_register_write(rt2x00dev, TXRX_CSR19, reg);
 }
 
@@ -1084,7 +1035,7 @@
  */
 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)
@@ -1156,8 +1107,8 @@
 /*
  * 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 +
@@ -1169,21 +1120,22 @@
 	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;
 }
 
 /*
@@ -1549,9 +1501,7 @@
 	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;
@@ -1621,10 +1571,8 @@
 	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);
 
 	/*
@@ -1638,6 +1586,82 @@
 /*
  * 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, &reg);
+	rt2x00_set_field16(&reg, TXRX_CSR2_DROP_CRC,
+			   !(*total_flags & FIF_FCSFAIL));
+	rt2x00_set_field16(&reg, TXRX_CSR2_DROP_PHYSICAL,
+			   !(*total_flags & FIF_PLCPFAIL));
+	rt2x00_set_field16(&reg, TXRX_CSR2_DROP_CONTROL,
+			   !(*total_flags & FIF_CONTROL));
+	rt2x00_set_field16(&reg, TXRX_CSR2_DROP_NOT_TO_ME,
+			   !(*total_flags & FIF_PROMISC_IN_BSS));
+	rt2x00_set_field16(&reg, TXRX_CSR2_DROP_TODS,
+			   !(*total_flags & FIF_PROMISC_IN_BSS));
+	rt2x00_set_field16(&reg, TXRX_CSR2_DROP_VERSION_ERROR, 1);
+	rt2x00_set_field16(&reg, TXRX_CSR2_DROP_MULTICAST,
+			   !(*total_flags & FIF_ALLMULTI));
+	rt2x00_set_field16(&reg, 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)
@@ -1714,11 +1738,13 @@
 
 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,
@@ -1739,7 +1765,6 @@
 	.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,
 };
diff --git a/drivers/net/wireless/rt2x00/rt2x00.h b/drivers/net/wireless/rt2x00/rt2x00.h
index 80b079d..046eecf 100644
--- a/drivers/net/wireless/rt2x00/rt2x00.h
+++ b/drivers/net/wireless/rt2x00/rt2x00.h
@@ -294,9 +294,6 @@
 
 	/*
 	 * 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;
@@ -314,18 +311,8 @@
 
 	/*
 	 * 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)
@@ -333,9 +320,9 @@
 	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;
 }
 
 /*
@@ -402,7 +389,7 @@
 	 */
 	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);
@@ -415,8 +402,8 @@
 	/*
 	 * 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.
@@ -511,11 +498,10 @@
 #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
@@ -606,9 +592,10 @@
 	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.
@@ -760,7 +747,7 @@
 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
@@ -785,8 +772,6 @@
 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,
diff --git a/drivers/net/wireless/rt2x00/rt2x00config.c b/drivers/net/wireless/rt2x00/rt2x00config.c
index de890a1..f962ce4 100644
--- a/drivers/net/wireless/rt2x00/rt2x00config.c
+++ b/drivers/net/wireless/rt2x00/rt2x00config.c
@@ -46,72 +46,24 @@
 		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)
diff --git a/drivers/net/wireless/rt2x00/rt2x00dev.c b/drivers/net/wireless/rt2x00/rt2x00dev.c
index cd82eef..bbccb89 100644
--- a/drivers/net/wireless/rt2x00/rt2x00dev.c
+++ b/drivers/net/wireless/rt2x00/rt2x00dev.c
@@ -135,10 +135,12 @@
 		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.
@@ -257,6 +259,17 @@
 			   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.
  */
@@ -337,7 +350,7 @@
 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;
@@ -358,22 +371,24 @@
 		 * 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
@@ -391,7 +406,7 @@
 			     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;
@@ -956,6 +971,7 @@
 	 * 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);
 
 	/*
@@ -1098,7 +1114,6 @@
 	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,
diff --git a/drivers/net/wireless/rt2x00/rt2x00lib.h b/drivers/net/wireless/rt2x00/rt2x00lib.h
index 3324090..fcc2ffd 100644
--- a/drivers/net/wireless/rt2x00/rt2x00lib.h
+++ b/drivers/net/wireless/rt2x00/rt2x00lib.h
@@ -51,7 +51,6 @@
  */
 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);
 
diff --git a/drivers/net/wireless/rt2x00/rt2x00mac.c b/drivers/net/wireless/rt2x00/rt2x00mac.c
index 778ed41..17802f6 100644
--- a/drivers/net/wireless/rt2x00/rt2x00mac.c
+++ b/drivers/net/wireless/rt2x00/rt2x00mac.c
@@ -176,46 +176,26 @@
 {
 	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;
+	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);
 
 	/*
-	 * 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;
-	}
-
-	/*
-	 * 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;
 }
@@ -230,22 +210,13 @@
 	/*
 	 * 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
@@ -254,12 +225,6 @@
 	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);
 
@@ -290,14 +255,6 @@
 	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.
 	 */
 	if (test_bit(DEVICE_ENABLED_RADIO, &rt2x00dev->flags))
@@ -326,13 +283,10 @@
 		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;
 
 	/*
@@ -360,36 +314,6 @@
 }
 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)
 {
diff --git a/drivers/net/wireless/rt2x00/rt2x00pci.c b/drivers/net/wireless/rt2x00/rt2x00pci.c
index 85629f1..2780df0 100644
--- a/drivers/net/wireless/rt2x00/rt2x00pci.c
+++ b/drivers/net/wireless/rt2x00/rt2x00pci.c
@@ -124,47 +124,40 @@
 	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);
diff --git a/drivers/net/wireless/rt2x00/rt2x00rfkill.c b/drivers/net/wireless/rt2x00/rt2x00rfkill.c
index dc5b696..b54457c 100644
--- a/drivers/net/wireless/rt2x00/rt2x00rfkill.c
+++ b/drivers/net/wireless/rt2x00/rt2x00rfkill.c
@@ -45,11 +45,9 @@
 		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) {
diff --git a/drivers/net/wireless/rt2x00/rt2x00ring.h b/drivers/net/wireless/rt2x00/rt2x00ring.h
index 122c752..1a864d3 100644
--- a/drivers/net/wireless/rt2x00/rt2x00ring.h
+++ b/drivers/net/wireless/rt2x00/rt2x00ring.h
@@ -41,11 +41,24 @@
 };
 
 /*
- * 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
diff --git a/drivers/net/wireless/rt2x00/rt2x00usb.c b/drivers/net/wireless/rt2x00/rt2x00usb.c
index a0f05ca..8d20811 100644
--- a/drivers/net/wireless/rt2x00/rt2x00usb.c
+++ b/drivers/net/wireless/rt2x00/rt2x00usb.c
@@ -220,11 +220,7 @@
 	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) ||
@@ -239,10 +235,8 @@
 	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.
@@ -261,12 +255,12 @@
 	 * 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,
diff --git a/drivers/net/wireless/rt2x00/rt61pci.c b/drivers/net/wireless/rt2x00/rt61pci.c
index 09c8c96..dea7a8a 100644
--- a/drivers/net/wireless/rt2x00/rt61pci.c
+++ b/drivers/net/wireless/rt2x00/rt61pci.c
@@ -312,23 +312,9 @@
 	rt2x00pci_register_multiwrite(rt2x00dev, MAC_CSR4, &reg, 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, &reg);
-	rt2x00_set_field32(&reg, TXRX_CSR0_DROP_NOT_TO_ME, !promisc);
-	rt2x00_set_field32(&reg, TXRX_CSR0_DROP_MULTICAST, !multicast);
-	rt2x00_set_field32(&reg, 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;
 
 	/*
@@ -344,56 +330,19 @@
 	rt2x00pci_register_write(rt2x00dev, HW_BEACON_BASE3, 0);
 
 	/*
-	 * Apply hardware packet filter.
-	 */
-	rt2x00pci_register_read(rt2x00dev, TXRX_CSR0, &reg);
-
-	if (!is_monitor_present(&rt2x00dev->interface) &&
-	    (type == IEEE80211_IF_TYPE_IBSS || type == IEEE80211_IF_TYPE_STA))
-		rt2x00_set_field32(&reg, TXRX_CSR0_DROP_TO_DS, 1);
-	else
-		rt2x00_set_field32(&reg, 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(&reg, TXRX_CSR0_DROP_CRC, 1);
-		rt2x00_set_field32(&reg, TXRX_CSR0_DROP_PHYSICAL, 1);
-		rt2x00_set_field32(&reg, TXRX_CSR0_DROP_CONTROL, 1);
-		rt2x00_set_field32(&reg, TXRX_CSR0_DROP_VERSION_ERROR, 1);
-		rt2x00_set_field32(&reg, TXRX_CSR0_DROP_ACK_CTS, 1);
-	} else if (is_monitor_present(&rt2x00dev->interface)) {
-		rt2x00_set_field32(&reg, TXRX_CSR0_DROP_CRC, 0);
-		rt2x00_set_field32(&reg, TXRX_CSR0_DROP_PHYSICAL, 0);
-		rt2x00_set_field32(&reg, TXRX_CSR0_DROP_CONTROL, 0);
-		rt2x00_set_field32(&reg, TXRX_CSR0_DROP_VERSION_ERROR, 0);
-		rt2x00_set_field32(&reg, TXRX_CSR0_DROP_ACK_CTS, 0);
-	}
-
-	rt2x00pci_register_write(rt2x00dev, TXRX_CSR0, reg);
-
-	/*
 	 * Enable synchronisation.
 	 */
 	rt2x00pci_register_read(rt2x00dev, TXRX_CSR9, &reg);
-	if (is_interface_present(&rt2x00dev->interface)) {
-		rt2x00_set_field32(&reg, TXRX_CSR9_TSF_TICKING, 1);
-		rt2x00_set_field32(&reg, TXRX_CSR9_TBTT_ENABLE, 1);
-	}
-
+	rt2x00_set_field32(&reg, TXRX_CSR9_TSF_TICKING, 1);
+	rt2x00_set_field32(&reg, TXRX_CSR9_TBTT_ENABLE, 1);
 	rt2x00_set_field32(&reg, 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(&reg, 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(&reg, TXRX_CSR9_TSF_SYNC, 1);
-	else if (is_monitor_present(&rt2x00dev->interface) &&
-		 !is_interface_present(&rt2x00dev->interface))
+	else
 		rt2x00_set_field32(&reg, TXRX_CSR9_TSF_SYNC, 0);
-
 	rt2x00pci_register_write(rt2x00dev, TXRX_CSR9, reg);
 }
 
@@ -1686,7 +1635,7 @@
  */
 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)
@@ -1826,8 +1775,8 @@
 	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;
@@ -1836,19 +1785,19 @@
 	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;
 }
 
 /*
@@ -2340,9 +2289,7 @@
 	 */
 	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;
@@ -2426,6 +2373,74 @@
 /*
  * 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, &reg);
+	rt2x00_set_field32(&reg, TXRX_CSR0_DROP_CRC,
+			   !(*total_flags & FIF_FCSFAIL));
+	rt2x00_set_field32(&reg, TXRX_CSR0_DROP_PHYSICAL,
+			   !(*total_flags & FIF_PLCPFAIL));
+	rt2x00_set_field32(&reg, TXRX_CSR0_DROP_CONTROL,
+			   !(*total_flags & FIF_CONTROL));
+	rt2x00_set_field32(&reg, TXRX_CSR0_DROP_NOT_TO_ME,
+			   !(*total_flags & FIF_PROMISC_IN_BSS));
+	rt2x00_set_field32(&reg, TXRX_CSR0_DROP_TO_DS,
+			   !(*total_flags & FIF_PROMISC_IN_BSS));
+	rt2x00_set_field32(&reg, TXRX_CSR0_DROP_VERSION_ERROR, 1);
+	rt2x00_set_field32(&reg, TXRX_CSR0_DROP_MULTICAST,
+			   !(*total_flags & FIF_ALLMULTI));
+	rt2x00_set_field32(&reg, TXRX_CSR0_DROP_BORADCAST, 0);
+	rt2x00_set_field32(&reg, 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)
 {
@@ -2506,11 +2521,13 @@
 
 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,
@@ -2540,7 +2557,6 @@
 	.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,
 };
diff --git a/drivers/net/wireless/rt2x00/rt73usb.c b/drivers/net/wireless/rt2x00/rt73usb.c
index 3397881..aac13aa 100644
--- a/drivers/net/wireless/rt2x00/rt73usb.c
+++ b/drivers/net/wireless/rt2x00/rt73usb.c
@@ -293,23 +293,9 @@
 	rt73usb_register_multiwrite(rt2x00dev, MAC_CSR4, &reg, 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, &reg);
-	rt2x00_set_field32(&reg, TXRX_CSR0_DROP_NOT_TO_ME, !promisc);
-	rt2x00_set_field32(&reg, TXRX_CSR0_DROP_MULTICAST, !multicast);
-	rt2x00_set_field32(&reg, 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;
 
 	/*
@@ -325,56 +311,19 @@
 	rt73usb_register_write(rt2x00dev, HW_BEACON_BASE3, 0);
 
 	/*
-	 * Apply hardware packet filter.
-	 */
-	rt73usb_register_read(rt2x00dev, TXRX_CSR0, &reg);
-
-	if (!is_monitor_present(&rt2x00dev->interface) &&
-	    (type == IEEE80211_IF_TYPE_IBSS || type == IEEE80211_IF_TYPE_STA))
-		rt2x00_set_field32(&reg, TXRX_CSR0_DROP_TO_DS, 1);
-	else
-		rt2x00_set_field32(&reg, 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(&reg, TXRX_CSR0_DROP_CRC, 1);
-		rt2x00_set_field32(&reg, TXRX_CSR0_DROP_PHYSICAL, 1);
-		rt2x00_set_field32(&reg, TXRX_CSR0_DROP_CONTROL, 1);
-		rt2x00_set_field32(&reg, TXRX_CSR0_DROP_VERSION_ERROR, 1);
-		rt2x00_set_field32(&reg, TXRX_CSR0_DROP_ACK_CTS, 1);
-	} else if (is_monitor_present(&rt2x00dev->interface)) {
-		rt2x00_set_field32(&reg, TXRX_CSR0_DROP_CRC, 0);
-		rt2x00_set_field32(&reg, TXRX_CSR0_DROP_PHYSICAL, 0);
-		rt2x00_set_field32(&reg, TXRX_CSR0_DROP_CONTROL, 0);
-		rt2x00_set_field32(&reg, TXRX_CSR0_DROP_VERSION_ERROR, 0);
-		rt2x00_set_field32(&reg, TXRX_CSR0_DROP_ACK_CTS, 0);
-	}
-
-	rt73usb_register_write(rt2x00dev, TXRX_CSR0, reg);
-
-	/*
 	 * Enable synchronisation.
 	 */
 	rt73usb_register_read(rt2x00dev, TXRX_CSR9, &reg);
-	if (is_interface_present(&rt2x00dev->interface)) {
-		rt2x00_set_field32(&reg, TXRX_CSR9_TSF_TICKING, 1);
-		rt2x00_set_field32(&reg, TXRX_CSR9_TBTT_ENABLE, 1);
-	}
-
+	rt2x00_set_field32(&reg, TXRX_CSR9_TSF_TICKING, 1);
+	rt2x00_set_field32(&reg, TXRX_CSR9_TBTT_ENABLE, 1);
 	rt2x00_set_field32(&reg, 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(&reg, 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(&reg, TXRX_CSR9_TSF_SYNC, 1);
-	else if (is_monitor_present(&rt2x00dev->interface) &&
-		 !is_interface_present(&rt2x00dev->interface))
+	else
 		rt2x00_set_field32(&reg, TXRX_CSR9_TSF_SYNC, 0);
-
 	rt73usb_register_write(rt2x00dev, TXRX_CSR9, reg);
 }
 
@@ -1301,7 +1250,7 @@
  */
 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)
@@ -1429,8 +1378,8 @@
 	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;
@@ -1439,24 +1388,24 @@
 	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;
 }
 
 /*
@@ -1802,9 +1751,7 @@
 	 */
 	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;
@@ -1878,11 +1825,9 @@
 	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.
@@ -1895,6 +1840,83 @@
 /*
  * 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, &reg);
+	rt2x00_set_field32(&reg, TXRX_CSR0_DROP_CRC,
+			   !(*total_flags & FIF_FCSFAIL));
+	rt2x00_set_field32(&reg, TXRX_CSR0_DROP_PHYSICAL,
+			   !(*total_flags & FIF_PLCPFAIL));
+	rt2x00_set_field32(&reg, TXRX_CSR0_DROP_CONTROL,
+			   !(*total_flags & FIF_CONTROL));
+	rt2x00_set_field32(&reg, TXRX_CSR0_DROP_NOT_TO_ME,
+			   !(*total_flags & FIF_PROMISC_IN_BSS));
+	rt2x00_set_field32(&reg, TXRX_CSR0_DROP_TO_DS,
+			   !(*total_flags & FIF_PROMISC_IN_BSS));
+	rt2x00_set_field32(&reg, TXRX_CSR0_DROP_VERSION_ERROR, 1);
+	rt2x00_set_field32(&reg, TXRX_CSR0_DROP_MULTICAST,
+			   !(*total_flags & FIF_ALLMULTI));
+	rt2x00_set_field32(&reg, TXRX_CSR0_DROP_BROADCAST, 0);
+	rt2x00_set_field32(&reg, 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)
 {
@@ -1977,11 +1999,13 @@
 
 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,
@@ -2012,7 +2036,6 @@
 	.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,
 };
diff --git a/drivers/net/wireless/rt2x00/rt73usb.h b/drivers/net/wireless/rt2x00/rt73usb.h
index 5d63a1a..f095151 100644
--- a/drivers/net/wireless/rt2x00/rt73usb.h
+++ b/drivers/net/wireless/rt2x00/rt73usb.h
@@ -290,7 +290,7 @@
 #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)
 
diff --git a/drivers/net/wireless/rtl8187.h b/drivers/net/wireless/rtl8187.h
index 7993b3d..6ad322e 100644
--- a/drivers/net/wireless/rtl8187.h
+++ b/drivers/net/wireless/rtl8187.h
@@ -36,8 +36,7 @@
 };
 
 struct rtl8187_rx_hdr {
-	__le16 len;
-	__le16 rate;
+	__le32 flags;
 	u8 noise;
 	u8 signal;
 	u8 agc;
@@ -74,7 +73,7 @@
 	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;
diff --git a/drivers/net/wireless/rtl8187_dev.c b/drivers/net/wireless/rtl8187_dev.c
index bf9f0cc..b0a92f5 100644
--- a/drivers/net/wireless/rtl8187_dev.c
+++ b/drivers/net/wireless/rtl8187_dev.c
@@ -41,6 +41,57 @@
 
 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;
@@ -125,6 +176,7 @@
 	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)
@@ -143,10 +195,11 @@
 
 	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;
@@ -169,6 +222,8 @@
 	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);
@@ -293,8 +348,6 @@
 	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);
@@ -365,7 +418,7 @@
 	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;
@@ -383,16 +436,13 @@
 	      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);
@@ -419,7 +469,7 @@
 	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;
@@ -445,28 +495,31 @@
 		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;
 }
@@ -475,7 +528,7 @@
 				     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)
@@ -523,14 +576,52 @@
 	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)
@@ -604,7 +695,7 @@
 	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);
diff --git a/drivers/net/wireless/rtl818x.h b/drivers/net/wireless/rtl818x.h
index 283de30..880d4be 100644
--- a/drivers/net/wireless/rtl818x.h
+++ b/drivers/net/wireless/rtl818x.h
@@ -71,6 +71,7 @@
 #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)