2 * This file is part of wl18xx
4 * Copyright (C) 2012 Texas Instruments. All rights reserved.
6 * This program is free software; you can redistribute it and/or
7 * modify it under the terms of the GNU General Public License
8 * version 2 as published by the Free Software Foundation.
10 * This program is distributed in the hope that it will be useful, but
11 * WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 * General Public License for more details.
15 * You should have received a copy of the GNU General Public License
16 * along with this program; if not, write to the Free Software
17 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
22 #include <linux/ieee80211.h>
24 #include "../wlcore/debug.h"
26 static void wl18xx_adjust_channels(struct wl18xx_cmd_scan_params
*cmd
,
27 struct wlcore_scan_channels
*cmd_channels
)
29 memcpy(cmd
->passive
, cmd_channels
->passive
, sizeof(cmd
->passive
));
30 memcpy(cmd
->active
, cmd_channels
->active
, sizeof(cmd
->active
));
31 cmd
->dfs
= cmd_channels
->dfs
;
32 cmd
->passive_active
= cmd_channels
->passive_active
;
34 memcpy(cmd
->channels_2
, cmd_channels
->channels_2
,
35 sizeof(cmd
->channels_2
));
36 memcpy(cmd
->channels_5
, cmd_channels
->channels_5
,
37 sizeof(cmd
->channels_5
));
38 /* channels_4 are not supported, so no need to copy them */
41 static int wl18xx_scan_send(struct wl1271
*wl
, struct wl12xx_vif
*wlvif
,
42 struct cfg80211_scan_request
*req
)
44 struct wl18xx_cmd_scan_params
*cmd
;
45 struct wlcore_scan_channels
*cmd_channels
= NULL
;
48 cmd
= kzalloc(sizeof(*cmd
), GFP_KERNEL
);
54 cmd
->role_id
= wlvif
->role_id
;
56 if (WARN_ON(cmd
->role_id
== WL12XX_INVALID_ROLE_ID
)) {
61 cmd
->scan_type
= SCAN_TYPE_SEARCH
;
62 cmd
->rssi_threshold
= -127;
63 cmd
->snr_threshold
= 0;
65 cmd
->bss_type
= SCAN_BSS_TYPE_ANY
;
67 cmd
->ssid_from_list
= 0;
69 cmd
->add_broadcast
= 0;
74 cmd
->n_probe_reqs
= wl
->conf
.scan
.num_probe_reqs
;
75 cmd
->terminate_after
= 0;
77 /* configure channels */
78 WARN_ON(req
->n_ssids
> 1);
80 cmd_channels
= kzalloc(sizeof(*cmd_channels
), GFP_KERNEL
);
86 wlcore_set_scan_chan_params(wl
, cmd_channels
, req
->channels
,
87 req
->n_channels
, req
->n_ssids
,
89 wl18xx_adjust_channels(cmd
, cmd_channels
);
92 * all the cycles params (except total cycles) should
93 * remain 0 for normal scan
95 cmd
->total_cycles
= 1;
98 cmd
->rate
= WL18XX_SCAN_RATE_6
;
100 cmd
->tag
= WL1271_SCAN_DEFAULT_TAG
;
103 cmd
->ssid_len
= req
->ssids
[0].ssid_len
;
104 memcpy(cmd
->ssid
, req
->ssids
[0].ssid
, cmd
->ssid_len
);
107 /* TODO: per-band ies? */
108 if (cmd
->active
[0]) {
109 u8 band
= IEEE80211_BAND_2GHZ
;
110 ret
= wl12xx_cmd_build_probe_req(wl
, wlvif
,
112 req
->ssids
? req
->ssids
[0].ssid
: NULL
,
113 req
->ssids
? req
->ssids
[0].ssid_len
: 0,
118 wl1271_error("2.4GHz PROBE request template failed");
123 if (cmd
->active
[1] || cmd
->dfs
) {
124 u8 band
= IEEE80211_BAND_5GHZ
;
125 ret
= wl12xx_cmd_build_probe_req(wl
, wlvif
,
127 req
->ssids
? req
->ssids
[0].ssid
: NULL
,
128 req
->ssids
? req
->ssids
[0].ssid_len
: 0,
133 wl1271_error("5GHz PROBE request template failed");
138 wl1271_dump(DEBUG_SCAN
, "SCAN: ", cmd
, sizeof(*cmd
));
140 ret
= wl1271_cmd_send(wl
, CMD_SCAN
, cmd
, sizeof(*cmd
), 0);
142 wl1271_error("SCAN failed");
152 void wl18xx_scan_completed(struct wl1271
*wl
, struct wl12xx_vif
*wlvif
)
154 wl
->scan
.failed
= false;
155 cancel_delayed_work(&wl
->scan_complete_work
);
156 ieee80211_queue_delayed_work(wl
->hw
, &wl
->scan_complete_work
,
157 msecs_to_jiffies(0));
161 int wl18xx_scan_sched_scan_config(struct wl1271
*wl
,
162 struct wl12xx_vif
*wlvif
,
163 struct cfg80211_sched_scan_request
*req
,
164 struct ieee80211_sched_scan_ies
*ies
)
166 struct wl18xx_cmd_scan_params
*cmd
;
167 struct wlcore_scan_channels
*cmd_channels
= NULL
;
168 struct conf_sched_scan_settings
*c
= &wl
->conf
.sched_scan
;
172 wl1271_debug(DEBUG_CMD
, "cmd sched_scan scan config");
174 filter_type
= wlcore_scan_sched_scan_ssid_list(wl
, wlvif
, req
);
178 cmd
= kzalloc(sizeof(*cmd
), GFP_KERNEL
);
184 cmd
->role_id
= wlvif
->role_id
;
186 if (WARN_ON(cmd
->role_id
== WL12XX_INVALID_ROLE_ID
)) {
191 cmd
->scan_type
= SCAN_TYPE_PERIODIC
;
192 cmd
->rssi_threshold
= c
->rssi_threshold
;
193 cmd
->snr_threshold
= c
->snr_threshold
;
195 /* don't filter on BSS type */
196 cmd
->bss_type
= SCAN_BSS_TYPE_ANY
;
198 cmd
->ssid_from_list
= 1;
199 if (filter_type
== SCAN_SSID_FILTER_LIST
)
201 cmd
->add_broadcast
= 0;
206 cmd
->n_probe_reqs
= c
->num_probe_reqs
;
207 /* don't stop scanning automatically when something is found */
208 cmd
->terminate_after
= 0;
210 cmd_channels
= kzalloc(sizeof(*cmd_channels
), GFP_KERNEL
);
216 /* configure channels */
217 wlcore_set_scan_chan_params(wl
, cmd_channels
, req
->channels
,
218 req
->n_channels
, req
->n_ssids
,
220 wl18xx_adjust_channels(cmd
, cmd_channels
);
222 cmd
->short_cycles_sec
= 0;
223 cmd
->long_cycles_sec
= cpu_to_le16(req
->interval
);
224 cmd
->short_cycles_count
= 0;
226 cmd
->total_cycles
= 0;
228 cmd
->tag
= WL1271_SCAN_DEFAULT_TAG
;
230 /* create a PERIODIC_SCAN_REPORT_EVENT whenever we've got a match */
231 cmd
->report_threshold
= 1;
232 cmd
->terminate_on_report
= 0;
234 if (cmd
->active
[0]) {
235 u8 band
= IEEE80211_BAND_2GHZ
;
236 ret
= wl12xx_cmd_build_probe_req(wl
, wlvif
,
238 req
->ssids
? req
->ssids
[0].ssid
: NULL
,
239 req
->ssids
? req
->ssids
[0].ssid_len
: 0,
244 wl1271_error("2.4GHz PROBE request template failed");
249 if (cmd
->active
[1] || cmd
->dfs
) {
250 u8 band
= IEEE80211_BAND_5GHZ
;
251 ret
= wl12xx_cmd_build_probe_req(wl
, wlvif
,
253 req
->ssids
? req
->ssids
[0].ssid
: NULL
,
254 req
->ssids
? req
->ssids
[0].ssid_len
: 0,
259 wl1271_error("5GHz PROBE request template failed");
264 wl1271_dump(DEBUG_SCAN
, "SCAN: ", cmd
, sizeof(*cmd
));
266 ret
= wl1271_cmd_send(wl
, CMD_SCAN
, cmd
, sizeof(*cmd
), 0);
268 wl1271_error("SCAN failed");
278 int wl18xx_sched_scan_start(struct wl1271
*wl
, struct wl12xx_vif
*wlvif
,
279 struct cfg80211_sched_scan_request
*req
,
280 struct ieee80211_sched_scan_ies
*ies
)
282 return wl18xx_scan_sched_scan_config(wl
, wlvif
, req
, ies
);
285 static int __wl18xx_scan_stop(struct wl1271
*wl
, struct wl12xx_vif
*wlvif
,
288 struct wl18xx_cmd_scan_stop
*stop
;
291 wl1271_debug(DEBUG_CMD
, "cmd periodic scan stop");
293 stop
= kzalloc(sizeof(*stop
), GFP_KERNEL
);
295 wl1271_error("failed to alloc memory to send sched scan stop");
299 stop
->role_id
= wlvif
->role_id
;
300 stop
->scan_type
= scan_type
;
302 ret
= wl1271_cmd_send(wl
, CMD_STOP_SCAN
, stop
, sizeof(*stop
), 0);
304 wl1271_error("failed to send sched scan stop command");
313 void wl18xx_scan_sched_scan_stop(struct wl1271
*wl
, struct wl12xx_vif
*wlvif
)
315 __wl18xx_scan_stop(wl
, wlvif
, SCAN_TYPE_PERIODIC
);
317 int wl18xx_scan_start(struct wl1271
*wl
, struct wl12xx_vif
*wlvif
,
318 struct cfg80211_scan_request
*req
)
320 return wl18xx_scan_send(wl
, wlvif
, req
);
323 int wl18xx_scan_stop(struct wl1271
*wl
, struct wl12xx_vif
*wlvif
)
325 return __wl18xx_scan_stop(wl
, wlvif
, SCAN_TYPE_SEARCH
);