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: Sujith <Sujith.Manoharan@atheros.com> Signed-off-by: Johannes Berg <johannes@sipsolutions.net> Signed-off-by: John W. Linville <linville@tuxdriver.com>
This commit is contained in:
committed by
John W. Linville
parent
07c1e85251
commit
078e1e60dd
@@ -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 {
|
|||||||
*
|
*
|
||||||
* @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 {
|
|||||||
struct ieee80211_if_conf {
|
struct ieee80211_if_conf {
|
||||||
u32 changed;
|
u32 changed;
|
||||||
const u8 *bssid;
|
const u8 *bssid;
|
||||||
|
bool enable_beacon;
|
||||||
};
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|||||||
+3
-2
@@ -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)
|
|||||||
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) */
|
||||||
|
|||||||
+41
-1
@@ -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)
|
|||||||
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);
|
||||||
}
|
}
|
||||||
|
|||||||
+2
-1
@@ -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)
|
||||||
|
|||||||
+2
-1
@@ -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;
|
||||||
|
|||||||
+11
-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)
|
|||||||
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)
|
|||||||
}
|
}
|
||||||
} 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)
|
|||||||
}
|
}
|
||||||
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,
|
|||||||
|
|
||||||
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,
|
|||||||
} 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;
|
||||||
|
|||||||
Reference in New Issue
Block a user