2007-08-21 16:21:31

by Johannes Berg

[permalink] [raw]
Subject: [RFC 2/2] 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 according to the filter flags.

Multicast filtering is a bit special, which is why drivers
that do not require FIF_ALLMULTI for multicast address filters
(i.e. they actually have filters for multicast addresses)
need to set the new IEEE80211_HW_MULTICAST_FILTER flag and
call the ieee80211_get_mc_list_item() function.

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 multicast.

WARNING: This patch makes the ralink drivers BUG_ON().

Signed-off-by: Johannes Berg <[email protected]>
---
Changes since v1:
* introduce FIF_BCN_PRBRESP_PROMISC,
remove IEEE80211_HW_NO_PROBE_FILTERING

drivers/net/wireless/adm8211.c | 85 +++--
drivers/net/wireless/b43/b43.h | 15 -
drivers/net/wireless/b43/main.c | 232 ++++++++--------
drivers/net/wireless/iwl-base.c | 31 +-
drivers/net/wireless/rt2x00/rt2400pci.c | 7
drivers/net/wireless/rt2x00/rt2500pci.c | 7
drivers/net/wireless/rt2x00/rt2500usb.c | 6
drivers/net/wireless/rt2x00/rt61pci.c | 7
drivers/net/wireless/rt2x00/rt73usb.c | 6
drivers/net/wireless/rtl8187_dev.c | 23 +
drivers/net/wireless/zd1211rw-mac80211/zd_mac.c | 66 ++--
include/net/mac80211.h | 148 +++++++---
net/mac80211/debugfs_netdev.c | 16 -
net/mac80211/ieee80211.c | 343 ++++++++++--------------
net/mac80211/ieee80211_i.h | 1
net/mac80211/ieee80211_sta.c | 16 -
net/mac80211/rx.c | 4
17 files changed, 547 insertions(+), 466 deletions(-)

--- wireless-dev.orig/include/net/mac80211.h 2007-08-21 16:28:19.015923881 +0200
+++ wireless-dev/include/net/mac80211.h 2007-08-21 18:16:44.130411759 +0200
@@ -339,7 +339,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.
@@ -526,13 +525,12 @@ 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)
-
- /* Device does not need BSSID filter set to broadcast in order to
- * receive all probe responses while scanning */
-#define IEEE80211_HW_NO_PROBE_FILTERING (1<<10)
+ /*
+ * Device has multicast filters.
+ */
+#define IEEE80211_HW_MULTICAST_FILTER (1<<9)
+
+/* hole at 10 */

/* Channels are already configured to the default regulatory domain
* specified in the device's EEPROM */
@@ -579,6 +577,39 @@ 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.
+ */
+/*
+ * promiscuous mode within your BSS,
+ * think of the BSS as your network segment and then this corresponds
+ * to the regular ethernet device promiscuous mode
+ */
+#define FIF_PROMISC_IN_BSS 0x01
+/* show all multicast frames */
+#define FIF_ALLMULTI 0x02
+/* show frames with failed FCS, but set RX_FLAG_FAILED_FCS_CRC for them */
+#define FIF_FCSFAIL 0x04
+/* show frames with failed PLCP CRC, but set RX_FLAG_FAILED_PLCP_CRC for them */
+#define FIF_PLCPFAIL 0x08
+/*
+ * This flag is set during scanning to indicate to the hardware
+ * that it should not filter beacons or probe responses by BSSID.
+ */
+#define FIF_BCN_PRBRESP_PROMISC 0x10
+/*
+ * show control frames, if PROMISC_IN_BSS is not set then
+ * only those addressed to this station
+ */
+#define FIF_CONTROL 0x20
+/* show frames from other BSSes */
+#define FIF_OTHER_BSS 0x40
+
/* Configuration block used by the low-level driver to tell the 802.11 code
* about supported hardware features and to pass function pointers to callback
* functions. */
@@ -591,32 +622,55 @@ struct ieee80211_ops {
int (*tx)(struct ieee80211_hw *hw, struct sk_buff *skb,
struct ieee80211_tx_control *control);

- /* Handler that is called when any netdevice attached to the hardware
- * device is set UP for the first time. This can be used, e.g., to
- * enable interrupts and beacon sending. */
- int (*open)(struct ieee80211_hw *hw);
-
- /* Handler that is called when the last netdevice attached to the
- * hardware device is set DOWN. This can be used, e.g., to disable
- * interrupts and beacon sending. */
- int (*stop)(struct ieee80211_hw *hw);
-
- /* Handler for asking a driver if a new interface can be added (or,
- * more exactly, set UP). If the handler returns zero, the interface
- * is added. Driver should perform any initialization it needs prior
- * to returning zero. By returning non-zero addition of the interface
- * is inhibited. Unless monitor_during_oper is set, it is guaranteed
- * that monitor interfaces and normal interfaces are mutually
- * exclusive. If assigned, the open() handler is called after
- * add_interface() if this is the first device added. The
- * add_interface() callback has to be assigned because it is the only
- * way to obtain the requested MAC address for any interface.
+ /*
+ * Called before the first netdevice attached to the hardware
+ * is enabled. This should turn on the hardware and must turn on
+ * frame reception (for possibly enabled monitor interfaces.)
+ * Returns negative error codes, these may be seen in userspace,
+ * or zero.
+ * When the device is started it should not have a MAC address
+ * to avoid acknowledging frames before a non-monitor device
+ * is added.
+ *
+ * Must be implemented.
+ */
+ int (*start)(struct ieee80211_hw *hw);
+
+ /*
+ * Called after last netdevice attached to the hardware
+ * is disabled. This should turn off the hardware (at least
+ * it must turn off frame reception.)
+ * May be called right after add_interface if that rejects
+ * an interface.
+ *
+ * Must be implemented.
+ */
+ void (*stop)(struct ieee80211_hw *hw);
+
+ /*
+ * Called when a netdevice attached to the hardware is enabled.
+ * Because it is not called for monitor mode devices, open()
+ * and stop() must be implemented.
+ * The driver should perform any initialization it needs before
+ * the device can be enabled. The initial configuration for the
+ * interface is given in the conf parameter.
+ *
+ * Must be implemented.
*/
int (*add_interface)(struct ieee80211_hw *hw,
struct ieee80211_if_init_conf *conf);

- /* Notify a driver that an interface is going down. The stop() handler
- * is called prior to this if this is a last interface. */
+ /*
+ * Notifies a driver that an interface is going down. The stop() handler
+ * is called after this if it is the last interface and no monitor
+ * interfaces are present.
+ * When all interfaces are removed, the MAC address in the hardware
+ * must be cleared so the device no longer acknowledges packets,
+ * the mac_addr member of the conf structure is, however, set to the
+ * MAC address of the device going away.
+ *
+ * Hence, this callback must be implemented.
+ */
void (*remove_interface)(struct ieee80211_hw *hw,
struct ieee80211_if_init_conf *conf);

@@ -629,15 +683,31 @@ 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);
+ /*
+ * Configure the device's RX filter.
+ *
+ * The multi_count parameter tells how many multicast addresses are
+ * enabled. Use ieee80211_get_mc_list_item() to get the items.
+ * It will be -1 if the IEEE80211_HW_MULTICAST_FILTER flag is not
+ * included in the features or if the multicast list hasn't changed
+ * since the last call, otherwise the number of multicast addresses.
+ *
+ * NOTE: If the count is -1 then you may not call
+ * ieee80211_get_mc_list_item() from this function!
+ *
+ * NOTE: The count currently doesn't take into account duplicate
+ * addresses from different virtual interfaces!
+ *
+ * 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 (*configure_filter)(struct ieee80211_hw *hw, int multi_count,
+ 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-21 16:26:46.415923881 +0200
+++ wireless-dev/net/mac80211/ieee80211.c 2007-08-21 18:17:37.420411759 +0200
@@ -44,6 +44,18 @@ struct ieee80211_tx_status_rtap_hdr {
u8 data_retries;
} __attribute__ ((packed));

+/* locking must be nested */
+enum netif_tx_lock_class {
+ TX_LOCK_NORMAL,
+ TX_LOCK_MASTER,
+};
+
+static inline void netif_tx_lock_nested(struct net_device *dev, int subclass)
+{
+ spin_lock_nested(&dev->_xmit_lock, subclass);
+ dev->xmit_lock_owner = smp_processor_id();
+}
+
/* common interface routines */

static struct net_device_stats *ieee80211_get_stats(struct net_device *dev)
@@ -59,6 +71,53 @@ static int header_parse_80211(struct sk_
return ETH_ALEN;
}

+/* filter configuration */
+static void ieee80211_configure_filter(struct ieee80211_local *local)
+{
+ unsigned int changed_flags;
+ unsigned int new_flags = 0;
+ int mc_count = -1;
+
+ /* why? we need some lock to protect things, but this? */
+ netif_tx_lock_nested(local->mdev, TX_LOCK_MASTER);
+
+ if (local->iff_promiscs)
+ new_flags |= FIF_PROMISC_IN_BSS;
+
+ if (local->iff_allmultis ||
+ (local->mc_count > 0 &&
+ !(local->hw.flags & IEEE80211_HW_MULTICAST_FILTER)))
+ new_flags |= FIF_ALLMULTI;
+
+ if (local->monitors)
+ new_flags |= FIF_CONTROL |
+ FIF_OTHER_BSS |
+ FIF_BCN_PRBRESP_PROMISC;
+
+ changed_flags = local->filter_flags ^ new_flags;
+
+ if (local->hw.flags & IEEE80211_HW_MULTICAST_FILTER)
+ mc_count = local->mc_count;
+ else
+ mc_count = -1;
+
+ read_lock(&local->sub_if_lock);
+
+ /* be a bit nasty */
+ new_flags |= (1<<31);
+
+ local->ops->configure_filter(local_to_hw(local),
+ mc_count,
+ changed_flags,
+ &new_flags);
+
+ WARN_ON(new_flags & (1<<31));
+ local->filter_flags = new_flags & ~(1<<31);
+ read_unlock(&local->sub_if_lock);
+
+ netif_tx_unlock(local->mdev);
+}
+
/* master interface */

static int ieee80211_master_open(struct net_device *dev)
@@ -316,49 +375,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);
-
- 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;
@@ -384,84 +400,90 @@ 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));
- else if (!res && local->apdev)
- dev_open(local->apdev);
- }
- }
- if (res) {
- if (local->ops->remove_interface)
- local->ops->remove_interface(local_to_hw(local),
- &conf);
+ if (local->ops->start)
+ res = local->ops->start(local_to_hw(local));
+ if (res)
return res;
- }
}
- local->open_count++;

- if (sdata->type == IEEE80211_IF_TYPE_MNTR) {
+ switch (sdata->type) {
+ case IEEE80211_IF_TYPE_MNTR:
+ /* must be before the call to ieee80211_configure_filter */
local->monitors++;
- local->hw.conf.flags |= IEEE80211_CONF_RADIOTAP;
- } else {
+ if (local->monitors == 1) {
+ ieee80211_configure_filter(local);
+
+ local->hw.conf.flags |= IEEE80211_CONF_RADIOTAP;
+ ieee80211_hw_config(local);
+ }
+ break;
+ case IEEE80211_IF_TYPE_STA:
+ case IEEE80211_IF_TYPE_IBSS:
+ sdata->u.sta.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);
ieee80211_enable_keys(sdata);
+
+ if (sdata->type == IEEE80211_IF_TYPE_STA &&
+ !local->user_space_mlme)
+ netif_carrier_off(dev);
+ else
+ netif_carrier_on(dev);
}

- if (sdata->type == IEEE80211_IF_TYPE_STA &&
- !local->user_space_mlme)
- netif_carrier_off(dev);
- else
- netif_carrier_on(dev);
+ if (local->open_count == 0) {
+ res = dev_open(local->mdev);
+ WARN_ON(res);
+ if (local->apdev) {
+ res = dev_open(local->apdev);
+ WARN_ON(res);
+ }
+ tasklet_enable(&local->tx_pending_tasklet);
+ tasklet_enable(&local->tasklet);
+ }
+
+ local->open_count++;

netif_start_queue(dev);
+
return 0;
}

-static void ieee80211_if_shutdown(struct net_device *dev)
+static int ieee80211_stop(struct net_device *dev)
{
+ struct ieee80211_sub_if_data *sdata;
struct ieee80211_local *local = wdev_priv(dev->ieee80211_ptr);
- struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev);
+ struct ieee80211_if_init_conf conf;
+
+ sdata = IEEE80211_DEV_TO_SUB_IF(dev);
+
+ netif_stop_queue(dev);
+
+ local->open_count--;

