linux-wireless.vger.kernel.org archive mirror
 help / color / mirror / Atom feed
* [RFC] the recently discussed flags patch
@ 2007-08-14 16:21 Johannes Berg
  2007-08-14 16:48 ` Michael Buesch
                   ` (2 more replies)
  0 siblings, 3 replies; 5+ messages in thread
From: Johannes Berg @ 2007-08-14 16:21 UTC (permalink / raw)
  To: linux-wireless; +Cc: Jiri Benc, Michael Wu, Daniel Drake

Hey,

After noticing that set_multicast_list is totally useless but now we can
get a new callback from the netdev when the RX flags change, I decided
to go ahead and try that. Below is the patch introducing the filter
flags to mac80211.

set_multicast_list is removed completely because it's of no use right
now, if it's added back it can be done right. All the hard/soft monitor
business is removed, we simply update the flags to the driver and let it
do its best. Maybe it should be able to update the flags value so we can
tell userspace that things failed...

Please do write comments. I want to update drivers too but not before
I've seen comments. Even write if you like it.

johannes
---
 include/net/mac80211.h        |   35 +++++---
 net/mac80211/debugfs_netdev.c |   16 ---
 net/mac80211/ieee80211.c      |  176 +++++++++++++++++++-----------------------
 net/mac80211/ieee80211_i.h    |    5 -
 net/mac80211/rx.c             |    4 
 5 files changed, 108 insertions(+), 128 deletions(-)

--- wireless-dev.orig/include/net/mac80211.h	2007-08-14 17:29:27.180673066 +0200
+++ wireless-dev/include/net/mac80211.h	2007-08-14 18:16:12.500673066 +0200
@@ -489,9 +489,7 @@ struct ieee80211_hw {
 	 */
 #define IEEE80211_HW_DEVICE_STRIPS_MIC (1<<8)
 
-	/* Device is capable of performing full monitor mode even during
-	 * normal operation. */
-#define IEEE80211_HW_MONITOR_DURING_OPER (1<<9)
+/* hole at 9 */
 
 	/* Device does not need BSSID filter set to broadcast in order to
 	 * receive all probe responses while scanning */
@@ -542,6 +540,21 @@ static inline void SET_IEEE80211_PERM_AD
 	memcpy(hw->wiphy->perm_addr, addr, ETH_ALEN);
 }
 
+/*
+ * flags for change_filter_flags()
+ *
+ * Note that e.g. if PROMISC_IN_BSS is unset then
+ * you should still do MAC address filtering if
+ * possible even if OTHER_BSS is set to indicate
+ * no BSSID filtering should be done.
+ */
+#define FIF_PROMISC_IN_BSS	0x01
+#define FIF_ALLMULTI		0x02
+#define FIF_FCSFAIL		0x04
+#define FIF_PLCPFAIL		0x08
+#define FIF_CONTROL		0x10
+#define FIF_OTHER_BSS		0x20
+
 /* Configuration block used by the low-level driver to tell the 802.11 code
  * about supported hardware features and to pass function pointers to callback
  * functions. */
