mac80211: add support for HW scheduled scan
Implement support for HW scheduled scan. The mac80211 code doesn't perform scheduled scans itself, but calls the driver to start and stop scheduled scans. This patch also creates a trace event class to be used by drv_hw_scan and the new drv_sched_scan_start and drv_sched_stop functions, in order to avoid duplicate code. Signed-off-by: Luciano Coelho <coelho@ti.com> Signed-off-by: John W. Linville <linville@tuxdriver.com>
This commit is contained in:
committed by
John W. Linville
parent
807f8a8c30
commit
79f460ca49
@@ -1362,6 +1362,31 @@ static int ieee80211_scan(struct wiphy *wiphy,
|
||||
return ieee80211_request_scan(sdata, req);
|
||||
}
|
||||
|
||||
static int
|
||||
ieee80211_sched_scan_start(struct wiphy *wiphy,
|
||||
struct net_device *dev,
|
||||
struct cfg80211_sched_scan_request *req)
|
||||
{
|
||||
struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev);
|
||||
|
||||
if (!sdata->local->ops->sched_scan_start)
|
||||
return -EOPNOTSUPP;
|
||||
|
||||
return ieee80211_request_sched_scan_start(sdata, req);
|
||||
}
|
||||
|
||||
static int
|
||||
ieee80211_sched_scan_stop(struct wiphy *wiphy, struct net_device *dev,
|
||||
bool driver_initiated)
|
||||
{
|
||||
struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev);
|
||||
|
||||
if (!sdata->local->ops->sched_scan_stop)
|
||||
return -EOPNOTSUPP;
|
||||
|
||||
return ieee80211_request_sched_scan_stop(sdata, driver_initiated);
|
||||
}
|
||||
|
||||
static int ieee80211_auth(struct wiphy *wiphy, struct net_device *dev,
|
||||
struct cfg80211_auth_request *req)
|
||||
{
|
||||
@@ -2103,6 +2128,8 @@ struct cfg80211_ops mac80211_config_ops = {
|
||||
.suspend = ieee80211_suspend,
|
||||
.resume = ieee80211_resume,
|
||||
.scan = ieee80211_scan,
|
||||
.sched_scan_start = ieee80211_sched_scan_start,
|
||||
.sched_scan_stop = ieee80211_sched_scan_stop,
|
||||
.auth = ieee80211_auth,
|
||||
.assoc = ieee80211_assoc,
|
||||
.deauth = ieee80211_deauth,
|
||||
|
||||
@@ -212,12 +212,39 @@ static inline int drv_hw_scan(struct ieee80211_local *local,
|
||||
|
||||
might_sleep();
|
||||
|
||||
trace_drv_hw_scan(local, sdata, req);
|
||||
trace_drv_hw_scan(local, sdata);
|
||||
ret = local->ops->hw_scan(&local->hw, &sdata->vif, req);
|
||||
trace_drv_return_int(local, ret);
|
||||
return ret;
|
||||
}
|
||||
|
||||
static inline int
|
||||
drv_sched_scan_start(struct ieee80211_local *local,
|
||||
struct ieee80211_sub_if_data *sdata,
|
||||
struct cfg80211_sched_scan_request *req,
|
||||
struct ieee80211_sched_scan_ies *ies)
|
||||
{
|
||||
int ret;
|
||||
|
||||
might_sleep();
|
||||
|
||||
trace_drv_sched_scan_start(local, sdata);
|
||||
ret = local->ops->sched_scan_start(&local->hw, &sdata->vif,
|
||||
req, ies);
|
||||
trace_drv_return_int(local, ret);
|
||||
return ret;
|
||||
}
|
||||
|
||||
static inline void drv_sched_scan_stop(struct ieee80211_local *local,
|
||||
struct ieee80211_sub_if_data *sdata)
|
||||
{
|
||||
might_sleep();
|
||||
|
||||
trace_drv_sched_scan_stop(local, sdata);
|
||||
local->ops->sched_scan_stop(&local->hw, &sdata->vif);
|
||||
trace_drv_return_void(local);
|
||||
}
|
||||
|
||||
static inline void drv_sw_scan_start(struct ieee80211_local *local)
|
||||
{
|
||||
might_sleep();
|
||||
|
||||
@@ -98,6 +98,27 @@ DECLARE_EVENT_CLASS(local_u32_evt,
|
||||
)
|
||||
);
|
||||
|
||||
DECLARE_EVENT_CLASS(local_sdata_evt,
|
||||
TP_PROTO(struct ieee80211_local *local,
|
||||
struct ieee80211_sub_if_data *sdata),
|
||||
TP_ARGS(local, sdata),
|
||||
|
||||
TP_STRUCT__entry(
|
||||
LOCAL_ENTRY
|
||||
VIF_ENTRY
|
||||
),
|
||||
|
||||
TP_fast_assign(
|
||||
LOCAL_ASSIGN;
|
||||
VIF_ASSIGN;
|
||||
),
|
||||
|
||||
TP_printk(
|
||||
LOCAL_PR_FMT VIF_PR_FMT,
|
||||
LOCAL_PR_ARG, VIF_PR_ARG
|
||||
)
|
||||
);
|
||||
|
||||
DEFINE_EVENT(local_only_evt, drv_return_void,
|
||||
TP_PROTO(struct ieee80211_local *local),
|
||||
TP_ARGS(local)
|
||||
@@ -433,27 +454,22 @@ TRACE_EVENT(drv_update_tkip_key,
|
||||
)
|
||||
);
|
||||
|
||||
TRACE_EVENT(drv_hw_scan,
|
||||
DEFINE_EVENT(local_sdata_evt, drv_hw_scan,
|
||||
TP_PROTO(struct ieee80211_local *local,
|
||||
struct ieee80211_sub_if_data *sdata,
|
||||
struct cfg80211_scan_request *req),
|
||||
struct ieee80211_sub_if_data *sdata),
|
||||
TP_ARGS(local, sdata)
|
||||
);
|
||||
|
||||
TP_ARGS(local, sdata, req),
|
||||
DEFINE_EVENT(local_sdata_evt, drv_sched_scan_start,
|
||||
TP_PROTO(struct ieee80211_local *local,
|
||||
struct ieee80211_sub_if_data *sdata),
|
||||
TP_ARGS(local, sdata)
|
||||
);
|
||||
|
||||
TP_STRUCT__entry(
|
||||
LOCAL_ENTRY
|
||||
VIF_ENTRY
|
||||
),
|
||||
|
||||
TP_fast_assign(
|
||||
LOCAL_ASSIGN;
|
||||
VIF_ASSIGN;
|
||||
),
|
||||
|
||||
TP_printk(
|
||||
LOCAL_PR_FMT VIF_PR_FMT,
|
||||
LOCAL_PR_ARG,VIF_PR_ARG
|
||||
)
|
||||
DEFINE_EVENT(local_sdata_evt, drv_sched_scan_stop,
|
||||
TP_PROTO(struct ieee80211_local *local,
|
||||
struct ieee80211_sub_if_data *sdata),
|
||||
TP_ARGS(local, sdata)
|
||||
);
|
||||
|
||||
DEFINE_EVENT(local_only_evt, drv_sw_scan_start,
|
||||
@@ -1180,6 +1196,42 @@ TRACE_EVENT(api_scan_completed,
|
||||
)
|
||||
);
|
||||
|
||||
TRACE_EVENT(api_sched_scan_results,
|
||||
TP_PROTO(struct ieee80211_local *local),
|
||||
|
||||
TP_ARGS(local),
|
||||
|
||||
TP_STRUCT__entry(
|
||||
LOCAL_ENTRY
|
||||
),
|
||||
|
||||
TP_fast_assign(
|
||||
LOCAL_ASSIGN;
|
||||
),
|
||||
|
||||
TP_printk(
|
||||
LOCAL_PR_FMT, LOCAL_PR_ARG
|
||||
)
|
||||
);
|
||||
|
||||
TRACE_EVENT(api_sched_scan_stopped,
|
||||
TP_PROTO(struct ieee80211_local *local),
|
||||
|
||||
TP_ARGS(local),
|
||||
|
||||
TP_STRUCT__entry(
|
||||
LOCAL_ENTRY
|
||||
),
|
||||
|
||||
TP_fast_assign(
|
||||
LOCAL_ASSIGN;
|
||||
),
|
||||
|
||||
TP_printk(
|
||||
LOCAL_PR_FMT, LOCAL_PR_ARG
|
||||
)
|
||||
);
|
||||
|
||||
TRACE_EVENT(api_sta_block_awake,
|
||||
TP_PROTO(struct ieee80211_local *local,
|
||||
struct ieee80211_sta *sta, bool block),
|
||||
|
||||
@@ -847,6 +847,9 @@ struct ieee80211_local {
|
||||
int scan_channel_idx;
|
||||
int scan_ies_len;
|
||||
|
||||
bool sched_scanning;
|
||||
struct ieee80211_sched_scan_ies sched_scan_ies;
|
||||
|
||||
unsigned long leave_oper_channel_time;
|
||||
enum mac80211_scan_state next_scan_state;
|
||||
struct delayed_work scan_work;
|
||||
@@ -1154,6 +1157,12 @@ ieee80211_rx_bss_get(struct ieee80211_local *local, u8 *bssid, int freq,
|
||||
void ieee80211_rx_bss_put(struct ieee80211_local *local,
|
||||
struct ieee80211_bss *bss);
|
||||
|
||||
/* scheduled scan handling */
|
||||
int ieee80211_request_sched_scan_start(struct ieee80211_sub_if_data *sdata,
|
||||
struct cfg80211_sched_scan_request *req);
|
||||
int ieee80211_request_sched_scan_stop(struct ieee80211_sub_if_data *sdata,
|
||||
bool driver_initiated);
|
||||
|
||||
/* off-channel helpers */
|
||||
bool ieee80211_cfg_on_oper_channel(struct ieee80211_local *local);
|
||||
void ieee80211_offchannel_enable_all_ps(struct ieee80211_local *local,
|
||||
|
||||
@@ -358,7 +358,8 @@ static void ieee80211_restart_work(struct work_struct *work)
|
||||
flush_workqueue(local->workqueue);
|
||||
|
||||
mutex_lock(&local->mtx);
|
||||
WARN(test_bit(SCAN_HW_SCANNING, &local->scanning),
|
||||
WARN(test_bit(SCAN_HW_SCANNING, &local->scanning) ||
|
||||
local->sched_scanning,
|
||||
"%s called with hardware scan in progress\n", __func__);
|
||||
mutex_unlock(&local->mtx);
|
||||
|
||||
@@ -833,6 +834,9 @@ int ieee80211_register_hw(struct ieee80211_hw *hw)
|
||||
if (!local->ops->remain_on_channel)
|
||||
local->hw.wiphy->max_remain_on_channel_duration = 5000;
|
||||
|
||||
if (local->ops->sched_scan_start)
|
||||
local->hw.wiphy->flags |= WIPHY_FLAG_SUPPORTS_SCHED_SCAN;
|
||||
|
||||
result = wiphy_register(local->hw.wiphy);
|
||||
if (result < 0)
|
||||
goto fail_wiphy_register;
|
||||
|
||||
@@ -404,11 +404,13 @@ ieee80211_rx_h_passive_scan(struct ieee80211_rx_data *rx)
|
||||
struct ieee80211_rx_status *status = IEEE80211_SKB_RXCB(rx->skb);
|
||||
struct sk_buff *skb = rx->skb;
|
||||
|
||||
if (likely(!(status->rx_flags & IEEE80211_RX_IN_SCAN)))
|
||||
if (likely(!(status->rx_flags & IEEE80211_RX_IN_SCAN) &&
|
||||
!local->sched_scanning))
|
||||
return RX_CONTINUE;
|
||||
|
||||
if (test_bit(SCAN_HW_SCANNING, &local->scanning) ||
|
||||
test_bit(SCAN_SW_SCANNING, &local->scanning))
|
||||
test_bit(SCAN_SW_SCANNING, &local->scanning) ||
|
||||
local->sched_scanning)
|
||||
return ieee80211_scan_rx(rx->sdata, skb);
|
||||
|
||||
/* scanning finished during invoking of handlers */
|
||||
|
||||
@@ -15,6 +15,7 @@
|
||||
#include <linux/if_arp.h>
|
||||
#include <linux/rtnetlink.h>
|
||||
#include <linux/pm_qos_params.h>
|
||||
#include <linux/slab.h>
|
||||
#include <net/sch_generic.h>
|
||||
#include <linux/slab.h>
|
||||
#include <net/mac80211.h>
|
||||
@@ -850,3 +851,101 @@ void ieee80211_scan_cancel(struct ieee80211_local *local)
|
||||
}
|
||||
mutex_unlock(&local->mtx);
|
||||
}
|
||||
|
||||
int ieee80211_request_sched_scan_start(struct ieee80211_sub_if_data *sdata,
|
||||
struct cfg80211_sched_scan_request *req)
|
||||
{
|
||||
struct ieee80211_local *local = sdata->local;
|
||||
int ret, i;
|
||||
|
||||
mutex_lock(&sdata->local->mtx);
|
||||
|
||||
if (local->sched_scanning) {
|
||||
ret = -EBUSY;
|
||||
goto out;
|
||||
}
|
||||
|
||||
if (!local->ops->sched_scan_start) {
|
||||
ret = -ENOTSUPP;
|
||||
goto out;
|
||||
}
|
||||
|
||||
for (i = 0; i < IEEE80211_NUM_BANDS; i++) {
|
||||
local->sched_scan_ies.ie[i] = kzalloc(2 +
|
||||
IEEE80211_MAX_SSID_LEN +
|
||||
local->scan_ies_len,
|
||||
GFP_KERNEL);
|
||||
if (!local->sched_scan_ies.ie[i]) {
|
||||
ret = -ENOMEM;
|
||||
goto out_free;
|
||||
}
|
||||
|
||||
local->sched_scan_ies.len[i] =
|
||||
ieee80211_build_preq_ies(local,
|
||||
local->sched_scan_ies.ie[i],
|
||||
req->ie, req->ie_len, i,
|
||||
(u32) -1, 0);
|
||||
}
|
||||
|
||||
ret = drv_sched_scan_start(local, sdata, req,
|
||||
&local->sched_scan_ies);
|
||||
if (ret == 0) {
|
||||
local->sched_scanning = true;
|
||||
goto out;
|
||||
}
|
||||
|
||||
out_free:
|
||||
while (i > 0)
|
||||
kfree(local->sched_scan_ies.ie[--i]);
|
||||
out:
|
||||
mutex_unlock(&sdata->local->mtx);
|
||||
return ret;
|
||||
}
|
||||
|
||||
int ieee80211_request_sched_scan_stop(struct ieee80211_sub_if_data *sdata,
|
||||
bool driver_initiated)
|
||||
{
|
||||
struct ieee80211_local *local = sdata->local;
|
||||
int ret = 0, i;
|
||||
|
||||
mutex_lock(&sdata->local->mtx);
|
||||
|
||||
if (!local->ops->sched_scan_stop) {
|
||||
ret = -ENOTSUPP;
|
||||
goto out;
|
||||
}
|
||||
|
||||
if (local->sched_scanning) {
|
||||
for (i = 0; i < IEEE80211_NUM_BANDS; i++)
|
||||
kfree(local->sched_scan_ies.ie[i]);
|
||||
|
||||
if (!driver_initiated)
|
||||
drv_sched_scan_stop(local, sdata);
|
||||
local->sched_scanning = false;
|
||||
}
|
||||
|
||||
out:
|
||||
mutex_unlock(&sdata->local->mtx);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
void ieee80211_sched_scan_results(struct ieee80211_hw *hw)
|
||||
{
|
||||
struct ieee80211_local *local = hw_to_local(hw);
|
||||
|
||||
trace_api_sched_scan_results(local);
|
||||
|
||||
cfg80211_sched_scan_results(hw->wiphy);
|
||||
}
|
||||
EXPORT_SYMBOL(ieee80211_sched_scan_results);
|
||||
|
||||
void ieee80211_sched_scan_stopped(struct ieee80211_hw *hw)
|
||||
{
|
||||
struct ieee80211_local *local = hw_to_local(hw);
|
||||
|
||||
trace_api_sched_scan_stopped(local);
|
||||
|
||||
cfg80211_sched_scan_stopped(hw->wiphy);
|
||||
}
|
||||
EXPORT_SYMBOL(ieee80211_sched_scan_stopped);
|
||||
|
||||
Reference in New Issue
Block a user