- ASSERT_RTNL();
switch (sdata->type) {
+ case IEEE80211_IF_TYPE_MNTR:
+ local->monitors--;
+ if (local->monitors == 0) {
+ ieee80211_configure_filter(local);
+
+ local->hw.conf.flags |= IEEE80211_CONF_RADIOTAP;
+ ieee80211_hw_config(local);
+ }
+ break;
case IEEE80211_IF_TYPE_STA:
case IEEE80211_IF_TYPE_IBSS:
sdata->u.sta.state = IEEE80211_DISABLED;
@@ -483,118 +505,66 @@ 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;
- } else {
+ /* fall through */
+ default:
+ conf.if_id = dev->ifindex;
+ conf.type = sdata->type;
+ conf.mac_addr = dev->dev_addr;
/* disable all keys for as long as this netdev is down */
ieee80211_disable_keys(sdata);
+ local->ops->remove_interface(local_to_hw(local), &conf);
}

- local->open_count--;
if (local->open_count == 0) {
if (netif_running(local->mdev))
dev_close(local->mdev);
+
if (local->apdev)
dev_close(local->apdev);
+
if (local->ops->stop)
local->ops->stop(local_to_hw(local));
+
tasklet_disable(&local->tx_pending_tasklet);
tasklet_disable(&local->tasklet);
}
- if (local->ops->remove_interface) {
- struct ieee80211_if_init_conf conf;
-
- conf.if_id = dev->ifindex;
- conf.type = sdata->type;
- conf.mac_addr = dev->dev_addr;
- local->ops->remove_interface(local_to_hw(local), &conf);
- }
-
- ieee80211_start_hard_monitor(local);

return 0;
}

-enum netif_tx_lock_class {
- TX_LOCK_NORMAL,
- TX_LOCK_MASTER,
-};
-
-static inline void netif_tx_lock_nested(struct net_device *dev, int subclass)
-{
- spin_lock_nested(&dev->_xmit_lock, subclass);
- dev->xmit_lock_owner = smp_processor_id();
-}
-
static void ieee80211_set_multicast_list(struct net_device *dev)
{
struct ieee80211_local *local = wdev_priv(dev->ieee80211_ptr);
struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev);
- unsigned short flags;
+ int allmulti, promisc;

- 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;
+ allmulti = !!(dev->flags & IFF_ALLMULTI);
+ promisc = !!(dev->flags & IFF_PROMISC);
+
+ if (allmulti != sdata->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 (promisc != sdata->promisc) {
+ if (dev->flags & IFF_PROMISC)
local->iff_promiscs++;
- }
+ else
+ local->iff_promiscs--;
}
+
+ sdata->allmulti = allmulti;
+ sdata->promisc = promisc;
+
if (dev->mc_count != sdata->mc_count) {
local->mc_count = local->mc_count - sdata->mc_count +
dev->mc_count;
sdata->mc_count = dev->mc_count;
}
- if (local->ops->set_multicast_list) {
- flags = local->mdev->flags;
- if (local->iff_allmultis)
- flags |= IFF_ALLMULTI;
- if (local->iff_promiscs)
- flags |= IFF_PROMISC;
- read_lock(&local->sub_if_lock);
- local->ops->set_multicast_list(local_to_hw(local), flags,
- local->mc_count);
- read_unlock(&local->sub_if_lock);
- }
- netif_tx_unlock(local->mdev);
+
+ ieee80211_configure_filter(local);
}

/* Must not be called for mdev and apdev */
@@ -656,7 +626,6 @@ static int __ieee80211_if_config(struct
struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev);
struct ieee80211_local *local = wdev_priv(dev->ieee80211_ptr);
struct ieee80211_if_conf conf;
- static u8 scan_bssid[] = { 0xff, 0xff, 0xff, 0xff, 0xff, 0xff };

if (!local->ops->config_interface || !netif_running(dev))
return 0;
@@ -665,11 +634,7 @@ static int __ieee80211_if_config(struct
conf.type = sdata->type;
if (sdata->type == IEEE80211_IF_TYPE_STA ||
sdata->type == IEEE80211_IF_TYPE_IBSS) {
- if (local->sta_scanning &&
- local->scan_dev == dev)
- conf.bssid = scan_bssid;
- else
- conf.bssid = sdata->u.sta.bssid;
+ conf.bssid = sdata->u.sta.bssid;
conf.ssid = sdata->u.sta.ssid;
conf.ssid_len = sdata->u.sta.ssid_len;
conf.generic_elem = sdata->u.sta.extra_ie;
@@ -1192,8 +1157,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->configure_filter);
local->ops = ops;

/* for now, mdev needs sub_if_data :/ */
--- wireless-dev.orig/net/mac80211/ieee80211_i.h 2007-08-21 16:26:46.365923881 +0200
+++ wireless-dev/net/mac80211/ieee80211_i.h 2007-08-21 18:16:44.430411759 +0200
@@ -476,6 +476,7 @@ struct ieee80211_local {
struct net_device *apdev; /* wlan#ap - management frames (hostapd) */
int open_count;
int monitors;
+ unsigned int filter_flags; /* FIF_* */
struct iw_statistics wstats;
u8 wstats_flags;
int tx_headroom; /* required headroom for hardware/radiotap */
--- wireless-dev.orig/net/mac80211/rx.c 2007-08-21 16:28:19.015923881 +0200
+++ wireless-dev/net/mac80211/rx.c 2007-08-21 16:41:30.935923881 +0200
@@ -1450,7 +1450,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;
}
@@ -1465,7 +1465,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-21 14:58:37.375923881 +0200
+++ wireless-dev/net/mac80211/debugfs_netdev.c 2007-08-21 18:16:44.620411759 +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-21 16:26:46.435923881 +0200
+++ wireless-dev/drivers/net/wireless/b43/b43.h 2007-08-21 16:41:30.935923881 +0200
@@ -593,9 +593,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). */
@@ -604,14 +603,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;

@@ -768,8 +763,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-21 16:26:46.385923881 +0200
+++ wireless-dev/drivers/net/wireless/b43/main.c 2007-08-21 18:16:45.270411759 +0200
@@ -92,14 +92,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)");
@@ -562,12 +554,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)
@@ -2039,33 +2029,25 @@ static void b43_adjust_opmode(struct b43
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. */
@@ -2229,9 +2211,6 @@ static int b43_chip_init(struct b43_wlde
& ~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);
@@ -2970,21 +2949,41 @@ out:
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,
+ int multi_count,
+ 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 |
+ 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);
}

@@ -2999,18 +2998,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);
@@ -3430,7 +3427,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);

@@ -3460,21 +3458,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;

b43dbg(wl, "Adding Interface type %d\n", conf->type);

dev = wl->current_dev;
+ wl->operating = 1;
+ wl->if_id = conf->if_id;
+ wl->if_type = conf->type;
+ 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;
+
+ b43dbg(wl, "Removing Interface type %d\n", conf->type);
+
+ mutex_lock(&wl->mutex);
+
+ B43_WARN_ON(!wl->operating);
+ B43_WARN_ON(wl->if_id != conf->if_id);
+
+ wl->operating = 0;
+
+ spin_lock_irqsave(&wl->irq_lock, flags);
+ b43_adjust_opmode(dev);
+ 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) {
@@ -3484,59 +3541,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;
-
- b43dbg(wl, "Removing Interface type %d\n", conf->type);
+ struct b43_wldev *dev = wl->current_dev;

mutex_lock(&wl->mutex);
- if (conf->type == IEEE80211_IF_TYPE_MNTR) {
- wl->monitor--;
- B43_WARN_ON(wl->monitor < 0);
- } else {
- B43_WARN_ON(!wl->operating);
- wl->operating = 0;
- }
-
- dev = wl->current_dev;
- if (!wl->operating && wl->monitor == 0) {
- /* No interface left. */
- if (b43_status(dev) >= B43_STAT_STARTED)
- b43_wireless_core_stop(dev);
- b43_wireless_core_exit(dev);
- } else {
- /* Just monitor interfaces left. */
- spin_lock_irqsave(&wl->irq_lock, flags);
- b43_adjust_opmode(dev);
- if (!wl->operating)
- b43_upload_card_macaddress(dev, NULL);
- spin_unlock_irqrestore(&wl->irq_lock, flags);
- }
+ if (b43_status(dev) >= B43_STAT_STARTED)
+ b43_wireless_core_stop(dev);
+ b43_wireless_core_exit(dev);
mutex_unlock(&wl->mutex);
}

@@ -3547,10 +3566,12 @@ static const struct ieee80211_ops b43_hw
.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.
@@ -3888,7 +3909,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-21 16:26:46.395923881 +0200
+++ wireless-dev/drivers/net/wireless/iwl-base.c 2007-08-21 16:41:30.965923881 +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,18 @@ 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_configure_filter(struct ieee80211_hw *hw,
+ int multi_count,
+ 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 +7712,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
@@ -7714,8 +7728,14 @@ static int iwl_mac_config_interface(stru
IWL_DEBUG_MAC80211("bssid: " MAC_FMT "\n",
MAC_ARG(conf->bssid));

+ /*
+ * XXX: there was a test for IEEE80211_HW_NO_PROBE_FILTERING here
+ * which must have been wrong since it was always true.
+ * the test was:
if (unlikely(priv->status & STATUS_SCANNING) &&
!(priv->hw->flags & IEEE80211_HW_NO_PROBE_FILTERING)) {
+ */
+ if (unlikely(priv->status & STATUS_SCANNING)) {
IWL_DEBUG_MAC80211("leave - scanning\n");
mutex_unlock(&priv->mutex);
return 0;
@@ -7808,6 +7828,8 @@ static void iwl_mac_remove_interface(str
}
mutex_unlock(&priv->mutex);

+ /* TODO: clear MAC address in hardware */
+
IWL_DEBUG_MAC80211("leave\n");

}
@@ -9059,10 +9081,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,
+ .configure_filter = iwl_configure_filter,
.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-21 16:25:42.685923881 +0200
+++ wireless-dev/drivers/net/wireless/rtl8187_dev.c 2007-08-21 16:41:30.975923881 +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;
@@ -419,7 +419,7 @@ static int rtl8187_open(struct ieee80211
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,7 +445,6 @@ static int rtl8187_stop(struct ieee80211
usb_kill_urb(info->urb);
kfree_skb(skb);
}
- return 0;
}

static int rtl8187_add_interface(struct ieee80211_hw *dev,
@@ -476,6 +475,8 @@ static void rtl8187_remove_interface(str
{
struct rtl8187_priv *priv = dev->priv;
priv->mode = IEEE80211_IF_TYPE_MGMT;
+
+ /* TODO: reset MAC address to zeroes */
}

static int rtl8187_config(struct ieee80211_hw *dev, struct ieee80211_conf *conf)
@@ -523,14 +524,28 @@ static int rtl8187_config_interface(stru
return 0;
}

+static void rtl8187_configure_filter(struct ieee80211_hw *dev,
+ int multi_count,
+ 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,
+ .configure_filter = rtl8187_configure_filter,
};

static void rtl8187_eeprom_register_read(struct eeprom_93cx6 *eeprom)
--- wireless-dev.orig/drivers/net/wireless/adm8211.c 2007-08-21 16:26:46.425923881 +0200
+++ wireless-dev/drivers/net/wireless/adm8211.c 2007-08-21 16:41:30.975923881 +0200
@@ -349,25 +349,47 @@ 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_set_bssid(struct ieee80211_hw *dev, u8 *bssid)
+{
+ struct adm8211_priv *priv = dev->priv;
+ u32 reg;
+
+ reg = bssid[0] | (bssid[1] << 8) | (bssid[2] << 16) | (bssid[3] << 24);
+ ADM8211_CSR_WRITE(BSSID0, reg);
+ reg = ADM8211_CSR_READ(ABDA1);
+ reg &= 0x0000ffff;
+ reg |= (bssid[4] << 16) | (bssid[5] << 24);
+ ADM8211_CSR_WRITE(ABDA1, reg);
+}
+
+static void adm8211_configure_filter(struct ieee80211_hw *dev,
+ int multi_count,
+ unsigned int changed,
+ unsigned int *flags)
{
struct adm8211_priv *priv = dev->priv;
unsigned int bit_nr;
__le32 mc_filter[2];
struct dev_mc_list *mclist;
void *tmp;
+ int change = 0;
+ u8 bcast_addr[ETH_ALEN] = {0xff, 0xff, 0xff, 0xff, 0xff, 0xff};

- 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)) {
+ change = 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);
- } else {
+ change = 1;
+ } else if (multi_count >= 0) {
priv->nar &= ~(ADM8211_NAR_MM | ADM8211_NAR_PR);
mc_filter[1] = mc_filter[0] = 0;
mclist = NULL;
@@ -377,15 +399,27 @@ static void adm8211_set_rx_mode(struct i
bit_nr &= 0x3F;
mc_filter[bit_nr >> 5] |= cpu_to_le32(1 << (bit_nr & 31));
}
+ change = 1;
}

- ADM8211_IDLE_RX();
+ *flags &= FIF_PROMISC_IN_BSS | FIF_ALLMULTI | FIF_BCN_PRBRESP_PROMISC;

- ADM8211_CSR_WRITE(MAR0, mc_filter[0]);
- ADM8211_CSR_WRITE(MAR1, mc_filter[1]);
- ADM8211_CSR_READ(NAR);
+ if (change & FIF_BCN_PRBRESP_PROMISC) {
+ if (*flags & FIF_BCN_PRBRESP_PROMISC)
+ adm8211_set_bssid(dev, bcast_addr);
+ else
+ adm8211_set_bssid(dev, priv->bssid);
+ }

- ADM8211_RESTORE();
+ if (change) {
+ ADM8211_IDLE_RX();
+
+ ADM8211_CSR_WRITE(MAR0, mc_filter[0]);
+ ADM8211_CSR_WRITE(MAR1, mc_filter[1]);
+ ADM8211_CSR_READ(NAR);
+
+ ADM8211_RESTORE();
+ }
}

static int adm8211_get_tx_stats(struct ieee80211_hw *dev,
@@ -1414,19 +1448,6 @@ static void adm8211_set_interval(struct
ADM8211_CSR_WRITE(BPLI, reg);
}

-static void adm8211_set_bssid(struct ieee80211_hw *dev, u8 *bssid)
-{
- struct adm8211_priv *priv = dev->priv;
- u32 reg;
-
- reg = bssid[0] | (bssid[1] << 8) | (bssid[2] << 16) | (bssid[3] << 24);
- ADM8211_CSR_WRITE(BSSID0, reg);
- reg = ADM8211_CSR_READ(ABDA1);
- reg &= 0x0000ffff;
- reg |= (bssid[4] << 16) | (bssid[5] << 24);
- ADM8211_CSR_WRITE(ABDA1, reg);
-}
-
static int adm8211_set_ssid(struct ieee80211_hw *dev, u8 *ssid, size_t ssid_len)
{
struct adm8211_priv *priv = dev->priv;
@@ -1502,6 +1523,8 @@ static void adm8211_remove_interface(str
{
struct adm8211_priv *priv = dev->priv;
priv->mode = IEEE80211_IF_TYPE_MGMT;
+
+ /* TODO: clear MAC address */
}

static int adm8211_init_rings(struct ieee80211_hw *dev)
@@ -1585,7 +1608,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;
@@ -1628,7 +1651,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;

@@ -1640,7 +1663,6 @@ static int adm8211_stop(struct ieee80211
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,
@@ -1841,13 +1863,13 @@ static int adm8211_alloc_rings(struct ie

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
@@ -1953,7 +1975,8 @@ static int __devinit adm8211_probe(struc
SET_IEEE80211_PERM_ADDR(dev, perm_addr);

dev->extra_tx_headroom = sizeof(struct adm8211_tx_hdr);
- dev->flags = IEEE80211_HW_WEP_INCLUDE_IV;
+ dev->flags = IEEE80211_HW_WEP_INCLUDE_IV |
+ IEEE80211_HW_MULTICAST_FILTER;
// however, IEEE80211_HW_RX_INCLUDES_FCS in promisc mode

dev->channel_change_time = 1000;
@@ -2082,7 +2105,7 @@ static int adm8211_resume(struct pci_dev
pci_restore_state(pdev);

if (priv->mode != IEEE80211_IF_TYPE_MGMT) {
- adm8211_open(dev);
+ adm8211_start(dev);
ieee80211_start_queues(dev);
}

--- wireless-dev.orig/drivers/net/wireless/zd1211rw-mac80211/zd_mac.c 2007-08-21 14:58:37.695923881 +0200
+++ wireless-dev/drivers/net/wireless/zd1211rw-mac80211/zd_mac.c 2007-08-21 16:41:30.995923881 +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;
}

/**
@@ -693,7 +680,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);
@@ -715,7 +702,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;
@@ -765,18 +751,19 @@ 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_configure_filter(struct ieee80211_hw *hw,
+ int multi_count,
+ 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 {
+ } else if (multi_count >= 0) {
struct dev_mc_list *mc = NULL;
void *tmp = NULL;
zd_mc_clear(&hash);
@@ -787,10 +774,18 @@ static void zd_op_set_multicast_list(str
}
}

- spin_lock_irqsave(&mac->lock, flags);
- mac->multicast_hash = hash;
- spin_unlock_irqrestore(&mac->lock, flags);
- queue_work(zd_workqueue, &mac->set_multicast_hash_work);
+ /*
+ * XXX: probably not right, we probably see many other
+ * frames as well...
+ */
+ *filterflags &= FIF_PROMISC_IN_BSS | FIF_ALLMULTI;
+
+ if (multi_count >= 0) {
+ spin_lock_irqsave(&mac->lock, flags);
+ mac->multicast_hash = hash;
+ spin_unlock_irqrestore(&mac->lock, flags);
+ queue_work(zd_workqueue, &mac->set_multicast_hash_work);
+ }
}

static void set_rts_cts_work(struct work_struct *work)
@@ -834,13 +829,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,
+ .configure_filter = zd_op_configure_filter,
.erp_ie_changed = zd_op_erp_ie_changed,
};

@@ -880,7 +875,8 @@ struct ieee80211_hw *zd_mac_alloc_hw(str

hw->flags = IEEE80211_HW_RX_INCLUDES_FCS |
IEEE80211_HW_WEP_INCLUDE_IV |
- IEEE80211_HW_DEFAULT_REG_DOMAIN_CONFIGURED;
+ IEEE80211_HW_DEFAULT_REG_DOMAIN_CONFIGURED |
+ IEEE80211_HW_MULTICAST_FILTER;
hw->max_rssi = 100;
hw->max_signal = 100;

--- wireless-dev.orig/net/mac80211/ieee80211_sta.c 2007-08-21 16:25:44.625923881 +0200
+++ wireless-dev/net/mac80211/ieee80211_sta.c 2007-08-21 16:41:31.005923881 +0200
@@ -3583,10 +3583,10 @@ void ieee80211_scan_completed(struct iee
printk(KERN_DEBUG "%s: failed to restore operational"
"channel after scan\n", dev->name);

- if (!(local->hw.flags & IEEE80211_HW_NO_PROBE_FILTERING) &&
- ieee80211_if_config(dev))
- printk(KERN_DEBUG "%s: failed to restore operational"
- "BSSID after scan\n", dev->name);
+ local->filter_flags &= ~FIF_BCN_PRBRESP_PROMISC;
+ local->ops->configure_filter(local_to_hw(local), -1,
+ FIF_BCN_PRBRESP_PROMISC,
+ &local->filter_flags);

memset(&wrqu, 0, sizeof(wrqu));
wireless_send_event(dev, SIOCGIWSCAN, &wrqu, NULL);
@@ -3770,10 +3770,10 @@ static int ieee80211_sta_start_scan(stru
local->scan_channel_idx = 0;
local->scan_dev = dev;

- if (!(local->hw.flags & IEEE80211_HW_NO_PROBE_FILTERING) &&
- ieee80211_if_config(dev))
- printk(KERN_DEBUG "%s: failed to set BSSID for scan\n",
- dev->name);
+ local->filter_flags |= FIF_BCN_PRBRESP_PROMISC;
+ local->ops->configure_filter(local_to_hw(local), -1,
+ FIF_BCN_PRBRESP_PROMISC,
+ &local->filter_flags);

/* TODO: start scan as soon as all nullfunc frames are ACKed */
queue_delayed_work(local->hw.workqueue, &local->scan_work,
--- wireless-dev.orig/drivers/net/wireless/rt2x00/rt2400pci.c 2007-08-21 16:43:57.415923881 +0200
+++ wireless-dev/drivers/net/wireless/rt2x00/rt2400pci.c 2007-08-21 16:44:54.265923881 +0200
@@ -1447,10 +1447,7 @@ static void rt2400pci_probe_hw_mode(stru
/*
* 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;
@@ -1593,7 +1590,7 @@ static const struct ieee80211_ops rt2400
.remove_interface = rt2x00mac_remove_interface,
.config = rt2x00mac_config,
.config_interface = rt2x00mac_config_interface,
- .set_multicast_list = rt2x00mac_set_multicast_list,
+// .set_multicast_list = rt2x00mac_set_multicast_list,
.get_stats = rt2x00mac_get_stats,
.set_retry_limit = rt2400pci_set_retry_limit,
.conf_tx = rt2400pci_conf_tx,
--- wireless-dev.orig/drivers/net/wireless/rt2x00/rt2500pci.c 2007-08-21 16:45:36.915923881 +0200
+++ wireless-dev/drivers/net/wireless/rt2x00/rt2500pci.c 2007-08-21 16:45:44.825923881 +0200
@@ -1745,10 +1745,7 @@ static void rt2500pci_probe_hw_mode(stru
/*
* 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;
@@ -1884,7 +1881,7 @@ static const struct ieee80211_ops rt2500
.remove_interface = rt2x00mac_remove_interface,
.config = rt2x00mac_config,
.config_interface = rt2x00mac_config_interface,
- .set_multicast_list = rt2x00mac_set_multicast_list,
+// .set_multicast_list = rt2x00mac_set_multicast_list,
.get_stats = rt2x00mac_get_stats,
.set_retry_limit = rt2500pci_set_retry_limit,
.conf_tx = rt2x00mac_conf_tx,
--- wireless-dev.orig/drivers/net/wireless/rt2x00/rt61pci.c 2007-08-21 16:46:00.575923881 +0200
+++ wireless-dev/drivers/net/wireless/rt2x00/rt61pci.c 2007-08-21 16:46:09.275923881 +0200
@@ -2118,10 +2118,7 @@ static void rt61pci_probe_hw_mode(struct
/*
* 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;
@@ -2247,7 +2244,7 @@ static const struct ieee80211_ops rt61pc
.remove_interface = rt2x00mac_remove_interface,
.config = rt2x00mac_config,
.config_interface = rt2x00mac_config_interface,
- .set_multicast_list = rt2x00mac_set_multicast_list,
+// .set_multicast_list = rt2x00mac_set_multicast_list,
.get_stats = rt2x00mac_get_stats,
.set_retry_limit = rt61pci_set_retry_limit,
.conf_tx = rt2x00mac_conf_tx,
--- wireless-dev.orig/drivers/net/wireless/rt2x00/rt2500usb.c 2007-08-21 16:46:25.065923881 +0200
+++ wireless-dev/drivers/net/wireless/rt2x00/rt2500usb.c 2007-08-21 16:46:33.655923881 +0200
@@ -1467,9 +1467,7 @@ static void rt2500usb_probe_hw_mode(stru
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;
@@ -1562,7 +1560,7 @@ static const struct ieee80211_ops rt2500
.remove_interface = rt2x00mac_remove_interface,
.config = rt2x00mac_config,
.config_interface = rt2x00mac_config_interface,
- .set_multicast_list = rt2x00mac_set_multicast_list,
+// .set_multicast_list = rt2x00mac_set_multicast_list,
.get_stats = rt2x00mac_get_stats,
.conf_tx = rt2x00mac_conf_tx,
.get_tx_stats = rt2x00mac_get_tx_stats,
--- wireless-dev.orig/drivers/net/wireless/rt2x00/rt73usb.c 2007-08-21 16:46:47.145923881 +0200
+++ wireless-dev/drivers/net/wireless/rt2x00/rt73usb.c 2007-08-21 16:46:52.695923881 +0200
@@ -1713,9 +1713,7 @@ static void rt73usb_probe_hw_mode(struct
*/
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;
@@ -1856,7 +1854,7 @@ static const struct ieee80211_ops rt73us
.remove_interface = rt2x00mac_remove_interface,
.config = rt2x00mac_config,
.config_interface = rt2x00mac_config_interface,
- .set_multicast_list = rt2x00mac_set_multicast_list,
+// .set_multicast_list = rt2x00mac_set_multicast_list,
.get_stats = rt2x00mac_get_stats,
.set_retry_limit = rt73usb_set_retry_limit,
.conf_tx = rt2x00mac_conf_tx,

--



2007-08-21 21:06:46

by Ivo Van Doorn

[permalink] [raw]
Subject: Re: [RFC 2/2] mac80211: revamp interface and filter configuration

On Tuesday 21 August 2007, Johannes Berg wrote:
> 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 according to the filter flags.
>
> Multicast filtering is a bit special, which is why drivers
> that do not require FIF_ALLMULTI for multicast address filters
> (i.e. they actually have filters for multicast addresses)
> need to set the new IEEE80211_HW_MULTICAST_FILTER flag and
> call the ieee80211_get_mc_list_item() function.
>
> 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 multicast.

Personally I like the idea of this packet filtering, implementation
and driver interface looks allright to me.

> WARNING: This patch makes the ralink drivers BUG_ON().

If you can give me a warning when you are going to submit this
for inclusion, I'll cook up a patch to make it work for rt2x00. :)

Ivo

2007-08-22 09:27:06

by Johannes Berg

[permalink] [raw]
Subject: Re: [RFC 2/2] mac80211: revamp interface and filter configuration

On Tue, 2007-08-21 at 23:14 +0200, Ivo van Doorn wrote:

> > WARNING: This patch makes the ralink drivers BUG_ON().
>
> If you can give me a warning when you are going to submit this
> for inclusion, I'll cook up a patch to make it work for rt2x00. :)

Will do, thanks :)

johannes


Attachments:
signature.asc (190.00 B)
This is a digitally signed message part

2007-09-05 14:19:49

by Johannes Berg

[permalink] [raw]
Subject: Re: [RFC 2/2] mac80211: revamp interface and filter configuration

On Wed, 2007-09-05 at 16:16 +0200, Michael Buesch wrote:

> > > 1) Use ieee80211_stop_queues() in ->configure_filter() and
> > > ieee80211_wake_queues() at the end of the workqueue function.
> > >
> > > 2) Throw away all packets until the workqueue function
> > > terminates.
> > >
> > > 3) Implement our own tx queue.
> > >
> > > I prefer to do option (1) because it wouldn't require adding
> > > additional fields to our private structure beside the work_struct
> > > for the workqueue function, it is simple to implement and it would
> > > not throw away any packets. Are there any side effects that I have
> > > overlooked?
> >
> > I think Michael says it's currently buggy if called outside of ->tx().
>
> Yes, we had a bug in b43 where we used it in the periodic workqueue.
> It causes really hard to track down system freezes on UP
> systems due to races with the TX code.
> It will hang and busy wait in the qdisc code when this triggers.
> I didn't see a fix for this, yet.
> But I think a fix could probably be to take the netif_tx_lock
> in the ieee80211_stop_queues() function, so we make sure that no
> TX is in progress while we stop it.

Ok. Of course, for zd1211 it'd be easy to set a flag in
configure_filter() and check that flag in tx() and if it's set then call
stop_queues().

johannes


Attachments:
signature.asc (190.00 B)
This is a digitally signed message part

2007-09-03 08:34:50

by Johannes Berg

[permalink] [raw]
Subject: Re: [RFC 2/2] mac80211: revamp interface and filter configuration

On Sun, 2007-09-02 at 22:07 -0400, Daniel Drake wrote:

> This is slightly freaky for zd1211rw and probably other USB drivers. In
> most cases we can't act upon any of those filter flag changes in atomic
> context.

Yeah, I know, but it's running under the tx lock and I haven't seen a
way to drop that (yet)

> We could defer work like we do for multicast lists, but then the driver
> would be lying in that it would return from configure_filter saying that
> it has honoured some flags without actually having done so (yet).

Yup, I saw that you do that anyway so didn't think much of it.

> Will that be a problem? I'm thinking maybe not, since the flags only
> affect RX and we can't determine which frames will be in the air at any
> time. [as opposed to such atomicity problems that relate to TX, we can
> just disable TX until the work has completed]

It does matter a bit for scanning, if you have BSSID filters that affect
beacons and probe responses then you would want to turn those off before
transmitting the next probe response. However, when the multicast_count
parameter is -1 to indicate no changes in the multicast list (and you
then need to use the cached hash value in zd1211) the callback actually
*can* sleep.

This is a rather weird area of the patch. Splitting it up into two
callbacks makes no sense, and so far I have not understood why it runs
under the TX lock so haven't changed it.

> > + * This callback is must be implemented.
> > + */
>
> Typo.

Good point, thanks.

Slightly updated patch at
http://johannes.sipsolutions.net/patches/kernel/all/2007-09-03-08:32/021-mac80211-filter-flags.patch

johannes


Attachments:
signature.asc (190.00 B)
This is a digitally signed message part

2007-09-05 14:16:56

by Michael Büsch

[permalink] [raw]
Subject: Re: [RFC 2/2] mac80211: revamp interface and filter configuration

On Wednesday 05 September 2007, Johannes Berg wrote:
> On Wed, 2007-09-05 at 07:16 +0200, Ulrich Kunitz wrote:
>
> > I see three options to achieve this:
> >
> > 1) Use ieee80211_stop_queues() in ->configure_filter() and
> > ieee80211_wake_queues() at the end of the workqueue function.
> >
> > 2) Throw away all packets until the workqueue function
> > terminates.
> >
> > 3) Implement our own tx queue.
> >
> > I prefer to do option (1) because it wouldn't require adding
> > additional fields to our private structure beside the work_struct
> > for the workqueue function, it is simple to implement and it would
> > not throw away any packets. Are there any side effects that I have
> > overlooked?
>
> I think Michael says it's currently buggy if called outside of ->tx().

Yes, we had a bug in b43 where we used it in the periodic workqueue.
It causes really hard to track down system freezes on UP
systems due to races with the TX code.
It will hang and busy wait in the qdisc code when this triggers.
I didn't see a fix for this, yet.
But I think a fix could probably be to take the netif_tx_lock
in the ieee80211_stop_queues() function, so we make sure that no
TX is in progress while we stop it.

2007-09-05 14:25:50

by Michael Wu

[permalink] [raw]
Subject: Re: [RFC 2/2] mac80211: revamp interface and filter configuration

On Wednesday 05 September 2007 07:23, Johannes Berg wrote:
> > I prefer to do option (1) because it wouldn't require adding
> > additional fields to our private structure beside the work_struct
> > for the workqueue function, it is simple to implement and it would
> > not throw away any packets. Are there any side effects that I have
> > overlooked?
>
> I think Michael says it's currently buggy if called outside of ->tx().
>
That's just a general rule of thumb. configure_filter holds the tx lock so
it's actually safe to do that there. In other cases, it can be buggy (some tx
code can get stuck) and racy (frames can get enqueued after stopping the
queues). The first can be fixed in mac80211, but the second can't be. For
most cases, stopping the hardware queue(s) should be done instead and
possibly flushing the queue or waiting for it to empty, if you're trying to
adjust the radio.

-Michael Wu


Attachments:
(No filename) (912.00 B)
(No filename) (189.00 B)
Download all attachments

2007-09-03 14:12:08

by Johannes Berg

[permalink] [raw]
Subject: Re: [RFC 2/2] mac80211: revamp interface and filter configuration

On Mon, 2007-09-03 at 11:29 +0200, Johannes Berg wrote:
> Just had another idea related to this patch:

Just implemented that along with the race fix. Patch below.

johannes

Subject: 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, which is why drivers
that do not require FIF_ALLMULTI for multicast address filters
(i.e. they actually have filters for multicast addresses)
need to set the new IEEE80211_HW_MULTICAST_FILTER flag and
call the get_mc_item() function passed to the configure_filter
callback.

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.

WARNING: This patch makes the ralink and p54 drivers
BUG_ON().

Signed-off-by: Johannes Berg <[email protected]>
---
Changes since v1:
* introduce FIF_BCN_PRBRESP_PROMISC,
remove IEEE80211_HW_NO_PROBE_FILTERING

drivers/net/wireless/adm8211.c | 89 +++--
drivers/net/wireless/b43/b43.h | 15
drivers/net/wireless/b43/main.c | 244 +++++++------
drivers/net/wireless/iwl-base.c | 33 +
drivers/net/wireless/rt2x00/rt2400pci.c | 7
drivers/net/wireless/rt2x00/rt2500pci.c | 7
drivers/net/wireless/rt2x00/rt2500usb.c | 6
drivers/net/wireless/rt2x00/rt61pci.c | 7
drivers/net/wireless/rt2x00/rt73usb.c | 6
drivers/net/wireless/rtl8187_dev.c | 25 +
drivers/net/wireless/zd1211rw-mac80211/zd_mac.c | 76 ++--
include/net/mac80211.h | 160 +++++----
net/mac80211/debugfs_netdev.c | 16
net/mac80211/ieee80211.c | 419 +++++++++++-------------
net/mac80211/ieee80211_i.h | 1
net/mac80211/ieee80211_sta.c | 32 +
net/mac80211/rx.c | 4
17 files changed, 624 insertions(+), 523 deletions(-)

--- wireless-dev.orig/include/net/mac80211.h 2007-09-03 10:23:25.423978471 +0200
+++ wireless-dev/include/net/mac80211.h 2007-09-03 15:12:29.663973252 +0200
@@ -371,7 +371,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.
@@ -557,13 +556,12 @@ struct ieee80211_hw {

/* hole at 8 */

- /* Device is capable of performing full monitor mode even during
- * normal operation. */
-#define IEEE80211_HW_MONITOR_DURING_OPER (1<<9)
-
- /* Device does not need BSSID filter set to broadcast in order to
- * receive all probe responses while scanning */
-#define IEEE80211_HW_NO_PROBE_FILTERING (1<<10)
+ /*
+ * Device has multicast filters.
+ */
+#define IEEE80211_HW_MULTICAST_FILTER (1<<9)
+
+/* hole at 10 */

/* Channels are already configured to the default regulatory domain
* specified in the device's EEPROM */
@@ -601,6 +599,39 @@ 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.
+ */
+/*
+ * promiscuous mode within your BSS,
+ * think of the BSS as your network segment and then this corresponds
+ * to the regular ethernet device promiscuous mode
+ */
+#define FIF_PROMISC_IN_BSS 0x01
+/* show all multicast frames */
+#define FIF_ALLMULTI 0x02
+/* show frames with failed FCS, but set RX_FLAG_FAILED_FCS_CRC for them */
+#define FIF_FCSFAIL 0x04
+/* show frames with failed PLCP CRC, but set RX_FLAG_FAILED_PLCP_CRC for them */
+#define FIF_PLCPFAIL 0x08
+/*
+ * This flag is set during scanning to indicate to the hardware
+ * that it should not filter beacons or probe responses by BSSID.
+ */
+#define FIF_BCN_PRBRESP_PROMISC 0x10
+/*
+ * show control frames, if PROMISC_IN_BSS is not set then
+ * only those addressed to this station
+ */
+#define FIF_CONTROL 0x20
+/* show frames from other BSSes */
+#define FIF_OTHER_BSS 0x40
+
/* Configuration block used by the low-level driver to tell the 802.11 code
* about supported hardware features and to pass function pointers to callback
* functions. */
@@ -613,32 +644,55 @@ struct ieee80211_ops {
int (*tx)(struct ieee80211_hw *hw, struct sk_buff *skb,
struct ieee80211_tx_control *control);

- /* Handler that is called when any netdevice attached to the hardware
- * device is set UP for the first time. This can be used, e.g., to
- * enable interrupts and beacon sending. */
- int (*open)(struct ieee80211_hw *hw);
-
- /* Handler that is called when the last netdevice attached to the
- * hardware device is set DOWN. This can be used, e.g., to disable
- * interrupts and beacon sending. */
- int (*stop)(struct ieee80211_hw *hw);
-
- /* Handler for asking a driver if a new interface can be added (or,
- * more exactly, set UP). If the handler returns zero, the interface
- * is added. Driver should perform any initialization it needs prior
- * to returning zero. By returning non-zero addition of the interface
- * is inhibited. Unless monitor_during_oper is set, it is guaranteed
- * that monitor interfaces and normal interfaces are mutually
- * exclusive. If assigned, the open() handler is called after
- * add_interface() if this is the first device added. The
- * add_interface() callback has to be assigned because it is the only
- * way to obtain the requested MAC address for any interface.
+ /*
+ * Called before the first netdevice attached to the hardware
+ * is enabled. This should turn on the hardware and must turn on
+ * frame reception (for possibly enabled monitor interfaces.)
+ * Returns negative error codes, these may be seen in userspace,
+ * or zero.
+ * When the device is started it should not have a MAC address
+ * to avoid acknowledging frames before a non-monitor device
+ * is added.
+ *
+ * Must be implemented.
+ */
+ int (*start)(struct ieee80211_hw *hw);
+
+ /*
+ * Called after last netdevice attached to the hardware
+ * is disabled. This should turn off the hardware (at least
+ * it must turn off frame reception.)
+ * May be called right after add_interface if that rejects
+ * an interface.
+ *
+ * Must be implemented.
+ */
+ void (*stop)(struct ieee80211_hw *hw);
+
+ /*
+ * Called when a netdevice attached to the hardware is enabled.
+ * Because it is not called for monitor mode devices, open()
+ * and stop() must be implemented.
+ * The driver should perform any initialization it needs before
+ * the device can be enabled. The initial configuration for the
+ * interface is given in the conf parameter.
+ *
+ * Must be implemented.
*/
int (*add_interface)(struct ieee80211_hw *hw,
struct ieee80211_if_init_conf *conf);

- /* Notify a driver that an interface is going down. The stop() handler
- * is called prior to this if this is a last interface. */
+ /*
+ * Notifies a driver that an interface is going down. The stop() handler
+ * is called after this if it is the last interface and no monitor
+ * interfaces are present.
+ * When all interfaces are removed, the MAC address in the hardware
+ * must be cleared so the device no longer acknowledges packets,
+ * the mac_addr member of the conf structure is, however, set to the
+ * MAC address of the device going away.
+ *
+ * Hence, this callback must be implemented.
+ */
void (*remove_interface)(struct ieee80211_hw *hw,
struct ieee80211_if_init_conf *conf);

@@ -651,15 +705,25 @@ 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);
+ /*
+ * Configure the device's RX filter.
+ *
+ * If get_mc_item is assigned, then the multicast address filter
+ * must be changed if the hardware flags indicate that one is
+ * present. The get_mc_item function should be called until it
+ * returns %NULL, it must be passed the @get_mc_data pointer
+ * each time.
+ *
+ * All unsupported flags in 'total_flags' must be cleared,
+ * clear all bits except those you honoured.
+ *
+ * The callback must be implemented and must be atomic.
+ */
+ void (*configure_filter)(struct ieee80211_hw *hw,
+ struct dev_mc_list *(get_mc_item)(void *data),
+ void *get_mc_data,
+ 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
@@ -1078,24 +1142,6 @@ void ieee80211_stop_queues(struct ieee80
*/
void ieee80211_wake_queues(struct ieee80211_hw *hw);

-/**
- * ieee80211_get_mc_list_item - iteration over items in multicast list
- * @hw: pointer as obtained from ieee80211_alloc_hw().
- * @prev: value returned by previous call to ieee80211_get_mc_list_item() or
- * NULL to start a new iteration.
- * @ptr: pointer to buffer of void * type for internal usage of
- * ieee80211_get_mc_list_item().
- *
- * Iterates over items in multicast list of given device. To get the first
- * item, pass NULL in @prev and in *@ptr. In subsequent calls, pass the
- * value returned by previous call in @prev. Don't alter *@ptr during
- * iteration. When there are no more items, NULL is returned.
- */
-struct dev_mc_list *
-ieee80211_get_mc_list_item(struct ieee80211_hw *hw,
- struct dev_mc_list *prev,
- void **ptr);
-
/* called by driver to notify scan status completed */
void ieee80211_scan_completed(struct ieee80211_hw *hw);

--- wireless-dev.orig/net/mac80211/ieee80211.c 2007-09-03 10:23:23.243978471 +0200
+++ wireless-dev/net/mac80211/ieee80211.c 2007-09-03 15:12:29.733973252 +0200
@@ -44,6 +44,18 @@ struct ieee80211_tx_status_rtap_hdr {
u8 data_retries;
} __attribute__ ((packed));

+/* locking must be nested */
+enum netif_tx_lock_class {
+ TX_LOCK_NORMAL,
+ TX_LOCK_MASTER,
+};
+
+static inline void netif_tx_lock_nested(struct net_device *dev, int subclass)
+{
+ spin_lock_nested(&dev->_xmit_lock, subclass);
+ dev->xmit_lock_owner = smp_processor_id();
+}
+
/* common interface routines */

static struct net_device_stats *ieee80211_get_stats(struct net_device *dev)
@@ -59,6 +71,103 @@ static int header_parse_80211(struct sk_
return ETH_ALEN;
}

+/* filter configuration */
+struct get_mc_list_data {
+ struct ieee80211_local *local;
+ struct ieee80211_sub_if_data *sdata;
+ struct dev_mc_list *cur;
+};
+
+static struct dev_mc_list *ieee80211_get_mc_list_item(void *data)
+{
+ struct get_mc_list_data *mcd = data;
+ struct ieee80211_local *local = mcd->local;
+
+ if (mcd->sdata && !mcd->cur) {
+ WARN_ON(1);
+ return NULL;
+ }
+
+ /* start of iteration, both unassigned */
+ if (!mcd->cur && !mcd->sdata) {
+ mcd->sdata = list_entry(local->sub_if_list.next,
+ struct ieee80211_sub_if_data, list);
+ mcd->cur = mcd->sdata->dev->mc_list;
+ }
+
+ if (mcd->cur)
+ mcd->cur = mcd->cur->next;
+
+ while (!mcd->cur) {
+ /* reached end of interface list? */
+ if (mcd->sdata->list.next == &local->sub_if_list)
+ break;
+ /* otherwise try next interface */
+ mcd->sdata = list_entry(mcd->sdata->list.next,
+ struct ieee80211_sub_if_data, list);
+ mcd->cur = mcd->sdata->dev->mc_list;
+ }
+
+ return mcd->cur;
+}
+
+static void ieee80211_configure_filter(struct ieee80211_local *local)
+{
+ unsigned int changed_flags;
+ unsigned int new_flags = 0;
+ struct get_mc_list_data mcd = {
+ .local = local,
+ .cur = NULL,
+ .sdata = NULL,
+ };
+
+ /*
+ * Networking core locks the device we're invoked on
+ * for set_multicast_list, but we need to lock master
+ * to avoid concurrent calls.
+ */
+ netif_tx_lock_nested(local->mdev, TX_LOCK_MASTER);
+
+ if (local->iff_promiscs)
+ new_flags |= FIF_PROMISC_IN_BSS;
+
+ if (local->iff_allmultis ||
+ (local->mc_count > 0 &&
+ !(local->hw.flags & IEEE80211_HW_MULTICAST_FILTER)))
+ new_flags |= FIF_ALLMULTI;
+
+ if (local->monitors)
+ new_flags |= FIF_CONTROL |
+ FIF_OTHER_BSS |
+ FIF_BCN_PRBRESP_PROMISC;
+
+ changed_flags = local->filter_flags ^ new_flags;
+
+ /*
+ * We can iterate through the device list for the multicast
+ * address list so need to lock it.
+ */
+ read_lock(&local->sub_if_lock);
+
+ /* be a bit nasty */
+ new_flags |= (1<<31);
+
+ local->ops->configure_filter(local_to_hw(local),
+ ieee80211_get_mc_list_item, &mcd,
+ changed_flags,
+ &new_flags);
+
+ WARN_ON(new_flags & (1<<31));
+
+ /* buggy driver called but not until getting NULL */
+ WARN_ON(mcd.cur);
+
+ local->filter_flags = new_flags & ~(1<<31);
+ read_unlock(&local->sub_if_lock);
+
+ netif_tx_unlock(local->mdev);
+}
+
/* master interface */

static int ieee80211_master_open(struct net_device *dev)
@@ -312,49 +421,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);
-
- switch (sdata->type) {
- case IEEE80211_IF_TYPE_STA:
- case IEEE80211_IF_TYPE_IBSS:
- sdata->u.sta.flags &= ~IEEE80211_STA_PREV_BSSID_SET;
- break;
- }
-}
-
static int ieee80211_open(struct net_device *dev)
{
struct ieee80211_sub_if_data *sdata, *nsdata;
@@ -380,84 +446,90 @@ 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));
- else if (!res && local->apdev)
- dev_open(local->apdev);
- }
- }
- if (res) {
- if (local->ops->remove_interface)
- local->ops->remove_interface(local_to_hw(local),
- &conf);
+ if (local->ops->start)
+ res = local->ops->start(local_to_hw(local));
+ if (res)
return res;
- }
}
- local->open_count++;

- if (sdata->type == IEEE80211_IF_TYPE_MNTR) {
+ switch (sdata->type) {
+ case IEEE80211_IF_TYPE_MNTR:
+ /* must be before the call to ieee80211_configure_filter */
local->monitors++;
- local->hw.conf.flags |= IEEE80211_CONF_RADIOTAP;
- } else {
+ if (local->monitors == 1) {
+ ieee80211_configure_filter(local);
+
+ local->hw.conf.flags |= IEEE80211_CONF_RADIOTAP;
+ ieee80211_hw_config(local);
+ }
+ break;
+ case IEEE80211_IF_TYPE_STA:
+ case IEEE80211_IF_TYPE_IBSS:
+ sdata->u.sta.flags &= ~IEEE80211_STA_PREV_BSSID_SET;
+ /* fall through */
+ default:
+ conf.if_id = dev->ifindex;
+ conf.type = sdata->type;
+ conf.mac_addr = dev->dev_addr;
+ res = local->ops->add_interface(local_to_hw(local), &conf);
+ if (res && !local->open_count && local->ops->stop)
+ local->ops->stop(local_to_hw(local));
+ if (res)
+ return res;
+
ieee80211_if_config(dev);
ieee80211_reset_erp_info(dev);
ieee80211_enable_keys(sdata);
+
+ if (sdata->type == IEEE80211_IF_TYPE_STA &&
+ !local->user_space_mlme)
+ netif_carrier_off(dev);
+ else
+ netif_carrier_on(dev);
}

- if (sdata->type == IEEE80211_IF_TYPE_STA &&
- !local->user_space_mlme)
- netif_carrier_off(dev);
- else
- netif_carrier_on(dev);
+ if (local->open_count == 0) {
+ res = dev_open(local->mdev);
+ WARN_ON(res);
+ if (local->apdev) {
+ res = dev_open(local->apdev);
+ WARN_ON(res);
+ }
+ tasklet_enable(&local->tx_pending_tasklet);
+ tasklet_enable(&local->tasklet);
+ }
+
+ local->open_count++;

netif_start_queue(dev);
+
return 0;
}

