Search Linux Wireless

Re: [PATCH] mac80211: Add capability to enable/disable beaconing

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

 



On Tue, 2009-01-20 at 21:30 +0530, Sujith wrote:
> Johannes Berg wrote:
> > cOn Tue, 2009-01-20 at 13:27 +0530, Sujith wrote:
> > > This patch adds a flag to notify drivers to start and
> > > stop beaconing when needed, for example, during a scan run.
> > 
> > 
> > > +	if ((changed & IEEE80211_IFCC_BEACON) &&
> > > +	    (sdata->vif.type == NL80211_IFTYPE_AP ||
> > > +	     sdata->vif.type == NL80211_IFTYPE_ADHOC ||
> > > +	     sdata->vif.type == NL80211_IFTYPE_MESH_POINT)) {
> > > +		if (local->sw_scanning || local->hw_scanning)
> > > +			conf.enable_beacon = false;
> > > +		else
> > > +			conf.enable_beacon = true;
> > > +	}
> > > +
> > 
> > You really just want to do the minimal thing, right? :)
> 
> Oh, absolutely :)

:)

> > That won't work when userspace disables the beacon by removing it, for
> > instance, right now drivers won't know when hostapd removed the beacon
> > except that ieee80211_beacon_get will start returning 0... Also, I think
> > a separate change flag would be appropriate, sometimes we might just
> > re-enable the beacon without having changed it, after scanning?
> 
> Ok, how about this ?

How about this? Untested still though.

johannes
--- Begin Message ---
Using only the RTNL has a number of problems, most notably that
ieee80211_iterate_active_interfaces() and other interface list
traversals cannot be done from the internal workqueue because it
needs to be flushed under the RTNL.

This patch introduces a new mutex that protects the interface list
against modifications. A more detailed explanation is part of the
code change.

Signed-off-by: Johannes Berg <johannes@xxxxxxxxxxxxxxxx>
---
Need this for the scan stuff I'm doing next, but this has the side
effect of allowing you to call ieee80211_iterate_active_interfaces()
from mac80211's workqueue, which might be interesting.

 net/mac80211/ieee80211_i.h |    2 ++
 net/mac80211/iface.c       |   24 ++++++++++++++++++++++++
 net/mac80211/main.c        |    3 +++
 net/mac80211/util.c        |    4 ++--
 4 files changed, 31 insertions(+), 2 deletions(-)