@@ -595,15 +608,13 @@ struct ieee80211_ops {
 	int (*config_interface)(struct ieee80211_hw *hw,
 				int if_id, struct ieee80211_if_conf *conf);
 
-	/* ieee80211 drivers do not have access to the &struct net_device
-	 * that is (are) connected with their device. Hence (and because
-	 * we need to combine the multicast lists and flags for multiple
-	 * virtual interfaces), they cannot assign set_multicast_list.
-	 * The parameters here replace dev->flags and dev->mc_count,
-	 * dev->mc_list is replaced by calling ieee80211_get_mc_list_item.
-	 * Must be atomic. */
-	void (*set_multicast_list)(struct ieee80211_hw *hw,
-				   unsigned short flags, int mc_count);
+	/* Change filter flags, see above for FIF_* constants.
+	 *
+	 * Must be atomic due to running under the tx lock.
+	 * This callback is required.
+	 */
+	void (*change_filter_flags)(struct ieee80211_hw *hw,
+				    int changed_flags, int total_flags);
 
 	/* Set TIM bit handler. If the hardware/firmware takes care of beacon
 	 * generation, IEEE 802.11 code uses this function to tell the
--- wireless-dev.orig/net/mac80211/ieee80211.c	2007-08-14 17:24:41.250673066 +0200
+++ wireless-dev/net/mac80211/ieee80211.c	2007-08-14 18:18:43.850673066 +0200
@@ -118,6 +118,24 @@ static int ieee80211_change_mtu(struct n
 	return 0;
 }
 
+static inline void set_local_flag(struct ieee80211_local *local,
+				  int flag, int *changed)
+{
+	if (!(local->filter_flags & flag)) {
+		*changed |= flag;
+		local->filter_flags |= flag;
+	}
+}
+
+static inline void clear_local_flag(struct ieee80211_local *local,
+				    int flag, int *changed)
+{
+	if (local->filter_flags & flag) {
+		*changed |= flag;
+		local->filter_flags &= ~flag;
+	}
+}
+
 static inline int identical_mac_addr_allowed(int type1, int type2)
 {
 	return (type1 == IEEE80211_IF_TYPE_MNTR ||
@@ -134,37 +152,6 @@ static inline int identical_mac_addr_all
 		  type2 == IEEE80211_IF_TYPE_VLAN)));
 }
 
-/* Check if running monitor interfaces should go to a "soft monitor" mode
- * and switch them if necessary. */
-static inline void ieee80211_start_soft_monitor(struct ieee80211_local *local)
-{
-	struct ieee80211_if_init_conf conf;
-
-	if (local->open_count && local->open_count == local->monitors &&
-	    !(local->hw.flags & IEEE80211_HW_MONITOR_DURING_OPER) &&
-	    local->ops->remove_interface) {
-		conf.if_id = -1;
-		conf.type = IEEE80211_IF_TYPE_MNTR;
-		conf.mac_addr = NULL;
-		local->ops->remove_interface(local_to_hw(local), &conf);
-	}
-}
-
-/* Check if running monitor interfaces should go to a "hard monitor" mode
- * and switch them if necessary. */
-static void ieee80211_start_hard_monitor(struct ieee80211_local *local)
-{
-	struct ieee80211_if_init_conf conf;
-
-	if (local->open_count && local->open_count == local->monitors &&
-	    !(local->hw.flags & IEEE80211_HW_MONITOR_DURING_OPER)) {
-		conf.if_id = -1;
-		conf.type = IEEE80211_IF_TYPE_MNTR;
-		conf.mac_addr = NULL;
-		local->ops->add_interface(local_to_hw(local), &conf);
-	}
-}
-
 static void ieee80211_if_open(struct net_device *dev)
 {
 	struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev);
@@ -202,29 +189,31 @@ static int ieee80211_open(struct net_dev
 	    is_zero_ether_addr(sdata->u.wds.remote_addr))
 		return -ENOLINK;
 
-	if (sdata->type == IEEE80211_IF_TYPE_MNTR && local->open_count &&
-	    !(local->hw.flags & IEEE80211_HW_MONITOR_DURING_OPER)) {
-		/* run the interface in a "soft monitor" mode */
+	ieee80211_if_open(dev);
+
+	if (sdata->type == IEEE80211_IF_TYPE_MNTR) {
+		int change = 0;
+
+		if (!local->monitors) {
+			set_local_flag(local, FIF_CONTROL, &change);
+			set_local_flag(local, FIF_OTHER_BSS, &change);
+			local->hw.conf.flags |= IEEE80211_CONF_RADIOTAP;
+			local->ops->change_filter_flags(local_to_hw(local),
+							change,
+							local->filter_flags);
+			ieee80211_hw_config(local);
+		}
+
 		local->monitors++;
 		local->open_count++;
-		local->hw.conf.flags |= IEEE80211_CONF_RADIOTAP;
 		return 0;
 	}
-	ieee80211_if_open(dev);
-	ieee80211_start_soft_monitor(local);
 
 	conf.if_id = dev->ifindex;
 	conf.type = sdata->type;
-	if (sdata->type == IEEE80211_IF_TYPE_MNTR)
-		conf.mac_addr = NULL;
-	else
-		conf.mac_addr = dev->dev_addr;
 	res = local->ops->add_interface(local_to_hw(local), &conf);
-	if (res) {
-		if (sdata->type == IEEE80211_IF_TYPE_MNTR)
-			ieee80211_start_hard_monitor(local);
+	if (res)
 		return res;
-	}
 
 	if (local->open_count == 0) {
 		res = 0;
@@ -252,13 +241,8 @@ static int ieee80211_open(struct net_dev
 	}
 	local->open_count++;
 
-	if (sdata->type == IEEE80211_IF_TYPE_MNTR) {
-		local->monitors++;
-		local->hw.conf.flags |= IEEE80211_CONF_RADIOTAP;
-	} else {
-		ieee80211_if_config(dev);
-		ieee80211_reset_erp_info(dev);
-	}
+	ieee80211_if_config(dev);
+	ieee80211_reset_erp_info(dev);
 
 	if (sdata->type == IEEE80211_IF_TYPE_STA &&
 	    !local->user_space_mlme)
@@ -300,14 +284,22 @@ static int ieee80211_stop(struct net_dev
 
 	sdata = IEEE80211_DEV_TO_SUB_IF(dev);
 
-	if (sdata->type == IEEE80211_IF_TYPE_MNTR &&
-	    local->open_count > 1 &&
-	    !(local->hw.flags & IEEE80211_HW_MONITOR_DURING_OPER)) {
-		/* remove "soft monitor" interface */
-		local->open_count--;
+	if (sdata->type == IEEE80211_IF_TYPE_MNTR) {
+		int change = 0;
+
 		local->monitors--;
-		if (!local->monitors)
+		local->open_count--;
+
+		if (!local->monitors) {
+			clear_local_flag(local, FIF_CONTROL, &change);
+			clear_local_flag(local, FIF_OTHER_BSS, &change);
 			local->hw.conf.flags &= ~IEEE80211_CONF_RADIOTAP;
+			local->ops->change_filter_flags(local_to_hw(local),
+							change,
+							local->filter_flags);
+			ieee80211_hw_config(local);
+		}
+
 		return 0;
 	}
 
@@ -338,8 +330,6 @@ static int ieee80211_stop(struct net_dev
 		local->ops->remove_interface(local_to_hw(local), &conf);
 	}
 
-	ieee80211_start_hard_monitor(local);
-
 	return 0;
 }
 
@@ -354,47 +344,44 @@ static inline void netif_tx_lock_nested(
 	dev->xmit_lock_owner = smp_processor_id();
 }
 
-static void ieee80211_set_multicast_list(struct net_device *dev)
+static void ieee80211_change_rx_flags(struct net_device *dev, int change)
 {
 	struct ieee80211_local *local = wdev_priv(dev->ieee80211_ptr);
-	struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev);
-	unsigned short flags;
+	int changed_flags = 0;
 
+	/* why? we need some lock to lock local->filter_flags, but this? */
 	netif_tx_lock_nested(local->mdev, TX_LOCK_MASTER);
-	if (((dev->flags & IFF_ALLMULTI) != 0) ^ (sdata->allmulti != 0)) {
-		if (sdata->allmulti) {
-			sdata->allmulti = 0;
-			local->iff_allmultis--;
-		} else {
-			sdata->allmulti = 1;
+
+	if (change & IFF_ALLMULTI) {
+		if (dev->flags & IFF_ALLMULTI)
 			local->iff_allmultis++;
-		}
+		else
+			local->iff_allmultis--;
 	}
-	if (((dev->flags & IFF_PROMISC) != 0) ^ (sdata->promisc != 0)) {
-		if (sdata->promisc) {
-			sdata->promisc = 0;
-			local->iff_promiscs--;
-		} else {
-			sdata->promisc = 1;
+
+	if (change & IFF_PROMISC) {
+		if (dev->flags & IFF_PROMISC)
 			local->iff_promiscs++;
-		}
-	}
-	if (dev->mc_count != sdata->mc_count) {
-		local->mc_count = local->mc_count - sdata->mc_count +
-				  dev->mc_count;
-		sdata->mc_count = dev->mc_count;
-	}
-	if (local->ops->set_multicast_list) {
-		flags = local->mdev->flags;
-		if (local->iff_allmultis)
-			flags |= IFF_ALLMULTI;
-		if (local->iff_promiscs)
-			flags |= IFF_PROMISC;
-		read_lock(&local->sub_if_lock);
-		local->ops->set_multicast_list(local_to_hw(local), flags,
-					      local->mc_count);
-		read_unlock(&local->sub_if_lock);
+		else
+			local->iff_promiscs--;
 	}
+
+	if (local->iff_promiscs)
+		set_local_flag(local, FIF_PROMISC_IN_BSS, &changed_flags);
+	else
+		clear_local_flag(local, FIF_PROMISC_IN_BSS, &changed_flags);
+
+	if (local->iff_allmultis)
+		set_local_flag(local, FIF_ALLMULTI, &changed_flags);
+	else
+		clear_local_flag(local, FIF_ALLMULTI, &changed_flags);
+
+	read_lock(&local->sub_if_lock);
+	local->ops->change_filter_flags(local_to_hw(local),
+					changed_flags,
+					local->filter_flags);
+	read_unlock(&local->sub_if_lock);
+
 	netif_tx_unlock(local->mdev);
 }
 
@@ -405,7 +392,7 @@ void ieee80211_if_setup(struct net_devic
 	dev->hard_start_xmit = ieee80211_subif_start_xmit;
 	dev->wireless_handlers = &ieee80211_iw_handler_def;
 	dev->do_ioctl = ieee80211_ioctl;
-	dev->set_multicast_list = ieee80211_set_multicast_list;
+	dev->change_rx_flags = ieee80211_change_rx_flags;
 	dev->change_mtu = ieee80211_change_mtu;
 	dev->get_stats = ieee80211_get_stats;
 	dev->open = ieee80211_open;
@@ -971,6 +958,7 @@ struct ieee80211_hw *ieee80211_alloc_hw(
 	BUG_ON(!ops->tx);
 	BUG_ON(!ops->config);
 	BUG_ON(!ops->add_interface);
+	BUG_ON(!ops->change_filter_flags);
 	local->ops = ops;
 
 	/* for now, mdev needs sub_if_data :/ */
--- wireless-dev.orig/net/mac80211/ieee80211_i.h	2007-08-14 17:34:28.570673066 +0200
+++ wireless-dev/net/mac80211/ieee80211_i.h	2007-08-14 17:53:39.940673066 +0200
@@ -312,9 +312,6 @@ struct ieee80211_sub_if_data {
 	struct net_device *dev;
 	struct ieee80211_local *local;
 
-	int mc_count;
-	unsigned int allmulti:1;
-	unsigned int promisc:1;
 	unsigned int use_protection:1; /* CTS protect ERP frames */
 
 	/* use short preamble with IEEE 802.11b: this flag is set when the AP
@@ -465,6 +462,7 @@ struct ieee80211_local {
 	struct net_device *mdev; /* wmaster# - "master" 802.11 device */
 	int open_count;
 	int monitors;
+	int filter_flags; /* FIF_* */
 	struct iw_statistics wstats;
 	u8 wstats_flags;
 	int tx_headroom; /* required headroom for hardware/radiotap */
@@ -495,7 +493,6 @@ struct ieee80211_local {
 	struct ieee80211_tx_stored_packet pending_packet[NUM_TX_DATA_QUEUES];
 	struct tasklet_struct tx_pending_tasklet;
 
-	int mc_count;	/* total count of multicast entries in all interfaces */
 	int iff_allmultis, iff_promiscs;
 			/* number of interfaces with corresponding IFF_ flags */
 
--- wireless-dev.orig/net/mac80211/rx.c	2007-08-14 17:52:32.410673066 +0200
+++ wireless-dev/net/mac80211/rx.c	2007-08-14 17:54:03.090673066 +0200
@@ -1389,7 +1389,7 @@ static int prepare_for_handlers(struct i
 		} else if (!multicast &&
 			   compare_ether_addr(sdata->dev->dev_addr,
 					      hdr->addr1) != 0) {
-			if (!sdata->promisc)
+			if (!(sdata->dev->flags & IFF_PROMISC))
 				return 0;
 			rx->u.rx.ra_match = 0;
 		}
@@ -1404,7 +1404,7 @@ static int prepare_for_handlers(struct i
 		} else if (!multicast &&
 			   compare_ether_addr(sdata->dev->dev_addr,
 					      hdr->addr1) != 0) {
-			if (!sdata->promisc)
+			if (!(sdata->dev->flags & IFF_PROMISC))
 				return 0;
 			rx->u.rx.ra_match = 0;
 		} else if (!rx->sta)
--- wireless-dev.orig/net/mac80211/debugfs_netdev.c	2007-08-14 18:03:59.100673066 +0200
+++ wireless-dev/net/mac80211/debugfs_netdev.c	2007-08-14 18:04:29.050673066 +0200
@@ -425,20 +425,6 @@ IEEE80211_IF_FILE(peer, u.wds.remote_add
 /* VLAN attributes */
 IEEE80211_IF_FILE(vlan_id, u.vlan.id, DEC);
 
-/* MONITOR attributes */
-static ssize_t ieee80211_if_fmt_mode(
-	const struct ieee80211_sub_if_data *sdata, char *buf, int buflen)
-{
-	struct ieee80211_local *local = sdata->local;
-
-	return scnprintf(buf, buflen, "%s\n",
-			 ((local->hw.flags & IEEE80211_HW_MONITOR_DURING_OPER) ||
-			  local->open_count == local->monitors) ?
-			 "hard" : "soft");
-}
-__IEEE80211_IF_FILE(mode);
-
-
 #define DEBUGFS_ADD(name, type)\
 	sdata->debugfs.type.name = debugfs_create_file(#name, 0444,\
 		sdata->debugfsdir, sdata, &name##_ops);
@@ -542,7 +528,6 @@ static void add_vlan_files(struct ieee80
 
 static void add_monitor_files(struct ieee80211_sub_if_data *sdata)
 {
-	DEBUGFS_ADD(mode, monitor);
 }
 
 static void add_files(struct ieee80211_sub_if_data *sdata)
@@ -671,7 +656,6 @@ static void del_vlan_files(struct ieee80
 
 static void del_monitor_files(struct ieee80211_sub_if_data *sdata)
 {
-	DEBUGFS_DEL(mode, monitor);
 }
 
 static void del_files(struct ieee80211_sub_if_data *sdata, int type)



^ permalink raw reply	[flat|nested] 5+ messages in thread

* Re: [RFC] the recently discussed flags patch
  2007-08-14 16:21 [RFC] the recently discussed flags patch Johannes Berg
@ 2007-08-14 16:48 ` Michael Buesch
  2007-08-15 10:38   ` Johannes Berg
  2007-08-14 22:56 ` Johannes Berg
  2007-08-15 10:54 ` Johannes Berg
  2 siblings, 1 reply; 5+ messages in thread
From: Michael Buesch @ 2007-08-14 16:48 UTC (permalink / raw)
  To: Johannes Berg; +Cc: linux-wireless, Jiri Benc, Michael Wu, Daniel Drake

On Tuesday 14 August 2007 18:21:55 Johannes Berg wrote:
> +/*
> + * flags for change_filter_flags()
> + *
> + * Note that e.g. if PROMISC_IN_BSS is unset then
> + * you should still do MAC address filtering if
> + * possible even if OTHER_BSS is set to indicate
> + * no BSSID filtering should be done.
> + */
> +#define FIF_PROMISC_IN_BSS	0x01
> +#define FIF_ALLMULTI		0x02
> +#define FIF_FCSFAIL		0x04
> +#define FIF_PLCPFAIL		0x08
> +#define FIF_CONTROL		0x10
> +#define FIF_OTHER_BSS		0x20

Please some more comments on what they actually mean
and what's usually to do when the flag is set.

> +	/* Change filter flags, see above for FIF_* constants.
> +	 *
> +	 * Must be atomic due to running under the tx lock.
> +	 * This callback is required.
> +	 */
> +	void (*change_filter_flags)(struct ieee80211_hw *hw,
> +				    int changed_flags, int total_flags);

Better use unsigned int.

What does changed_flags and total_flags mean?
I thought we'd like to have a pointer here, to the driver
can clear what's not supported.

-- 
Greetings Michael.

^ permalink raw reply	[flat|nested] 5+ messages in thread

* Re: [RFC] the recently discussed flags patch
  2007-08-14 16:21 [RFC] the recently discussed flags patch Johannes Berg
  2007-08-14 16:48 ` Michael Buesch
@ 2007-08-14 22:56 ` Johannes Berg
  2007-08-15 10:54 ` Johannes Berg
  2 siblings, 0 replies; 5+ messages in thread
From: Johannes Berg @ 2007-08-14 22:56 UTC (permalink / raw)
  To: linux-wireless; +Cc: Jiri Benc, Michael Wu, Daniel Drake

Here's one that semi-updates drivers and actually works too. I need help
with the ralink drivers, don't understand how they handle flag changes,
so it won't even compile. b43 I've tested, but all other drivers will
probably not behave optimally/work at all.

---
 drivers/net/wireless/adm8211.c                  |   29 +-
 drivers/net/wireless/b43/b43.h                  |   15 -
 drivers/net/wireless/b43/main.c                 |  222 ++++++++--------
 drivers/net/wireless/iwl-base.c                 |   24 +
 drivers/net/wireless/rtl8187_dev.c              |   19 +
 drivers/net/wireless/zd1211rw-mac80211/zd_mac.c |   50 +--
 include/net/mac80211.h                          |  109 +++++---
 net/mac80211/debugfs_netdev.c                   |   16 -
 net/mac80211/ieee80211.c                        |  319 ++++++++++--------------
 net/mac80211/ieee80211_i.h                      |    5 
 net/mac80211/rx.c                               |   16 -
 11 files changed, 427 insertions(+), 397 deletions(-)

--- wireless-dev.orig/include/net/mac80211.h	2007-08-15 00:22:42.620200043 +0200
+++ wireless-dev/include/net/mac80211.h	2007-08-15 00:43:06.230200043 +0200
@@ -336,7 +336,6 @@ enum ieee80211_if_types {
  * @mac_addr: pointer to MAC address of the interface. This pointer is valid
  *	until the interface is removed (i.e. it cannot be used after
  *	remove_interface() callback was called for this interface).
- *	This pointer will be %NULL for monitor interfaces, be careful.
  *
  * This structure is used in add_interface() and remove_interface()
  * callbacks of &struct ieee80211_hw.
@@ -489,9 +488,7 @@ struct ieee80211_hw {
 	 */
 #define IEEE80211_HW_DEVICE_STRIPS_MIC (1<<8)
 
-	/* Device is capable of performing full monitor mode even during
-	 * normal operation. */
-#define IEEE80211_HW_MONITOR_DURING_OPER (1<<9)
+/* hole at 9 */
 
 	/* Device does not need BSSID filter set to broadcast in order to
 	 * receive all probe responses while scanning */
@@ -542,6 +539,21 @@ static inline void SET_IEEE80211_PERM_AD
 	memcpy(hw->wiphy->perm_addr, addr, ETH_ALEN);
 }
 
+/*
+ * flags for change_filter_flags()
+ *
+ * Note that e.g. if PROMISC_IN_BSS is unset then
+ * you should still do MAC address filtering if
+ * possible even if OTHER_BSS is set to indicate
+ * no BSSID filtering should be done.
+ */
+#define FIF_PROMISC_IN_BSS	0x01
+#define FIF_ALLMULTI		0x02
+#define FIF_FCSFAIL		0x04
+#define FIF_PLCPFAIL		0x08
+#define FIF_CONTROL		0x10
+#define FIF_OTHER_BSS		0x20
+
 /* Configuration block used by the low-level driver to tell the 802.11 code
  * about supported hardware features and to pass function pointers to callback
  * functions. */
@@ -557,32 +569,55 @@ struct ieee80211_ops {
 	/* Handler for performing hardware reset. */
 	int (*reset)(struct ieee80211_hw *hw);
 
-	/* Handler that is called when any netdevice attached to the hardware
-	 * device is set UP for the first time. This can be used, e.g., to
-	 * enable interrupts and beacon sending. */
-	int (*open)(struct ieee80211_hw *hw);
-
-	/* Handler that is called when the last netdevice attached to the
-	 * hardware device is set DOWN. This can be used, e.g., to disable
-	 * interrupts and beacon sending. */
-	int (*stop)(struct ieee80211_hw *hw);
-
-	/* Handler for asking a driver if a new interface can be added (or,
-	 * more exactly, set UP). If the handler returns zero, the interface
-	 * is added. Driver should perform any initialization it needs prior
-	 * to returning zero. By returning non-zero addition of the interface
-	 * is inhibited. Unless monitor_during_oper is set, it is guaranteed
-	 * that monitor interfaces and normal interfaces are mutually
-	 * exclusive. If assigned, the open() handler is called after
-	 * add_interface() if this is the first device added. The
-	 * add_interface() callback has to be assigned because it is the only
-	 * way to obtain the requested MAC address for any interface.
+	/*
+	 * Called before the first netdevice attached to the hardware
+	 * is enabled. This should turn on the hardware and must turn on
+	 * frame reception (for possibly enabled monitor interfaces.)
+	 * Returns negative error codes, these may be seen in userspace,
+	 * or zero.
+	 * When the device is started it should not have a MAC address
+	 * to avoid acknowledging frames before a non-monitor device
+	 * is added.
+	 *
+	 * Must be implemented.
+	 */
+	int (*start)(struct ieee80211_hw *hw);
+
+	/*
+	 * Called after last netdevice attached to the hardware
+	 * is disabled. This should turn off the hardware (at least
+	 * it must turn off frame reception.)
+	 * May be called right after add_interface if that rejects
+	 * an interface.
+	 *
+	 * Must be implemented.
+	 */
+	void (*stop)(struct ieee80211_hw *hw);
+
+	/*
+	 * Called when a netdevice attached to the hardware is enabled.
+	 * Because it is not called for monitor mode devices, open()
+	 * and stop() must be implemented.
+	 * The driver should perform any initialization it needs before
+	 * the device can be enabled. The initial configuration for the
+	 * interface is given in the conf parameter.
+	 *
+	 * Must be implemented.
 	 */
 	int (*add_interface)(struct ieee80211_hw *hw,
 			     struct ieee80211_if_init_conf *conf);
 
-	/* Notify a driver that an interface is going down. The stop() handler
-	 * is called prior to this if this is a last interface. */
+	/*
+	 * Notifies a driver that an interface is going down. The stop() handler
+	 * is called after this if it is the last interface and no monitor
+	 * interfaces are present.
+	 * When all interfaces are removed, the MAC address in the hardware
+	 * must be cleared so the device no longer acknowledges packets,
+	 * the mac_addr member of the conf structure is, however, set to the
+	 * MAC address of the device going away.
+	 *
+	 * Hence, this callback must be implemented.
+	 */
 	void (*remove_interface)(struct ieee80211_hw *hw,
 				 struct ieee80211_if_init_conf *conf);
 
@@ -595,15 +630,19 @@ struct ieee80211_ops {
 	int (*config_interface)(struct ieee80211_hw *hw,
 				int if_id, struct ieee80211_if_conf *conf);
 
-	/* ieee80211 drivers do not have access to the &struct net_device
-	 * that is (are) connected with their device. Hence (and because
-	 * we need to combine the multicast lists and flags for multiple
-	 * virtual interfaces), they cannot assign set_multicast_list.
-	 * The parameters here replace dev->flags and dev->mc_count,
-	 * dev->mc_list is replaced by calling ieee80211_get_mc_list_item.
-	 * Must be atomic. */
-	void (*set_multicast_list)(struct ieee80211_hw *hw,
-				   unsigned short flags, int mc_count);
+	/*
+	 * Change filter flags, see above for FIF_* constants.
+	 *
+	 * All unsupported flags in 'total_flags' must be cleared,
+	 * clear all bits except those you honoured.
+	 *
+	 * Must be atomic due to running under the tx lock.
+	 *
+	 * This callback is must be implemented.
+	 */
+	void (*change_filter_flags)(struct ieee80211_hw *hw,
+				    unsigned int changed_flags,
+				    unsigned int *total_flags);
 
 	/* Set TIM bit handler. If the hardware/firmware takes care of beacon
 	 * generation, IEEE 802.11 code uses this function to tell the
--- wireless-dev.orig/net/mac80211/ieee80211.c	2007-08-15 00:22:42.540200043 +0200
+++ wireless-dev/net/mac80211/ieee80211.c	2007-08-15 00:43:05.570200043 +0200
@@ -118,6 +118,26 @@ static int ieee80211_change_mtu(struct n
 	return 0;
 }
 
+static inline void set_local_flag(struct ieee80211_local *local,
+				  unsigned int flag,
+				  unsigned int *changed)
+{
+	if (!(local->filter_flags & flag)) {
+		*changed |= flag;
+		local->filter_flags |= flag;
+	}
+}
+
+static inline void clear_local_flag(struct ieee80211_local *local,
+				    unsigned int flag,
+				    unsigned int *changed)
+{
+	if (local->filter_flags & flag) {
+		*changed |= flag;
+		local->filter_flags &= ~flag;
+	}
+}
+
 static inline int identical_mac_addr_allowed(int type1, int type2)
 {
 	return (type1 == IEEE80211_IF_TYPE_MNTR ||
@@ -134,55 +154,13 @@ static inline int identical_mac_addr_all
 		  type2 == IEEE80211_IF_TYPE_VLAN)));
 }
 
-/* Check if running monitor interfaces should go to a "soft monitor" mode
- * and switch them if necessary. */
-static inline void ieee80211_start_soft_monitor(struct ieee80211_local *local)
-{
-	struct ieee80211_if_init_conf conf;
-
-	if (local->open_count && local->open_count == local->monitors &&
-	    !(local->hw.flags & IEEE80211_HW_MONITOR_DURING_OPER) &&
-	    local->ops->remove_interface) {
-		conf.if_id = -1;
-		conf.type = IEEE80211_IF_TYPE_MNTR;
-		conf.mac_addr = NULL;
-		local->ops->remove_interface(local_to_hw(local), &conf);
-	}
-}
-
-/* Check if running monitor interfaces should go to a "hard monitor" mode
- * and switch them if necessary. */
-static void ieee80211_start_hard_monitor(struct ieee80211_local *local)
-{
-	struct ieee80211_if_init_conf conf;
-
-	if (local->open_count && local->open_count == local->monitors &&
-	    !(local->hw.flags & IEEE80211_HW_MONITOR_DURING_OPER)) {
-		conf.if_id = -1;
-		conf.type = IEEE80211_IF_TYPE_MNTR;
-		conf.mac_addr = NULL;
-		local->ops->add_interface(local_to_hw(local), &conf);
-	}
-}
-
-static void ieee80211_if_open(struct net_device *dev)
-{
-	struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev);
-
-	switch (sdata->type) {
-	case IEEE80211_IF_TYPE_STA:
-	case IEEE80211_IF_TYPE_IBSS:
-		sdata->u.sta.prev_bssid_set = 0;
-		break;
-	}
-}
-
 static int ieee80211_open(struct net_device *dev)
 {
 	struct ieee80211_sub_if_data *sdata, *nsdata;
 	struct ieee80211_local *local = wdev_priv(dev->ieee80211_ptr);
 	struct ieee80211_if_init_conf conf;
 	int res;
+	unsigned int change = 0, flags;
 
 	sdata = IEEE80211_DEV_TO_SUB_IF(dev);
 	read_lock(&local->sub_if_lock);
@@ -202,81 +180,103 @@ static int ieee80211_open(struct net_dev
 	    is_zero_ether_addr(sdata->u.wds.remote_addr))
 		return -ENOLINK;
 
-	if (sdata->type == IEEE80211_IF_TYPE_MNTR && local->open_count &&
-	    !(local->hw.flags & IEEE80211_HW_MONITOR_DURING_OPER)) {
-		/* run the interface in a "soft monitor" mode */
-		local->monitors++;
-		local->open_count++;
-		local->hw.conf.flags |= IEEE80211_CONF_RADIOTAP;
-		return 0;
-	}
-	ieee80211_if_open(dev);
-	ieee80211_start_soft_monitor(local);
-
-	conf.if_id = dev->ifindex;
-	conf.type = sdata->type;
-	if (sdata->type == IEEE80211_IF_TYPE_MNTR)
-		conf.mac_addr = NULL;
-	else
-		conf.mac_addr = dev->dev_addr;
-	res = local->ops->add_interface(local_to_hw(local), &conf);
-	if (res) {
-		if (sdata->type == IEEE80211_IF_TYPE_MNTR)
-			ieee80211_start_hard_monitor(local);
-		return res;
-	}
-
 	if (local->open_count == 0) {
 		res = 0;
-		tasklet_enable(&local->tx_pending_tasklet);
-		tasklet_enable(&local->tasklet);
-		if (local->ops->open)
-			res = local->ops->open(local_to_hw(local));
-		if (res == 0) {
-			res = dev_open(local->mdev);
-			if (res) {
-				if (local->ops->stop)
-					local->ops->stop(local_to_hw(local));
-			} else {
-				res = ieee80211_hw_config(local);
-				if (res && local->ops->stop)
-					local->ops->stop(local_to_hw(local));
-			}
-		}
-		if (res) {
-			if (local->ops->remove_interface)
-				local->ops->remove_interface(local_to_hw(local),
-							    &conf);
+		if (local->ops->start)
+			res = local->ops->start(local_to_hw(local));
+		if (res)
 			return res;
-		}
 	}
-	local->open_count++;
 
-	if (sdata->type == IEEE80211_IF_TYPE_MNTR) {
+	switch (sdata->type) {
+	/* XXX: handle VLANs specially and not bother drivers */
+	case IEEE80211_IF_TYPE_MNTR:
+		if (!local->monitors) {
+			set_local_flag(local, FIF_CONTROL, &change);
+			set_local_flag(local, FIF_OTHER_BSS, &change);
+			local->hw.conf.flags |= IEEE80211_CONF_RADIOTAP;
+			flags = local->filter_flags;
+			/* be a bit nasty */
+			flags |= (1<<31);
+			local->ops->change_filter_flags(local_to_hw(local),
+							change, &flags);
+			WARN_ON(flags & (1<<31));
+			local->filter_flags = flags;
+			ieee80211_hw_config(local);
+		}
+
 		local->monitors++;
-		local->hw.conf.flags |= IEEE80211_CONF_RADIOTAP;
-	} else {
+		break;
+	case IEEE80211_IF_TYPE_STA:
+	case IEEE80211_IF_TYPE_IBSS:
+		sdata->u.sta.prev_bssid_set = 0;
+		/* fall through */
+	default:
+		conf.if_id = dev->ifindex;
+		conf.type = sdata->type;
+		conf.mac_addr = dev->dev_addr;
+		res = local->ops->add_interface(local_to_hw(local), &conf);
+		if (res && !local->open_count && local->ops->stop)
+			local->ops->stop(local_to_hw(local));
+		if (res)
+			return res;
+
 		ieee80211_if_config(dev);
 		ieee80211_reset_erp_info(dev);
+
+		if (sdata->type == IEEE80211_IF_TYPE_STA &&
+		    !local->user_space_mlme)
+			netif_carrier_off(dev);
+		else
+			netif_carrier_on(dev);
 	}
 
-	if (sdata->type == IEEE80211_IF_TYPE_STA &&
-	    !local->user_space_mlme)
-		netif_carrier_off(dev);
-	else
-		netif_carrier_on(dev);
+	if (local->open_count == 0) {
+		res = dev_open(local->mdev);
+		WARN_ON(res);
+		tasklet_enable(&local->tx_pending_tasklet);
+		tasklet_enable(&local->tasklet);
+	}
+
+	local->open_count++;
 
 	netif_start_queue(dev);
+
 	return 0;
 }
 
-static void ieee80211_if_shutdown(struct net_device *dev)
+static int ieee80211_stop(struct net_device *dev)
 {
+	struct ieee80211_sub_if_data *sdata;
 	struct ieee80211_local *local = wdev_priv(dev->ieee80211_ptr);
-	struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev);
+	unsigned int change = 0, flags;
+	struct ieee80211_if_init_conf conf;
+
+	sdata = IEEE80211_DEV_TO_SUB_IF(dev);
+
+	netif_stop_queue(dev);
+
+	local->open_count--;
 
-	ASSERT_RTNL();
 	switch (sdata->type) {
+	/* XXX: handle VLANs specially and not bother drivers */
+	case IEEE80211_IF_TYPE_MNTR:
+		local->monitors--;
+
+		if (!local->monitors) {
+			clear_local_flag(local, FIF_CONTROL, &change);
+			clear_local_flag(local, FIF_OTHER_BSS, &change);
+			local->hw.conf.flags &= ~IEEE80211_CONF_RADIOTAP;
+			flags = local->filter_flags;
+			/* be a bit nasty */
+			flags |= (1<<31);
+			local->ops->change_filter_flags(local_to_hw(local),
+							change, &flags);
+			WARN_ON(flags & (1<<31));
+			local->filter_flags = flags;
+			ieee80211_hw_config(local);
+		}
+		break;
 	case IEEE80211_IF_TYPE_STA:
 	case IEEE80211_IF_TYPE_IBSS:
 		sdata->u.sta.state = IEEE80211_DISABLED;
@@ -289,56 +289,24 @@ static void ieee80211_if_shutdown(struct
 			cancel_delayed_work(&local->scan_work);
 		}
 		flush_workqueue(local->hw.workqueue);
-		break;
-	}
-}
-
-static int ieee80211_stop(struct net_device *dev)
-{
-	struct ieee80211_sub_if_data *sdata;
-	struct ieee80211_local *local = wdev_priv(dev->ieee80211_ptr);
-
-	sdata = IEEE80211_DEV_TO_SUB_IF(dev);
-
-	if (sdata->type == IEEE80211_IF_TYPE_MNTR &&
-	    local->open_count > 1 &&
-	    !(local->hw.flags & IEEE80211_HW_MONITOR_DURING_OPER)) {
-		/* remove "soft monitor" interface */
-		local->open_count--;
-		local->monitors--;
-		if (!local->monitors)
-			local->hw.conf.flags &= ~IEEE80211_CONF_RADIOTAP;
-		return 0;
-	}
-
-	netif_stop_queue(dev);
-	ieee80211_if_shutdown(dev);
-
-	if (sdata->type == IEEE80211_IF_TYPE_MNTR) {
-		local->monitors--;
-		if (!local->monitors)
-			local->hw.conf.flags &= ~IEEE80211_CONF_RADIOTAP;
+		/* fall through */
+	default:
+		conf.if_id = dev->ifindex;
+		conf.type = sdata->type;
+		conf.mac_addr = dev->dev_addr;
+		local->ops->remove_interface(local_to_hw(local), &conf);
 	}
 
-	local->open_count--;
 	if (local->open_count == 0) {
 		if (netif_running(local->mdev))
 			dev_close(local->mdev);
+
 		if (local->ops->stop)
 			local->ops->stop(local_to_hw(local));
+
 		tasklet_disable(&local->tx_pending_tasklet);
 		tasklet_disable(&local->tasklet);
 	}
-	if (local->ops->remove_interface) {
-		struct ieee80211_if_init_conf conf;
-
-		conf.if_id = dev->ifindex;
-		conf.type = sdata->type;
-		conf.mac_addr = dev->dev_addr;
-		local->ops->remove_interface(local_to_hw(local), &conf);
-	}
-
-	ieee80211_start_hard_monitor(local);
 
 	return 0;
 }
@@ -354,47 +322,48 @@ static inline void netif_tx_lock_nested(
 	dev->xmit_lock_owner = smp_processor_id();
 }
 
-static void ieee80211_set_multicast_list(struct net_device *dev)
+static void ieee80211_change_rx_flags(struct net_device *dev, int change)
 {
 	struct ieee80211_local *local = wdev_priv(dev->ieee80211_ptr);
-	struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev);
-	unsigned short flags;
+	unsigned int changed_flags = 0, flags;
 
+	/* why? we need some lock to lock local->filter_flags, but this? */
 	netif_tx_lock_nested(local->mdev, TX_LOCK_MASTER);
-	if (((dev->flags & IFF_ALLMULTI) != 0) ^ (sdata->allmulti != 0)) {
-		if (sdata->allmulti) {
-			sdata->allmulti = 0;
-			local->iff_allmultis--;
-		} else {
-			sdata->allmulti = 1;
+
+	if (change & IFF_ALLMULTI) {
+		if (dev->flags & IFF_ALLMULTI)
 			local->iff_allmultis++;
-		}
+		else
+			local->iff_allmultis--;
 	}
-	if (((dev->flags & IFF_PROMISC) != 0) ^ (sdata->promisc != 0)) {
-		if (sdata->promisc) {
-			sdata->promisc = 0;
-			local->iff_promiscs--;
-		} else {
-			sdata->promisc = 1;
+
+	if (change & IFF_PROMISC) {
+		if (dev->flags & IFF_PROMISC)
 			local->iff_promiscs++;
-		}
-	}
-	if (dev->mc_count != sdata->mc_count) {
-		local->mc_count = local->mc_count - sdata->mc_count +
-				  dev->mc_count;
-		sdata->mc_count = dev->mc_count;
-	}
-	if (local->ops->set_multicast_list) {
-		flags = local->mdev->flags;
-		if (local->iff_allmultis)
-			flags |= IFF_ALLMULTI;
-		if (local->iff_promiscs)
-			flags |= IFF_PROMISC;
-		read_lock(&local->sub_if_lock);
-		local->ops->set_multicast_list(local_to_hw(local), flags,
-					      local->mc_count);
-		read_unlock(&local->sub_if_lock);
+		else
+			local->iff_promiscs--;
 	}
+
+	if (local->iff_promiscs)
+		set_local_flag(local, FIF_PROMISC_IN_BSS, &changed_flags);
+	else
+		clear_local_flag(local, FIF_PROMISC_IN_BSS, &changed_flags);
+
+	if (local->iff_allmultis)
+		set_local_flag(local, FIF_ALLMULTI, &changed_flags);
+	else
+		clear_local_flag(local, FIF_ALLMULTI, &changed_flags);
+
+	read_lock(&local->sub_if_lock);
+	flags = local->filter_flags;
+	/* be a bit nasty */
+	flags |= (1<<31);
+	local->ops->change_filter_flags(local_to_hw(local),
+					changed_flags, &flags);
+	WARN_ON(flags & (1<<31));
+	local->filter_flags = flags;
+	read_unlock(&local->sub_if_lock);
+
 	netif_tx_unlock(local->mdev);
 }
 
@@ -405,7 +374,7 @@ void ieee80211_if_setup(struct net_devic
 	dev->hard_start_xmit = ieee80211_subif_start_xmit;
 	dev->wireless_handlers = &ieee80211_iw_handler_def;
 	dev->do_ioctl = ieee80211_ioctl;
-	dev->set_multicast_list = ieee80211_set_multicast_list;
+	dev->change_rx_flags = ieee80211_change_rx_flags;
 	dev->change_mtu = ieee80211_change_mtu;
 	dev->get_stats = ieee80211_get_stats;
 	dev->open = ieee80211_open;
@@ -969,8 +938,12 @@ struct ieee80211_hw *ieee80211_alloc_hw(
 			   NETDEV_ALIGN_CONST) & ~NETDEV_ALIGN_CONST);
 
 	BUG_ON(!ops->tx);
+	BUG_ON(!ops->start);
+	BUG_ON(!ops->stop);
 	BUG_ON(!ops->config);
 	BUG_ON(!ops->add_interface);
+	BUG_ON(!ops->remove_interface);
+	BUG_ON(!ops->change_filter_flags);
 	local->ops = ops;
 
 	/* for now, mdev needs sub_if_data :/ */
--- wireless-dev.orig/net/mac80211/ieee80211_i.h	2007-08-15 00:22:42.880200043 +0200
+++ wireless-dev/net/mac80211/ieee80211_i.h	2007-08-15 00:43:05.740200043 +0200
@@ -312,9 +312,6 @@ struct ieee80211_sub_if_data {
 	struct net_device *dev;
 	struct ieee80211_local *local;
 
-	int mc_count;
-	unsigned int allmulti:1;
-	unsigned int promisc:1;
 	unsigned int use_protection:1; /* CTS protect ERP frames */
 
 	/* use short preamble with IEEE 802.11b: this flag is set when the AP
@@ -465,6 +462,7 @@ struct ieee80211_local {
 	struct net_device *mdev; /* wmaster# - "master" 802.11 device */
 	int open_count;
 	int monitors;
+	unsigned int filter_flags; /* FIF_* */
 	struct iw_statistics wstats;
 	u8 wstats_flags;
 	int tx_headroom; /* required headroom for hardware/radiotap */
@@ -495,7 +493,6 @@ struct ieee80211_local {
 	struct ieee80211_tx_stored_packet pending_packet[NUM_TX_DATA_QUEUES];
 	struct tasklet_struct tx_pending_tasklet;
 
-	int mc_count;	/* total count of multicast entries in all interfaces */
 	int iff_allmultis, iff_promiscs;
 			/* number of interfaces with corresponding IFF_ flags */
 
--- wireless-dev.orig/net/mac80211/rx.c	2007-08-15 00:22:42.940200043 +0200
+++ wireless-dev/net/mac80211/rx.c	2007-08-15 00:43:06.020200043 +0200
@@ -963,9 +963,8 @@ ieee80211_rx_h_data_agg(struct ieee80211
 		sdata->stats.rx_bytes += frame->len;
 
 		if (local->bridge_packets &&
-		    (sdata->type == IEEE80211_IF_TYPE_AP ||
-		     sdata->type == IEEE80211_IF_TYPE_VLAN) &&
-		     rx->u.rx.ra_match) {
+		    sdata->type == IEEE80211_IF_TYPE_AP &&
+		    rx->u.rx.ra_match) {
 			if (is_multicast_ether_addr(frame->data)) {
 				/* send multicast frames both to higher layers
 				* in local net stack and back to the wireless
@@ -1061,8 +1060,7 @@ ieee80211_rx_h_data(struct ieee80211_txr
 		memcpy(dst, hdr->addr3, ETH_ALEN);
 		memcpy(src, hdr->addr2, ETH_ALEN);
 
-		if (unlikely(sdata->type != IEEE80211_IF_TYPE_AP &&
-			     sdata->type != IEEE80211_IF_TYPE_VLAN)) {
+		if (unlikely(sdata->type != IEEE80211_IF_TYPE_AP)) {
 			if (net_ratelimit())
 				printk(KERN_DEBUG "%s: dropped ToDS frame "
 				       "(BSSID=" MAC_FMT
@@ -1159,8 +1157,8 @@ ieee80211_rx_h_data(struct ieee80211_txr
 	sdata->stats.rx_packets++;
 	sdata->stats.rx_bytes += skb->len;
 
-	if (local->bridge_packets && (sdata->type == IEEE80211_IF_TYPE_AP
-	    || sdata->type == IEEE80211_IF_TYPE_VLAN) && rx->u.rx.ra_match) {
+	if (local->bridge_packets && (sdata->type == IEEE80211_IF_TYPE_AP) &&
+	    rx->u.rx.ra_match) {
 		if (is_multicast_ether_addr(skb->data)) {
 			/* send multicast frames both to higher layers in
 			 * local net stack and back to the wireless media */
@@ -1389,7 +1387,7 @@ static int prepare_for_handlers(struct i
 		} else if (!multicast &&
 			   compare_ether_addr(sdata->dev->dev_addr,
 					      hdr->addr1) != 0) {
-			if (!sdata->promisc)
+			if (!(sdata->dev->flags & IFF_PROMISC))
 				return 0;
 			rx->u.rx.ra_match = 0;
 		}
@@ -1404,7 +1402,7 @@ static int prepare_for_handlers(struct i
 		} else if (!multicast &&
 			   compare_ether_addr(sdata->dev->dev_addr,
 					      hdr->addr1) != 0) {
-			if (!sdata->promisc)
+			if (!(sdata->dev->flags & IFF_PROMISC))
 				return 0;
 			rx->u.rx.ra_match = 0;
 		} else if (!rx->sta)
--- wireless-dev.orig/net/mac80211/debugfs_netdev.c	2007-08-15 00:22:39.040200043 +0200
+++ wireless-dev/net/mac80211/debugfs_netdev.c	2007-08-15 00:43:05.640200043 +0200
@@ -425,20 +425,6 @@ IEEE80211_IF_FILE(peer, u.wds.remote_add
 /* VLAN attributes */
 IEEE80211_IF_FILE(vlan_id, u.vlan.id, DEC);
 
-/* MONITOR attributes */
-static ssize_t ieee80211_if_fmt_mode(
-	const struct ieee80211_sub_if_data *sdata, char *buf, int buflen)
-{
-	struct ieee80211_local *local = sdata->local;
-
-	return scnprintf(buf, buflen, "%s\n",
-			 ((local->hw.flags & IEEE80211_HW_MONITOR_DURING_OPER) ||
-			  local->open_count == local->monitors) ?
-			 "hard" : "soft");
-}
-__IEEE80211_IF_FILE(mode);
-
-
 #define DEBUGFS_ADD(name, type)\
 	sdata->debugfs.type.name = debugfs_create_file(#name, 0444,\
 		sdata->debugfsdir, sdata, &name##_ops);
@@ -542,7 +528,6 @@ static void add_vlan_files(struct ieee80
 
 static void add_monitor_files(struct ieee80211_sub_if_data *sdata)
 {
-	DEBUGFS_ADD(mode, monitor);
 }
 
 static void add_files(struct ieee80211_sub_if_data *sdata)
@@ -671,7 +656,6 @@ static void del_vlan_files(struct ieee80
 
 static void del_monitor_files(struct ieee80211_sub_if_data *sdata)
 {
-	DEBUGFS_DEL(mode, monitor);
 }
 
 static void del_files(struct ieee80211_sub_if_data *sdata, int type)
--- wireless-dev.orig/drivers/net/wireless/b43/b43.h	2007-08-15 00:22:39.000200043 +0200
+++ wireless-dev/drivers/net/wireless/b43/b43.h	2007-08-15 00:22:43.010200043 +0200
@@ -572,9 +572,8 @@ struct b43_wl {
 	 * 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). */
@@ -583,14 +582,10 @@ struct b43_wl {
 	const u8 *bssid;
 	/* 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;
 
@@ -747,8 +742,6 @@ static inline struct b43_wldev *dev_to_b
 /* 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);
 }
 
--- wireless-dev.orig/drivers/net/wireless/b43/main.c	2007-08-15 00:22:40.860200043 +0200
+++ wireless-dev/drivers/net/wireless/b43/main.c	2007-08-15 00:31:49.370200043 +0200
@@ -91,14 +91,6 @@ static char modparam_fwpostfix[16];
 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,12 +553,10 @@ static void b43_write_mac_bssid_template
 	}
 }
 
-static void b43_upload_card_macaddress(struct b43_wldev *dev,
-				       const u8 * mac_addr)
+static void b43_upload_card_macaddress(struct b43_wldev *dev)
 {
-	dev->wl->mac_addr = mac_addr;
 	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)
@@ -1959,31 +1949,20 @@ static void b43_adjust_opmode(struct b43
 	ctl &= ~B43_MACCTL_PROMISC;
 	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;
+
 	/* Workaround: On old hardware the HW-MAC-address-filter
 	 * doesn't work properly, so always run promisc in filter
 	 * it in software. */
@@ -2908,21 +2887,37 @@ out:
 	return err;
 }
 
-static void b43_set_multicast_list(struct ieee80211_hw *hw,
-				   unsigned short netflags, int mc_count)
+static void b43_change_filter_flags(struct ieee80211_hw *hw,
+				    unsigned int changed, unsigned int *fflags)
 {
 	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;
+
+	changed &= FIF_PROMISC_IN_BSS |
+		   FIF_ALLMULTI |
+		   FIF_FCSFAIL |
+		   FIF_PLCPFAIL |
+		   FIF_CONTROL |
+		   FIF_OTHER_BSS;
+
+	wl->filter_flags = *fflags;
+
+	if (changed && b43_status(dev) >= B43_STAT_INITIALIZED)
+		b43_adjust_opmode(dev);
 	spin_unlock_irqrestore(&wl->irq_lock, flags);
 }
 
@@ -2937,18 +2932,16 @@ static int b43_config_interface(struct i
 		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);
-		wl->bssid = conf->bssid;
-		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);
+	wl->bssid = conf->bssid;
+	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);
@@ -3368,7 +3361,8 @@ static int b43_wireless_core_init(struct
 
 	ssb_bus_powerup(bus, 1);	/* Enable dynamic PCTL */
 	wl->bssid = NULL;
-	b43_upload_card_macaddress(dev, NULL);
+	wl->mac_addr = NULL;
+	b43_upload_card_macaddress(dev);
 	b43_security_init(dev);
 	b43_rng_init(wl);
 
@@ -3398,21 +3392,80 @@ static int b43_add_interface(struct ieee
 	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;
 
 	bcmdbg(wl, "Adding Interface type %d\n", conf->type);
 
 	dev = wl->current_dev;
+	wl->operating = 1;
+	wl->if_id = conf->if_id;
+	wl->if_type = conf->type;
+	wl->mac_addr = conf->mac_addr;
+
+	spin_lock_irqsave(&wl->irq_lock, flags);
+	b43_adjust_opmode(dev);
+	b43_upload_card_macaddress(dev);
+	spin_unlock_irqrestore(&wl->irq_lock, flags);
+
+	err = 0;
+ out_mutex_unlock:
+	mutex_unlock(&wl->mutex);
+
+	return err;
+}
+
+static void b43_remove_interface(struct ieee80211_hw *hw,
+				 struct ieee80211_if_init_conf *conf)
+{
+	struct b43_wl *wl = hw_to_b43_wl(hw);
+	struct b43_wldev *dev = wl->current_dev;
+	unsigned long flags;
+
+	bcmdbg(wl, "Removing Interface type %d\n", conf->type);
+
+	mutex_lock(&wl->mutex);
+
+	B43_WARN_ON(!wl->operating);
+	B43_WARN_ON(wl->if_id != conf->if_id);
+
+	wl->operating = 0;
+
+	spin_lock_irqsave(&wl->irq_lock, flags);
+	b43_adjust_opmode(dev);
+	wl->mac_addr = NULL;
+	b43_upload_card_macaddress(dev);
+	spin_unlock_irqrestore(&wl->irq_lock, flags);
+
+	mutex_unlock(&wl->mutex);
+}
+
+static int b43_start(struct ieee80211_hw *hw)
+{
+	struct b43_wl *wl = hw_to_b43_wl(hw);
+	struct b43_wldev *dev = wl->current_dev;
+	int did_init = 0;
+	int err;
+
+	mutex_lock(&wl->mutex);
+
 	if (b43_status(dev) < B43_STAT_INITIALIZED) {
 		err = b43_wireless_core_init(dev);
 		if (err)
 			goto out_mutex_unlock;
 		did_init = 1;
 	}
+
 	if (b43_status(dev) < B43_STAT_STARTED) {
 		err = b43_wireless_core_start(dev);
 		if (err) {
@@ -3422,59 +3475,21 @@ static int b43_add_interface(struct ieee
 		}
 	}
 
-	spin_lock_irqsave(&wl->irq_lock, flags);
-	switch (conf->type) {
-	case IEEE80211_IF_TYPE_MNTR:
-		wl->monitor++;
-		break;
-	default:
-		wl->operating = 1;
-		wl->if_id = conf->if_id;
-		wl->if_type = conf->type;
-		b43_upload_card_macaddress(dev, conf->mac_addr);
-	}
-	b43_adjust_opmode(dev);
-	spin_unlock_irqrestore(&wl->irq_lock, flags);
-
-	err = 0;
-      out_mutex_unlock:
+ out_mutex_unlock:
 	mutex_unlock(&wl->mutex);
 
 	return err;
 }
 
-static void b43_remove_interface(struct ieee80211_hw *hw,
-				 struct ieee80211_if_init_conf *conf)
+void b43_stop(struct ieee80211_hw *hw)
 {
 	struct b43_wl *wl = hw_to_b43_wl(hw);
-	struct b43_wldev *dev;
-	unsigned long flags;
-
-	bcmdbg(wl, "Removing Interface type %d\n", conf->type);
+	struct b43_wldev *dev = wl->current_dev;
 
 	mutex_lock(&wl->mutex);
-	if (conf->type == IEEE80211_IF_TYPE_MNTR) {
-		wl->monitor--;
-		B43_WARN_ON(wl->monitor < 0);
-	} else {
-		B43_WARN_ON(!wl->operating);
-		wl->operating = 0;
-	}
-
-	dev = wl->current_dev;
-	if (!wl->operating && wl->monitor == 0) {
-		/* No interface left. */
-		if (b43_status(dev) >= B43_STAT_STARTED)
-			b43_wireless_core_stop(dev);
-		b43_wireless_core_exit(dev);
-	} else {
-		/* Just monitor interfaces left. */
-		spin_lock_irqsave(&wl->irq_lock, flags);
-		b43_adjust_opmode(dev);
-		if (!wl->operating)
-			b43_upload_card_macaddress(dev, NULL);
-		spin_unlock_irqrestore(&wl->irq_lock, flags);
-	}
+	if (b43_status(dev) >= B43_STAT_STARTED)
+		b43_wireless_core_stop(dev);
+	b43_wireless_core_exit(dev);
 	mutex_unlock(&wl->mutex);
 }
 
@@ -3486,10 +3501,12 @@ static const struct ieee80211_ops b43_hw
 	.reset = b43_dev_reset,
 	.config = b43_dev_config,
 	.config_interface = b43_config_interface,
-	.set_multicast_list = b43_set_multicast_list,
+	.change_filter_flags = b43_change_filter_flags,
 	.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.
@@ -3827,7 +3844,6 @@ static int b43_wireless_init(struct ssb_
 
 	/* fill hw info */
 	hw->flags = IEEE80211_HW_HOST_GEN_BEACON_TEMPLATE |
-	    IEEE80211_HW_MONITOR_DURING_OPER |
 	    IEEE80211_HW_DEVICE_HIDES_WEP | IEEE80211_HW_WEP_INCLUDE_IV;
 	hw->max_signal = 100;
 	hw->max_rssi = -110;
--- wireless-dev.orig/drivers/net/wireless/iwl-base.c	2007-08-15 00:22:39.010200043 +0200
+++ wireless-dev/drivers/net/wireless/iwl-base.c	2007-08-15 00:22:43.030200043 +0200
@@ -2591,6 +2591,8 @@ static void iwl_set_flags_for_phymode(st
 
 /*
  * initilize rxon structure with default values fromm eeprom
+ *
+ * XXX: This function should use the filter flags instead!
  */
 static void iwl_connection_init_rx_config(struct iwl_priv *priv)
 {
@@ -7502,7 +7504,7 @@ static void iwl_bg_scan_completed(struct
  *
  *****************************************************************************/
 
-static int iwl_mac_open(struct ieee80211_hw *hw)
+static int iwl_mac_start(struct ieee80211_hw *hw)
 {
 	struct iwl_priv *priv = hw->priv;
 
@@ -7521,7 +7523,7 @@ static int iwl_mac_open(struct ieee80211
 	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;
 
@@ -7530,8 +7532,17 @@ static int iwl_mac_stop(struct ieee80211
 	/*netif_stop_queue(dev); */
 	flush_workqueue(priv->workqueue);
 	IWL_DEBUG_MAC80211("leave\n");
+}
 
-	return 0;
+static void iwl_change_filter_flags(struct ieee80211_hw *hw,
+				    unsigned int changed_flags,
+				    unsigned int *total_flags)
+{
+	/*
+	 * XXX: dummy
+	 * see also iwl_connection_init_rx_config
+	 */
+	*total_flags = 0;
 }
 
 static int iwl_mac_tx(struct ieee80211_hw *hw, struct sk_buff *skb,
@@ -7700,6 +7711,8 @@ static int iwl_mac_config_interface(stru
 	if (conf == NULL)
 		return -EIO;
 
+	/* TODO: use conf->mac_addr */
+
 	if ((priv->iw_mode == IEEE80211_IF_TYPE_AP) &&
 	    (!conf->beacon || !conf->ssid_len)) {
 		IWL_DEBUG_MAC80211
@@ -7808,6 +7821,8 @@ static void iwl_mac_remove_interface(str
 	}
 	mutex_unlock(&priv->mutex);
 
+	/* TODO: clear MAC address in hardware */
+
 	IWL_DEBUG_MAC80211("leave\n");
 
 }
@@ -9056,10 +9071,11 @@ static struct attribute_group iwl_attrib
 
 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,
+	.change_filter_flags = iwl_change_filter_flags,
 	.config = iwl_mac_config,
 	.config_interface = iwl_mac_config_interface,
 	.set_key = iwl_mac_set_key,
--- wireless-dev.orig/drivers/net/wireless/rtl8187_dev.c	2007-08-15 00:22:42.250200043 +0200
+++ wireless-dev/drivers/net/wireless/rtl8187_dev.c	2007-08-15 00:22:43.030200043 +0200
@@ -365,7 +365,7 @@ static void rtl8187_set_channel(struct i
 	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;
@@ -476,6 +476,8 @@ static void rtl8187_remove_interface(str
 {
 	struct rtl8187_priv *priv = dev->priv;
 	priv->mode = IEEE80211_IF_TYPE_NONE;
+
+	/* TODO: reset MAC address to zeroes */
 }
 
 static int rtl8187_config(struct ieee80211_hw *dev, struct ieee80211_conf *conf)
@@ -523,14 +525,27 @@ static int rtl8187_config_interface(stru
 	return 0;
 }
 
+static void rtl8187_change_filter_flags(struct ieee80211_hw *dev,
+					unsigned int changed,
+					unsigned int *flags)
+{
+	/*
+	 * XXX: dummy
+	 *
+	 * TODO: change filter flags
+	 */
+	*flags = 0;
+}
+
 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,
+	.change_filter_flags	= rtl8187_change_filter_flags,
 };
 
 static void rtl8187_eeprom_register_read(struct eeprom_93cx6 *eeprom)
--- wireless-dev.orig/drivers/net/wireless/adm8211.c	2007-08-15 00:22:42.250200043 +0200
+++ wireless-dev/drivers/net/wireless/adm8211.c	2007-08-15 00:22:43.040200043 +0200
@@ -349,8 +349,9 @@ static int adm8211_get_stats(struct ieee
 	return 0;
 }
 
-static void adm8211_set_rx_mode(struct ieee80211_hw *dev,
-				unsigned short flags, int mc_count)
+static void adm8211_change_filter_flags(struct ieee80211_hw *dev,
+					unsigned int changed,
+					unsigned int *flags)
 {
 	struct adm8211_priv *priv = dev->priv;
 	unsigned int bit_nr;
@@ -358,12 +359,15 @@ static void adm8211_set_rx_mode(struct i
 	struct dev_mc_list *mclist;
 	void *tmp;
 
-		mc_filter[1] = mc_filter[0] = 0;
-	if (flags & IFF_PROMISC) {
+	/* TODO: honour more flags */
+
+	mc_filter[1] = mc_filter[0] = 0;
+
+	if (*flags & FIF_PROMISC_IN_BSS) {
 		priv->nar |= ADM8211_NAR_PR;
 		priv->nar &= ~ADM8211_NAR_MM;
 		mc_filter[1] = mc_filter[0] = cpu_to_le32(~0);
-	} else if ((flags & IFF_ALLMULTI) || (mc_count > -1)) {
+	} else if (*flags & FIF_ALLMULTI) {
 		priv->nar &= ~ADM8211_NAR_PR;
 		priv->nar |= ADM8211_NAR_MM;
 		mc_filter[1] = mc_filter[0] = cpu_to_le32(~0);
@@ -379,6 +383,8 @@ static void adm8211_set_rx_mode(struct i
 		}
 	}
 
+	*flags &= FIF_PROMISC_IN_BSS | FIF_ALLMULTI;
+
 	ADM8211_IDLE_RX();
 
 	ADM8211_CSR_WRITE(MAR0, mc_filter[0]);
@@ -1500,6 +1506,8 @@ static void adm8211_remove_interface(str
 {
 	struct adm8211_priv *priv = dev->priv;
 	priv->mode = IEEE80211_IF_TYPE_NONE;
+
+	/* TODO: clear MAC address */
 }
 
 static int adm8211_init_rings(struct ieee80211_hw *dev)
@@ -1583,7 +1591,7 @@ static void adm8211_free_rings(struct ie
 	}
 }
 
-static int adm8211_open(struct ieee80211_hw *dev)
+static int adm8211_start(struct ieee80211_hw *dev)
 {
 	struct adm8211_priv *priv = dev->priv;
 	int retval;
@@ -1626,7 +1634,7 @@ fail:
 	return retval;
 }
 
-static int adm8211_stop(struct ieee80211_hw *dev)
+static void adm8211_stop(struct ieee80211_hw *dev)
 {
 	struct adm8211_priv *priv = dev->priv;
 
@@ -1638,7 +1646,6 @@ static int adm8211_stop(struct ieee80211
 	free_irq(priv->pdev->irq, dev);
 
 	adm8211_free_rings(dev);
-	return 0;
 }
 
 static int adm8211_reset(struct ieee80211_hw *dev)
@@ -1877,13 +1884,13 @@ static int adm8211_alloc_rings(struct ie
 static const struct ieee80211_ops adm8211_ops = {
 	.tx			= adm8211_tx,
 	.reset			= adm8211_reset,
-	.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,
+	.change_filter_flags	= adm8211_change_filter_flags,
 	.get_stats		= adm8211_get_stats,
 	.get_tx_stats		= adm8211_get_tx_stats,
 	.get_tsf		= adm8211_get_tsft
@@ -2118,7 +2125,7 @@ static int adm8211_resume(struct pci_dev
 	pci_restore_state(pdev);
 
 	if (priv->mode != IEEE80211_IF_TYPE_NONE) {
-		adm8211_open(dev);
+		adm8211_start(dev);
 		ieee80211_start_queues(dev);
 	}
 
--- wireless-dev.orig/drivers/net/wireless/zd1211rw-mac80211/zd_mac.c	2007-08-15 00:22:42.250200043 +0200
+++ wireless-dev/drivers/net/wireless/zd1211rw-mac80211/zd_mac.c	2007-08-15 00:22:43.040200043 +0200
@@ -170,29 +170,18 @@ void zd_mac_clear(struct zd_mac *mac)
 	ZD_MEMCLEAR(mac, sizeof(struct zd_mac));
 }
 
-/**
- * has_monitor_interfaces - have monitor interfaces been enabled?
- * @mac: the struct zd_mac pointer
- *
- * The function returns, whether the device has monitor interfaces attached.
- */
-static int has_monitor_interfaces(struct zd_mac *mac)
-{
-	return mac->type == IEEE80211_IF_TYPE_MNTR;
-}
-
 static int set_rx_filter(struct zd_mac *mac)
 {
-	u32 filter = has_monitor_interfaces(mac) ? ~0 : STA_RX_FILTER;
+	/* XXX: need to work off the filter flags! */
+	u32 filter = STA_RX_FILTER;
 
 	return zd_iowrite32(&mac->chip, CR_RX_FILTER, filter);
 }
 
 static int set_sniffer(struct zd_mac *mac)
 {
-	return zd_iowrite32(&mac->chip, CR_SNIFFER_ON,
-		has_monitor_interfaces(mac) ? 1 : 0);
-	return 0;
+	/* XXX: need to work off the filter flags! */
+	return zd_iowrite32(&mac->chip, CR_SNIFFER_ON, 0);
 }
 
 static int set_mc_hash(struct zd_mac *mac)
@@ -200,13 +189,13 @@ static int set_mc_hash(struct zd_mac *ma
 	struct zd_mc_hash hash;
 
 	zd_mc_clear(&hash);
-	if (has_monitor_interfaces(mac))
+	if (0) /* XXX: need to work off the filter flags! */
 		zd_mc_add_all(&hash);
 
 	return zd_chip_set_multicast_hash(&mac->chip, &hash);
 }
 
-static int zd_op_open(struct ieee80211_hw *hw)
+static int zd_op_start(struct ieee80211_hw *hw)
 {
 	struct zd_mac *mac = zd_hw_mac(hw);
 	struct zd_chip *chip = &mac->chip;
@@ -290,7 +279,7 @@ static void kfree_tx_skb(struct sk_buff 
 	dev_kfree_skb_any(skb);
 }
 
-static int zd_op_stop(struct ieee80211_hw *hw)
+static void zd_op_stop(struct ieee80211_hw *hw)
 {
 	struct zd_mac *mac = zd_hw_mac(hw);
 	struct zd_chip *chip = &mac->chip;
@@ -313,8 +302,6 @@ static int zd_op_stop(struct ieee80211_h
 
 	while ((skb = skb_dequeue(ack_wait_queue)))
 		kfree_tx_skb(skb);
-
-	return 0;
 }
 
 /**
@@ -689,7 +676,7 @@ int zd_mac_rx(struct ieee80211_hw *hw, c
 	buffer += ZD_PLCP_HEADER_SIZE;
 
 	if (filter_ack(hw, (struct ieee80211_hdr *)buffer, &stats) &&
-	    !has_monitor_interfaces(mac))
+	    0 /* XXX: need to work off the filter flags! */)
 		return 0;
 
 	skb = dev_alloc_skb(length);
@@ -711,7 +698,6 @@ static int zd_op_add_interface(struct ie
 		return -1;
 
 	switch (conf->type) {
-	case IEEE80211_IF_TYPE_MNTR:
 	case IEEE80211_IF_TYPE_STA:
 		mac->type = conf->type;
 		break;
@@ -761,16 +747,16 @@ static void set_multicast_hash_handler(s
 	zd_chip_set_multicast_hash(&mac->chip, &hash);
 }
 
-static void zd_op_set_multicast_list(struct ieee80211_hw *hw,
-				      unsigned short dev_flags, int mc_count)
+static void zd_op_change_filter_flags(struct ieee80211_hw *hw,
+				      unsigned int change,
+				      unsigned int *filterflags)
 {
 	struct zd_mc_hash hash;
 	struct zd_mac *mac = zd_hw_mac(hw);
 	unsigned long flags;
 
-	if ((dev_flags & (IFF_PROMISC|IFF_ALLMULTI)) ||
-	     has_monitor_interfaces(mac))
-	{
+	if (*filterflags & (FIF_PROMISC_IN_BSS | FIF_ALLMULTI)) {
+		/* XXX: can we do better, with finer granularity? */
 		zd_mc_add_all(&hash);
 	} else {
 		struct dev_mc_list *mc = NULL;
@@ -783,6 +769,12 @@ static void zd_op_set_multicast_list(str
 		}
 	}
 
+	/*
+	 * XXX: probably not right, we probably see many other
+	 * frames as well...
+	 */
+	*filterflags &= FIF_PROMISC_IN_BSS | FIF_ALLMULTI;
+
 	spin_lock_irqsave(&mac->lock, flags);
 	mac->multicast_hash = hash;
 	spin_unlock_irqrestore(&mac->lock, flags);
@@ -830,13 +822,13 @@ static void zd_op_erp_ie_changed(struct 
 
 static const struct ieee80211_ops zd_ops = {
 	.tx			= zd_op_tx,
-	.open			= zd_op_open,
+	.start			= zd_op_start,
 	.stop			= zd_op_stop,
 	.add_interface		= zd_op_add_interface,
 	.remove_interface	= zd_op_remove_interface,
 	.config			= zd_op_config,
 	.config_interface	= zd_op_config_interface,
-	.set_multicast_list	= zd_op_set_multicast_list,
+	.change_filter_flags	= zd_op_change_filter_flags,
 	.erp_ie_changed		= zd_op_erp_ie_changed,
 };
 



^ permalink raw reply	[flat|nested] 5+ messages in thread

* Re: [RFC] the recently discussed flags patch
  2007-08-14 16:48 ` Michael Buesch
@ 2007-08-15 10:38   ` Johannes Berg
  0 siblings, 0 replies; 5+ messages in thread
From: Johannes Berg @ 2007-08-15 10:38 UTC (permalink / raw)
  To: Michael Buesch; +Cc: linux-wireless, Jiri Benc, Michael Wu, Daniel Drake

[-- Attachment #1: Type: text/plain, Size: 862 bytes --]

On Tue, 2007-08-14 at 18:48 +0200, Michael Buesch wrote:

> Please some more comments on what they actually mean
> and what's usually to do when the flag is set.

Will do.

> > +	/* Change filter flags, see above for FIF_* constants.
> > +	 *
> > +	 * Must be atomic due to running under the tx lock.
> > +	 * This callback is required.
> > +	 */
> > +	void (*change_filter_flags)(struct ieee80211_hw *hw,
> > +				    int changed_flags, int total_flags);
> 
> Better use unsigned int.

Yeah, did that.

> What does changed_flags and total_flags mean?
> I thought we'd like to have a pointer here, to the driver
> can clear what's not supported.

I changed that in the second version, and changed_flags indicates which
ones have changed since the last call so the driver need not set all of
them if that might be expensive.

johannes

[-- Attachment #2: This is a digitally signed message part --]
[-- Type: application/pgp-signature, Size: 190 bytes --]

^ permalink raw reply	[flat|nested] 5+ messages in thread

* Re: [RFC] the recently discussed flags patch
  2007-08-14 16:21 [RFC] the recently discussed flags patch Johannes Berg
  2007-08-14 16:48 ` Michael Buesch
  2007-08-14 22:56 ` Johannes Berg
@ 2007-08-15 10:54 ` Johannes Berg
  2 siblings, 0 replies; 5+ messages in thread
From: Johannes Berg @ 2007-08-15 10:54 UTC (permalink / raw)
  To: linux-wireless; +Cc: Jiri Benc, Michael Wu, Daniel Drake

[-- Attachment #1: Type: text/plain, Size: 294 bytes --]


> After noticing that set_multicast_list is totally useless

That, of course, isn't true, so I shall be updating this patch to have
set_multicast_list again but only implement it for drivers that can
actually do multi-multicast filters, and use FIF_ALLMULTI for the
others.

johannes

[-- Attachment #2: This is a digitally signed message part --]
[-- Type: application/pgp-signature, Size: 190 bytes --]

^ permalink raw reply	[flat|nested] 5+ messages in thread

end of thread, other threads:[~2007-08-15 10:52 UTC | newest]

Thread overview: 5+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2007-08-14 16:21 [RFC] the recently discussed flags patch Johannes Berg
2007-08-14 16:48 ` Michael Buesch
2007-08-15 10:38   ` Johannes Berg
2007-08-14 22:56 ` Johannes Berg
2007-08-15 10:54 ` Johannes Berg

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).