-static void ieee80211_if_shutdown(struct net_device *dev)
+static int ieee80211_stop(struct net_device *dev)
{
+ struct ieee80211_sub_if_data *sdata;
struct ieee80211_local *local = wdev_priv(dev->ieee80211_ptr);
- struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev);
+ struct ieee80211_if_init_conf conf;
+
+ sdata = IEEE80211_DEV_TO_SUB_IF(dev);
+
+ netif_stop_queue(dev);
+
+ local->open_count--;

- ASSERT_RTNL();
switch (sdata->type) {
+ case IEEE80211_IF_TYPE_MNTR:
+ local->monitors--;
+ if (local->monitors == 0) {
+ ieee80211_configure_filter(local);
+
+ local->hw.conf.flags |= IEEE80211_CONF_RADIOTAP;
+ ieee80211_hw_config(local);
+ }
+ break;
case IEEE80211_IF_TYPE_STA:
case IEEE80211_IF_TYPE_IBSS:
sdata->u.sta.state = IEEE80211_DISABLED;
@@ -479,116 +551,67 @@ 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;
- } else {
+ /* fall through */
+ default:
+ conf.if_id = dev->ifindex;
+ conf.type = sdata->type;
+ conf.mac_addr = dev->dev_addr;
/* disable all keys for as long as this netdev is down */
ieee80211_disable_keys(sdata);
+ local->ops->remove_interface(local_to_hw(local), &conf);
}

