scan.c (12234B)
1// SPDX-License-Identifier: GPL-2.0-only 2/* 3 * This file is part of wl1271 4 * 5 * Copyright (C) 2009-2010 Nokia Corporation 6 * 7 * Contact: Luciano Coelho <luciano.coelho@nokia.com> 8 */ 9 10#include <linux/ieee80211.h> 11#include <linux/pm_runtime.h> 12 13#include "wlcore.h" 14#include "debug.h" 15#include "cmd.h" 16#include "scan.h" 17#include "acx.h" 18#include "tx.h" 19 20void wl1271_scan_complete_work(struct work_struct *work) 21{ 22 struct delayed_work *dwork; 23 struct wl1271 *wl; 24 struct wl12xx_vif *wlvif; 25 struct cfg80211_scan_info info = { 26 .aborted = false, 27 }; 28 int ret; 29 30 dwork = to_delayed_work(work); 31 wl = container_of(dwork, struct wl1271, scan_complete_work); 32 33 wl1271_debug(DEBUG_SCAN, "Scanning complete"); 34 35 mutex_lock(&wl->mutex); 36 37 if (unlikely(wl->state != WLCORE_STATE_ON)) 38 goto out; 39 40 if (wl->scan.state == WL1271_SCAN_STATE_IDLE) 41 goto out; 42 43 wlvif = wl->scan_wlvif; 44 45 /* 46 * Rearm the tx watchdog just before idling scan. This 47 * prevents just-finished scans from triggering the watchdog 48 */ 49 wl12xx_rearm_tx_watchdog_locked(wl); 50 51 wl->scan.state = WL1271_SCAN_STATE_IDLE; 52 memset(wl->scan.scanned_ch, 0, sizeof(wl->scan.scanned_ch)); 53 wl->scan.req = NULL; 54 wl->scan_wlvif = NULL; 55 56 ret = pm_runtime_resume_and_get(wl->dev); 57 if (ret < 0) 58 goto out; 59 60 if (test_bit(WLVIF_FLAG_STA_ASSOCIATED, &wlvif->flags)) { 61 /* restore hardware connection monitoring template */ 62 wl1271_cmd_build_ap_probe_req(wl, wlvif, wlvif->probereq); 63 } 64 65 if (wl->scan.failed) { 66 wl1271_info("Scan completed due to error."); 67 wl12xx_queue_recovery_work(wl); 68 } 69 70 wlcore_cmd_regdomain_config_locked(wl); 71 72 pm_runtime_mark_last_busy(wl->dev); 73 pm_runtime_put_autosuspend(wl->dev); 74 75 ieee80211_scan_completed(wl->hw, &info); 76 77out: 78 mutex_unlock(&wl->mutex); 79 80} 81 82static void wlcore_started_vifs_iter(void *data, u8 *mac, 83 struct ieee80211_vif *vif) 84{ 85 struct wl12xx_vif *wlvif = wl12xx_vif_to_data(vif); 86 bool active = false; 87 int *count = (int *)data; 88 89 /* 90 * count active interfaces according to interface type. 91 * checking only bss_conf.idle is bad for some cases, e.g. 92 * we don't want to count sta in p2p_find as active interface. 93 */ 94 switch (wlvif->bss_type) { 95 case BSS_TYPE_STA_BSS: 96 if (test_bit(WLVIF_FLAG_STA_ASSOCIATED, &wlvif->flags)) 97 active = true; 98 break; 99 100 case BSS_TYPE_AP_BSS: 101 if (wlvif->wl->active_sta_count > 0) 102 active = true; 103 break; 104 105 default: 106 break; 107 } 108 109 if (active) 110 (*count)++; 111} 112 113static int wlcore_count_started_vifs(struct wl1271 *wl) 114{ 115 int count = 0; 116 117 ieee80211_iterate_active_interfaces_atomic(wl->hw, 118 IEEE80211_IFACE_ITER_RESUME_ALL, 119 wlcore_started_vifs_iter, &count); 120 return count; 121} 122 123static int 124wlcore_scan_get_channels(struct wl1271 *wl, 125 struct ieee80211_channel *req_channels[], 126 u32 n_channels, 127 u32 n_ssids, 128 struct conn_scan_ch_params *channels, 129 u32 band, bool radar, bool passive, 130 int start, int max_channels, 131 u8 *n_pactive_ch, 132 int scan_type) 133{ 134 int i, j; 135 u32 flags; 136 bool force_passive = !n_ssids; 137 u32 min_dwell_time_active, max_dwell_time_active; 138 u32 dwell_time_passive, dwell_time_dfs; 139 140 /* configure dwell times according to scan type */ 141 if (scan_type == SCAN_TYPE_SEARCH) { 142 struct conf_scan_settings *c = &wl->conf.scan; 143 bool active_vif_exists = !!wlcore_count_started_vifs(wl); 144 145 min_dwell_time_active = active_vif_exists ? 146 c->min_dwell_time_active : 147 c->min_dwell_time_active_long; 148 max_dwell_time_active = active_vif_exists ? 149 c->max_dwell_time_active : 150 c->max_dwell_time_active_long; 151 dwell_time_passive = c->dwell_time_passive; 152 dwell_time_dfs = c->dwell_time_dfs; 153 } else { 154 struct conf_sched_scan_settings *c = &wl->conf.sched_scan; 155 u32 delta_per_probe; 156 157 if (band == NL80211_BAND_5GHZ) 158 delta_per_probe = c->dwell_time_delta_per_probe_5; 159 else 160 delta_per_probe = c->dwell_time_delta_per_probe; 161 162 min_dwell_time_active = c->base_dwell_time + 163 n_ssids * c->num_probe_reqs * delta_per_probe; 164 165 max_dwell_time_active = min_dwell_time_active + 166 c->max_dwell_time_delta; 167 dwell_time_passive = c->dwell_time_passive; 168 dwell_time_dfs = c->dwell_time_dfs; 169 } 170 min_dwell_time_active = DIV_ROUND_UP(min_dwell_time_active, 1000); 171 max_dwell_time_active = DIV_ROUND_UP(max_dwell_time_active, 1000); 172 dwell_time_passive = DIV_ROUND_UP(dwell_time_passive, 1000); 173 dwell_time_dfs = DIV_ROUND_UP(dwell_time_dfs, 1000); 174 175 for (i = 0, j = start; 176 i < n_channels && j < max_channels; 177 i++) { 178 flags = req_channels[i]->flags; 179 180 if (force_passive) 181 flags |= IEEE80211_CHAN_NO_IR; 182 183 if ((req_channels[i]->band == band) && 184 !(flags & IEEE80211_CHAN_DISABLED) && 185 (!!(flags & IEEE80211_CHAN_RADAR) == radar) && 186 /* if radar is set, we ignore the passive flag */ 187 (radar || 188 !!(flags & IEEE80211_CHAN_NO_IR) == passive)) { 189 if (flags & IEEE80211_CHAN_RADAR) { 190 channels[j].flags |= SCAN_CHANNEL_FLAGS_DFS; 191 192 channels[j].passive_duration = 193 cpu_to_le16(dwell_time_dfs); 194 } else { 195 channels[j].passive_duration = 196 cpu_to_le16(dwell_time_passive); 197 } 198 199 channels[j].min_duration = 200 cpu_to_le16(min_dwell_time_active); 201 channels[j].max_duration = 202 cpu_to_le16(max_dwell_time_active); 203 204 channels[j].tx_power_att = req_channels[i]->max_power; 205 channels[j].channel = req_channels[i]->hw_value; 206 207 if (n_pactive_ch && 208 (band == NL80211_BAND_2GHZ) && 209 (channels[j].channel >= 12) && 210 (channels[j].channel <= 14) && 211 (flags & IEEE80211_CHAN_NO_IR) && 212 !force_passive) { 213 /* pactive channels treated as DFS */ 214 channels[j].flags = SCAN_CHANNEL_FLAGS_DFS; 215 216 /* 217 * n_pactive_ch is counted down from the end of 218 * the passive channel list 219 */ 220 (*n_pactive_ch)++; 221 wl1271_debug(DEBUG_SCAN, "n_pactive_ch = %d", 222 *n_pactive_ch); 223 } 224 225 wl1271_debug(DEBUG_SCAN, "freq %d, ch. %d, flags 0x%x, power %d, min/max_dwell %d/%d%s%s", 226 req_channels[i]->center_freq, 227 req_channels[i]->hw_value, 228 req_channels[i]->flags, 229 req_channels[i]->max_power, 230 min_dwell_time_active, 231 max_dwell_time_active, 232 flags & IEEE80211_CHAN_RADAR ? 233 ", DFS" : "", 234 flags & IEEE80211_CHAN_NO_IR ? 235 ", NO-IR" : ""); 236 j++; 237 } 238 } 239 240 return j - start; 241} 242 243bool 244wlcore_set_scan_chan_params(struct wl1271 *wl, 245 struct wlcore_scan_channels *cfg, 246 struct ieee80211_channel *channels[], 247 u32 n_channels, 248 u32 n_ssids, 249 int scan_type) 250{ 251 u8 n_pactive_ch = 0; 252 253 cfg->passive[0] = 254 wlcore_scan_get_channels(wl, 255 channels, 256 n_channels, 257 n_ssids, 258 cfg->channels_2, 259 NL80211_BAND_2GHZ, 260 false, true, 0, 261 MAX_CHANNELS_2GHZ, 262 &n_pactive_ch, 263 scan_type); 264 cfg->active[0] = 265 wlcore_scan_get_channels(wl, 266 channels, 267 n_channels, 268 n_ssids, 269 cfg->channels_2, 270 NL80211_BAND_2GHZ, 271 false, false, 272 cfg->passive[0], 273 MAX_CHANNELS_2GHZ, 274 &n_pactive_ch, 275 scan_type); 276 cfg->passive[1] = 277 wlcore_scan_get_channels(wl, 278 channels, 279 n_channels, 280 n_ssids, 281 cfg->channels_5, 282 NL80211_BAND_5GHZ, 283 false, true, 0, 284 wl->max_channels_5, 285 &n_pactive_ch, 286 scan_type); 287 cfg->dfs = 288 wlcore_scan_get_channels(wl, 289 channels, 290 n_channels, 291 n_ssids, 292 cfg->channels_5, 293 NL80211_BAND_5GHZ, 294 true, true, 295 cfg->passive[1], 296 wl->max_channels_5, 297 &n_pactive_ch, 298 scan_type); 299 cfg->active[1] = 300 wlcore_scan_get_channels(wl, 301 channels, 302 n_channels, 303 n_ssids, 304 cfg->channels_5, 305 NL80211_BAND_5GHZ, 306 false, false, 307 cfg->passive[1] + cfg->dfs, 308 wl->max_channels_5, 309 &n_pactive_ch, 310 scan_type); 311 312 /* 802.11j channels are not supported yet */ 313 cfg->passive[2] = 0; 314 cfg->active[2] = 0; 315 316 cfg->passive_active = n_pactive_ch; 317 318 wl1271_debug(DEBUG_SCAN, " 2.4GHz: active %d passive %d", 319 cfg->active[0], cfg->passive[0]); 320 wl1271_debug(DEBUG_SCAN, " 5GHz: active %d passive %d", 321 cfg->active[1], cfg->passive[1]); 322 wl1271_debug(DEBUG_SCAN, " DFS: %d", cfg->dfs); 323 324 return cfg->passive[0] || cfg->active[0] || 325 cfg->passive[1] || cfg->active[1] || cfg->dfs || 326 cfg->passive[2] || cfg->active[2]; 327} 328EXPORT_SYMBOL_GPL(wlcore_set_scan_chan_params); 329 330int wlcore_scan(struct wl1271 *wl, struct ieee80211_vif *vif, 331 const u8 *ssid, size_t ssid_len, 332 struct cfg80211_scan_request *req) 333{ 334 struct wl12xx_vif *wlvif = wl12xx_vif_to_data(vif); 335 336 /* 337 * cfg80211 should guarantee that we don't get more channels 338 * than what we have registered. 339 */ 340 BUG_ON(req->n_channels > WL1271_MAX_CHANNELS); 341 342 if (wl->scan.state != WL1271_SCAN_STATE_IDLE) 343 return -EBUSY; 344 345 wl->scan.state = WL1271_SCAN_STATE_2GHZ_ACTIVE; 346 347 if (ssid_len && ssid) { 348 wl->scan.ssid_len = ssid_len; 349 memcpy(wl->scan.ssid, ssid, ssid_len); 350 } else { 351 wl->scan.ssid_len = 0; 352 } 353 354 wl->scan_wlvif = wlvif; 355 wl->scan.req = req; 356 memset(wl->scan.scanned_ch, 0, sizeof(wl->scan.scanned_ch)); 357 358 /* we assume failure so that timeout scenarios are handled correctly */ 359 wl->scan.failed = true; 360 ieee80211_queue_delayed_work(wl->hw, &wl->scan_complete_work, 361 msecs_to_jiffies(WL1271_SCAN_TIMEOUT)); 362 363 wl->ops->scan_start(wl, wlvif, req); 364 365 return 0; 366} 367/* Returns the scan type to be used or a negative value on error */ 368int 369wlcore_scan_sched_scan_ssid_list(struct wl1271 *wl, 370 struct wl12xx_vif *wlvif, 371 struct cfg80211_sched_scan_request *req) 372{ 373 struct wl1271_cmd_sched_scan_ssid_list *cmd = NULL; 374 struct cfg80211_match_set *sets = req->match_sets; 375 struct cfg80211_ssid *ssids = req->ssids; 376 int ret = 0, type, i, j, n_match_ssids = 0; 377 378 wl1271_debug((DEBUG_CMD | DEBUG_SCAN), "cmd sched scan ssid list"); 379 380 /* count the match sets that contain SSIDs */ 381 for (i = 0; i < req->n_match_sets; i++) 382 if (sets[i].ssid.ssid_len > 0) 383 n_match_ssids++; 384 385 /* No filter, no ssids or only bcast ssid */ 386 if (!n_match_ssids && 387 (!req->n_ssids || 388 (req->n_ssids == 1 && req->ssids[0].ssid_len == 0))) { 389 type = SCAN_SSID_FILTER_ANY; 390 goto out; 391 } 392 393 cmd = kzalloc(sizeof(*cmd), GFP_KERNEL); 394 if (!cmd) { 395 ret = -ENOMEM; 396 goto out; 397 } 398 399 cmd->role_id = wlvif->role_id; 400 if (!n_match_ssids) { 401 /* No filter, with ssids */ 402 type = SCAN_SSID_FILTER_DISABLED; 403 404 for (i = 0; i < req->n_ssids; i++) { 405 cmd->ssids[cmd->n_ssids].type = (ssids[i].ssid_len) ? 406 SCAN_SSID_TYPE_HIDDEN : SCAN_SSID_TYPE_PUBLIC; 407 cmd->ssids[cmd->n_ssids].len = ssids[i].ssid_len; 408 memcpy(cmd->ssids[cmd->n_ssids].ssid, ssids[i].ssid, 409 ssids[i].ssid_len); 410 cmd->n_ssids++; 411 } 412 } else { 413 type = SCAN_SSID_FILTER_LIST; 414 415 /* Add all SSIDs from the filters */ 416 for (i = 0; i < req->n_match_sets; i++) { 417 /* ignore sets without SSIDs */ 418 if (!sets[i].ssid.ssid_len) 419 continue; 420 421 cmd->ssids[cmd->n_ssids].type = SCAN_SSID_TYPE_PUBLIC; 422 cmd->ssids[cmd->n_ssids].len = sets[i].ssid.ssid_len; 423 memcpy(cmd->ssids[cmd->n_ssids].ssid, 424 sets[i].ssid.ssid, sets[i].ssid.ssid_len); 425 cmd->n_ssids++; 426 } 427 if ((req->n_ssids > 1) || 428 (req->n_ssids == 1 && req->ssids[0].ssid_len > 0)) { 429 /* 430 * Mark all the SSIDs passed in the SSID list as HIDDEN, 431 * so they're used in probe requests. 432 */ 433 for (i = 0; i < req->n_ssids; i++) { 434 if (!req->ssids[i].ssid_len) 435 continue; 436 437 for (j = 0; j < cmd->n_ssids; j++) 438 if ((req->ssids[i].ssid_len == 439 cmd->ssids[j].len) && 440 !memcmp(req->ssids[i].ssid, 441 cmd->ssids[j].ssid, 442 req->ssids[i].ssid_len)) { 443 cmd->ssids[j].type = 444 SCAN_SSID_TYPE_HIDDEN; 445 break; 446 } 447 /* Fail if SSID isn't present in the filters */ 448 if (j == cmd->n_ssids) { 449 ret = -EINVAL; 450 goto out_free; 451 } 452 } 453 } 454 } 455 456 ret = wl1271_cmd_send(wl, CMD_CONNECTION_SCAN_SSID_CFG, cmd, 457 sizeof(*cmd), 0); 458 if (ret < 0) { 459 wl1271_error("cmd sched scan ssid list failed"); 460 goto out_free; 461 } 462 463out_free: 464 kfree(cmd); 465out: 466 if (ret < 0) 467 return ret; 468 return type; 469} 470EXPORT_SYMBOL_GPL(wlcore_scan_sched_scan_ssid_list); 471 472void wlcore_scan_sched_scan_results(struct wl1271 *wl) 473{ 474 wl1271_debug(DEBUG_SCAN, "got periodic scan results"); 475 476 ieee80211_sched_scan_results(wl->hw); 477} 478EXPORT_SYMBOL_GPL(wlcore_scan_sched_scan_results);