return RX_CONTINUE;
if (skb->len < 24)
- return RX_DROP_MONITOR;
+ return RX_CONTINUE;
presp = ieee80211_is_probe_resp(fc);
if (presp) {
local->hw_scan_req->n_channels = n_chans;
ielen = ieee80211_build_preq_ies(local, (u8 *)local->hw_scan_req->ie,
- req->ie, req->ie_len, band, (u32) -1,
- 0);
+ req->ie, req->ie_len, band,
+ req->rates[band], 0);
local->hw_scan_req->ie_len = ielen;
return true;
{
int i;
struct ieee80211_sub_if_data *sdata = local->scan_sdata;
+ enum ieee80211_band band = local->hw.conf.channel->band;
for (i = 0; i < local->scan_req->n_ssids; i++)
ieee80211_send_probe_req(
sdata, NULL,
local->scan_req->ssids[i].ssid,
local->scan_req->ssids[i].ssid_len,
- local->scan_req->ie, local->scan_req->ie_len);
+ local->scan_req->ie, local->scan_req->ie_len,
+ local->scan_req->rates[band], false);
/*
* After sending probe requests, wait for probe responses
* without scheduling a new work
*/
do {
+ if (!ieee80211_sdata_running(sdata)) {
+ aborted = true;
+ goto out_complete;
+ }
+
switch (local->next_scan_state) {
case SCAN_DECISION:
/* if no more bands/channels left, complete scan */
*/
void ieee80211_scan_cancel(struct ieee80211_local *local)
{
- bool abortscan;
-
/*
- * We are only canceling software scan, or deferred scan that was not
+ * We are canceling software scan, or deferred scan that was not
* yet really started (see __ieee80211_start_scan ).
*
* Regarding hardware scan:
* - we can not cancel scan_work since driver can schedule it
* by ieee80211_scan_completed(..., true) to finish scan
*
- * Hence low lever driver is responsible for canceling HW scan.
+ * Hence we only call the cancel_hw_scan() callback, but the low-level
+ * driver is still responsible for calling ieee80211_scan_completed()
+ * after the scan was completed/aborted.
*/
mutex_lock(&local->mtx);
- abortscan = local->scan_req && !test_bit(SCAN_HW_SCANNING, &local->scanning);
- if (abortscan) {
- /*
- * The scan is canceled, but stop work from being pending.
- *
- * If the work is currently running, it must be blocked on
- * the mutex, but we'll set scan_sdata = NULL and it'll
- * simply exit once it acquires the mutex.
- */
- cancel_delayed_work(&local->scan_work);
- /* and clean up */
- __ieee80211_scan_completed(&local->hw, true, false);
+ if (!local->scan_req)
+ goto out;
+
+ if (test_bit(SCAN_HW_SCANNING, &local->scanning)) {
+ if (local->ops->cancel_hw_scan)
+ drv_cancel_hw_scan(local, local->scan_sdata);
+ goto out;
}
+
+ /*
+ * If the work is currently running, it must be blocked on
+ * the mutex, but we'll set scan_sdata = NULL and it'll
+ * simply exit once it acquires the mutex.
+ */
+ cancel_delayed_work(&local->scan_work);
+ /* and clean up */
+ __ieee80211_scan_completed(&local->hw, true, false);
+out:
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 +
+ req->ie_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)
+{
+ 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]);
+
+ 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_work(struct work_struct *work)
+{
+ struct ieee80211_local *local =
+ container_of(work, struct ieee80211_local,
+ sched_scan_stopped_work);
+ int i;
+
+ mutex_lock(&local->mtx);
+
+ if (!local->sched_scanning) {
+ mutex_unlock(&local->mtx);
+ return;
+ }
+
+ for (i = 0; i < IEEE80211_NUM_BANDS; i++)
+ kfree(local->sched_scan_ies.ie[i]);
+
+ local->sched_scanning = false;
+
+ mutex_unlock(&local->mtx);
+
+ cfg80211_sched_scan_stopped(local->hw.wiphy);
+}
+
+void ieee80211_sched_scan_stopped(struct ieee80211_hw *hw)
+{
+ struct ieee80211_local *local = hw_to_local(hw);
+
+ trace_api_sched_scan_stopped(local);
+
+ ieee80211_queue_work(&local->hw, &local->sched_scan_stopped_work);
+}
+EXPORT_SYMBOL(ieee80211_sched_scan_stopped);