- local->open_count--;
if (local->open_count == 0) {
if (netif_running(local->mdev))
dev_close(local->mdev);
+
if (local->apdev)
dev_close(local->apdev);
+
if (local->ops->stop)
local->ops->stop(local_to_hw(local));
+
tasklet_disable(&local->tx_pending_tasklet);
tasklet_disable(&local->tasklet);
}
- if (local->ops->remove_interface) {
- struct ieee80211_if_init_conf conf;
-
- conf.if_id = dev->ifindex;
- conf.type = sdata->type;
- conf.mac_addr = dev->dev_addr;
- local->ops->remove_interface(local_to_hw(local), &conf);
- }
-
- ieee80211_start_hard_monitor(local);

return 0;
}

-enum netif_tx_lock_class {
- TX_LOCK_NORMAL,
- TX_LOCK_MASTER,
-};
-
-static inline void netif_tx_lock_nested(struct net_device *dev, int subclass)
-{
- spin_lock_nested(&dev->_xmit_lock, subclass);
- dev->xmit_lock_owner = smp_processor_id();
-}
-
static void ieee80211_set_multicast_list(struct net_device *dev)
{
struct ieee80211_local *local = wdev_priv(dev->ieee80211_ptr);
struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev);
- unsigned short flags;
+ int allmulti, promisc, sdata_allmulti, sdata_promisc;

- netif_tx_lock_nested(local->mdev, TX_LOCK_MASTER);
- if (((dev->flags & IFF_ALLMULTI) != 0) ^
- ((sdata->flags & IEEE80211_SDATA_ALLMULTI) != 0)) {
- if (sdata->flags & IEEE80211_SDATA_ALLMULTI)
- local->iff_allmultis--;
- else
+ allmulti = !!(dev->flags & IFF_ALLMULTI);
+ promisc = !!(dev->flags & IFF_PROMISC);
+ sdata_allmulti = sdata->flags & IEEE80211_SDATA_ALLMULTI;
+ sdata_promisc = sdata->flags & IEEE80211_SDATA_PROMISC;
+
+ if (allmulti != sdata_allmulti) {
+ if (dev->flags & IFF_ALLMULTI)
local->iff_allmultis++;
+ else
+ local->iff_allmultis--;
sdata->flags ^= IEEE80211_SDATA_ALLMULTI;
}
- if (((dev->flags & IFF_PROMISC) != 0) ^
- ((sdata->flags & IEEE80211_SDATA_PROMISC) != 0)) {
- if (sdata->flags & IEEE80211_SDATA_PROMISC)
- local->iff_promiscs--;
- else
+
+ if (promisc != sdata_promisc) {
+ if (dev->flags & IFF_PROMISC)
local->iff_promiscs++;
+ else
+ local->iff_promiscs--;
sdata->flags ^= IEEE80211_SDATA_PROMISC;
}
+
if (dev->mc_count != sdata->mc_count) {
local->mc_count = local->mc_count - sdata->mc_count +
dev->mc_count;
sdata->mc_count = dev->mc_count;
}
- if (local->ops->set_multicast_list) {
- flags = local->mdev->flags;
- if (local->iff_allmultis)
- flags |= IFF_ALLMULTI;
- if (local->iff_promiscs)
- flags |= IFF_PROMISC;
- read_lock(&local->sub_if_lock);
- local->ops->set_multicast_list(local_to_hw(local), flags,
- local->mc_count);
- read_unlock(&local->sub_if_lock);
- }
- netif_tx_unlock(local->mdev);
+
+ ieee80211_configure_filter(local);
}

/* Must not be called for mdev and apdev */
@@ -650,7 +673,6 @@ static int __ieee80211_if_config(struct
struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev);
struct ieee80211_local *local = wdev_priv(dev->ieee80211_ptr);
struct ieee80211_if_conf conf;
- static u8 scan_bssid[] = { 0xff, 0xff, 0xff, 0xff, 0xff, 0xff };

if (!local->ops->config_interface || !netif_running(dev))
return 0;
@@ -659,11 +681,7 @@ static int __ieee80211_if_config(struct
conf.type = sdata->type;
if (sdata->type == IEEE80211_IF_TYPE_STA ||
sdata->type == IEEE80211_IF_TYPE_IBSS) {
- if (local->sta_scanning &&
- local->scan_dev == dev)
- conf.bssid = scan_bssid;
- else
- conf.bssid = sdata->u.sta.bssid;
+ conf.bssid = sdata->u.sta.bssid;
conf.ssid = sdata->u.sta.ssid;
conf.ssid_len = sdata->u.sta.ssid_len;
conf.generic_elem = sdata->u.sta.extra_ie;
@@ -755,37 +773,6 @@ void ieee80211_reset_erp_info(struct net
IEEE80211_ERP_CHANGE_PREAMBLE);
}

-struct dev_mc_list *ieee80211_get_mc_list_item(struct ieee80211_hw *hw,
- struct dev_mc_list *prev,
- void **ptr)
-{
- struct ieee80211_local *local = hw_to_local(hw);
- struct ieee80211_sub_if_data *sdata = *ptr;
- struct dev_mc_list *mc;
-
- if (!prev) {
- WARN_ON(sdata);
- sdata = NULL;
- }
- if (!prev || !prev->next) {
- if (sdata)
- sdata = list_entry(sdata->list.next,
- struct ieee80211_sub_if_data, list);
- else
- sdata = list_entry(local->sub_if_list.next,
- struct ieee80211_sub_if_data, list);
- if (&sdata->list != &local->sub_if_list)
- mc = sdata->dev->mc_list;
- else
- mc = NULL;
- } else
- mc = prev->next;
-
- *ptr = sdata;
- return mc;
-}
-EXPORT_SYMBOL(ieee80211_get_mc_list_item);
-
void ieee80211_tx_status_irqsafe(struct ieee80211_hw *hw,
struct sk_buff *skb,
struct ieee80211_tx_status *status)
@@ -1191,8 +1178,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->configure_filter);
local->ops = ops;

/* for now, mdev needs sub_if_data :/ */
--- wireless-dev.orig/net/mac80211/ieee80211_i.h 2007-09-02 21:00:18.553985563 +0200
+++ wireless-dev/net/mac80211/ieee80211_i.h 2007-09-03 15:12:29.773973252 +0200
@@ -482,6 +482,7 @@ struct ieee80211_local {
struct net_device *apdev; /* wlan#ap - management frames (hostapd) */
int open_count;
int monitors;
+ unsigned int filter_flags; /* FIF_* */
struct iw_statistics wstats;
u8 wstats_flags;
int tx_headroom; /* required headroom for hardware/radiotap */
--- wireless-dev.orig/net/mac80211/rx.c 2007-09-03 10:23:25.403978471 +0200
+++ wireless-dev/net/mac80211/rx.c 2007-09-03 15:12:27.683973252 +0200
@@ -1457,7 +1457,7 @@ static int prepare_for_handlers(struct i
} else if (!multicast &&
compare_ether_addr(sdata->dev->dev_addr,
hdr->addr1) != 0) {
- if (!(sdata->flags & IEEE80211_SDATA_PROMISC))
+ if (!(sdata->dev->flags & IFF_PROMISC))
return 0;
rx->flags &= ~IEEE80211_TXRXD_RXRA_MATCH;
}
@@ -1472,7 +1472,7 @@ static int prepare_for_handlers(struct i
} else if (!multicast &&
compare_ether_addr(sdata->dev->dev_addr,
hdr->addr1) != 0) {
- if (!(sdata->flags & IEEE80211_SDATA_PROMISC))
+ if (!(sdata->dev->flags & IFF_PROMISC))
return 0;
rx->flags &= ~IEEE80211_TXRXD_RXRA_MATCH;
} else if (!rx->sta)
--- wireless-dev.orig/net/mac80211/debugfs_netdev.c 2007-09-02 21:00:18.603985563 +0200
+++ wireless-dev/net/mac80211/debugfs_netdev.c 2007-09-03 15:12:29.913973252 +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-09-02 21:00:18.673985563 +0200
+++ wireless-dev/drivers/net/wireless/b43/b43.h 2007-09-03 10:23:25.643978471 +0200
@@ -595,9 +595,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;
/* The MAC address of the operating interface. */
@@ -606,14 +605,10 @@ struct b43_wl {
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;

@@ -770,8 +765,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-09-03 10:23:25.013978471 +0200
+++ wireless-dev/drivers/net/wireless/b43/main.c 2007-09-03 15:12:26.313973252 +0200
@@ -92,14 +92,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,15 +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)
{
- 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)
@@ -2054,33 +2041,25 @@ static void b43_adjust_opmode(struct b43
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. */
@@ -2244,9 +2223,6 @@ static int b43_chip_init(struct b43_wlde
& ~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);
@@ -2988,21 +2964,42 @@ out:
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,
+ struct dev_mc_list *(*get_mc_item)(void *data),
+ void *get_mc_data,
+ 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 |
+ 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);
}

@@ -3017,21 +3014,19 @@ 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);
- 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);
@@ -3459,7 +3454,8 @@ static int b43_wireless_core_init(struct

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);

@@ -3489,21 +3485,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;

b43dbg(wl, "Adding Interface type %d\n", conf->type);

