Skip to content

Commit

Permalink
mac80211: add support for HW scheduled scan
Browse files Browse the repository at this point in the history
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>
  • Loading branch information
Luciano Coelho authored and John W. Linville committed May 11, 2011
1 parent 807f8a8 commit 79f460c
Show file tree
Hide file tree
Showing 8 changed files with 292 additions and 22 deletions.
50 changes: 50 additions & 0 deletions include/net/mac80211.h
Original file line number Diff line number Diff line change
Expand Up @@ -537,6 +537,21 @@ struct ieee80211_tx_info {
};
};

/**
* ieee80211_sched_scan_ies - scheduled scan IEs
*
* This structure is used to pass the appropriate IEs to be used in scheduled
* scans for all bands. It contains both the IEs passed from the userspace
* and the ones generated by mac80211.
*
* @ie: array with the IEs for each supported band
* @len: array with the total length of the IEs for each band
*/
struct ieee80211_sched_scan_ies {
u8 *ie[IEEE80211_NUM_BANDS];
size_t len[IEEE80211_NUM_BANDS];
};

static inline struct ieee80211_tx_info *IEEE80211_SKB_CB(struct sk_buff *skb)
{
return (struct ieee80211_tx_info *)skb->cb;
Expand Down Expand Up @@ -1693,6 +1708,13 @@ enum ieee80211_ampdu_mlme_action {
* any error unless this callback returned a negative error code.
* The callback can sleep.
*
* @sched_scan_start: Ask the hardware to start scanning repeatedly at
* specific intervals. The driver must call the
* ieee80211_sched_scan_results() function whenever it finds results.
* This process will continue until sched_scan_stop is called.
*
* @sched_scan_stop: Tell the hardware to stop an ongoing scheduled scan.
*
* @sw_scan_start: Notifier function that is called just before a software scan
* is started. Can be NULL, if the driver doesn't need this notification.
* The callback can sleep.
Expand Down Expand Up @@ -1877,6 +1899,12 @@ struct ieee80211_ops {
u32 iv32, u16 *phase1key);
int (*hw_scan)(struct ieee80211_hw *hw, struct ieee80211_vif *vif,
struct cfg80211_scan_request *req);
int (*sched_scan_start)(struct ieee80211_hw *hw,
struct ieee80211_vif *vif,
struct cfg80211_sched_scan_request *req,
struct ieee80211_sched_scan_ies *ies);
void (*sched_scan_stop)(struct ieee80211_hw *hw,
struct ieee80211_vif *vif);
void (*sw_scan_start)(struct ieee80211_hw *hw);
void (*sw_scan_complete)(struct ieee80211_hw *hw);
int (*get_stats)(struct ieee80211_hw *hw,
Expand Down Expand Up @@ -2593,6 +2621,28 @@ void ieee80211_wake_queues(struct ieee80211_hw *hw);
*/
void ieee80211_scan_completed(struct ieee80211_hw *hw, bool aborted);

/**
* ieee80211_sched_scan_results - got results from scheduled scan
*
* When a scheduled scan is running, this function needs to be called by the
* driver whenever there are new scan results available.
*
* @hw: the hardware that is performing scheduled scans
*/
void ieee80211_sched_scan_results(struct ieee80211_hw *hw);

/**
* ieee80211_sched_scan_stopped - inform that the scheduled scan has stopped
*
* When a scheduled scan is running, this function can be called by
* the driver if it needs to stop the scan to perform another task.
* Usual scenarios are drivers that cannot continue the scheduled scan
* while associating, for instance.
*
* @hw: the hardware that is performing scheduled scans
*/
void ieee80211_sched_scan_stopped(struct ieee80211_hw *hw);

/**
* ieee80211_iterate_active_interfaces - iterate active interfaces
*
Expand Down
27 changes: 27 additions & 0 deletions net/mac80211/cfg.c
Original file line number Diff line number Diff line change
Expand Up @@ -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)
{
Expand Down Expand Up @@ -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,
Expand Down
29 changes: 28 additions & 1 deletion net/mac80211/driver-ops.h
Original file line number Diff line number Diff line change
Expand Up @@ -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();
Expand Down
88 changes: 70 additions & 18 deletions net/mac80211/driver-trace.h
Original file line number Diff line number Diff line change
Expand Up @@ -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)
Expand Down Expand Up @@ -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),

TP_ARGS(local, sdata, req),

TP_STRUCT__entry(
LOCAL_ENTRY
VIF_ENTRY
),
struct ieee80211_sub_if_data *sdata),
TP_ARGS(local, sdata)
);

TP_fast_assign(
LOCAL_ASSIGN;
VIF_ASSIGN;
),
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_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,
Expand Down Expand Up @@ -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),
Expand Down
9 changes: 9 additions & 0 deletions net/mac80211/ieee80211_i.h
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down Expand Up @@ -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,
Expand Down
6 changes: 5 additions & 1 deletion net/mac80211/main.c
Original file line number Diff line number Diff line change
Expand Up @@ -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);

Expand Down Expand Up @@ -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;
Expand Down
6 changes: 4 additions & 2 deletions net/mac80211/rx.c
Original file line number Diff line number Diff line change
Expand Up @@ -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 */
Expand Down
Loading

0 comments on commit 79f460c

Please sign in to comment.