1 /* 2 * This file is part of wl18xx 3 * 4 * Copyright (C) 2012 Texas Instruments. All rights reserved. 5 * 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. 9 * 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. 14 * 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 18 * 02110-1301 USA 19 * 20 */ 21 22 #include <linux/ieee80211.h> 23 #include "scan.h" 24 #include "../wlcore/debug.h" 25 26 static void wl18xx_adjust_channels(struct wl18xx_cmd_scan_params *cmd, 27 struct wlcore_scan_channels *cmd_channels) 28 { 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; 33 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 */ 39 } 40 41 static int wl18xx_scan_send(struct wl1271 *wl, struct wl12xx_vif *wlvif, 42 struct cfg80211_scan_request *req) 43 { 44 struct wl18xx_cmd_scan_params *cmd; 45 struct wlcore_scan_channels *cmd_channels = NULL; 46 int ret; 47 48 cmd = kzalloc(sizeof(*cmd), GFP_KERNEL); 49 if (!cmd) { 50 ret = -ENOMEM; 51 goto out; 52 } 53 54 /* scan on the dev role if the regular one is not started */ 55 if (wlcore_is_p2p_mgmt(wlvif)) 56 cmd->role_id = wlvif->dev_role_id; 57 else 58 cmd->role_id = wlvif->role_id; 59 60 if (WARN_ON(cmd->role_id == WL12XX_INVALID_ROLE_ID)) { 61 ret = -EINVAL; 62 goto out; 63 } 64 65 cmd->scan_type = SCAN_TYPE_SEARCH; 66 cmd->rssi_threshold = -127; 67 cmd->snr_threshold = 0; 68 69 cmd->bss_type = SCAN_BSS_TYPE_ANY; 70 71 cmd->ssid_from_list = 0; 72 cmd->filter = 0; 73 cmd->add_broadcast = 0; 74 75 cmd->urgency = 0; 76 cmd->protect = 0; 77 78 cmd->n_probe_reqs = wl->conf.scan.num_probe_reqs; 79 cmd->terminate_after = 0; 80 81 /* configure channels */ 82 WARN_ON(req->n_ssids > 1); 83 84 cmd_channels = kzalloc(sizeof(*cmd_channels), GFP_KERNEL); 85 if (!cmd_channels) { 86 ret = -ENOMEM; 87 goto out; 88 } 89 90 wlcore_set_scan_chan_params(wl, cmd_channels, req->channels, 91 req->n_channels, req->n_ssids, 92 SCAN_TYPE_SEARCH); 93 wl18xx_adjust_channels(cmd, cmd_channels); 94 95 /* 96 * all the cycles params (except total cycles) should 97 * remain 0 for normal scan 98 */ 99 cmd->total_cycles = 1; 100 101 if (req->no_cck) 102 cmd->rate = WL18XX_SCAN_RATE_6; 103 104 cmd->tag = WL1271_SCAN_DEFAULT_TAG; 105 106 if (req->n_ssids) { 107 cmd->ssid_len = req->ssids[0].ssid_len; 108 memcpy(cmd->ssid, req->ssids[0].ssid, cmd->ssid_len); 109 } 110 111 /* TODO: per-band ies? */ 112 if (cmd->active[0]) { 113 u8 band = NL80211_BAND_2GHZ; 114 ret = wl12xx_cmd_build_probe_req(wl, wlvif, 115 cmd->role_id, band, 116 req->ssids ? req->ssids[0].ssid : NULL, 117 req->ssids ? req->ssids[0].ssid_len : 0, 118 req->ie, 119 req->ie_len, 120 NULL, 121 0, 122 false); 123 if (ret < 0) { 124 wl1271_error("2.4GHz PROBE request template failed"); 125 goto out; 126 } 127 } 128 129 if (cmd->active[1] || cmd->dfs) { 130 u8 band = NL80211_BAND_5GHZ; 131 ret = wl12xx_cmd_build_probe_req(wl, wlvif, 132 cmd->role_id, band, 133 req->ssids ? req->ssids[0].ssid : NULL, 134 req->ssids ? req->ssids[0].ssid_len : 0, 135 req->ie, 136 req->ie_len, 137 NULL, 138 0, 139 false); 140 if (ret < 0) { 141 wl1271_error("5GHz PROBE request template failed"); 142 goto out; 143 } 144 } 145 146 wl1271_dump(DEBUG_SCAN, "SCAN: ", cmd, sizeof(*cmd)); 147 148 ret = wl1271_cmd_send(wl, CMD_SCAN, cmd, sizeof(*cmd), 0); 149 if (ret < 0) { 150 wl1271_error("SCAN failed"); 151 goto out; 152 } 153 154 out: 155 kfree(cmd_channels); 156 kfree(cmd); 157 return ret; 158 } 159 160 void wl18xx_scan_completed(struct wl1271 *wl, struct wl12xx_vif *wlvif) 161 { 162 wl->scan.failed = false; 163 cancel_delayed_work(&wl->scan_complete_work); 164 ieee80211_queue_delayed_work(wl->hw, &wl->scan_complete_work, 165 msecs_to_jiffies(0)); 166 } 167 168 static 169 int wl18xx_scan_sched_scan_config(struct wl1271 *wl, 170 struct wl12xx_vif *wlvif, 171 struct cfg80211_sched_scan_request *req, 172 struct ieee80211_scan_ies *ies) 173 { 174 struct wl18xx_cmd_scan_params *cmd; 175 struct wlcore_scan_channels *cmd_channels = NULL; 176 struct conf_sched_scan_settings *c = &wl->conf.sched_scan; 177 int ret; 178 int filter_type; 179 180 wl1271_debug(DEBUG_CMD, "cmd sched_scan scan config"); 181 182 filter_type = wlcore_scan_sched_scan_ssid_list(wl, wlvif, req); 183 if (filter_type < 0) 184 return filter_type; 185 186 cmd = kzalloc(sizeof(*cmd), GFP_KERNEL); 187 if (!cmd) { 188 ret = -ENOMEM; 189 goto out; 190 } 191 192 cmd->role_id = wlvif->role_id; 193 194 if (WARN_ON(cmd->role_id == WL12XX_INVALID_ROLE_ID)) { 195 ret = -EINVAL; 196 goto out; 197 } 198 199 cmd->scan_type = SCAN_TYPE_PERIODIC; 200 cmd->rssi_threshold = c->rssi_threshold; 201 cmd->snr_threshold = c->snr_threshold; 202 203 /* don't filter on BSS type */ 204 cmd->bss_type = SCAN_BSS_TYPE_ANY; 205 206 cmd->ssid_from_list = 1; 207 if (filter_type == SCAN_SSID_FILTER_LIST) 208 cmd->filter = 1; 209 cmd->add_broadcast = 0; 210 211 cmd->urgency = 0; 212 cmd->protect = 0; 213 214 cmd->n_probe_reqs = c->num_probe_reqs; 215 /* don't stop scanning automatically when something is found */ 216 cmd->terminate_after = 0; 217 218 cmd_channels = kzalloc(sizeof(*cmd_channels), GFP_KERNEL); 219 if (!cmd_channels) { 220 ret = -ENOMEM; 221 goto out; 222 } 223 224 /* configure channels */ 225 wlcore_set_scan_chan_params(wl, cmd_channels, req->channels, 226 req->n_channels, req->n_ssids, 227 SCAN_TYPE_PERIODIC); 228 wl18xx_adjust_channels(cmd, cmd_channels); 229 230 if (c->num_short_intervals && c->long_interval && 231 c->long_interval > req->scan_plans[0].interval * MSEC_PER_SEC) { 232 cmd->short_cycles_msec = 233 cpu_to_le16(req->scan_plans[0].interval * MSEC_PER_SEC); 234 cmd->long_cycles_msec = cpu_to_le16(c->long_interval); 235 cmd->short_cycles_count = c->num_short_intervals; 236 } else { 237 cmd->short_cycles_msec = 0; 238 cmd->long_cycles_msec = 239 cpu_to_le16(req->scan_plans[0].interval * MSEC_PER_SEC); 240 cmd->short_cycles_count = 0; 241 } 242 wl1271_debug(DEBUG_SCAN, "short_interval: %d, long_interval: %d, num_short: %d", 243 le16_to_cpu(cmd->short_cycles_msec), 244 le16_to_cpu(cmd->long_cycles_msec), 245 cmd->short_cycles_count); 246 247 cmd->total_cycles = 0; 248 249 cmd->tag = WL1271_SCAN_DEFAULT_TAG; 250 251 /* create a PERIODIC_SCAN_REPORT_EVENT whenever we've got a match */ 252 cmd->report_threshold = 1; 253 cmd->terminate_on_report = 0; 254 255 if (cmd->active[0]) { 256 u8 band = NL80211_BAND_2GHZ; 257 ret = wl12xx_cmd_build_probe_req(wl, wlvif, 258 cmd->role_id, band, 259 req->ssids ? req->ssids[0].ssid : NULL, 260 req->ssids ? req->ssids[0].ssid_len : 0, 261 ies->ies[band], 262 ies->len[band], 263 ies->common_ies, 264 ies->common_ie_len, 265 true); 266 if (ret < 0) { 267 wl1271_error("2.4GHz PROBE request template failed"); 268 goto out; 269 } 270 } 271 272 if (cmd->active[1] || cmd->dfs) { 273 u8 band = NL80211_BAND_5GHZ; 274 ret = wl12xx_cmd_build_probe_req(wl, wlvif, 275 cmd->role_id, band, 276 req->ssids ? req->ssids[0].ssid : NULL, 277 req->ssids ? req->ssids[0].ssid_len : 0, 278 ies->ies[band], 279 ies->len[band], 280 ies->common_ies, 281 ies->common_ie_len, 282 true); 283 if (ret < 0) { 284 wl1271_error("5GHz PROBE request template failed"); 285 goto out; 286 } 287 } 288 289 wl1271_dump(DEBUG_SCAN, "SCAN: ", cmd, sizeof(*cmd)); 290 291 ret = wl1271_cmd_send(wl, CMD_SCAN, cmd, sizeof(*cmd), 0); 292 if (ret < 0) { 293 wl1271_error("SCAN failed"); 294 goto out; 295 } 296 297 out: 298 kfree(cmd_channels); 299 kfree(cmd); 300 return ret; 301 } 302 303 int wl18xx_sched_scan_start(struct wl1271 *wl, struct wl12xx_vif *wlvif, 304 struct cfg80211_sched_scan_request *req, 305 struct ieee80211_scan_ies *ies) 306 { 307 return wl18xx_scan_sched_scan_config(wl, wlvif, req, ies); 308 } 309 310 static int __wl18xx_scan_stop(struct wl1271 *wl, struct wl12xx_vif *wlvif, 311 u8 scan_type) 312 { 313 struct wl18xx_cmd_scan_stop *stop; 314 int ret; 315 316 wl1271_debug(DEBUG_CMD, "cmd periodic scan stop"); 317 318 stop = kzalloc(sizeof(*stop), GFP_KERNEL); 319 if (!stop) { 320 wl1271_error("failed to alloc memory to send sched scan stop"); 321 return -ENOMEM; 322 } 323 324 stop->role_id = wlvif->role_id; 325 stop->scan_type = scan_type; 326 327 ret = wl1271_cmd_send(wl, CMD_STOP_SCAN, stop, sizeof(*stop), 0); 328 if (ret < 0) { 329 wl1271_error("failed to send sched scan stop command"); 330 goto out_free; 331 } 332 333 out_free: 334 kfree(stop); 335 return ret; 336 } 337 338 void wl18xx_scan_sched_scan_stop(struct wl1271 *wl, struct wl12xx_vif *wlvif) 339 { 340 __wl18xx_scan_stop(wl, wlvif, SCAN_TYPE_PERIODIC); 341 } 342 int wl18xx_scan_start(struct wl1271 *wl, struct wl12xx_vif *wlvif, 343 struct cfg80211_scan_request *req) 344 { 345 return wl18xx_scan_send(wl, wlvif, req); 346 } 347 348 int wl18xx_scan_stop(struct wl1271 *wl, struct wl12xx_vif *wlvif) 349 { 350 return __wl18xx_scan_stop(wl, wlvif, SCAN_TYPE_SEARCH); 351 } 352