dev = wl->current_dev;
+ wl->operating = 1;
+ wl->if_id = conf->if_id;
+ wl->if_type = conf->type;
+ memcpy(wl->mac_addr, conf->mac_addr, ETH_ALEN);
+
+ spin_lock_irqsave(&wl->irq_lock, flags);
+ b43_adjust_opmode(dev);
+ b43_upload_card_macaddress(dev);
+ spin_unlock_irqrestore(&wl->irq_lock, flags);
+
+ err = 0;
+ out_mutex_unlock:
+ mutex_unlock(&wl->mutex);
+
+ return err;
+}
+
+static void b43_remove_interface(struct ieee80211_hw *hw,
+ struct ieee80211_if_init_conf *conf)
+{
+ struct b43_wl *wl = hw_to_b43_wl(hw);
+ struct b43_wldev *dev = wl->current_dev;
+ unsigned long flags;
+
+ b43dbg(wl, "Removing Interface type %d\n", conf->type);
+
+ mutex_lock(&wl->mutex);
+
+ B43_WARN_ON(!wl->operating);
+ B43_WARN_ON(wl->if_id != conf->if_id);
+
+ wl->operating = 0;
+
+ spin_lock_irqsave(&wl->irq_lock, flags);
+ b43_adjust_opmode(dev);
+ memset(wl->mac_addr, 0, ETH_ALEN);
+ b43_upload_card_macaddress(dev);
+ spin_unlock_irqrestore(&wl->irq_lock, flags);
+
+ mutex_unlock(&wl->mutex);
+}
+
+static int b43_start(struct ieee80211_hw *hw)
+{
+ struct b43_wl *wl = hw_to_b43_wl(hw);
+ struct b43_wldev *dev = wl->current_dev;
+ int did_init = 0;
+ int err;
+
+ mutex_lock(&wl->mutex);
+
if (b43_status(dev) < B43_STAT_INITIALIZED) {
err = b43_wireless_core_init(dev);
if (err)
goto out_mutex_unlock;
did_init = 1;
}
+
if (b43_status(dev) < B43_STAT_STARTED) {
err = b43_wireless_core_start(dev);
if (err) {
@@ -3513,59 +3568,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;
-
- b43dbg(wl, "Removing Interface type %d\n", conf->type);
+ struct b43_wldev *dev = wl->current_dev;

mutex_lock(&wl->mutex);
- if (conf->type == IEEE80211_IF_TYPE_MNTR) {
- wl->monitor--;
- B43_WARN_ON(wl->monitor < 0);
- } else {
- B43_WARN_ON(!wl->operating);
- wl->operating = 0;
- }
-
- dev = wl->current_dev;
- if (!wl->operating && wl->monitor == 0) {
- /* No interface left. */
- if (b43_status(dev) >= B43_STAT_STARTED)
- b43_wireless_core_stop(dev);
- b43_wireless_core_exit(dev);
- } else {
- /* Just monitor interfaces left. */
- spin_lock_irqsave(&wl->irq_lock, flags);
- b43_adjust_opmode(dev);
- if (!wl->operating)
- b43_upload_card_macaddress(dev, NULL);
- spin_unlock_irqrestore(&wl->irq_lock, flags);
- }
+ if (b43_status(dev) >= B43_STAT_STARTED)
+ b43_wireless_core_stop(dev);
+ b43_wireless_core_exit(dev);
mutex_unlock(&wl->mutex);
}

@@ -3576,10 +3593,12 @@ static const struct ieee80211_ops b43_hw
.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.
@@ -3916,8 +3935,7 @@ static int b43_wireless_init(struct ssb_
}

/* 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;
--- wireless-dev.orig/drivers/net/wireless/iwl-base.c 2007-09-03 10:23:24.763978471 +0200
+++ wireless-dev/drivers/net/wireless/iwl-base.c 2007-09-03 15:12:26.373973252 +0200
@@ -2589,6 +2589,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)
{
@@ -7481,7 +7483,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;

@@ -7500,7 +7502,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;

@@ -7509,8 +7511,20 @@ 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_configure_filter(struct ieee80211_hw *hw,
+ struct dev_mc_list *(*get_mc_item)(void *data),
+ void *get_mc_data,
+ 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,
@@ -7679,6 +7693,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
@@ -7693,8 +7709,14 @@ static int iwl_mac_config_interface(stru
IWL_DEBUG_MAC80211("bssid: " MAC_FMT "\n",
MAC_ARG(conf->bssid));

+ /*
+ * XXX: there was a test for IEEE80211_HW_NO_PROBE_FILTERING here
+ * which must have been wrong since it was always true.
+ * the test was:
if (unlikely(priv->status & STATUS_SCANNING) &&
!(priv->hw->flags & IEEE80211_HW_NO_PROBE_FILTERING)) {
+ */
+ if (unlikely(priv->status & STATUS_SCANNING)) {
IWL_DEBUG_MAC80211("leave - scanning\n");
mutex_unlock(&priv->mutex);
return 0;
@@ -7787,6 +7809,8 @@ static void iwl_mac_remove_interface(str
}
mutex_unlock(&priv->mutex);

+ /* TODO: clear MAC address in hardware */
+
IWL_DEBUG_MAC80211("leave\n");

}
@@ -9039,10 +9063,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,
+ .configure_filter = iwl_configure_filter,
.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-09-03 10:23:23.683978471 +0200
+++ wireless-dev/drivers/net/wireless/rtl8187_dev.c 2007-09-03 14:49:40.943973252 +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;
@@ -419,7 +419,7 @@ static int rtl8187_open(struct ieee80211
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,7 +445,6 @@ static int rtl8187_stop(struct ieee80211
usb_kill_urb(info->urb);
kfree_skb(skb);
}
- return 0;
}

static int rtl8187_add_interface(struct ieee80211_hw *dev,
@@ -476,6 +475,8 @@ static void rtl8187_remove_interface(str
{
struct rtl8187_priv *priv = dev->priv;
priv->mode = IEEE80211_IF_TYPE_MGMT;
+
+ /* TODO: reset MAC address to zeroes */
}

static int rtl8187_config(struct ieee80211_hw *dev, struct ieee80211_conf *conf)
@@ -523,14 +524,30 @@ static int rtl8187_config_interface(stru
return 0;
}

+static void
+rtl8187_configure_filter(struct ieee80211_hw *dev,
+ struct dev_mc_list *(*get_mc_item)(void *data),
+ void *get_mc_data,
+ 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,
+ .configure_filter = rtl8187_configure_filter,
};

static void rtl8187_eeprom_register_read(struct eeprom_93cx6 *eeprom)
--- wireless-dev.orig/drivers/net/wireless/adm8211.c 2007-09-03 10:23:23.713978471 +0200
+++ wireless-dev/drivers/net/wireless/adm8211.c 2007-09-03 14:41:59.643973252 +0200
@@ -349,43 +349,78 @@ 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_set_bssid(struct ieee80211_hw *dev, u8 *bssid)
+{
+ struct adm8211_priv *priv = dev->priv;
+ u32 reg;
+
+ reg = bssid[0] | (bssid[1] << 8) | (bssid[2] << 16) | (bssid[3] << 24);
+ ADM8211_CSR_WRITE(BSSID0, reg);
+ reg = ADM8211_CSR_READ(ABDA1);
+ reg &= 0x0000ffff;
+ reg |= (bssid[4] << 16) | (bssid[5] << 24);
+ ADM8211_CSR_WRITE(ABDA1, reg);
+}
+
+static void
+adm8211_configure_filter(struct ieee80211_hw *dev,
+ struct dev_mc_list *(get_mc_item)(void *data),
+ void *get_mc_data,
+ unsigned int changed,
+ unsigned int *flags)
{
struct adm8211_priv *priv = dev->priv;
unsigned int bit_nr;
__le32 mc_filter[2];
struct dev_mc_list *mclist;
- void *tmp;
+ int mcchanged = 0;
+ u8 bcast_addr[ETH_ALEN] = {0xff, 0xff, 0xff, 0xff, 0xff, 0xff};

- 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)) {
+ mcchanged = 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);
- } else {
+ mcchanged = 1;
+ } else if (get_mc_item) {
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))) {
+ while ((mclist = get_mc_item(get_mc_data))) {
bit_nr = ether_crc(ETH_ALEN, mclist->dmi_addr) >> 26;

bit_nr &= 0x3F;
mc_filter[bit_nr >> 5] |= cpu_to_le32(1 << (bit_nr & 31));
}
+ mcchanged = 1;
}

- ADM8211_IDLE_RX();
+ *flags &= FIF_PROMISC_IN_BSS | FIF_ALLMULTI | FIF_BCN_PRBRESP_PROMISC;

- ADM8211_CSR_WRITE(MAR0, mc_filter[0]);
- ADM8211_CSR_WRITE(MAR1, mc_filter[1]);
- ADM8211_CSR_READ(NAR);
+ if (changed & FIF_BCN_PRBRESP_PROMISC) {
+ if (*flags & FIF_BCN_PRBRESP_PROMISC)
+ adm8211_set_bssid(dev, bcast_addr);
+ else
+ adm8211_set_bssid(dev, priv->bssid);
+ }

- ADM8211_RESTORE();
+ if (mcchanged) {
+ ADM8211_IDLE_RX();
+
+ ADM8211_CSR_WRITE(MAR0, mc_filter[0]);
+ ADM8211_CSR_WRITE(MAR1, mc_filter[1]);
+ ADM8211_CSR_READ(NAR);
+
+ ADM8211_RESTORE();
+ }
}