--- wireless-testing.orig/net/mac80211/ieee80211_i.h	2009-01-21 12:19:47.000000000 +0100
+++ wireless-testing/net/mac80211/ieee80211_i.h	2009-01-21 12:22:02.000000000 +0100
@@ -643,7 +643,9 @@ struct ieee80211_local {
 	struct crypto_blkcipher *wep_rx_tfm;
 	u32 wep_iv;
 
+	/* see iface.c */
 	struct list_head interfaces;
+	struct mutex iflist_mtx;
 
 	/*
 	 * Key lock, protects sdata's key_list and sta_info's
--- wireless-testing.orig/net/mac80211/iface.c	2009-01-21 12:20:40.000000000 +0100
+++ wireless-testing/net/mac80211/iface.c	2009-01-21 12:28:15.000000000 +0100
@@ -21,6 +21,23 @@
 #include "mesh.h"
 #include "led.h"
 
+/**
+ * DOC: Interface list locking
+ *
+ * The interface list in each struct ieee80211_local is protected
+ * three-fold:
+ *
+ * (1) modifications may only be done under the RTNL
+ * (2) modifications and readers are protected against each other by
+ *     the iflist_mtx.
+ * (3) modifications are done in an RCU manner so atomic readers
+ *     can traverse the list in RCU-safe blocks.
+ *
+ * As a consequence, reads (traversals) of the list can be protected
+ * by either the RTNL, the iflist_mtx or RCU.
+ */
+
+
 static int ieee80211_change_mtu(struct net_device *dev, int new_mtu)
 {
 	int meshhdrlen;
@@ -800,7 +817,9 @@ int ieee80211_if_add(struct ieee80211_lo
 					    params->mesh_id_len,
 					    params->mesh_id);
 
+	mutex_lock(&local->iflist_mtx);
 	list_add_tail_rcu(&sdata->list, &local->interfaces);
+	mutex_unlock(&local->iflist_mtx);
 
 	if (new_dev)
 		*new_dev = ndev;
@@ -816,7 +835,10 @@ void ieee80211_if_remove(struct ieee8021
 {
 	ASSERT_RTNL();
 
+	mutex_lock(&sdata->local->iflist_mtx);
 	list_del_rcu(&sdata->list);
+	mutex_unlock(&sdata->local->iflist_mtx);
+
 	synchronize_rcu();
 	unregister_netdevice(sdata->dev);
 }
@@ -831,8 +853,10 @@ void ieee80211_remove_interfaces(struct 
 
 	ASSERT_RTNL();
 
+	mutex_lock(&local->iflist_mtx);
 	list_for_each_entry_safe(sdata, tmp, &local->interfaces, list) {
 		list_del(&sdata->list);
 		unregister_netdevice(sdata->dev);
 	}
+	mutex_unlock(&local->iflist_mtx);
 }
--- wireless-testing.orig/net/mac80211/main.c	2009-01-21 12:26:36.000000000 +0100
+++ wireless-testing/net/mac80211/main.c	2009-01-21 12:27:19.000000000 +0100
@@ -718,6 +718,7 @@ struct ieee80211_hw *ieee80211_alloc_hw(
 	local->hw.conf.radio_enabled = true;
 
 	INIT_LIST_HEAD(&local->interfaces);
+	mutex_init(&local->iflist_mtx);
 
 	spin_lock_init(&local->key_lock);
 
@@ -968,6 +969,8 @@ void ieee80211_free_hw(struct ieee80211_
 {
 	struct ieee80211_local *local = hw_to_local(hw);
 
+	mutex_destroy(&local->iflist_mtx);
+
 	wiphy_free(local->hw.wiphy);
 }
 EXPORT_SYMBOL(ieee80211_free_hw);
--- wireless-testing.orig/net/mac80211/util.c	2009-01-21 12:28:36.000000000 +0100
+++ wireless-testing/net/mac80211/util.c	2009-01-21 12:29:01.000000000 +0100
@@ -459,7 +459,7 @@ void ieee80211_iterate_active_interfaces
 	struct ieee80211_local *local = hw_to_local(hw);
 	struct ieee80211_sub_if_data *sdata;
 
-	rtnl_lock();
+	mutex_lock(&local->iflist_mtx);
 
 	list_for_each_entry(sdata, &local->interfaces, list) {
 		switch (sdata->vif.type) {
@@ -480,7 +480,7 @@ void ieee80211_iterate_active_interfaces
 				 &sdata->vif);
 	}
 
-	rtnl_unlock();
+	mutex_unlock(&local->iflist_mtx);
 }
 EXPORT_SYMBOL_GPL(ieee80211_iterate_active_interfaces);
 

--- End Message ---
--- Begin Message ---
This patch adds a flag to notify drivers to start and
stop beaconing when needed, for example, during a scan run.

Signed-off-by: Sujith <Sujith.Manoharan@xxxxxxxxxxx>
Signed-off-by: Johannes Berg <johannes@xxxxxxxxxxxxxxxx>
---
 include/net/mac80211.h |    9 +++++++--
 net/mac80211/cfg.c     |    5 +++--
 net/mac80211/main.c    |   42 +++++++++++++++++++++++++++++++++++++++++-
 net/mac80211/mesh.c    |    3 ++-
 net/mac80211/mlme.c    |    3 ++-
 net/mac80211/scan.c    |   18 +++++++++++-------
 6 files changed, 66 insertions(+), 14 deletions(-)

--- wireless-testing.orig/include/net/mac80211.h	2009-01-21 12:44:02.000000000 +0100
+++ wireless-testing/include/net/mac80211.h	2009-01-21 12:44:16.000000000 +0100
@@ -626,10 +626,12 @@ struct ieee80211_if_init_conf {
  * @IEEE80211_IFCC_BSSID: The BSSID changed.
  * @IEEE80211_IFCC_BEACON: The beacon for this interface changed
  *	(currently AP and MESH only), use ieee80211_beacon_get().
+ * @IEEE80211_IFCC_BEACON_ENABLED: The enable_beacon value changed.
  */
 enum ieee80211_if_conf_change {
-	IEEE80211_IFCC_BSSID	= BIT(0),
-	IEEE80211_IFCC_BEACON	= BIT(1),
+	IEEE80211_IFCC_BSSID		= BIT(0),
+	IEEE80211_IFCC_BEACON		= BIT(1),
+	IEEE80211_IFCC_BEACON_ENABLED	= BIT(2),
 };
 
 /**
@@ -637,6 +639,8 @@ enum ieee80211_if_conf_change {
  *
  * @changed: parameters that have changed, see &enum ieee80211_if_conf_change.
  * @bssid: BSSID of the network we are associated to/creating.
+ * @enable_beacon: Indicates whether beacons can be sent.
+ *	This is valid only for AP/IBSS/MESH modes.
  *
  * This structure is passed to the config_interface() callback of
  * &struct ieee80211_hw.
@@ -644,6 +648,7 @@ enum ieee80211_if_conf_change {
 struct ieee80211_if_conf {
 	u32 changed;
 	const u8 *bssid;
+	bool enable_beacon;
 };
 
 /**
--- wireless-testing.orig/net/mac80211/main.c	2009-01-21 12:44:04.000000000 +0100
+++ wireless-testing/net/mac80211/main.c	2009-01-21 12:44:16.000000000 +0100
@@ -168,7 +168,6 @@ int ieee80211_if_config(struct ieee80211
 		return 0;
 
 	memset(&conf, 0, sizeof(conf));
-	conf.changed = changed;
 
 	if (sdata->vif.type == NL80211_IFTYPE_STATION ||
 	    sdata->vif.type == NL80211_IFTYPE_ADHOC)
@@ -183,9 +182,50 @@ int ieee80211_if_config(struct ieee80211
 		return -EINVAL;
 	}
 
+	switch (sdata->vif.type) {
+	case NL80211_IFTYPE_AP:
+	case NL80211_IFTYPE_ADHOC:
+	case NL80211_IFTYPE_MESH_POINT:
+		break;
+	default:
+		/* do not warn to simplify caller in scan.c */
+		changed &= ~IEEE80211_IFCC_BEACON_ENABLED;
+		if (WARN_ON(changed & IEEE80211_IFCC_BEACON))
+			return -EINVAL;
+		changed &= ~IEEE80211_IFCC_BEACON;
+		break;
+	}
+
+	if (changed & IEEE80211_IFCC_BEACON_ENABLED) {
+		if (local->sw_scanning) {
+			conf.enable_beacon = false;
+		} else {
+			/*
+			 * Beacon should be enabled, but AP mode must
+			 * check whether there is a beacon configured.
+			 */
+			switch (sdata->vif.type) {
+			case NL80211_IFTYPE_AP:
+				conf.enable_beacon =
+					!!rcu_dereference(sdata->u.ap.beacon);
+				break;
+			case NL80211_IFTYPE_ADHOC:
+			case NL80211_IFTYPE_MESH_POINT:
+				conf.enable_beacon = true;
+				break;
+			default:
+				/* not reached */
+				WARN_ON(1);
+				break;
+			}
+		}
+	}
+
 	if (WARN_ON(!conf.bssid && (changed & IEEE80211_IFCC_BSSID)))
 		return -EINVAL;
 
+	conf.changed = changed;
+
 	return local->ops->config_interface(local_to_hw(local),
 					    &sdata->vif, &conf);
 }
--- wireless-testing.orig/net/mac80211/scan.c	2009-01-21 12:43:32.000000000 +0100
+++ wireless-testing/net/mac80211/scan.c	2009-01-21 12:44:16.000000000 +0100
@@ -20,6 +20,7 @@
 
 #include <linux/wireless.h>
 #include <linux/if_arp.h>
+#include <linux/rtnetlink.h>
 #include <net/mac80211.h>
 #include <net/iw_handler.h>
 
@@ -472,8 +473,8 @@ void ieee80211_scan_completed(struct iee
 	netif_addr_unlock(local->mdev);
 	netif_tx_unlock_bh(local->mdev);
 
-	rcu_read_lock();
-	list_for_each_entry_rcu(sdata, &local->interfaces, list) {
+	mutex_lock(&local->iflist_mtx);
+	list_for_each_entry(sdata, &local->interfaces, list) {
 		/* Tell AP we're back */
 		if (sdata->vif.type == NL80211_IFTYPE_STATION) {
 			if (sdata->u.sta.flags & IEEE80211_STA_ASSOCIATED) {
@@ -482,8 +483,10 @@ void ieee80211_scan_completed(struct iee
 			}
 		} else
 			netif_tx_wake_all_queues(sdata->dev);
+
+		ieee80211_if_config(sdata, IEEE80211_IFCC_BEACON_ENABLED);
 	}
-	rcu_read_unlock();
+	mutex_unlock(&local->iflist_mtx);
 
  done:
 	ieee80211_mlme_notify_scan_completed(local);
@@ -491,7 +494,6 @@ void ieee80211_scan_completed(struct iee
 }
 EXPORT_SYMBOL(ieee80211_scan_completed);
 
-
 void ieee80211_scan_work(struct work_struct *work)
 {
 	struct ieee80211_local *local =
@@ -633,8 +635,10 @@ int ieee80211_start_scan(struct ieee8021
 
 	local->sw_scanning = true;
 
-	rcu_read_lock();
-	list_for_each_entry_rcu(sdata, &local->interfaces, list) {
+	mutex_lock(&local->iflist_mtx);
+	list_for_each_entry(sdata, &local->interfaces, list) {
+		ieee80211_if_config(sdata, IEEE80211_IFCC_BEACON_ENABLED);
+
 		if (sdata->vif.type == NL80211_IFTYPE_STATION) {
 			if (sdata->u.sta.flags & IEEE80211_STA_ASSOCIATED) {
 				netif_tx_stop_all_queues(sdata->dev);
@@ -643,7 +647,7 @@ int ieee80211_start_scan(struct ieee8021
 		} else
 			netif_tx_stop_all_queues(sdata->dev);
 	}
-	rcu_read_unlock();
+	mutex_unlock(&local->iflist_mtx);
 
 	if (ssid) {
 		local->scan_ssid_len = ssid_len;
--- wireless-testing.orig/net/mac80211/mesh.c	2009-01-21 12:43:32.000000000 +0100
+++ wireless-testing/net/mac80211/mesh.c	2009-01-21 12:44:16.000000000 +0100
@@ -442,7 +442,8 @@ void ieee80211_start_mesh(struct ieee802
 
 	ifmsh->housekeeping = true;
 	queue_work(local->hw.workqueue, &ifmsh->work);
-	ieee80211_if_config(sdata, IEEE80211_IFCC_BEACON);
+	ieee80211_if_config(sdata, IEEE80211_IFCC_BEACON |
+				   IEEE80211_IFCC_BEACON_ENABLED);
 }
 
 void ieee80211_stop_mesh(struct ieee80211_sub_if_data *sdata)
--- wireless-testing.orig/net/mac80211/mlme.c	2009-01-21 12:43:32.000000000 +0100
+++ wireless-testing/net/mac80211/mlme.c	2009-01-21 12:44:16.000000000 +0100
@@ -1598,7 +1598,8 @@ static int ieee80211_sta_join_ibss(struc
 
 	ifsta->probe_resp = skb;
 
-	ieee80211_if_config(sdata, IEEE80211_IFCC_BEACON);
+	ieee80211_if_config(sdata, IEEE80211_IFCC_BEACON |
+				   IEEE80211_IFCC_BEACON_ENABLED);
 
 
 	rates = 0;
--- wireless-testing.orig/net/mac80211/cfg.c	2009-01-21 12:43:32.000000000 +0100
+++ wireless-testing/net/mac80211/cfg.c	2009-01-21 12:44:16.000000000 +0100
@@ -523,7 +523,8 @@ static int ieee80211_config_beacon(struc
 
 	kfree(old);
 
-	return ieee80211_if_config(sdata, IEEE80211_IFCC_BEACON);
+	return ieee80211_if_config(sdata, IEEE80211_IFCC_BEACON |
+					  IEEE80211_IFCC_BEACON_ENABLED);
 }
 
 static int ieee80211_add_beacon(struct wiphy *wiphy, struct net_device *dev,
@@ -583,7 +584,7 @@ static int ieee80211_del_beacon(struct w
 	synchronize_rcu();
 	kfree(old);
 
-	return ieee80211_if_config(sdata, IEEE80211_IFCC_BEACON);
+	return ieee80211_if_config(sdata, IEEE80211_IFCC_BEACON_ENABLED);
 }
 
 /* Layer 2 Update frame (802.2 Type 1 LLC XID Update response) */

--- End Message ---

Attachment: signature.asc
Description: This is a digitally signed message part


[Index of Archives]     [Linux Host AP]     [ATH6KL]     [Linux Bluetooth]     [Linux Netdev]     [Kernel Newbies]     [Linux Kernel]     [IDE]     [Security]     [Git]     [Netfilter]     [Bugtraq]     [Yosemite News]     [MIPS Linux]     [ARM Linux]     [Linux Security]     [Linux RAID]     [Linux ATA RAID]     [Samba]     [Device Mapper]
  Powered by Linux