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 = IEEE80211_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 = IEEE80211_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->interval) { 232 cmd->short_cycles_msec = cpu_to_le16(req->interval); 233 cmd->long_cycles_msec = cpu_to_le16(c->long_interval); 234 cmd->short_cycles_count = c->num_short_intervals; 235 } else { 236 cmd->short_cycles_msec = 0; 237 cmd->long_cycles_msec = cpu_to_le16(req->interval); 238 cmd->short_cycles_count = 0; 239 } 240 wl1271_debug(DEBUG_SCAN, "short_interval: %d, long_interval: %d, num_short: %d", 241 le16_to_cpu(cmd->short_cycles_msec), 242 le16_to_cpu(cmd->long_cycles_msec), 243 cmd->short_cycles_count); 244 245 cmd->total_cycles = 0; 246 247 cmd->tag = WL1271_SCAN_DEFAULT_TAG; 248 249 /* create a PERIODIC_SCAN_REPORT_EVENT whenever we've got a match */ 250 cmd->report_threshold = 1; 251 cmd->terminate_on_report = 0; 252 253 if (cmd->active[0]) { 254 u8 band = IEEE80211_BAND_2GHZ; 255 ret = wl12xx_cmd_build_probe_req(wl, wlvif, 256 cmd->role_id, band, 257 req->ssids ? req->ssids[0].ssid : NULL, 258 req->ssids ? req->ssids[0].ssid_len : 0, 259 ies->ies[band], 260 ies->len[band], 261 ies->common_ies, 262 ies->common_ie_len, 263 true); 264 if (ret < 0) { 265 wl1271_error("2.4GHz PROBE request template failed"); 266 goto out; 267 } 268 } 269 270 if (cmd->active[1] || cmd->dfs) { 271 u8 band = IEEE80211_BAND_5GHZ; 272 ret = wl12xx_cmd_build_probe_req(wl, wlvif, 273 cmd->role_id, band, 274 req->ssids ? req->ssids[0].ssid : NULL, 275 req->ssids ? req->ssids[0].ssid_len : 0, 276 ies->ies[band], 277 ies->len[band], 278 ies->common_ies, 279 ies->common_ie_len, 280 true); 281 if (ret < 0) { 282 wl1271_error("5GHz PROBE request template failed"); 283 goto out; 284 } 285 } 286 287 wl1271_dump(DEBUG_SCAN, "SCAN: ", cmd, sizeof(*cmd)); 288 289 ret = wl1271_cmd_send(wl, CMD_SCAN, cmd, sizeof(*cmd), 0); 290 if (ret < 0) { 291 wl1271_error("SCAN failed"); 292 goto out; 293 } 294 295 out: 296 kfree(cmd_channels); 297 kfree(cmd); 298 return ret; 299 } 300 301 int wl18xx_sched_scan_start(struct wl1271 *wl, struct wl12xx_vif *wlvif, 302 struct cfg80211_sched_scan_request *req, 303 struct ieee80211_scan_ies *ies) 304 { 305 return wl18xx_scan_sched_scan_config(wl, wlvif, req, ies); 306 } 307 308 static int __wl18xx_scan_stop(struct wl1271 *wl, struct wl12xx_vif *wlvif, 309 u8 scan_type) 310 { 311 struct wl18xx_cmd_scan_stop *stop; 312 int ret; 313 314 wl1271_debug(DEBUG_CMD, "cmd periodic scan stop"); 315 316 stop = kzalloc(sizeof(*stop), GFP_KERNEL); 317 if (!stop) { 318 wl1271_error("failed to alloc memory to send sched scan stop"); 319 return -ENOMEM; 320 } 321 322 stop->role_id = wlvif->role_id; 323 stop->scan_type = scan_type; 324 325 ret = wl1271_cmd_send(wl, CMD_STOP_SCAN, stop, sizeof(*stop), 0); 326 if (ret < 0) { 327 wl1271_error("failed to send sched scan stop command"); 328 goto out_free; 329 } 330 331 out_free: 332 kfree(stop); 333 return ret; 334 } 335 336 void wl18xx_scan_sched_scan_stop(struct wl1271 *wl, struct wl12xx_vif *wlvif) 337 { 338 __wl18xx_scan_stop(wl, wlvif, SCAN_TYPE_PERIODIC); 339 } 340 int wl18xx_scan_start(struct wl1271 *wl, struct wl12xx_vif *wlvif, 341 struct cfg80211_scan_request *req) 342 { 343 return wl18xx_scan_send(wl, wlvif, req); 344 } 345 346 int wl18xx_scan_stop(struct wl1271 *wl, struct wl12xx_vif *wlvif) 347 { 348 return __wl18xx_scan_stop(wl, wlvif, SCAN_TYPE_SEARCH); 349 } 350