static int adm8211_get_tx_stats(struct ieee80211_hw *dev,
@@ -1414,19 +1449,6 @@ static void adm8211_set_interval(struct
ADM8211_CSR_WRITE(BPLI, reg);
}

-static void adm8211_set_bssid(struct ieee80211_hw *dev, u8 *bssid)
-{
- struct adm8211_priv *priv = dev->priv;
- u32 reg;
-
- reg = bssid[0] | (bssid[1] << 8) | (bssid[2] << 16) | (bssid[3] << 24);
- ADM8211_CSR_WRITE(BSSID0, reg);
- reg = ADM8211_CSR_READ(ABDA1);
- reg &= 0x0000ffff;
- reg |= (bssid[4] << 16) | (bssid[5] << 24);
- ADM8211_CSR_WRITE(ABDA1, reg);
-}
-
static int adm8211_set_ssid(struct ieee80211_hw *dev, u8 *ssid, size_t ssid_len)
{
struct adm8211_priv *priv = dev->priv;
@@ -1502,6 +1524,8 @@ static void adm8211_remove_interface(str
{
struct adm8211_priv *priv = dev->priv;
priv->mode = IEEE80211_IF_TYPE_MGMT;
+
+ /* TODO: clear MAC address */
}

static int adm8211_init_rings(struct ieee80211_hw *dev)
@@ -1585,7 +1609,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;
@@ -1628,7 +1652,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;

@@ -1640,7 +1664,6 @@ static int adm8211_stop(struct ieee80211
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,
@@ -1841,13 +1864,13 @@ static int adm8211_alloc_rings(struct ie

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
@@ -1953,7 +1976,7 @@ static int __devinit adm8211_probe(struc
SET_IEEE80211_PERM_ADDR(dev, perm_addr);

dev->extra_tx_headroom = sizeof(struct adm8211_tx_hdr);
- dev->flags = 0;
+ dev->flags = IEEE80211_HW_MULTICAST_FILTER;
// however, IEEE80211_HW_RX_INCLUDES_FCS in promisc mode

dev->channel_change_time = 1000;
@@ -2082,7 +2105,7 @@ static int adm8211_resume(struct pci_dev
pci_restore_state(pdev);

if (priv->mode != IEEE80211_IF_TYPE_MGMT) {
- adm8211_open(dev);
+ adm8211_start(dev);
ieee80211_start_queues(dev);
}

--- wireless-dev.orig/drivers/net/wireless/zd1211rw-mac80211/zd_mac.c 2007-09-03 10:23:24.303978471 +0200
+++ wireless-dev/drivers/net/wireless/zd1211rw-mac80211/zd_mac.c 2007-09-03 14:49:10.813973252 +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;
}

/**
@@ -693,7 +680,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);
@@ -715,7 +702,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;
@@ -765,32 +751,45 @@ 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_configure_filter(struct ieee80211_hw *hw,
+ struct dev_mc_list *(*get_mc_item)(void *data),
+ void *get_mc_data,
+ unsigned int change,
+ unsigned int *filterflags)
{
struct zd_mc_hash hash;
+ struct dev_mc_list *mc;
struct zd_mac *mac = zd_hw_mac(hw);
unsigned long flags;
+ int hash_changed = 0;

- 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;
- void *tmp = NULL;
+ hash_changed = 1;
+ } else if (get_mc_item) {
zd_mc_clear(&hash);
- while ((mc = ieee80211_get_mc_list_item(hw, mc, &tmp))) {
+ hash_changed = 1;
+ while ((mc = get_mc_item(get_mc_data))) {
dev_dbg_f(zd_mac_dev(mac), "mc addr " MAC_FMT "\n",
MAC_ARG(mc->dmi_addr));
zd_mc_add_addr(&hash, mc->dmi_addr);
}
}

- spin_lock_irqsave(&mac->lock, flags);
- mac->multicast_hash = hash;
- spin_unlock_irqrestore(&mac->lock, flags);
- queue_work(zd_workqueue, &mac->set_multicast_hash_work);
+ /*
+ * XXX: probably not right, we probably see many other
+ * frames as well...
+ */
+ *filterflags &= FIF_PROMISC_IN_BSS | FIF_ALLMULTI;
+
+ if (hash_changed) {
+ spin_lock_irqsave(&mac->lock, flags);
+ mac->multicast_hash = hash;
+ spin_unlock_irqrestore(&mac->lock, flags);
+ queue_work(zd_workqueue, &mac->set_multicast_hash_work);
+ }
}

static void set_rts_cts_work(struct work_struct *work)
@@ -834,13 +833,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,
+ .configure_filter = zd_op_configure_filter,
.erp_ie_changed = zd_op_erp_ie_changed,
};

@@ -879,7 +878,8 @@ struct ieee80211_hw *zd_mac_alloc_hw(str
mac->modes[1].channels = mac->channels;

hw->flags = IEEE80211_HW_RX_INCLUDES_FCS |
- IEEE80211_HW_DEFAULT_REG_DOMAIN_CONFIGURED;
+ IEEE80211_HW_DEFAULT_REG_DOMAIN_CONFIGURED |
+ IEEE80211_HW_MULTICAST_FILTER;
hw->max_rssi = 100;
hw->max_signal = 100;

--- wireless-dev.orig/net/mac80211/ieee80211_sta.c 2007-09-03 10:23:23.263978471 +0200
+++ wireless-dev/net/mac80211/ieee80211_sta.c 2007-09-03 15:15:50.383973252 +0200
@@ -3581,10 +3581,19 @@ void ieee80211_scan_completed(struct iee
printk(KERN_DEBUG "%s: failed to restore operational"
"channel after scan\n", dev->name);

- if (!(local->hw.flags & IEEE80211_HW_NO_PROBE_FILTERING) &&
- ieee80211_if_config(dev))
- printk(KERN_DEBUG "%s: failed to restore operational"
- "BSSID after scan\n", dev->name);
+
+ /*
+ * We need to take this lock in the set_multicast_list path
+ * leading to configure_filter, so use it to protect the
+ * local->filter_flags as well.
+ */
+ netif_tx_lock(local->mdev);
+ local->filter_flags &= ~FIF_BCN_PRBRESP_PROMISC;
+ local->ops->configure_filter(local_to_hw(local), NULL, NULL,
+ FIF_BCN_PRBRESP_PROMISC,
+ &local->filter_flags);
+
+ netif_tx_unlock(local->mdev);

memset(&wrqu, 0, sizeof(wrqu));
wireless_send_event(dev, SIOCGIWSCAN, &wrqu, NULL);
@@ -3768,10 +3777,17 @@ static int ieee80211_sta_start_scan(stru
local->scan_channel_idx = 0;
local->scan_dev = dev;

- if (!(local->hw.flags & IEEE80211_HW_NO_PROBE_FILTERING) &&
- ieee80211_if_config(dev))
- printk(KERN_DEBUG "%s: failed to set BSSID for scan\n",
- dev->name);
+ /*
+ * We need to take this lock in the set_multicast_list path
+ * leading to configure_filter, so use it to protect the
+ * local->filter_flags as well.
+ */
+ netif_tx_lock(local->mdev);
+ local->filter_flags |= FIF_BCN_PRBRESP_PROMISC;
+ local->ops->configure_filter(local_to_hw(local), NULL, NULL,
+ FIF_BCN_PRBRESP_PROMISC,
+ &local->filter_flags);
+ netif_tx_unlock(local->mdev);

/* TODO: start scan as soon as all nullfunc frames are ACKed */
queue_delayed_work(local->hw.workqueue, &local->scan_work,
--- wireless-dev.orig/drivers/net/wireless/rt2x00/rt2400pci.c 2007-09-02 21:00:19.473985563 +0200
+++ wireless-dev/drivers/net/wireless/rt2x00/rt2400pci.c 2007-09-03 10:23:25.863978471 +0200
@@ -1447,10 +1447,7 @@ static void rt2400pci_probe_hw_mode(stru
/*
* 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;
@@ -1593,7 +1590,7 @@ static const struct ieee80211_ops rt2400
.remove_interface = rt2x00mac_remove_interface,
.config = rt2x00mac_config,
.config_interface = rt2x00mac_config_interface,
- .set_multicast_list = rt2x00mac_set_multicast_list,
+// .set_multicast_list = rt2x00mac_set_multicast_list,
.get_stats = rt2x00mac_get_stats,
.set_retry_limit = rt2400pci_set_retry_limit,
.conf_tx = rt2400pci_conf_tx,
--- wireless-dev.orig/drivers/net/wireless/rt2x00/rt2500pci.c 2007-09-02 21:00:19.503985563 +0200
+++ wireless-dev/drivers/net/wireless/rt2x00/rt2500pci.c 2007-09-03 10:23:25.873978471 +0200
@@ -1745,10 +1745,7 @@ static void rt2500pci_probe_hw_mode(stru
/*
* 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;
@@ -1884,7 +1881,7 @@ static const struct ieee80211_ops rt2500
.remove_interface = rt2x00mac_remove_interface,
.config = rt2x00mac_config,
.config_interface = rt2x00mac_config_interface,
- .set_multicast_list = rt2x00mac_set_multicast_list,
+// .set_multicast_list = rt2x00mac_set_multicast_list,
.get_stats = rt2x00mac_get_stats,
.set_retry_limit = rt2500pci_set_retry_limit,
.conf_tx = rt2x00mac_conf_tx,
--- wireless-dev.orig/drivers/net/wireless/rt2x00/rt61pci.c 2007-09-02 21:00:19.553985563 +0200
+++ wireless-dev/drivers/net/wireless/rt2x00/rt61pci.c 2007-09-03 10:23:25.893978471 +0200
@@ -2118,10 +2118,7 @@ static void rt61pci_probe_hw_mode(struct
/*
* 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;
@@ -2247,7 +2244,7 @@ static const struct ieee80211_ops rt61pc
.remove_interface = rt2x00mac_remove_interface,
.config = rt2x00mac_config,
.config_interface = rt2x00mac_config_interface,
- .set_multicast_list = rt2x00mac_set_multicast_list,
+// .set_multicast_list = rt2x00mac_set_multicast_list,
.get_stats = rt2x00mac_get_stats,
.set_retry_limit = rt61pci_set_retry_limit,
.conf_tx = rt2x00mac_conf_tx,
--- wireless-dev.orig/drivers/net/wireless/rt2x00/rt2500usb.c 2007-09-02 21:00:19.573985563 +0200
+++ wireless-dev/drivers/net/wireless/rt2x00/rt2500usb.c 2007-09-03 10:23:25.923978471 +0200
@@ -1467,9 +1467,7 @@ static void rt2500usb_probe_hw_mode(stru
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;
@@ -1562,7 +1560,7 @@ static const struct ieee80211_ops rt2500
.remove_interface = rt2x00mac_remove_interface,
.config = rt2x00mac_config,
.config_interface = rt2x00mac_config_interface,
- .set_multicast_list = rt2x00mac_set_multicast_list,
+// .set_multicast_list = rt2x00mac_set_multicast_list,
.get_stats = rt2x00mac_get_stats,
.conf_tx = rt2x00mac_conf_tx,
.get_tx_stats = rt2x00mac_get_tx_stats,
--- wireless-dev.orig/drivers/net/wireless/rt2x00/rt73usb.c 2007-09-02 21:00:19.633985563 +0200
+++ wireless-dev/drivers/net/wireless/rt2x00/rt73usb.c 2007-09-03 10:23:25.933978471 +0200
@@ -1713,9 +1713,7 @@ static void rt73usb_probe_hw_mode(struct
*/
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;
@@ -1856,7 +1854,7 @@ static const struct ieee80211_ops rt73us
.remove_interface = rt2x00mac_remove_interface,
.config = rt2x00mac_config,
.config_interface = rt2x00mac_config_interface,
- .set_multicast_list = rt2x00mac_set_multicast_list,
+// .set_multicast_list = rt2x00mac_set_multicast_list,
.get_stats = rt2x00mac_get_stats,
.set_retry_limit = rt73usb_set_retry_limit,
.conf_tx = rt2x00mac_conf_tx,



2007-09-03 02:09:41

by Daniel Drake

[permalink] [raw]
Subject: Re: [RFC 2/2] mac80211: revamp interface and filter configuration

Johannes Berg wrote:
> + /*
> + * Configure the device's RX filter.
[...]
> + * Must be atomic due to running under the tx lock.

This is slightly freaky for zd1211rw and probably other USB drivers. In
most cases we can't act upon any of those filter flag changes in atomic
context.

We could defer work like we do for multicast lists, but then the driver
would be lying in that it would return from configure_filter saying that
it has honoured some flags without actually having done so (yet).

Will that be a problem? I'm thinking maybe not, since the flags only
affect RX and we can't determine which frames will be in the air at any
time. [as opposed to such atomicity problems that relate to TX, we can
just disable TX until the work has completed]

> + * This callback is must be implemented.
> + */

Typo.

Daniel

2007-09-05 11:22:02

by Johannes Berg

[permalink] [raw]
Subject: Re: [RFC 2/2] mac80211: revamp interface and filter configuration

On Wed, 2007-09-05 at 07:16 +0200, Ulrich Kunitz wrote:

> I see three options to achieve this:
>
> 1) Use ieee80211_stop_queues() in ->configure_filter() and
> ieee80211_wake_queues() at the end of the workqueue function.
>
> 2) Throw away all packets until the workqueue function
> terminates.
>
> 3) Implement our own tx queue.
>
> I prefer to do option (1) because it wouldn't require adding
> additional fields to our private structure beside the work_struct
> for the workqueue function, it is simple to implement and it would
> not throw away any packets. Are there any side effects that I have
> overlooked?

I think Michael says it's currently buggy if called outside of ->tx().

johannes


Attachments:
signature.asc (190.00 B)
This is a digitally signed message part

2007-09-05 14:31:43

by Johannes Berg

[permalink] [raw]
Subject: Re: [RFC 2/2] mac80211: revamp interface and filter configuration

On Wed, 2007-09-05 at 10:23 -0400, Michael Wu wrote:

> That's just a general rule of thumb. configure_filter holds the tx lock so
> it's actually safe to do that there.

Good point.

> In other cases, it can be buggy (some tx
> code can get stuck) and racy (frames can get enqueued after stopping the
> queues). The first can be fixed in mac80211, but the second can't be.

I think that we should be able to get all this resolved when we rip out
the queue code and implement multiqueue devices. But if I want to do
that I need to reverse engineer b43 QoS first to have multiple queues ;)

> For
> most cases, stopping the hardware queue(s) should be done instead and
> possibly flushing the queue or waiting for it to empty, if you're trying to
> adjust the radio.

In this case it's about adjusting the MAC (filtering) and I'm not even
sure the the USB device has a queue that can be stopped.

johannes


Attachments:
signature.asc (190.00 B)
This is a digitally signed message part

2007-09-03 09:27:50

by Johannes Berg

[permalink] [raw]
Subject: Re: [RFC 2/2] mac80211: revamp interface and filter configuration

Just had another idea related to this patch:

Currently, we pass multi_count >= 0 or == -1. And then we expect the
driver to call ieee80211_get_mc_list_item() to get the items. However,
the count is bogus because we add up all counts of the virtual
interfaces and don't account for duplicates. Also, however, no driver
cares about the count anyway.

Hence, we could instead of passing multi_count pass the getter function:

- void (*configure_filter)(struct ieee80211_hw *hw, int multi_count,
- unsigned int changed_flags,
- unsigned int *total_flags);
+ void (*configure_filter)(struct ieee80211_hw *hw,
+ struct dev_mc_list * (*get_mc_item)(struct ieee80211_hw *hw,
+ void *cookie),
+ void *cookie,
+ unsigned int changed_flags, unsigned int total_flags)

That way,
(1) we get rid of the export of ieee80211_get_mc_list_item
(2) get_mc_item gets to have a nicer interface without double pointers
(3) there's no danger of somebody calling it outside the right place
(4) we can use a NULL function/cookie ptr to indicate that the
list hasn't changed.

Thoughts? I think I'll implement this, I like it much better than the
current interface. And I'll also look into getting it non-atomic. We're
not protected against concurrent execution anyway, but I expect drivers
would handle that? Or do we want that here? We can't protect all
callbacks among each other anyway with the tx() callback etc...

johannes


Attachments:
signature.asc (190.00 B)
This is a digitally signed message part

2007-09-03 14:09:39

by Johannes Berg

[permalink] [raw]
Subject: Re: [RFC 2/2] mac80211: revamp interface and filter configuration

On Mon, 2007-09-03 at 11:29 +0200, Johannes Berg wrote:
> And I'll also look into getting it non-atomic. We're
> not protected against concurrent execution anyway, but I expect drivers
> would handle that? Or do we want that here? We can't protect all
> callbacks among each other anyway with the tx() callback etc...

Ah, I see now, no way to do it because the networking core already locks
around set_multicast_list using netif_tx_lock_bh, probably for good
reason. And then propagating that lock to the master device is the right
thing to do as well. Looks like you'll have to continue offloading the
actual reconfiguration to the workqueue when called from set_multicast.

And in fact, it seems that to protect against concurrent modification in
different code paths I'll have to use the tx lock when calling this from
the MLME code. Can you make sure that the filter will be reconfigured
before further packets are transmitted, that is packets that are going
to go into ->tx() after ->configure_filter()?

johannes


Attachments:
signature.asc (190.00 B)
This is a digitally signed message part

2007-09-05 05:16:27

by Ulrich Kunitz

[permalink] [raw]
Subject: Re: [RFC 2/2] mac80211: revamp interface and filter configuration

Johannes Berg wrote:

> And in fact, it seems that to protect against concurrent modification in
> different code paths I'll have to use the tx lock when calling this from
> the MLME code. Can you make sure that the filter will be reconfigured
> before further packets are transmitted, that is packets that are going
> to go into ->tx() after ->configure_filter()?

I see three options to achieve this:

1) Use ieee80211_stop_queues() in ->configure_filter() and
ieee80211_wake_queues() at the end of the workqueue function.

2) Throw away all packets until the workqueue function
terminates.

3) Implement our own tx queue.

I prefer to do option (1) because it wouldn't require adding
additional fields to our private structure beside the work_struct
for the workqueue function, it is simple to implement and it would
not throw away any packets. Are there any side effects that I have
overlooked?

--
Uli Kunitz