Commit 078e1e60 authored by Johannes Berg's avatar Johannes Berg Committed by John W. Linville

mac80211: Add capability to enable/disable beaconing

This patch adds a flag to notify drivers to start and stop
beaconing when needed, for example, during a scan run. Based
on Sujith's first patch to do the same, but now disables
beaconing for all virtual interfaces while scanning, has a
separate change flag and tracks user-space requests.
Signed-off-by: default avatarSujith <Sujith.Manoharan@atheros.com>
Signed-off-by: default avatarJohannes Berg <johannes@sipsolutions.net>
Signed-off-by: default avatarJohn W. Linville <linville@tuxdriver.com>
parent 07c1e852
...@@ -646,10 +646,12 @@ struct ieee80211_if_init_conf { ...@@ -646,10 +646,12 @@ struct ieee80211_if_init_conf {
* @IEEE80211_IFCC_BSSID: The BSSID changed. * @IEEE80211_IFCC_BSSID: The BSSID changed.
* @IEEE80211_IFCC_BEACON: The beacon for this interface changed * @IEEE80211_IFCC_BEACON: The beacon for this interface changed
* (currently AP and MESH only), use ieee80211_beacon_get(). * (currently AP and MESH only), use ieee80211_beacon_get().
* @IEEE80211_IFCC_BEACON_ENABLED: The enable_beacon value changed.
*/ */
enum ieee80211_if_conf_change { enum ieee80211_if_conf_change {
IEEE80211_IFCC_BSSID = BIT(0), IEEE80211_IFCC_BSSID = BIT(0),
IEEE80211_IFCC_BEACON = BIT(1), IEEE80211_IFCC_BEACON = BIT(1),
IEEE80211_IFCC_BEACON_ENABLED = BIT(2),
}; };
/** /**
...@@ -657,6 +659,8 @@ enum ieee80211_if_conf_change { ...@@ -657,6 +659,8 @@ enum ieee80211_if_conf_change {
* *
* @changed: parameters that have changed, see &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. * @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 * This structure is passed to the config_interface() callback of
* &struct ieee80211_hw. * &struct ieee80211_hw.
...@@ -664,6 +668,7 @@ enum ieee80211_if_conf_change { ...@@ -664,6 +668,7 @@ enum ieee80211_if_conf_change {
struct ieee80211_if_conf { struct ieee80211_if_conf {
u32 changed; u32 changed;
const u8 *bssid; const u8 *bssid;
bool enable_beacon;
}; };
/** /**
......
...@@ -523,7 +523,8 @@ static int ieee80211_config_beacon(struct ieee80211_sub_if_data *sdata, ...@@ -523,7 +523,8 @@ static int ieee80211_config_beacon(struct ieee80211_sub_if_data *sdata,
kfree(old); 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, static int ieee80211_add_beacon(struct wiphy *wiphy, struct net_device *dev,
...@@ -583,7 +584,7 @@ static int ieee80211_del_beacon(struct wiphy *wiphy, struct net_device *dev) ...@@ -583,7 +584,7 @@ static int ieee80211_del_beacon(struct wiphy *wiphy, struct net_device *dev)
synchronize_rcu(); synchronize_rcu();
kfree(old); 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) */ /* Layer 2 Update frame (802.2 Type 1 LLC XID Update response) */
......
...@@ -168,7 +168,6 @@ int ieee80211_if_config(struct ieee80211_sub_if_data *sdata, u32 changed) ...@@ -168,7 +168,6 @@ int ieee80211_if_config(struct ieee80211_sub_if_data *sdata, u32 changed)
return 0; return 0;
memset(&conf, 0, sizeof(conf)); memset(&conf, 0, sizeof(conf));
conf.changed = changed;
if (sdata->vif.type == NL80211_IFTYPE_STATION || if (sdata->vif.type == NL80211_IFTYPE_STATION ||
sdata->vif.type == NL80211_IFTYPE_ADHOC) sdata->vif.type == NL80211_IFTYPE_ADHOC)
...@@ -183,9 +182,50 @@ int ieee80211_if_config(struct ieee80211_sub_if_data *sdata, u32 changed) ...@@ -183,9 +182,50 @@ int ieee80211_if_config(struct ieee80211_sub_if_data *sdata, u32 changed)
return -EINVAL; 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))) if (WARN_ON(!conf.bssid && (changed & IEEE80211_IFCC_BSSID)))
return -EINVAL; return -EINVAL;
conf.changed = changed;
return local->ops->config_interface(local_to_hw(local), return local->ops->config_interface(local_to_hw(local),
&sdata->vif, &conf); &sdata->vif, &conf);
} }
......
...@@ -442,7 +442,8 @@ void ieee80211_start_mesh(struct ieee80211_sub_if_data *sdata) ...@@ -442,7 +442,8 @@ void ieee80211_start_mesh(struct ieee80211_sub_if_data *sdata)
ifmsh->housekeeping = true; ifmsh->housekeeping = true;
queue_work(local->hw.workqueue, &ifmsh->work); 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) void ieee80211_stop_mesh(struct ieee80211_sub_if_data *sdata)
......
...@@ -1599,7 +1599,8 @@ static int ieee80211_sta_join_ibss(struct ieee80211_sub_if_data *sdata, ...@@ -1599,7 +1599,8 @@ static int ieee80211_sta_join_ibss(struct ieee80211_sub_if_data *sdata,
ifsta->probe_resp = skb; ifsta->probe_resp = skb;
ieee80211_if_config(sdata, IEEE80211_IFCC_BEACON); ieee80211_if_config(sdata, IEEE80211_IFCC_BEACON |
IEEE80211_IFCC_BEACON_ENABLED);
rates = 0; rates = 0;
......
...@@ -20,6 +20,7 @@ ...@@ -20,6 +20,7 @@
#include <linux/wireless.h> #include <linux/wireless.h>
#include <linux/if_arp.h> #include <linux/if_arp.h>
#include <linux/rtnetlink.h>
#include <net/mac80211.h> #include <net/mac80211.h>
#include <net/iw_handler.h> #include <net/iw_handler.h>
...@@ -472,8 +473,8 @@ void ieee80211_scan_completed(struct ieee80211_hw *hw) ...@@ -472,8 +473,8 @@ void ieee80211_scan_completed(struct ieee80211_hw *hw)
netif_addr_unlock(local->mdev); netif_addr_unlock(local->mdev);
netif_tx_unlock_bh(local->mdev); netif_tx_unlock_bh(local->mdev);
rcu_read_lock(); mutex_lock(&local->iflist_mtx);
list_for_each_entry_rcu(sdata, &local->interfaces, list) { list_for_each_entry(sdata, &local->interfaces, list) {
/* Tell AP we're back */ /* Tell AP we're back */
if (sdata->vif.type == NL80211_IFTYPE_STATION) { if (sdata->vif.type == NL80211_IFTYPE_STATION) {
if (sdata->u.sta.flags & IEEE80211_STA_ASSOCIATED) { if (sdata->u.sta.flags & IEEE80211_STA_ASSOCIATED) {
...@@ -482,8 +483,10 @@ void ieee80211_scan_completed(struct ieee80211_hw *hw) ...@@ -482,8 +483,10 @@ void ieee80211_scan_completed(struct ieee80211_hw *hw)
} }
} else } else
netif_tx_wake_all_queues(sdata->dev); netif_tx_wake_all_queues(sdata->dev);
ieee80211_if_config(sdata, IEEE80211_IFCC_BEACON_ENABLED);
} }
rcu_read_unlock(); mutex_unlock(&local->iflist_mtx);
done: done:
ieee80211_mlme_notify_scan_completed(local); ieee80211_mlme_notify_scan_completed(local);
...@@ -491,7 +494,6 @@ void ieee80211_scan_completed(struct ieee80211_hw *hw) ...@@ -491,7 +494,6 @@ void ieee80211_scan_completed(struct ieee80211_hw *hw)
} }
EXPORT_SYMBOL(ieee80211_scan_completed); EXPORT_SYMBOL(ieee80211_scan_completed);
void ieee80211_scan_work(struct work_struct *work) void ieee80211_scan_work(struct work_struct *work)
{ {
struct ieee80211_local *local = struct ieee80211_local *local =
...@@ -633,8 +635,10 @@ int ieee80211_start_scan(struct ieee80211_sub_if_data *scan_sdata, ...@@ -633,8 +635,10 @@ int ieee80211_start_scan(struct ieee80211_sub_if_data *scan_sdata,
local->sw_scanning = true; local->sw_scanning = true;
rcu_read_lock(); mutex_lock(&local->iflist_mtx);
list_for_each_entry_rcu(sdata, &local->interfaces, list) { 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->vif.type == NL80211_IFTYPE_STATION) {
if (sdata->u.sta.flags & IEEE80211_STA_ASSOCIATED) { if (sdata->u.sta.flags & IEEE80211_STA_ASSOCIATED) {
netif_tx_stop_all_queues(sdata->dev); netif_tx_stop_all_queues(sdata->dev);
...@@ -643,7 +647,7 @@ int ieee80211_start_scan(struct ieee80211_sub_if_data *scan_sdata, ...@@ -643,7 +647,7 @@ int ieee80211_start_scan(struct ieee80211_sub_if_data *scan_sdata,
} else } else
netif_tx_stop_all_queues(sdata->dev); netif_tx_stop_all_queues(sdata->dev);
} }
rcu_read_unlock(); mutex_unlock(&local->iflist_mtx);
if (ssid) { if (ssid) {
local->scan_ssid_len = ssid_len; local->scan_ssid_len = ssid_len;
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment