1 /* 2 * Copyright (c) 2012-2021 The Linux Foundation. All rights reserved. 3 * Copyright (c) 2022-2023 Qualcomm Innovation Center, Inc. All rights reserved. 4 * 5 * Permission to use, copy, modify, and/or distribute this software for 6 * any purpose with or without fee is hereby granted, provided that the 7 * above copyright notice and this permission notice appear in all 8 * copies. 9 * 10 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL 11 * WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED 12 * WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE 13 * AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL 14 * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR 15 * PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER 16 * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR 17 * PERFORMANCE OF THIS SOFTWARE. 18 */ 19 20 /** 21 * DOC: wlan_hdd_ext_scan.c 22 * 23 * WLAN Host Device Driver EXT SCAN feature implementation 24 * 25 */ 26 27 #ifdef FEATURE_WLAN_EXTSCAN 28 29 #include "osif_sync.h" 30 #include "wlan_hdd_ext_scan.h" 31 #include "wlan_hdd_regulatory.h" 32 #include "cds_utils.h" 33 #include "cds_sched.h" 34 #include <qca_vendor.h> 35 #include "wlan_extscan_ucfg_api.h" 36 #include "wlan_hdd_scan.h" 37 38 /* amount of time to wait for a synchronous request/response operation */ 39 #define WLAN_WAIT_TIME_EXTSCAN 1000 40 41 /** 42 * struct hdd_ext_scan_context - hdd ext scan context 43 * @request_id: userspace-assigned ID associated with the request 44 * @response_event: Ext scan wait event 45 * @response_status: Status returned by FW in response to a request 46 * @ignore_cached_results: Flag to ignore cached results or not 47 * @context_lock: Spinlock to serialize all context accesses 48 * @capability_response: Ext scan capability response data from target 49 * @buckets_scanned: bitmask of buckets scanned in extscan cycle 50 */ 51 struct hdd_ext_scan_context { 52 uint32_t request_id; 53 int response_status; 54 bool ignore_cached_results; 55 struct completion response_event; 56 spinlock_t context_lock; 57 struct ext_scan_capabilities_response capability_response; 58 uint32_t buckets_scanned; 59 }; 60 static struct hdd_ext_scan_context ext_scan_context; 61 62 const struct nla_policy 63 wlan_hdd_extscan_config_policy[EXTSCAN_PARAM_MAX + 1] = { 64 [QCA_WLAN_VENDOR_ATTR_EXTSCAN_SUBCMD_CONFIG_PARAM_REQUEST_ID] = { 65 .type = NLA_U32}, 66 [QCA_WLAN_VENDOR_ATTR_EXTSCAN_CHANNEL_SPEC_CHANNEL] = {.type = NLA_U32}, 67 [QCA_WLAN_VENDOR_ATTR_EXTSCAN_CHANNEL_SPEC_DWELL_TIME] = { 68 .type = NLA_U32}, 69 [QCA_WLAN_VENDOR_ATTR_EXTSCAN_CHANNEL_SPEC_PASSIVE] = {.type = NLA_U8}, 70 [QCA_WLAN_VENDOR_ATTR_EXTSCAN_CHANNEL_SPEC_CLASS] = {.type = NLA_U8}, 71 72 [QCA_WLAN_VENDOR_ATTR_EXTSCAN_BUCKET_SPEC_INDEX] = {.type = NLA_U8}, 73 [QCA_WLAN_VENDOR_ATTR_EXTSCAN_BUCKET_SPEC_BAND] = {.type = NLA_U8}, 74 [QCA_WLAN_VENDOR_ATTR_EXTSCAN_BUCKET_SPEC_PERIOD] = {.type = NLA_U32}, 75 [QCA_WLAN_VENDOR_ATTR_EXTSCAN_BUCKET_SPEC_REPORT_EVENTS] = { 76 .type = NLA_U8}, 77 [QCA_WLAN_VENDOR_ATTR_EXTSCAN_BUCKET_SPEC_NUM_CHANNEL_SPECS] = { 78 .type = NLA_U32}, 79 [QCA_WLAN_VENDOR_ATTR_EXTSCAN_SCAN_CMD_PARAMS_BASE_PERIOD] = { 80 .type = NLA_U32}, 81 [QCA_WLAN_VENDOR_ATTR_EXTSCAN_SCAN_CMD_PARAMS_MAX_AP_PER_SCAN] = { 82 .type = NLA_U32}, 83 [QCA_WLAN_VENDOR_ATTR_EXTSCAN_SCAN_CMD_PARAMS_REPORT_THRESHOLD_PERCENT] = { 84 .type = NLA_U8}, 85 [QCA_WLAN_VENDOR_ATTR_EXTSCAN_SCAN_CMD_PARAMS_REPORT_THRESHOLD_NUM_SCANS] = { 86 .type = NLA_U8 }, 87 [QCA_WLAN_VENDOR_ATTR_EXTSCAN_SCAN_CMD_PARAMS_NUM_BUCKETS] = { 88 .type = NLA_U8}, 89 [QCA_WLAN_VENDOR_ATTR_EXTSCAN_GET_CACHED_SCAN_RESULTS_CONFIG_PARAM_FLUSH] = { 90 .type = NLA_U8}, 91 92 [QCA_WLAN_VENDOR_ATTR_EXTSCAN_GET_CACHED_SCAN_RESULTS_CONFIG_PARAM_MAX] = { 93 .type = NLA_U32}, 94 [QCA_WLAN_VENDOR_ATTR_EXTSCAN_AP_THRESHOLD_PARAM_BSSID] = 95 VENDOR_NLA_POLICY_MAC_ADDR, 96 [QCA_WLAN_VENDOR_ATTR_EXTSCAN_AP_THRESHOLD_PARAM_RSSI_LOW] = { 97 .type = NLA_S32}, 98 [QCA_WLAN_VENDOR_ATTR_EXTSCAN_AP_THRESHOLD_PARAM_RSSI_HIGH] = { 99 .type = NLA_S32}, 100 [QCA_WLAN_VENDOR_ATTR_EXTSCAN_AP_THRESHOLD_PARAM_CHANNEL] = { 101 .type = NLA_U32}, 102 [QCA_WLAN_VENDOR_ATTR_EXTSCAN_BSSID_HOTLIST_PARAMS_NUM_AP] = { 103 .type = NLA_U32}, 104 [QCA_WLAN_VENDOR_ATTR_EXTSCAN_SIGNIFICANT_CHANGE_PARAMS_RSSI_SAMPLE_SIZE] = { 105 .type = NLA_U32}, 106 [QCA_WLAN_VENDOR_ATTR_EXTSCAN_SIGNIFICANT_CHANGE_PARAMS_LOST_AP_SAMPLE_SIZE] = { 107 .type = NLA_U32}, 108 [QCA_WLAN_VENDOR_ATTR_EXTSCAN_SIGNIFICANT_CHANGE_PARAMS_MIN_BREACHING] = { 109 .type = NLA_U32}, 110 [QCA_WLAN_VENDOR_ATTR_EXTSCAN_SIGNIFICANT_CHANGE_PARAMS_NUM_AP] = { 111 .type = NLA_U32}, 112 [QCA_WLAN_VENDOR_ATTR_EXTSCAN_BUCKET_SPEC_MAX_PERIOD] = { 113 .type = NLA_U32}, 114 [QCA_WLAN_VENDOR_ATTR_EXTSCAN_BUCKET_SPEC_BASE] = { 115 .type = NLA_U32}, 116 [QCA_WLAN_VENDOR_ATTR_EXTSCAN_BUCKET_SPEC_STEP_COUNT] = { 117 .type = NLA_U32}, 118 [QCA_WLAN_VENDOR_ATTR_EXTSCAN_SSID_THRESHOLD_PARAM_SSID] = { 119 .type = NLA_BINARY, 120 .len = IEEE80211_MAX_SSID_LEN + 1 }, 121 [QCA_WLAN_VENDOR_ATTR_EXTSCAN_SSID_HOTLIST_PARAMS_LOST_SSID_SAMPLE_SIZE] = { 122 .type = NLA_U32 }, 123 [QCA_WLAN_VENDOR_ATTR_EXTSCAN_SSID_HOTLIST_PARAMS_NUM_SSID] = { 124 .type = NLA_U32 }, 125 [QCA_WLAN_VENDOR_ATTR_EXTSCAN_SSID_THRESHOLD_PARAM_BAND] = { 126 .type = NLA_U8 }, 127 [QCA_WLAN_VENDOR_ATTR_EXTSCAN_SSID_THRESHOLD_PARAM_RSSI_LOW] = { 128 .type = NLA_S32 }, 129 [QCA_WLAN_VENDOR_ATTR_EXTSCAN_SSID_THRESHOLD_PARAM_RSSI_HIGH] = { 130 .type = NLA_S32 }, 131 [QCA_WLAN_VENDOR_ATTR_EXTSCAN_CONFIGURATION_FLAGS] = { 132 .type = NLA_U32 }, 133 [QCA_WLAN_VENDOR_ATTR_EXTSCAN_BSSID_HOTLIST_PARAMS_LOST_AP_SAMPLE_SIZE] = { 134 .type = NLA_U32}, 135 }; 136 137 const struct nla_policy 138 wlan_hdd_pno_config_policy[QCA_WLAN_VENDOR_ATTR_PNO_MAX + 1] = { 139 [QCA_WLAN_VENDOR_ATTR_PNO_PASSPOINT_LIST_PARAM_NUM] = { 140 .type = NLA_U32 141 }, 142 [QCA_WLAN_VENDOR_ATTR_PNO_PASSPOINT_NETWORK_PARAM_ID] = { 143 .type = NLA_U32 144 }, 145 [QCA_WLAN_VENDOR_ATTR_PNO_SET_LIST_PARAM_NUM_NETWORKS] = { 146 .type = NLA_U32 147 }, 148 [QCA_WLAN_VENDOR_ATTR_PNO_SET_LIST_PARAM_EPNO_NETWORK_SSID] = { 149 .type = NLA_BINARY, 150 .len = IEEE80211_MAX_SSID_LEN + 1 151 }, 152 [QCA_WLAN_VENDOR_ATTR_PNO_SET_LIST_PARAM_EPNO_NETWORK_FLAGS] = { 153 .type = NLA_U8 154 }, 155 [QCA_WLAN_VENDOR_ATTR_PNO_SET_LIST_PARAM_EPNO_NETWORK_AUTH_BIT] = { 156 .type = NLA_U8 157 }, 158 [QCA_WLAN_VENDOR_ATTR_EPNO_MIN5GHZ_RSSI] = { 159 .type = NLA_U32 160 }, 161 [QCA_WLAN_VENDOR_ATTR_EPNO_MIN24GHZ_RSSI] = { 162 .type = NLA_U32 163 }, 164 [QCA_WLAN_VENDOR_ATTR_EPNO_INITIAL_SCORE_MAX] = { 165 .type = NLA_U32 166 }, 167 [QCA_WLAN_VENDOR_ATTR_EPNO_CURRENT_CONNECTION_BONUS] = { 168 .type = NLA_U32 169 }, 170 [QCA_WLAN_VENDOR_ATTR_EPNO_SAME_NETWORK_BONUS] = { 171 .type = NLA_U32 172 }, 173 [QCA_WLAN_VENDOR_ATTR_EPNO_SECURE_BONUS] = { 174 .type = NLA_U32 175 }, 176 [QCA_WLAN_VENDOR_ATTR_EPNO_BAND5GHZ_BONUS] = { 177 .type = NLA_U32 178 }, 179 [QCA_WLAN_VENDOR_ATTR_PNO_CONFIG_REQUEST_ID] = { 180 .type = NLA_U32 181 }, 182 }; 183 184 /** 185 * wlan_hdd_cfg80211_extscan_get_capabilities_rsp() - response from target 186 * @hdd_ctx: Pointer to hdd context 187 * @data: Pointer to ext scan capabilities response from fw 188 * 189 * Return: None 190 */ 191 static void 192 wlan_hdd_cfg80211_extscan_get_capabilities_rsp(struct hdd_context *hdd_ctx, 193 struct ext_scan_capabilities_response *data) 194 { 195 struct hdd_ext_scan_context *context; 196 197 hdd_enter(); 198 199 if (wlan_hdd_validate_context(hdd_ctx)) 200 return; 201 if (!data) { 202 hdd_err("data is null"); 203 return; 204 } 205 206 context = &ext_scan_context; 207 208 spin_lock(&context->context_lock); 209 /* validate response received from target*/ 210 if (context->request_id != data->requestId) { 211 spin_unlock(&context->context_lock); 212 hdd_err("Target response id did not match. request_id: %d response_id: %d", 213 context->request_id, data->requestId); 214 return; 215 } 216 217 context->capability_response = *data; 218 complete(&context->response_event); 219 spin_unlock(&context->context_lock); 220 } 221 222 /* 223 * define short names for the global vendor params 224 * used by hdd_extscan_nl_fill_bss() 225 */ 226 #define PARAM_TIME_STAMP \ 227 QCA_WLAN_VENDOR_ATTR_EXTSCAN_RESULTS_SCAN_RESULT_TIME_STAMP 228 #define PARAM_SSID \ 229 QCA_WLAN_VENDOR_ATTR_EXTSCAN_RESULTS_SCAN_RESULT_SSID 230 #define PARAM_BSSID \ 231 QCA_WLAN_VENDOR_ATTR_EXTSCAN_RESULTS_SCAN_RESULT_BSSID 232 #define PARAM_CHANNEL \ 233 QCA_WLAN_VENDOR_ATTR_EXTSCAN_RESULTS_SCAN_RESULT_CHANNEL 234 #define PARAM_RSSI \ 235 QCA_WLAN_VENDOR_ATTR_EXTSCAN_RESULTS_SCAN_RESULT_RSSI 236 #define PARAM_RTT \ 237 QCA_WLAN_VENDOR_ATTR_EXTSCAN_RESULTS_SCAN_RESULT_RTT 238 #define PARAM_RTT_SD \ 239 QCA_WLAN_VENDOR_ATTR_EXTSCAN_RESULTS_SCAN_RESULT_RTT_SD 240 #define PARAM_BEACON_PERIOD \ 241 QCA_WLAN_VENDOR_ATTR_EXTSCAN_RESULTS_SCAN_RESULT_BEACON_PERIOD 242 #define PARAM_CAPABILITY \ 243 QCA_WLAN_VENDOR_ATTR_EXTSCAN_RESULTS_SCAN_RESULT_CAPABILITY 244 #define PARAM_IE_LENGTH \ 245 QCA_WLAN_VENDOR_ATTR_EXTSCAN_RESULTS_SCAN_RESULT_IE_LENGTH 246 #define PARAM_IE_DATA \ 247 QCA_WLAN_VENDOR_ATTR_EXTSCAN_RESULTS_SCAN_RESULT_IE_DATA 248 249 /** hdd_extscan_nl_fill_bss() - extscan nl fill bss 250 * @skb: socket buffer 251 * @ap: bss information 252 * @idx: nesting index 253 * 254 * Return: 0 on success; error number otherwise 255 */ 256 static int hdd_extscan_nl_fill_bss(struct sk_buff *skb, tSirWifiScanResult *ap, 257 int idx) 258 { 259 struct nlattr *nla_ap; 260 261 nla_ap = nla_nest_start(skb, idx); 262 if (!nla_ap) 263 return -EINVAL; 264 265 if (hdd_wlan_nla_put_u64(skb, PARAM_TIME_STAMP, ap->ts) || 266 nla_put(skb, PARAM_SSID, sizeof(ap->ssid), ap->ssid) || 267 nla_put(skb, PARAM_BSSID, sizeof(ap->bssid), ap->bssid.bytes) || 268 nla_put_u32(skb, PARAM_CHANNEL, ap->channel) || 269 nla_put_s32(skb, PARAM_RSSI, ap->rssi) || 270 nla_put_u32(skb, PARAM_RTT, ap->rtt) || 271 nla_put_u32(skb, PARAM_RTT_SD, ap->rtt_sd) || 272 nla_put_u16(skb, PARAM_BEACON_PERIOD, ap->beaconPeriod) || 273 nla_put_u16(skb, PARAM_CAPABILITY, ap->capability) || 274 nla_put_u16(skb, PARAM_IE_LENGTH, ap->ieLength)) { 275 hdd_err("put fail"); 276 return -EINVAL; 277 } 278 279 if (ap->ieLength) 280 if (nla_put(skb, PARAM_IE_DATA, ap->ieLength, ap->ieData)) { 281 hdd_err("put fail"); 282 return -EINVAL; 283 } 284 285 nla_nest_end(skb, nla_ap); 286 287 return 0; 288 } 289 /* 290 * done with short names for the global vendor params 291 * used by hdd_extscan_nl_fill_bss() 292 */ 293 #undef PARAM_TIME_STAMP 294 #undef PARAM_SSID 295 #undef PARAM_BSSID 296 #undef PARAM_CHANNEL 297 #undef PARAM_RSSI 298 #undef PARAM_RTT 299 #undef PARAM_RTT_SD 300 #undef PARAM_BEACON_PERIOD 301 #undef PARAM_CAPABILITY 302 #undef PARAM_IE_LENGTH 303 #undef PARAM_IE_DATA 304 305 /** 306 * wlan_hdd_cfg80211_extscan_cached_results_ind() - get cached results 307 * @hdd_ctx: hdd global context 308 * @data: cached results 309 * 310 * This function reads the cached results %data, populated the NL 311 * attributes and sends the NL event to the upper layer. 312 * 313 * Return: none 314 */ 315 static void 316 wlan_hdd_cfg80211_extscan_cached_results_ind(struct hdd_context *hdd_ctx, 317 struct extscan_cached_scan_results *data) 318 { 319 struct sk_buff *skb = NULL; 320 struct hdd_ext_scan_context *context; 321 struct extscan_cached_scan_result *result; 322 tSirWifiScanResult *ap; 323 uint32_t i, j, nl_buf_len; 324 bool ignore_cached_results = false; 325 326 /* ENTER() intentionally not used in a frequently invoked API */ 327 328 if (wlan_hdd_validate_context(hdd_ctx)) 329 return; 330 if (!data) { 331 hdd_err("data is null"); 332 return; 333 } 334 335 context = &ext_scan_context; 336 spin_lock(&context->context_lock); 337 ignore_cached_results = context->ignore_cached_results; 338 spin_unlock(&context->context_lock); 339 340 if (ignore_cached_results) { 341 hdd_err("Ignore the cached results received after timeout"); 342 return; 343 } 344 345 #define EXTSCAN_CACHED_NEST_HDRLEN NLA_HDRLEN 346 #define EXTSCAN_CACHED_NL_FIXED_TLV \ 347 ((sizeof(data->request_id) + NLA_HDRLEN) + \ 348 (sizeof(data->num_scan_ids) + NLA_HDRLEN) + \ 349 (sizeof(data->more_data) + NLA_HDRLEN)) 350 #define EXTSCAN_CACHED_NL_SCAN_ID_TLV \ 351 ((sizeof(result->scan_id) + NLA_HDRLEN) + \ 352 (sizeof(result->flags) + NLA_HDRLEN) + \ 353 (sizeof(result->num_results) + NLA_HDRLEN))+ \ 354 (sizeof(result->buckets_scanned) + NLA_HDRLEN) 355 #define EXTSCAN_CACHED_NL_SCAN_RESULTS_TLV \ 356 ((sizeof(ap->ts) + NLA_HDRLEN) + \ 357 (sizeof(ap->ssid) + NLA_HDRLEN) + \ 358 (sizeof(ap->bssid) + NLA_HDRLEN) + \ 359 (sizeof(ap->channel) + NLA_HDRLEN) + \ 360 (sizeof(ap->rssi) + NLA_HDRLEN) + \ 361 (sizeof(ap->rtt) + NLA_HDRLEN) + \ 362 (sizeof(ap->rtt_sd) + NLA_HDRLEN) + \ 363 (sizeof(ap->beaconPeriod) + NLA_HDRLEN) + \ 364 (sizeof(ap->capability) + NLA_HDRLEN) + \ 365 (sizeof(ap->ieLength) + NLA_HDRLEN)) 366 #define EXTSCAN_CACHED_NL_SCAN_RESULTS_IE_DATA_TLV \ 367 (ap->ieLength + NLA_HDRLEN) 368 369 nl_buf_len = NLMSG_HDRLEN; 370 nl_buf_len += EXTSCAN_CACHED_NL_FIXED_TLV; 371 if (data->num_scan_ids) { 372 nl_buf_len += sizeof(result->scan_id) + NLA_HDRLEN; 373 nl_buf_len += EXTSCAN_CACHED_NEST_HDRLEN; 374 result = &data->result[0]; 375 for (i = 0; i < data->num_scan_ids; i++) { 376 nl_buf_len += EXTSCAN_CACHED_NEST_HDRLEN; 377 nl_buf_len += EXTSCAN_CACHED_NL_SCAN_ID_TLV; 378 nl_buf_len += EXTSCAN_CACHED_NEST_HDRLEN; 379 380 ap = &result->ap[0]; 381 for (j = 0; j < result->num_results; j++) { 382 nl_buf_len += EXTSCAN_CACHED_NEST_HDRLEN; 383 nl_buf_len += 384 EXTSCAN_CACHED_NL_SCAN_RESULTS_TLV; 385 if (ap->ieLength) 386 nl_buf_len += 387 EXTSCAN_CACHED_NL_SCAN_RESULTS_IE_DATA_TLV; 388 ap++; 389 } 390 result++; 391 } 392 } 393 394 skb = wlan_cfg80211_vendor_cmd_alloc_reply_skb(hdd_ctx->wiphy, 395 nl_buf_len); 396 if (!skb) { 397 hdd_err("wlan_cfg80211_vendor_cmd_alloc_reply_skb failed"); 398 goto fail; 399 } 400 hdd_debug("Req Id %u Num_scan_ids %u More Data %u", 401 data->request_id, data->num_scan_ids, data->more_data); 402 403 result = &data->result[0]; 404 for (i = 0; i < data->num_scan_ids; i++) { 405 hdd_debug("[i=%d] scan_id %u flags %u num_results %u buckets scanned %u", 406 i, result->scan_id, result->flags, result->num_results, 407 result->buckets_scanned); 408 409 ap = &result->ap[0]; 410 for (j = 0; j < result->num_results; j++) { 411 /* 412 * Firmware returns timestamp from ext scan start till 413 * BSSID was cached (in micro seconds). Add this with 414 * time gap between system boot up to ext scan start 415 * to derive the time since boot when the 416 * BSSID was cached. 417 */ 418 ap->ts += hdd_ctx->ext_scan_start_since_boot; 419 hdd_debug("Timestamp %llu Ssid: " QDF_SSID_FMT " Bssid (" QDF_MAC_ADDR_FMT ") Channel %u Rssi %d RTT %u RTT_SD %u Beacon Period %u Capability 0x%x Ie length %d", 420 ap->ts, 421 QDF_SSID_REF(WLAN_SSID_MAX_LEN, ap->ssid), 422 QDF_MAC_ADDR_REF(ap->bssid.bytes), 423 ap->channel, ap->rssi, ap->rtt, ap->rtt_sd, 424 ap->beaconPeriod, ap->capability, 425 ap->ieLength); 426 ap++; 427 } 428 result++; 429 } 430 431 if (nla_put_u32(skb, QCA_WLAN_VENDOR_ATTR_EXTSCAN_RESULTS_REQUEST_ID, 432 data->request_id) || 433 nla_put_u32(skb, 434 QCA_WLAN_VENDOR_ATTR_EXTSCAN_RESULTS_NUM_RESULTS_AVAILABLE, 435 data->num_scan_ids) || 436 nla_put_u8(skb, 437 QCA_WLAN_VENDOR_ATTR_EXTSCAN_RESULTS_SCAN_RESULT_MORE_DATA, 438 data->more_data)) { 439 hdd_err("put fail"); 440 goto fail; 441 } 442 443 if (data->num_scan_ids) { 444 struct nlattr *nla_results; 445 446 result = &data->result[0]; 447 448 if (nla_put_u32(skb, 449 QCA_WLAN_VENDOR_ATTR_EXTSCAN_CACHED_RESULTS_SCAN_ID, 450 result->scan_id)) { 451 hdd_err("put fail"); 452 goto fail; 453 } 454 nla_results = nla_nest_start(skb, 455 QCA_WLAN_VENDOR_ATTR_EXTSCAN_CACHED_RESULTS_LIST); 456 if (!nla_results) 457 goto fail; 458 459 for (i = 0; i < data->num_scan_ids; i++) { 460 struct nlattr *nla_result; 461 struct nlattr *nla_aps; 462 463 nla_result = nla_nest_start(skb, i); 464 if (!nla_result) 465 goto fail; 466 467 if (nla_put_u32(skb, 468 QCA_WLAN_VENDOR_ATTR_EXTSCAN_CACHED_RESULTS_SCAN_ID, 469 result->scan_id) || 470 nla_put_u32(skb, 471 QCA_WLAN_VENDOR_ATTR_EXTSCAN_CACHED_RESULTS_FLAGS, 472 result->flags) || 473 nla_put_u32(skb, 474 QCA_WLAN_VENDOR_ATTR_EXTSCAN_RESULTS_BUCKETS_SCANNED, 475 result->buckets_scanned) || 476 nla_put_u32(skb, 477 QCA_WLAN_VENDOR_ATTR_EXTSCAN_RESULTS_NUM_RESULTS_AVAILABLE, 478 result->num_results)) { 479 hdd_err("put fail"); 480 goto fail; 481 } 482 483 nla_aps = nla_nest_start(skb, 484 QCA_WLAN_VENDOR_ATTR_EXTSCAN_RESULTS_LIST); 485 if (!nla_aps) 486 goto fail; 487 488 ap = &result->ap[0]; 489 for (j = 0; j < result->num_results; j++) { 490 if (hdd_extscan_nl_fill_bss(skb, ap, j)) 491 goto fail; 492 493 ap++; 494 } 495 nla_nest_end(skb, nla_aps); 496 nla_nest_end(skb, nla_result); 497 result++; 498 } 499 nla_nest_end(skb, nla_results); 500 } 501 502 wlan_cfg80211_vendor_cmd_reply(skb); 503 504 if (!data->more_data) { 505 spin_lock(&context->context_lock); 506 context->response_status = 0; 507 complete(&context->response_event); 508 spin_unlock(&context->context_lock); 509 } 510 return; 511 512 fail: 513 wlan_cfg80211_vendor_free_skb(skb); 514 spin_lock(&context->context_lock); 515 context->response_status = -EINVAL; 516 spin_unlock(&context->context_lock); 517 } 518 519 /** 520 * wlan_hdd_cfg80211_extscan_hotlist_match_ind() - hot list match ind 521 * @hdd_ctx: Pointer to hdd context 522 * @data: Pointer to ext scan result event 523 * 524 * This callback execute in atomic context and must not invoke any 525 * blocking calls. 526 * 527 * Return: none 528 */ 529 static void 530 wlan_hdd_cfg80211_extscan_hotlist_match_ind(struct hdd_context *hdd_ctx, 531 struct extscan_hotlist_match *data) 532 { 533 struct sk_buff *skb = NULL; 534 uint32_t i, index; 535 int flags = cds_get_gfp_flags(); 536 537 hdd_enter(); 538 539 if (wlan_hdd_validate_context(hdd_ctx)) 540 return; 541 if (!data) { 542 hdd_err("data is null"); 543 return; 544 } 545 546 if (data->ap_found) 547 index = QCA_NL80211_VENDOR_SUBCMD_EXTSCAN_HOTLIST_AP_FOUND_INDEX; 548 else 549 index = QCA_NL80211_VENDOR_SUBCMD_EXTSCAN_HOTLIST_AP_LOST_INDEX; 550 551 skb = wlan_cfg80211_vendor_event_alloc( 552 hdd_ctx->wiphy, 553 NULL, 554 EXTSCAN_EVENT_BUF_SIZE + NLMSG_HDRLEN, 555 index, flags); 556 557 if (!skb) { 558 hdd_err("wlan_cfg80211_vendor_event_alloc failed"); 559 return; 560 } 561 hdd_debug("Req Id: %u Num_APs: %u MoreData: %u ap_found: %u", 562 data->requestId, data->numOfAps, data->moreData, 563 data->ap_found); 564 565 for (i = 0; i < data->numOfAps; i++) { 566 data->ap[i].ts = qdf_get_monotonic_boottime(); 567 hdd_debug("[i=%d] Timestamp %llu Ssid: " QDF_SSID_FMT " Bssid (" QDF_MAC_ADDR_FMT ") Channel %u Rssi %d RTT %u RTT_SD %u", 568 i, data->ap[i].ts, 569 QDF_SSID_REF(WLAN_SSID_MAX_LEN, data->ap[i].ssid), 570 QDF_MAC_ADDR_REF(data->ap[i].bssid.bytes), 571 data->ap[i].channel, data->ap[i].rssi, 572 data->ap[i].rtt, data->ap[i].rtt_sd); 573 } 574 575 if (nla_put_u32(skb, 576 QCA_WLAN_VENDOR_ATTR_EXTSCAN_RESULTS_REQUEST_ID, 577 data->requestId) || 578 nla_put_u32(skb, 579 QCA_WLAN_VENDOR_ATTR_EXTSCAN_RESULTS_NUM_RESULTS_AVAILABLE, 580 data->numOfAps)) { 581 hdd_err("put fail"); 582 goto fail; 583 } 584 585 if (data->numOfAps) { 586 struct nlattr *aps; 587 588 aps = nla_nest_start(skb, 589 QCA_WLAN_VENDOR_ATTR_EXTSCAN_RESULTS_LIST); 590 if (!aps) 591 goto fail; 592 593 for (i = 0; i < data->numOfAps; i++) { 594 struct nlattr *ap; 595 596 ap = nla_nest_start(skb, i); 597 if (!ap) 598 goto fail; 599 600 if (hdd_wlan_nla_put_u64(skb, 601 QCA_WLAN_VENDOR_ATTR_EXTSCAN_RESULTS_SCAN_RESULT_TIME_STAMP, 602 data->ap[i].ts) || 603 nla_put(skb, 604 QCA_WLAN_VENDOR_ATTR_EXTSCAN_RESULTS_SCAN_RESULT_SSID, 605 sizeof(data->ap[i].ssid), 606 data->ap[i].ssid) || 607 nla_put(skb, 608 QCA_WLAN_VENDOR_ATTR_EXTSCAN_RESULTS_SCAN_RESULT_BSSID, 609 sizeof(data->ap[i].bssid), 610 data->ap[i].bssid.bytes) || 611 nla_put_u32(skb, 612 QCA_WLAN_VENDOR_ATTR_EXTSCAN_RESULTS_SCAN_RESULT_CHANNEL, 613 data->ap[i].channel) || 614 nla_put_s32(skb, 615 QCA_WLAN_VENDOR_ATTR_EXTSCAN_RESULTS_SCAN_RESULT_RSSI, 616 data->ap[i].rssi) || 617 nla_put_u32(skb, 618 QCA_WLAN_VENDOR_ATTR_EXTSCAN_RESULTS_SCAN_RESULT_RTT, 619 data->ap[i].rtt) || 620 nla_put_u32(skb, 621 QCA_WLAN_VENDOR_ATTR_EXTSCAN_RESULTS_SCAN_RESULT_RTT_SD, 622 data->ap[i].rtt_sd)) 623 goto fail; 624 625 nla_nest_end(skb, ap); 626 } 627 nla_nest_end(skb, aps); 628 629 if (nla_put_u8(skb, 630 QCA_WLAN_VENDOR_ATTR_EXTSCAN_RESULTS_SCAN_RESULT_MORE_DATA, 631 data->moreData)) 632 goto fail; 633 } 634 635 wlan_cfg80211_vendor_event(skb, flags); 636 hdd_exit(); 637 return; 638 639 fail: 640 wlan_cfg80211_vendor_free_skb(skb); 641 } 642 643 /** 644 * wlan_hdd_cfg80211_extscan_signif_wifi_change_results_ind() - 645 * significant wifi change results indication 646 * @hdd_ctx: Pointer to hdd context 647 * @data: Pointer to signif wifi change event 648 * 649 * This callback execute in atomic context and must not invoke any 650 * blocking calls. 651 * 652 * Return: none 653 */ 654 static void 655 wlan_hdd_cfg80211_extscan_signif_wifi_change_results_ind( 656 struct hdd_context *hdd_ctx, 657 tpSirWifiSignificantChangeEvent data) 658 { 659 struct sk_buff *skb = NULL; 660 tSirWifiSignificantChange *ap_info; 661 int32_t *rssi; 662 uint32_t i, j; 663 int flags = cds_get_gfp_flags(); 664 665 hdd_enter(); 666 667 if (wlan_hdd_validate_context(hdd_ctx)) 668 return; 669 if (!data) { 670 hdd_err("data is null"); 671 return; 672 } 673 674 skb = wlan_cfg80211_vendor_event_alloc( 675 hdd_ctx->wiphy, 676 NULL, 677 EXTSCAN_EVENT_BUF_SIZE + NLMSG_HDRLEN, 678 QCA_NL80211_VENDOR_SUBCMD_EXTSCAN_SIGNIFICANT_CHANGE_INDEX, 679 flags); 680 681 if (!skb) { 682 hdd_err("wlan_cfg80211_vendor_event_alloc failed"); 683 return; 684 } 685 hdd_debug("Req Id %u Num results %u More Data %u", 686 data->requestId, data->numResults, data->moreData); 687 688 ap_info = &data->ap[0]; 689 for (i = 0; i < data->numResults; i++) { 690 hdd_debug("[i=%d] " 691 "Bssid (" QDF_MAC_ADDR_FMT ") " 692 "Channel %u " 693 "numOfRssi %d", 694 i, 695 QDF_MAC_ADDR_REF(ap_info->bssid.bytes), 696 ap_info->channel, ap_info->numOfRssi); 697 rssi = &(ap_info)->rssi[0]; 698 for (j = 0; j < ap_info->numOfRssi; j++) 699 hdd_debug("Rssi %d", *rssi++); 700 701 ap_info = (tSirWifiSignificantChange *)((char *)ap_info + 702 ap_info->numOfRssi * sizeof(*rssi) + 703 sizeof(*ap_info)); 704 } 705 706 if (nla_put_u32(skb, 707 QCA_WLAN_VENDOR_ATTR_EXTSCAN_RESULTS_REQUEST_ID, 708 data->requestId) || 709 nla_put_u32(skb, 710 QCA_WLAN_VENDOR_ATTR_EXTSCAN_RESULTS_NUM_RESULTS_AVAILABLE, 711 data->numResults)) { 712 hdd_err("put fail"); 713 goto fail; 714 } 715 716 if (data->numResults) { 717 struct nlattr *aps; 718 719 aps = nla_nest_start(skb, 720 QCA_WLAN_VENDOR_ATTR_EXTSCAN_RESULTS_LIST); 721 if (!aps) 722 goto fail; 723 724 ap_info = &data->ap[0]; 725 for (i = 0; i < data->numResults; i++) { 726 struct nlattr *ap; 727 728 ap = nla_nest_start(skb, i); 729 if (!ap) 730 goto fail; 731 732 if (nla_put(skb, 733 QCA_WLAN_VENDOR_ATTR_EXTSCAN_RESULTS_SIGNIFICANT_CHANGE_RESULT_BSSID, 734 QDF_MAC_ADDR_SIZE, ap_info->bssid.bytes) || 735 nla_put_u32(skb, 736 QCA_WLAN_VENDOR_ATTR_EXTSCAN_RESULTS_SIGNIFICANT_CHANGE_RESULT_CHANNEL, 737 ap_info->channel) || 738 nla_put_u32(skb, 739 QCA_WLAN_VENDOR_ATTR_EXTSCAN_RESULTS_SIGNIFICANT_CHANGE_RESULT_NUM_RSSI, 740 ap_info->numOfRssi) || 741 nla_put(skb, 742 QCA_WLAN_VENDOR_ATTR_EXTSCAN_RESULTS_SIGNIFICANT_CHANGE_RESULT_RSSI_LIST, 743 sizeof(s32) * ap_info->numOfRssi, 744 &(ap_info)->rssi[0])) 745 goto fail; 746 747 nla_nest_end(skb, ap); 748 749 ap_info = (tSirWifiSignificantChange *)((char *)ap_info 750 + ap_info->numOfRssi * sizeof(*rssi) + 751 sizeof(*ap_info)); 752 } 753 nla_nest_end(skb, aps); 754 755 if (nla_put_u8(skb, 756 QCA_WLAN_VENDOR_ATTR_EXTSCAN_RESULTS_SCAN_RESULT_MORE_DATA, 757 data->moreData)) 758 goto fail; 759 } 760 761 wlan_cfg80211_vendor_event(skb, flags); 762 return; 763 764 fail: 765 wlan_cfg80211_vendor_free_skb(skb); 766 return; 767 768 } 769 770 /** 771 * wlan_hdd_cfg80211_extscan_full_scan_result_event() - full scan result event 772 * @hdd_ctx: Pointer to hdd context 773 * @data: Pointer to full scan result event 774 * 775 * This callback execute in atomic context and must not invoke any 776 * blocking calls. 777 * 778 * Return: none 779 */ 780 static void 781 wlan_hdd_cfg80211_extscan_full_scan_result_event(struct hdd_context *hdd_ctx, 782 tpSirWifiFullScanResultEvent 783 data) 784 { 785 struct sk_buff *skb; 786 struct hdd_ext_scan_context *context; 787 788 int flags = cds_get_gfp_flags(); 789 790 /* ENTER() intentionally not used in a frequently invoked API */ 791 792 if (wlan_hdd_validate_context(hdd_ctx)) 793 return; 794 if (!data) { 795 hdd_err("data is null"); 796 return; 797 } 798 799 if ((sizeof(*data) + data->ap.ieLength) >= EXTSCAN_EVENT_BUF_SIZE) { 800 hdd_err("Frame exceeded NL size limitation, drop it!!"); 801 return; 802 } 803 skb = wlan_cfg80211_vendor_event_alloc( 804 hdd_ctx->wiphy, 805 NULL, 806 EXTSCAN_EVENT_BUF_SIZE + NLMSG_HDRLEN, 807 QCA_NL80211_VENDOR_SUBCMD_EXTSCAN_FULL_SCAN_RESULT_INDEX, 808 flags); 809 810 if (!skb) { 811 hdd_err("wlan_cfg80211_vendor_event_alloc failed"); 812 return; 813 } 814 815 data->ap.channel = cds_chan_to_freq(data->ap.channel); 816 817 /* 818 * Android does not want the time stamp from the frame. 819 * Instead it wants a monotonic increasing value since boot 820 */ 821 data->ap.ts = qdf_get_monotonic_boottime(); 822 823 hdd_debug("Req Id %u More Data %u", data->requestId, data->moreData); 824 hdd_debug("AP Info: Timestamp %llu Ssid: " QDF_SSID_FMT " Bssid (" QDF_MAC_ADDR_FMT ") Channel %u Rssi %d RTT %u RTT_SD %u Bcn Period %d Capability 0x%X IE Length %d", 825 data->ap.ts, 826 QDF_SSID_REF(WLAN_SSID_MAX_LEN, data->ap.ssid), 827 QDF_MAC_ADDR_REF(data->ap.bssid.bytes), 828 data->ap.channel, data->ap.rssi, data->ap.rtt, 829 data->ap.rtt_sd, data->ap.beaconPeriod, 830 data->ap.capability, data->ap.ieLength); 831 832 if (nla_put_u32(skb, 833 QCA_WLAN_VENDOR_ATTR_EXTSCAN_RESULTS_REQUEST_ID, 834 data->requestId) || 835 hdd_wlan_nla_put_u64(skb, 836 QCA_WLAN_VENDOR_ATTR_EXTSCAN_RESULTS_SCAN_RESULT_TIME_STAMP, 837 data->ap.ts) || 838 nla_put(skb, 839 QCA_WLAN_VENDOR_ATTR_EXTSCAN_RESULTS_SCAN_RESULT_SSID, 840 sizeof(data->ap.ssid), 841 data->ap.ssid) || 842 nla_put(skb, QCA_WLAN_VENDOR_ATTR_EXTSCAN_RESULTS_SCAN_RESULT_BSSID, 843 sizeof(data->ap.bssid), 844 data->ap.bssid.bytes) || 845 nla_put_u32(skb, 846 QCA_WLAN_VENDOR_ATTR_EXTSCAN_RESULTS_SCAN_RESULT_CHANNEL, 847 data->ap.channel) || 848 nla_put_s32(skb, 849 QCA_WLAN_VENDOR_ATTR_EXTSCAN_RESULTS_SCAN_RESULT_RSSI, 850 data->ap.rssi) || 851 nla_put_u32(skb, 852 QCA_WLAN_VENDOR_ATTR_EXTSCAN_RESULTS_SCAN_RESULT_RTT, 853 data->ap.rtt) || 854 nla_put_u32(skb, 855 QCA_WLAN_VENDOR_ATTR_EXTSCAN_RESULTS_SCAN_RESULT_RTT_SD, 856 data->ap.rtt_sd) || 857 nla_put_u16(skb, 858 QCA_WLAN_VENDOR_ATTR_EXTSCAN_RESULTS_SCAN_RESULT_BEACON_PERIOD, 859 data->ap.beaconPeriod) || 860 nla_put_u16(skb, 861 QCA_WLAN_VENDOR_ATTR_EXTSCAN_RESULTS_SCAN_RESULT_CAPABILITY, 862 data->ap.capability) || 863 nla_put_u32(skb, 864 QCA_WLAN_VENDOR_ATTR_EXTSCAN_RESULTS_SCAN_RESULT_IE_LENGTH, 865 data->ap.ieLength) || 866 nla_put_u8(skb, 867 QCA_WLAN_VENDOR_ATTR_EXTSCAN_RESULTS_SCAN_RESULT_MORE_DATA, 868 data->moreData)) { 869 hdd_err("nla put fail"); 870 goto nla_put_failure; 871 } 872 873 if (data->ap.ieLength) { 874 if (nla_put(skb, 875 QCA_WLAN_VENDOR_ATTR_EXTSCAN_RESULTS_SCAN_RESULT_IE_DATA, 876 data->ap.ieLength, data->ap.ieData)) 877 goto nla_put_failure; 878 } 879 880 context = &ext_scan_context; 881 spin_lock(&context->context_lock); 882 if (nla_put_u32(skb, 883 QCA_WLAN_VENDOR_ATTR_EXTSCAN_RESULTS_BUCKETS_SCANNED, 884 context->buckets_scanned)) { 885 spin_unlock(&context->context_lock); 886 hdd_debug("Failed to include buckets_scanned"); 887 goto nla_put_failure; 888 } 889 spin_unlock(&context->context_lock); 890 891 wlan_cfg80211_vendor_event(skb, flags); 892 return; 893 894 nla_put_failure: 895 wlan_cfg80211_vendor_free_skb(skb); 896 } 897 898 /** 899 * wlan_hdd_cfg80211_extscan_scan_res_available_event() - scan result event 900 * @hdd_ctx: Pointer to hdd context 901 * @data: Pointer to scan results available indication param 902 * 903 * This callback execute in atomic context and must not invoke any 904 * blocking calls. 905 * 906 * Return: none 907 */ 908 static void 909 wlan_hdd_cfg80211_extscan_scan_res_available_event( 910 struct hdd_context *hdd_ctx, 911 tpSirExtScanResultsAvailableIndParams data) 912 { 913 struct sk_buff *skb; 914 int flags = cds_get_gfp_flags(); 915 916 hdd_enter(); 917 918 if (wlan_hdd_validate_context(hdd_ctx)) 919 return; 920 if (!data) { 921 hdd_err("data is null"); 922 return; 923 } 924 925 skb = wlan_cfg80211_vendor_event_alloc( 926 hdd_ctx->wiphy, 927 NULL, 928 EXTSCAN_EVENT_BUF_SIZE + NLMSG_HDRLEN, 929 QCA_NL80211_VENDOR_SUBCMD_EXTSCAN_SCAN_RESULTS_AVAILABLE_INDEX, 930 flags); 931 932 if (!skb) { 933 hdd_err("wlan_cfg80211_vendor_event_alloc failed"); 934 return; 935 } 936 937 hdd_debug("Req Id %u Num results %u", 938 data->requestId, data->numResultsAvailable); 939 if (nla_put_u32(skb, 940 QCA_WLAN_VENDOR_ATTR_EXTSCAN_RESULTS_REQUEST_ID, 941 data->requestId) || 942 nla_put_u32(skb, 943 QCA_WLAN_VENDOR_ATTR_EXTSCAN_RESULTS_NUM_RESULTS_AVAILABLE, 944 data->numResultsAvailable)) { 945 hdd_err("nla put fail"); 946 goto nla_put_failure; 947 } 948 949 wlan_cfg80211_vendor_event(skb, flags); 950 hdd_exit(); 951 return; 952 953 nla_put_failure: 954 wlan_cfg80211_vendor_free_skb(skb); 955 } 956 957 /** 958 * wlan_hdd_cfg80211_extscan_scan_progress_event() - scan progress event 959 * @hdd_ctx: Pointer to hdd context 960 * @data: Pointer to scan event indication param 961 * 962 * This callback execute in atomic context and must not invoke any 963 * blocking calls. 964 * 965 * Return: none 966 */ 967 static void 968 wlan_hdd_cfg80211_extscan_scan_progress_event(struct hdd_context *hdd_ctx, 969 tpSirExtScanOnScanEventIndParams 970 data) 971 { 972 struct sk_buff *skb; 973 int flags = cds_get_gfp_flags(); 974 struct hdd_ext_scan_context *context; 975 976 /* ENTER() intentionally not used in a frequently invoked API */ 977 978 if (wlan_hdd_validate_context(hdd_ctx)) 979 return; 980 if (!data) { 981 hdd_err("data is null"); 982 return; 983 } 984 985 skb = wlan_cfg80211_vendor_event_alloc( 986 hdd_ctx->wiphy, 987 NULL, 988 EXTSCAN_EVENT_BUF_SIZE + NLMSG_HDRLEN, 989 QCA_NL80211_VENDOR_SUBCMD_EXTSCAN_SCAN_EVENT_INDEX, 990 flags); 991 992 if (!skb) { 993 hdd_err("wlan_cfg80211_vendor_event_alloc failed"); 994 return; 995 } 996 997 hdd_debug("Request Id: %u Scan event type: %u Scan event status: %u buckets scanned: %u", 998 data->requestId, data->scanEventType, data->status, 999 data->buckets_scanned); 1000 1001 context = &ext_scan_context; 1002 spin_lock(&context->context_lock); 1003 if (data->scanEventType == WIFI_EXTSCAN_CYCLE_COMPLETED_EVENT) { 1004 context->buckets_scanned = 0; 1005 data->scanEventType = WIFI_EXTSCAN_RESULTS_AVAILABLE; 1006 spin_unlock(&context->context_lock); 1007 } else if (data->scanEventType == WIFI_EXTSCAN_CYCLE_STARTED_EVENT) { 1008 context->buckets_scanned = data->buckets_scanned; 1009 /* No need to report to user space */ 1010 spin_unlock(&context->context_lock); 1011 goto nla_put_failure; 1012 } else { 1013 spin_unlock(&context->context_lock); 1014 } 1015 1016 if (nla_put_u32(skb, QCA_WLAN_VENDOR_ATTR_EXTSCAN_RESULTS_REQUEST_ID, 1017 data->requestId) || 1018 nla_put_u8(skb, 1019 QCA_WLAN_VENDOR_ATTR_EXTSCAN_RESULTS_SCAN_EVENT_TYPE, 1020 data->scanEventType)) { 1021 hdd_err("nla put fail"); 1022 goto nla_put_failure; 1023 } 1024 1025 wlan_cfg80211_vendor_event(skb, flags); 1026 return; 1027 1028 nla_put_failure: 1029 wlan_cfg80211_vendor_free_skb(skb); 1030 } 1031 1032 /** 1033 * wlan_hdd_cfg80211_extscan_epno_match_found() - pno match found 1034 * @hdd_ctx: HDD context 1035 * @data: matched network data 1036 * 1037 * This function reads the matched network data and fills NL vendor attributes 1038 * and send it to upper layer. 1039 * This callback execute in atomic context and must not invoke any 1040 * blocking calls. 1041 * 1042 * Return: 0 on success, error number otherwise 1043 */ 1044 static void 1045 wlan_hdd_cfg80211_extscan_epno_match_found(struct hdd_context *hdd_ctx, 1046 struct pno_match_found *data) 1047 { 1048 struct sk_buff *skb; 1049 uint32_t len, i; 1050 int flags = cds_get_gfp_flags(); 1051 enum qca_nl80211_vendor_subcmds_index index = 1052 QCA_NL80211_VENDOR_SUBCMD_EXTSCAN_PNO_NETWORK_FOUND_INDEX; 1053 1054 hdd_enter(); 1055 1056 if (wlan_hdd_validate_context(hdd_ctx)) 1057 return; 1058 if (!data) { 1059 hdd_err("data is null"); 1060 return; 1061 } 1062 1063 /* 1064 * If the number of match found APs including IE data exceeds NL 4K size 1065 * limitation, drop that beacon/probe rsp frame. 1066 */ 1067 len = sizeof(*data) + 1068 (data->num_results + sizeof(tSirWifiScanResult)); 1069 for (i = 0; i < data->num_results; i++) 1070 len += data->ap[i].ieLength; 1071 1072 if (len >= EXTSCAN_EVENT_BUF_SIZE) { 1073 hdd_err("Frame exceeded NL size limitation, drop it!"); 1074 return; 1075 } 1076 1077 skb = wlan_cfg80211_vendor_event_alloc(hdd_ctx->wiphy, NULL, 1078 EXTSCAN_EVENT_BUF_SIZE + 1079 NLMSG_HDRLEN, 1080 index, flags); 1081 if (!skb) { 1082 hdd_err("wlan_cfg80211_vendor_event_alloc failed"); 1083 return; 1084 } 1085 1086 hdd_debug("Req Id %u More Data %u num_results %d", 1087 data->request_id, data->more_data, data->num_results); 1088 for (i = 0; i < data->num_results; i++) { 1089 data->ap[i].channel = cds_chan_to_freq(data->ap[i].channel); 1090 hdd_debug("AP Info: Timestamp %llu) Ssid: " QDF_SSID_FMT " Bssid (" QDF_MAC_ADDR_FMT ") Channel %u Rssi %d RTT %u RTT_SD %u Bcn Period %d Capability 0x%X IE Length %d", 1091 data->ap[i].ts, 1092 QDF_SSID_REF(WLAN_SSID_MAX_LEN, data->ap[i].ssid), 1093 QDF_MAC_ADDR_REF(data->ap[i].bssid.bytes), 1094 data->ap[i].channel, data->ap[i].rssi, 1095 data->ap[i].rtt, data->ap[i].rtt_sd, 1096 data->ap[i].beaconPeriod, data->ap[i].capability, 1097 data->ap[i].ieLength); 1098 } 1099 1100 if (nla_put_u32(skb, QCA_WLAN_VENDOR_ATTR_EXTSCAN_RESULTS_REQUEST_ID, 1101 data->request_id) || 1102 nla_put_u32(skb, 1103 QCA_WLAN_VENDOR_ATTR_EXTSCAN_RESULTS_NUM_RESULTS_AVAILABLE, 1104 data->num_results) || 1105 nla_put_u8(skb, 1106 QCA_WLAN_VENDOR_ATTR_EXTSCAN_RESULTS_SCAN_RESULT_MORE_DATA, 1107 data->more_data)) { 1108 hdd_err("nla put fail"); 1109 goto fail; 1110 } 1111 1112 if (data->num_results) { 1113 struct nlattr *nla_aps; 1114 1115 nla_aps = nla_nest_start(skb, 1116 QCA_WLAN_VENDOR_ATTR_EXTSCAN_RESULTS_LIST); 1117 if (!nla_aps) 1118 goto fail; 1119 1120 for (i = 0; i < data->num_results; i++) { 1121 if (hdd_extscan_nl_fill_bss(skb, &data->ap[i], i)) 1122 goto fail; 1123 } 1124 nla_nest_end(skb, nla_aps); 1125 } 1126 1127 wlan_cfg80211_vendor_event(skb, flags); 1128 return; 1129 1130 fail: 1131 wlan_cfg80211_vendor_free_skb(skb); 1132 } 1133 1134 /** 1135 * wlan_hdd_cfg80211_passpoint_match_found() - passpoint match found 1136 * @ctx: HDD context 1137 * @data: matched network data 1138 * 1139 * This function reads the match network %data and fill in the skb with 1140 * NL attributes and send up the NL event 1141 * This callback execute in atomic context and must not invoke any 1142 * blocking calls. 1143 * 1144 * Return: none 1145 */ 1146 static void 1147 wlan_hdd_cfg80211_passpoint_match_found(void *ctx, 1148 struct wifi_passpoint_match *data) 1149 { 1150 struct hdd_context *hdd_ctx = ctx; 1151 struct sk_buff *skb = NULL; 1152 uint32_t len, i, num_matches = 1, more_data = 0; 1153 struct nlattr *nla_aps, *nla_bss; 1154 int flags = cds_get_gfp_flags(); 1155 enum qca_nl80211_vendor_subcmds_index index = 1156 QCA_NL80211_VENDOR_SUBCMD_EXTSCAN_PNO_PASSPOINT_NETWORK_FOUND_INDEX; 1157 1158 hdd_enter(); 1159 1160 if (wlan_hdd_validate_context(hdd_ctx)) 1161 return; 1162 if (!data) { 1163 hdd_err("data is null"); 1164 return; 1165 } 1166 1167 len = sizeof(*data) + data->ap.ieLength + data->anqp_len; 1168 if (len >= EXTSCAN_EVENT_BUF_SIZE) { 1169 hdd_err("Result exceeded NL size limitation, drop it"); 1170 return; 1171 } 1172 1173 skb = wlan_cfg80211_vendor_event_alloc(hdd_ctx->wiphy, NULL, 1174 EXTSCAN_EVENT_BUF_SIZE + 1175 NLMSG_HDRLEN, 1176 index, flags); 1177 if (!skb) { 1178 hdd_err("wlan_cfg80211_vendor_event_alloc failed"); 1179 return; 1180 } 1181 1182 hdd_debug("Req Id %u Id %u ANQP length %u num_matches %u", 1183 data->request_id, data->id, data->anqp_len, num_matches); 1184 for (i = 0; i < num_matches; i++) { 1185 hdd_debug("AP Info: Timestamp %llu Ssid: " QDF_SSID_FMT " Bssid (" QDF_MAC_ADDR_FMT ") Channel %u Rssi %d RTT %u RTT_SD %u Bcn Period %d Capability 0x%X IE Length %d", 1186 data->ap.ts, 1187 QDF_SSID_REF(WLAN_SSID_MAX_LEN, data->ap.ssid), 1188 QDF_MAC_ADDR_REF(data->ap.bssid.bytes), 1189 data->ap.channel, data->ap.rssi, data->ap.rtt, 1190 data->ap.rtt_sd, data->ap.beaconPeriod, 1191 data->ap.capability, data->ap.ieLength); 1192 } 1193 1194 if (nla_put_u32(skb, QCA_WLAN_VENDOR_ATTR_EXTSCAN_RESULTS_REQUEST_ID, 1195 data->request_id) || 1196 nla_put_u32(skb, 1197 QCA_WLAN_VENDOR_ATTR_EXTSCAN_PNO_RESULTS_PASSPOINT_NETWORK_FOUND_NUM_MATCHES, 1198 num_matches) || 1199 nla_put_u8(skb, 1200 QCA_WLAN_VENDOR_ATTR_EXTSCAN_RESULTS_SCAN_RESULT_MORE_DATA, 1201 more_data)) { 1202 hdd_err("nla put fail"); 1203 goto fail; 1204 } 1205 1206 nla_aps = nla_nest_start(skb, 1207 QCA_WLAN_VENDOR_ATTR_EXTSCAN_PNO_RESULTS_PASSPOINT_MATCH_RESULT_LIST); 1208 if (!nla_aps) 1209 goto fail; 1210 1211 for (i = 0; i < num_matches; i++) { 1212 struct nlattr *nla_ap; 1213 1214 nla_ap = nla_nest_start(skb, i); 1215 if (!nla_ap) 1216 goto fail; 1217 1218 if (nla_put_u32(skb, 1219 QCA_WLAN_VENDOR_ATTR_EXTSCAN_PNO_RESULTS_PASSPOINT_MATCH_ID, 1220 data->id) || 1221 nla_put_u32(skb, 1222 QCA_WLAN_VENDOR_ATTR_EXTSCAN_PNO_RESULTS_PASSPOINT_MATCH_ANQP_LEN, 1223 data->anqp_len)) { 1224 goto fail; 1225 } 1226 1227 if (data->anqp_len) 1228 if (nla_put(skb, 1229 QCA_WLAN_VENDOR_ATTR_EXTSCAN_PNO_RESULTS_PASSPOINT_MATCH_ANQP, 1230 data->anqp_len, data->anqp)) 1231 goto fail; 1232 1233 nla_bss = nla_nest_start(skb, 1234 QCA_WLAN_VENDOR_ATTR_EXTSCAN_RESULTS_LIST); 1235 if (!nla_bss) 1236 goto fail; 1237 1238 if (hdd_extscan_nl_fill_bss(skb, &data->ap, 0)) 1239 goto fail; 1240 1241 nla_nest_end(skb, nla_bss); 1242 nla_nest_end(skb, nla_ap); 1243 } 1244 nla_nest_end(skb, nla_aps); 1245 1246 wlan_cfg80211_vendor_event(skb, flags); 1247 return; 1248 1249 fail: 1250 wlan_cfg80211_vendor_free_skb(skb); 1251 } 1252 1253 /** 1254 * wlan_hdd_cfg80211_extscan_generic_rsp() - 1255 * Handle a generic ExtScan Response message 1256 * @hdd_ctx: HDD context registered with SME 1257 * @response: The ExtScan response from firmware 1258 * 1259 * This function will handle a generic ExtScan response message from 1260 * firmware and will communicate the result to the userspace thread 1261 * that is waiting for the response. 1262 * 1263 * Return: none 1264 */ 1265 static void 1266 wlan_hdd_cfg80211_extscan_generic_rsp(struct hdd_context *hdd_ctx, 1267 struct sir_extscan_generic_response *response) 1268 { 1269 struct hdd_ext_scan_context *context; 1270 1271 hdd_enter(); 1272 1273 if (wlan_hdd_validate_context(hdd_ctx) || !response) { 1274 hdd_err("HDD context is not valid or response(%pK) is null", 1275 response); 1276 return; 1277 } 1278 1279 hdd_debug("request %u status %u", 1280 response->request_id, response->status); 1281 1282 context = &ext_scan_context; 1283 spin_lock(&context->context_lock); 1284 if (context->request_id == response->request_id) { 1285 context->response_status = response->status ? -EINVAL : 0; 1286 complete(&context->response_event); 1287 } 1288 spin_unlock(&context->context_lock); 1289 } 1290 1291 void wlan_hdd_cfg80211_extscan_callback(hdd_handle_t hdd_handle, 1292 const uint16_t event_id, void *msg) 1293 { 1294 struct hdd_context *hdd_ctx = hdd_handle_to_context(hdd_handle); 1295 1296 /* ENTER() intentionally not used in a frequently invoked API */ 1297 1298 if (wlan_hdd_validate_context(hdd_ctx)) 1299 return; 1300 1301 hdd_debug("Rcvd Event %d", event_id); 1302 1303 switch (event_id) { 1304 case eSIR_EXTSCAN_CACHED_RESULTS_RSP: 1305 /* There is no need to send this response to upper layer 1306 * Just log the message 1307 */ 1308 hdd_debug("Rcvd eSIR_EXTSCAN_CACHED_RESULTS_RSP"); 1309 break; 1310 1311 case eSIR_EXTSCAN_GET_CAPABILITIES_IND: 1312 wlan_hdd_cfg80211_extscan_get_capabilities_rsp(hdd_ctx, msg); 1313 break; 1314 1315 case eSIR_EXTSCAN_HOTLIST_MATCH_IND: 1316 wlan_hdd_cfg80211_extscan_hotlist_match_ind(hdd_ctx, msg); 1317 break; 1318 1319 case eSIR_EXTSCAN_SIGNIFICANT_WIFI_CHANGE_RESULTS_IND: 1320 wlan_hdd_cfg80211_extscan_signif_wifi_change_results_ind(hdd_ctx, 1321 msg); 1322 break; 1323 1324 case eSIR_EXTSCAN_CACHED_RESULTS_IND: 1325 wlan_hdd_cfg80211_extscan_cached_results_ind(hdd_ctx, msg); 1326 break; 1327 1328 case eSIR_EXTSCAN_SCAN_RES_AVAILABLE_IND: 1329 wlan_hdd_cfg80211_extscan_scan_res_available_event(hdd_ctx, 1330 msg); 1331 break; 1332 1333 case eSIR_EXTSCAN_FULL_SCAN_RESULT_IND: 1334 wlan_hdd_cfg80211_extscan_full_scan_result_event(hdd_ctx, msg); 1335 break; 1336 1337 case eSIR_EPNO_NETWORK_FOUND_IND: 1338 wlan_hdd_cfg80211_extscan_epno_match_found(hdd_ctx, msg); 1339 break; 1340 1341 case eSIR_EXTSCAN_SCAN_PROGRESS_EVENT_IND: 1342 wlan_hdd_cfg80211_extscan_scan_progress_event(hdd_ctx, msg); 1343 break; 1344 1345 case eSIR_PASSPOINT_NETWORK_FOUND_IND: 1346 wlan_hdd_cfg80211_passpoint_match_found(hdd_ctx, msg); 1347 break; 1348 1349 case eSIR_EXTSCAN_START_RSP: 1350 case eSIR_EXTSCAN_STOP_RSP: 1351 case eSIR_EXTSCAN_SET_BSSID_HOTLIST_RSP: 1352 case eSIR_EXTSCAN_RESET_BSSID_HOTLIST_RSP: 1353 case eSIR_EXTSCAN_SET_SIGNIFICANT_WIFI_CHANGE_RSP: 1354 case eSIR_EXTSCAN_RESET_SIGNIFICANT_WIFI_CHANGE_RSP: 1355 case eSIR_EXTSCAN_SET_SSID_HOTLIST_RSP: 1356 case eSIR_EXTSCAN_RESET_SSID_HOTLIST_RSP: 1357 wlan_hdd_cfg80211_extscan_generic_rsp(hdd_ctx, msg); 1358 break; 1359 1360 default: 1361 hdd_err("Unknown event type: %u", event_id); 1362 break; 1363 } 1364 } 1365 1366 /* 1367 * define short names for the global vendor params 1368 * used by wlan_hdd_send_ext_scan_capability() 1369 */ 1370 #define PARAM_REQUEST_ID \ 1371 QCA_WLAN_VENDOR_ATTR_EXTSCAN_SUBCMD_CONFIG_PARAM_REQUEST_ID 1372 #define PARAM_STATUS \ 1373 QCA_WLAN_VENDOR_ATTR_EXTSCAN_STATUS 1374 #define MAX_EXTSCAN_CACHE_SIZE \ 1375 QCA_WLAN_VENDOR_ATTR_EXTSCAN_RESULTS_CAPABILITIES_MAX_SCAN_CACHE_SIZE 1376 #define MAX_SCAN_BUCKETS \ 1377 QCA_WLAN_VENDOR_ATTR_EXTSCAN_RESULTS_CAPABILITIES_MAX_SCAN_BUCKETS 1378 #define MAX_AP_CACHE_PER_SCAN \ 1379 QCA_WLAN_VENDOR_ATTR_EXTSCAN_RESULTS_CAPABILITIES_MAX_AP_CACHE_PER_SCAN 1380 #define MAX_RSSI_SAMPLE_SIZE \ 1381 QCA_WLAN_VENDOR_ATTR_EXTSCAN_RESULTS_CAPABILITIES_MAX_RSSI_SAMPLE_SIZE 1382 #define MAX_SCAN_RPT_THRHOLD \ 1383 QCA_WLAN_VENDOR_ATTR_EXTSCAN_RESULTS_CAPABILITIES_MAX_SCAN_REPORTING_THRESHOLD 1384 #define MAX_HOTLIST_BSSIDS \ 1385 QCA_WLAN_VENDOR_ATTR_EXTSCAN_RESULTS_CAPABILITIES_MAX_HOTLIST_BSSIDS 1386 #define MAX_SIGNIFICANT_WIFI_CHANGE_APS \ 1387 QCA_WLAN_VENDOR_ATTR_EXTSCAN_RESULTS_CAPABILITIES_MAX_SIGNIFICANT_WIFI_CHANGE_APS 1388 #define MAX_BSSID_HISTORY_ENTRIES \ 1389 QCA_WLAN_VENDOR_ATTR_EXTSCAN_RESULTS_CAPABILITIES_MAX_BSSID_HISTORY_ENTRIES 1390 #define MAX_HOTLIST_SSIDS \ 1391 QCA_WLAN_VENDOR_ATTR_EXTSCAN_RESULTS_CAPABILITIES_MAX_HOTLIST_SSIDS 1392 #define MAX_NUM_EPNO_NETS \ 1393 QCA_WLAN_VENDOR_ATTR_EXTSCAN_RESULTS_CAPABILITIES_MAX_NUM_EPNO_NETS 1394 #define MAX_NUM_EPNO_NETS_BY_SSID \ 1395 QCA_WLAN_VENDOR_ATTR_EXTSCAN_RESULTS_CAPABILITIES_MAX_NUM_EPNO_NETS_BY_SSID 1396 #define MAX_NUM_WHITELISTED_SSID \ 1397 QCA_WLAN_VENDOR_ATTR_EXTSCAN_RESULTS_CAPABILITIES_MAX_NUM_WHITELISTED_SSID 1398 #define MAX_NUM_BLACKLISTED_BSSID \ 1399 QCA_WLAN_VENDOR_ATTR_EXTSCAN_MAX_NUM_BLACKLISTED_BSSID 1400 /** 1401 * wlan_hdd_send_ext_scan_capability - send ext scan capability to user space 1402 * @hdd_ctx: Pointer to hdd context 1403 * 1404 * Return: 0 for success, non-zero for failure 1405 */ 1406 static int wlan_hdd_send_ext_scan_capability(struct hdd_context *hdd_ctx) 1407 { 1408 int ret; 1409 struct sk_buff *skb; 1410 struct ext_scan_capabilities_response *data; 1411 uint32_t nl_buf_len; 1412 1413 ret = wlan_hdd_validate_context(hdd_ctx); 1414 if (0 != ret) 1415 return ret; 1416 1417 data = &(ext_scan_context.capability_response); 1418 nl_buf_len = NLMSG_HDRLEN; 1419 nl_buf_len += (sizeof(data->requestId) + NLA_HDRLEN) + 1420 (sizeof(data->status) + NLA_HDRLEN) + 1421 (sizeof(data->max_scan_cache_size) + NLA_HDRLEN) + 1422 (sizeof(data->max_scan_buckets) + NLA_HDRLEN) + 1423 (sizeof(data->max_ap_cache_per_scan) + NLA_HDRLEN) + 1424 (sizeof(data->max_rssi_sample_size) + NLA_HDRLEN) + 1425 (sizeof(data->max_scan_reporting_threshold) + NLA_HDRLEN) + 1426 (sizeof(data->max_hotlist_bssids) + NLA_HDRLEN) + 1427 (sizeof(data->max_significant_wifi_change_aps) + NLA_HDRLEN) + 1428 (sizeof(data->max_bssid_history_entries) + NLA_HDRLEN) + 1429 (sizeof(data->max_hotlist_ssids) + NLA_HDRLEN) + 1430 (sizeof(data->max_number_epno_networks) + NLA_HDRLEN) + 1431 (sizeof(data->max_number_epno_networks_by_ssid) + NLA_HDRLEN) + 1432 (sizeof(data->max_number_of_allow_listed_ssid) + NLA_HDRLEN) + 1433 (sizeof(data->max_number_of_deny_listed_bssid) + NLA_HDRLEN); 1434 skb = wlan_cfg80211_vendor_cmd_alloc_reply_skb(hdd_ctx->wiphy, 1435 nl_buf_len); 1436 if (!skb) { 1437 hdd_err("wlan_cfg80211_vendor_cmd_alloc_reply_skb failed"); 1438 return -ENOMEM; 1439 } 1440 1441 1442 hdd_debug("Req Id %u", data->requestId); 1443 hdd_debug("Status %u", data->status); 1444 hdd_debug("Scan cache size %u", 1445 data->max_scan_cache_size); 1446 hdd_debug("Scan buckets %u", data->max_scan_buckets); 1447 hdd_debug("Max AP per scan %u", 1448 data->max_ap_cache_per_scan); 1449 hdd_debug("max_rssi_sample_size %u", 1450 data->max_rssi_sample_size); 1451 hdd_debug("max_scan_reporting_threshold %u", 1452 data->max_scan_reporting_threshold); 1453 hdd_debug("max_hotlist_bssids %u", 1454 data->max_hotlist_bssids); 1455 hdd_debug("max_significant_wifi_change_aps %u", 1456 data->max_significant_wifi_change_aps); 1457 hdd_debug("max_bssid_history_entries %u", 1458 data->max_bssid_history_entries); 1459 hdd_debug("max_hotlist_ssids %u", data->max_hotlist_ssids); 1460 hdd_debug("max_number_epno_networks %u", 1461 data->max_number_epno_networks); 1462 hdd_debug("max_number_epno_networks_by_ssid %u", 1463 data->max_number_epno_networks_by_ssid); 1464 hdd_debug("max_number_of_allow_listed_ssid %u", 1465 data->max_number_of_allow_listed_ssid); 1466 hdd_debug("max_number_of_deny_listed_bssid (%u)", 1467 data->max_number_of_deny_listed_bssid); 1468 1469 if (nla_put_u32(skb, PARAM_REQUEST_ID, data->requestId) || 1470 nla_put_u32(skb, PARAM_STATUS, data->status) || 1471 nla_put_u32(skb, MAX_EXTSCAN_CACHE_SIZE, 1472 data->max_scan_cache_size) || 1473 nla_put_u32(skb, MAX_SCAN_BUCKETS, data->max_scan_buckets) || 1474 nla_put_u32(skb, MAX_AP_CACHE_PER_SCAN, 1475 data->max_ap_cache_per_scan) || 1476 nla_put_u32(skb, MAX_RSSI_SAMPLE_SIZE, 1477 data->max_rssi_sample_size) || 1478 nla_put_u32(skb, MAX_SCAN_RPT_THRHOLD, 1479 data->max_scan_reporting_threshold) || 1480 nla_put_u32(skb, MAX_HOTLIST_BSSIDS, data->max_hotlist_bssids) || 1481 nla_put_u32(skb, MAX_SIGNIFICANT_WIFI_CHANGE_APS, 1482 data->max_significant_wifi_change_aps) || 1483 nla_put_u32(skb, MAX_BSSID_HISTORY_ENTRIES, 1484 data->max_bssid_history_entries) || 1485 nla_put_u32(skb, MAX_HOTLIST_SSIDS, data->max_hotlist_ssids) || 1486 nla_put_u32(skb, MAX_NUM_EPNO_NETS, 1487 data->max_number_epno_networks) || 1488 nla_put_u32(skb, MAX_NUM_EPNO_NETS_BY_SSID, 1489 data->max_number_epno_networks_by_ssid) || 1490 nla_put_u32(skb, MAX_NUM_WHITELISTED_SSID, 1491 data->max_number_of_allow_listed_ssid) || 1492 nla_put_u32(skb, MAX_NUM_BLACKLISTED_BSSID, 1493 data->max_number_of_deny_listed_bssid)) { 1494 hdd_err("nla put fail"); 1495 goto nla_put_failure; 1496 } 1497 1498 wlan_cfg80211_vendor_cmd_reply(skb); 1499 return 0; 1500 1501 nla_put_failure: 1502 wlan_cfg80211_vendor_free_skb(skb); 1503 return -EINVAL; 1504 } 1505 /* 1506 * done with short names for the global vendor params 1507 * used by wlan_hdd_send_ext_scan_capability() 1508 */ 1509 #undef PARAM_REQUEST_ID 1510 #undef PARAM_STATUS 1511 #undef MAX_EXTSCAN_CACHE_SIZE 1512 #undef MAX_SCAN_BUCKETS 1513 #undef MAX_AP_CACHE_PER_SCAN 1514 #undef MAX_RSSI_SAMPLE_SIZE 1515 #undef MAX_SCAN_RPT_THRHOLD 1516 #undef MAX_HOTLIST_BSSIDS 1517 #undef MAX_SIGNIFICANT_WIFI_CHANGE_APS 1518 #undef MAX_BSSID_HISTORY_ENTRIES 1519 #undef MAX_HOTLIST_SSIDS 1520 #undef MAX_NUM_EPNO_NETS 1521 #undef MAX_NUM_EPNO_NETS_BY_SSID 1522 #undef MAX_NUM_WHITELISTED_SSID 1523 #undef MAX_NUM_BLACKLISTED_BSSID 1524 1525 /** 1526 * __wlan_hdd_cfg80211_extscan_get_capabilities() - get ext scan capabilities 1527 * @wiphy: Pointer to wireless phy 1528 * @wdev: Pointer to wireless device 1529 * @data: Pointer to data 1530 * @data_len: Data length 1531 * 1532 * Return: none 1533 */ 1534 static int 1535 __wlan_hdd_cfg80211_extscan_get_capabilities(struct wiphy *wiphy, 1536 struct wireless_dev *wdev, 1537 const void *data, int data_len) 1538 { 1539 int id, ret; 1540 unsigned long rc; 1541 struct hdd_ext_scan_context *context; 1542 struct extscan_capabilities_params params; 1543 struct net_device *dev = wdev->netdev; 1544 struct hdd_adapter *adapter = WLAN_HDD_GET_PRIV_PTR(dev); 1545 struct hdd_context *hdd_ctx = wiphy_priv(wiphy); 1546 struct nlattr *tb[EXTSCAN_PARAM_MAX + 1]; 1547 QDF_STATUS status; 1548 1549 hdd_enter_dev(dev); 1550 1551 if (QDF_GLOBAL_FTM_MODE == hdd_get_conparam()) { 1552 hdd_err("Command not allowed in FTM mode"); 1553 return -EPERM; 1554 } 1555 1556 ret = wlan_hdd_validate_context(hdd_ctx); 1557 if (0 != ret) 1558 return -EINVAL; 1559 1560 if (hdd_ctx->driver_status == DRIVER_MODULES_CLOSED) { 1561 hdd_err("Driver Modules are closed"); 1562 return -EINVAL; 1563 } 1564 1565 if (!ucfg_extscan_get_enable(hdd_ctx->psoc)) { 1566 hdd_err("extscan not supported"); 1567 return -ENOTSUPP; 1568 } 1569 if (wlan_cfg80211_nla_parse(tb, EXTSCAN_PARAM_MAX, data, data_len, 1570 wlan_hdd_extscan_config_policy)) { 1571 hdd_err("Invalid ATTR"); 1572 return -EINVAL; 1573 } 1574 1575 /* Parse and fetch request Id */ 1576 id = QCA_WLAN_VENDOR_ATTR_EXTSCAN_SUBCMD_CONFIG_PARAM_REQUEST_ID; 1577 if (!tb[id]) { 1578 hdd_err("attr request id failed"); 1579 return -EINVAL; 1580 } 1581 1582 params.request_id = nla_get_u32(tb[id]); 1583 params.vdev_id = adapter->deflink->vdev_id; 1584 hdd_debug("Req Id %d Vdev Id %d", params.request_id, params.vdev_id); 1585 1586 context = &ext_scan_context; 1587 spin_lock(&context->context_lock); 1588 context->request_id = params.request_id; 1589 INIT_COMPLETION(context->response_event); 1590 spin_unlock(&context->context_lock); 1591 1592 status = sme_ext_scan_get_capabilities(hdd_ctx->mac_handle, ¶ms); 1593 if (!QDF_IS_STATUS_SUCCESS(status)) { 1594 hdd_err("sme_ext_scan_get_capabilities failed(err=%d)", 1595 status); 1596 return -EINVAL; 1597 } 1598 1599 rc = wait_for_completion_timeout(&context->response_event, 1600 msecs_to_jiffies(WLAN_WAIT_TIME_EXTSCAN)); 1601 if (!rc) { 1602 hdd_err("Target response timed out"); 1603 return -ETIMEDOUT; 1604 } 1605 1606 ret = wlan_hdd_send_ext_scan_capability(hdd_ctx); 1607 if (ret) 1608 hdd_err("Failed to send ext scan capability to user space"); 1609 hdd_exit(); 1610 return ret; 1611 } 1612 1613 /** 1614 * wlan_hdd_cfg80211_extscan_get_capabilities() - get ext scan capabilities 1615 * @wiphy: Pointer to wiphy 1616 * @wdev: Pointer to wdev 1617 * @data: Pointer to data 1618 * @data_len: Data length 1619 * 1620 * Return: 0 for success, non-zero for failure 1621 */ 1622 int wlan_hdd_cfg80211_extscan_get_capabilities(struct wiphy *wiphy, 1623 struct wireless_dev *wdev, 1624 const void *data, int data_len) 1625 { 1626 int errno; 1627 struct osif_vdev_sync *vdev_sync; 1628 1629 errno = osif_vdev_sync_op_start(wdev->netdev, &vdev_sync); 1630 if (errno) 1631 return errno; 1632 1633 errno = __wlan_hdd_cfg80211_extscan_get_capabilities(wiphy, wdev, 1634 data, data_len); 1635 1636 osif_vdev_sync_op_stop(vdev_sync); 1637 1638 return errno; 1639 } 1640 1641 /** 1642 * __wlan_hdd_cfg80211_extscan_get_cached_results() - extscan get cached results 1643 * @wiphy: wiphy pointer 1644 * @wdev: pointer to struct wireless_dev 1645 * @data: pointer to incoming NL vendor data 1646 * @data_len: length of @data 1647 * 1648 * This function parses the incoming NL vendor command data attributes and 1649 * invokes the SME Api and blocks on a completion variable. 1650 * Each WMI event with cached scan results data chunk results in 1651 * function call wlan_hdd_cfg80211_extscan_cached_results_ind and each 1652 * data chunk is sent up the layer in wlan_cfg80211_vendor_cmd_alloc_reply_skb. 1653 * 1654 * If timeout happens before receiving all of the data, this function sets 1655 * a context variable @ignore_cached_results to %true, all of the next data 1656 * chunks are checked against this variable and dropped. 1657 * 1658 * Return: 0 on success; error number otherwise. 1659 */ 1660 static int 1661 __wlan_hdd_cfg80211_extscan_get_cached_results(struct wiphy *wiphy, 1662 struct wireless_dev *wdev, 1663 const void *data, 1664 int data_len) 1665 { 1666 struct extscan_cached_result_params params; 1667 struct net_device *dev = wdev->netdev; 1668 struct hdd_adapter *adapter = WLAN_HDD_GET_PRIV_PTR(dev); 1669 struct hdd_context *hdd_ctx = wiphy_priv(wiphy); 1670 struct nlattr *tb[EXTSCAN_PARAM_MAX + 1]; 1671 struct hdd_ext_scan_context *context; 1672 QDF_STATUS status; 1673 int id, retval; 1674 unsigned long rc; 1675 1676 /* ENTER_DEV() intentionally not used in a frequently invoked API */ 1677 1678 if (QDF_GLOBAL_FTM_MODE == hdd_get_conparam()) { 1679 hdd_err("Command not allowed in FTM mode"); 1680 return -EPERM; 1681 } 1682 1683 retval = wlan_hdd_validate_context(hdd_ctx); 1684 if (0 != retval) 1685 return -EINVAL; 1686 1687 if (!ucfg_extscan_get_enable(hdd_ctx->psoc)) { 1688 hdd_err("extscan not supported"); 1689 return -ENOTSUPP; 1690 } 1691 if (wlan_cfg80211_nla_parse(tb, EXTSCAN_PARAM_MAX, data, data_len, 1692 wlan_hdd_extscan_config_policy)) { 1693 hdd_err("Invalid ATTR"); 1694 return -EINVAL; 1695 } 1696 1697 /* Parse and fetch request Id */ 1698 id = QCA_WLAN_VENDOR_ATTR_EXTSCAN_SUBCMD_CONFIG_PARAM_REQUEST_ID; 1699 if (!tb[id]) { 1700 hdd_err("attr request id failed"); 1701 return -EINVAL; 1702 } 1703 1704 params.request_id = nla_get_u32(tb[id]); 1705 params.vdev_id = adapter->deflink->vdev_id; 1706 1707 /* Parse and fetch flush parameter */ 1708 id = QCA_WLAN_VENDOR_ATTR_EXTSCAN_GET_CACHED_SCAN_RESULTS_CONFIG_PARAM_FLUSH; 1709 if (!tb[id]) { 1710 hdd_err("attr flush failed"); 1711 return -EINVAL; 1712 } 1713 params.flush = nla_get_u8(tb[id]); 1714 hdd_debug("Req Id: %u Vdev Id: %d Flush: %d", 1715 params.request_id, params.vdev_id, params.flush); 1716 1717 context = &ext_scan_context; 1718 spin_lock(&context->context_lock); 1719 context->request_id = params.request_id; 1720 context->ignore_cached_results = false; 1721 INIT_COMPLETION(context->response_event); 1722 spin_unlock(&context->context_lock); 1723 1724 status = sme_get_cached_results(hdd_ctx->mac_handle, ¶ms); 1725 if (!QDF_IS_STATUS_SUCCESS(status)) { 1726 hdd_err("sme_get_cached_results failed(err=%d)", status); 1727 return -EINVAL; 1728 } 1729 1730 rc = wait_for_completion_timeout(&context->response_event, 1731 msecs_to_jiffies(WLAN_WAIT_TIME_EXTSCAN)); 1732 if (!rc) { 1733 hdd_err("Target response timed out"); 1734 retval = -ETIMEDOUT; 1735 spin_lock(&context->context_lock); 1736 context->ignore_cached_results = true; 1737 spin_unlock(&context->context_lock); 1738 } else { 1739 spin_lock(&context->context_lock); 1740 retval = context->response_status; 1741 spin_unlock(&context->context_lock); 1742 } 1743 return retval; 1744 } 1745 1746 /** 1747 * wlan_hdd_cfg80211_extscan_get_cached_results() - extscan get cached results 1748 * @wiphy: wiphy pointer 1749 * @wdev: pointer to struct wireless_dev 1750 * @data: pointer to incoming NL vendor data 1751 * @data_len: length of @data 1752 * 1753 * This function parses the incoming NL vendor command data attributes and 1754 * invokes the SME Api and blocks on a completion variable. 1755 * Each WMI event with cached scan results data chunk results in 1756 * function call wlan_hdd_cfg80211_extscan_cached_results_ind and each 1757 * data chunk is sent up the layer in wlan_cfg80211_vendor_cmd_alloc_reply_skb. 1758 * 1759 * If timeout happens before receiving all of the data, this function sets 1760 * a context variable @ignore_cached_results to %true, all of the next data 1761 * chunks are checked against this variable and dropped. 1762 * 1763 * Return: 0 on success; error number otherwise. 1764 */ 1765 int wlan_hdd_cfg80211_extscan_get_cached_results(struct wiphy *wiphy, 1766 struct wireless_dev *wdev, 1767 const void *data, int data_len) 1768 { 1769 int errno; 1770 struct osif_vdev_sync *vdev_sync; 1771 1772 errno = osif_vdev_sync_op_start(wdev->netdev, &vdev_sync); 1773 if (errno) 1774 return errno; 1775 1776 errno = __wlan_hdd_cfg80211_extscan_get_cached_results(wiphy, wdev, 1777 data, data_len); 1778 1779 osif_vdev_sync_op_stop(vdev_sync); 1780 1781 return errno; 1782 } 1783 1784 /** 1785 * hdd_parse_ap_rssi_threshold() - parse AP RSSI threshold parameters 1786 * @attr: netlink attribute containing the AP RSSI threshold parameters 1787 * @ap: destination buffer for the parsed parameters 1788 * 1789 * This function parses the BSSID, low RSSI and high RSSI values from 1790 * the @attr netlink attribute, storing the parsed values in @ap. 1791 * 1792 * Return: 0 if @attr is parsed and all required attributes are 1793 * present, otherwise a negative errno. 1794 */ 1795 static int hdd_parse_ap_rssi_threshold(struct nlattr *attr, 1796 struct ap_threshold_params *ap) 1797 { 1798 struct nlattr *tb[EXTSCAN_PARAM_MAX + 1]; 1799 int id; 1800 1801 if (wlan_cfg80211_nla_parse(tb, EXTSCAN_PARAM_MAX, 1802 nla_data(attr), nla_len(attr), 1803 wlan_hdd_extscan_config_policy)) { 1804 hdd_err("nla_parse failed"); 1805 return -EINVAL; 1806 } 1807 1808 /* Parse and fetch MAC address */ 1809 id = QCA_WLAN_VENDOR_ATTR_EXTSCAN_AP_THRESHOLD_PARAM_BSSID; 1810 if (!tb[id]) { 1811 hdd_err("attr mac address failed"); 1812 return -EINVAL; 1813 } 1814 nla_memcpy(ap->bssid.bytes, tb[id], QDF_MAC_ADDR_SIZE); 1815 hdd_debug("BSSID: " QDF_MAC_ADDR_FMT, 1816 QDF_MAC_ADDR_REF(ap->bssid.bytes)); 1817 1818 /* Parse and fetch low RSSI */ 1819 id = QCA_WLAN_VENDOR_ATTR_EXTSCAN_AP_THRESHOLD_PARAM_RSSI_LOW; 1820 if (!tb[id]) { 1821 hdd_err("attr low RSSI failed"); 1822 return -EINVAL; 1823 } 1824 ap->low = nla_get_s32(tb[id]); 1825 hdd_debug("RSSI low %d", ap->low); 1826 1827 /* Parse and fetch high RSSI */ 1828 id = QCA_WLAN_VENDOR_ATTR_EXTSCAN_AP_THRESHOLD_PARAM_RSSI_HIGH; 1829 if (!tb[id]) { 1830 hdd_err("attr high RSSI failed"); 1831 return -EINVAL; 1832 } 1833 ap->high = nla_get_s32(tb[id]); 1834 hdd_debug("RSSI High %d", ap->high); 1835 1836 return 0; 1837 } 1838 1839 /** 1840 * __wlan_hdd_cfg80211_extscan_set_bssid_hotlist() - set bssid hot list 1841 * @wiphy: Pointer to wireless phy 1842 * @wdev: Pointer to wireless device 1843 * @data: Pointer to data 1844 * @data_len: Data length 1845 * 1846 * Return: none 1847 */ 1848 static int 1849 __wlan_hdd_cfg80211_extscan_set_bssid_hotlist(struct wiphy *wiphy, 1850 struct wireless_dev *wdev, 1851 const void *data, 1852 int data_len) 1853 { 1854 struct extscan_bssid_hotlist_set_params *params; 1855 struct net_device *dev = wdev->netdev; 1856 struct hdd_adapter *adapter = WLAN_HDD_GET_PRIV_PTR(dev); 1857 struct hdd_context *hdd_ctx = wiphy_priv(wiphy); 1858 struct nlattr *tb[EXTSCAN_PARAM_MAX + 1]; 1859 struct nlattr *apth; 1860 struct hdd_ext_scan_context *context; 1861 QDF_STATUS status; 1862 uint8_t i; 1863 int id, rem, retval; 1864 unsigned long rc; 1865 1866 hdd_enter_dev(dev); 1867 1868 if (QDF_GLOBAL_FTM_MODE == hdd_get_conparam()) { 1869 hdd_err("Command not allowed in FTM mode"); 1870 return -EPERM; 1871 } 1872 1873 retval = wlan_hdd_validate_context(hdd_ctx); 1874 if (0 != retval) 1875 return -EINVAL; 1876 1877 if (!ucfg_extscan_get_enable(hdd_ctx->psoc)) { 1878 hdd_err("extscan not supported"); 1879 return -ENOTSUPP; 1880 } 1881 1882 if (wlan_cfg80211_nla_parse(tb, EXTSCAN_PARAM_MAX, 1883 data, data_len, 1884 wlan_hdd_extscan_config_policy)) { 1885 hdd_err("Invalid ATTR"); 1886 return -EINVAL; 1887 } 1888 1889 params = qdf_mem_malloc(sizeof(*params)); 1890 if (!params) 1891 return -ENOMEM; 1892 1893 /* assume the worst until proven otherwise */ 1894 retval = -EINVAL; 1895 1896 /* Parse and fetch request Id */ 1897 id = QCA_WLAN_VENDOR_ATTR_EXTSCAN_SUBCMD_CONFIG_PARAM_REQUEST_ID; 1898 if (!tb[id]) { 1899 hdd_err("attr request id failed"); 1900 goto fail; 1901 } 1902 1903 params->request_id = nla_get_u32(tb[id]); 1904 hdd_debug("Req Id %d", params->request_id); 1905 1906 /* Parse and fetch number of APs */ 1907 id = QCA_WLAN_VENDOR_ATTR_EXTSCAN_BSSID_HOTLIST_PARAMS_NUM_AP; 1908 if (!tb[id]) { 1909 hdd_err("attr number of AP failed"); 1910 goto fail; 1911 } 1912 1913 params->num_ap = nla_get_u32(tb[id]); 1914 if (params->num_ap > WMI_WLAN_EXTSCAN_MAX_HOTLIST_APS) { 1915 hdd_err("Number of AP: %u exceeds max: %u", 1916 params->num_ap, WMI_WLAN_EXTSCAN_MAX_HOTLIST_APS); 1917 goto fail; 1918 } 1919 params->vdev_id = adapter->deflink->vdev_id; 1920 hdd_debug("Number of AP %d vdev Id %d", 1921 params->num_ap, params->vdev_id); 1922 1923 /* Parse and fetch lost ap sample size */ 1924 id = QCA_WLAN_VENDOR_ATTR_EXTSCAN_BSSID_HOTLIST_PARAMS_LOST_AP_SAMPLE_SIZE; 1925 if (!tb[id]) { 1926 hdd_err("attr lost ap sample size failed"); 1927 goto fail; 1928 } 1929 1930 params->lost_ap_sample_size = nla_get_u32(tb[id]); 1931 hdd_debug("Lost ap sample size %d", 1932 params->lost_ap_sample_size); 1933 1934 /* Parse the AP Threshold array */ 1935 id = QCA_WLAN_VENDOR_ATTR_EXTSCAN_AP_THRESHOLD_PARAM; 1936 if (!tb[id]) { 1937 hdd_err("attr ap threshold failed"); 1938 goto fail; 1939 } 1940 1941 i = 0; 1942 nla_for_each_nested(apth, tb[id], rem) { 1943 if (i == params->num_ap) { 1944 hdd_warn("Ignoring excess AP"); 1945 break; 1946 } 1947 1948 retval = hdd_parse_ap_rssi_threshold(apth, ¶ms->ap[i]); 1949 if (retval) 1950 goto fail; 1951 1952 i++; 1953 } 1954 1955 if (i < params->num_ap) { 1956 hdd_warn("Number of AP %u less than expected %u", 1957 i, params->num_ap); 1958 params->num_ap = i; 1959 } 1960 1961 context = &ext_scan_context; 1962 spin_lock(&context->context_lock); 1963 INIT_COMPLETION(context->response_event); 1964 context->request_id = params->request_id; 1965 spin_unlock(&context->context_lock); 1966 1967 status = sme_set_bss_hotlist(hdd_ctx->mac_handle, params); 1968 if (!QDF_IS_STATUS_SUCCESS(status)) { 1969 hdd_err("sme_set_bss_hotlist failed(err=%d)", status); 1970 retval = qdf_status_to_os_return(status); 1971 goto fail; 1972 } 1973 1974 /* request was sent -- wait for the response */ 1975 rc = wait_for_completion_timeout 1976 (&context->response_event, 1977 msecs_to_jiffies(WLAN_WAIT_TIME_EXTSCAN)); 1978 1979 if (!rc) { 1980 hdd_err("sme_set_bss_hotlist timed out"); 1981 retval = -ETIMEDOUT; 1982 } else { 1983 spin_lock(&context->context_lock); 1984 if (context->request_id == params->request_id) 1985 retval = context->response_status; 1986 else 1987 retval = -EINVAL; 1988 spin_unlock(&context->context_lock); 1989 } 1990 hdd_exit(); 1991 1992 fail: 1993 qdf_mem_free(params); 1994 return retval; 1995 } 1996 1997 /** 1998 * wlan_hdd_cfg80211_extscan_set_bssid_hotlist() - set ext scan bssid hotlist 1999 * @wiphy: Pointer to wiphy 2000 * @wdev: Pointer to wdev 2001 * @data: Pointer to data 2002 * @data_len: Data length 2003 * 2004 * Return: 0 for success, non-zero for failure 2005 */ 2006 int wlan_hdd_cfg80211_extscan_set_bssid_hotlist(struct wiphy *wiphy, 2007 struct wireless_dev *wdev, 2008 const void *data, int data_len) 2009 { 2010 int errno; 2011 struct osif_vdev_sync *vdev_sync; 2012 2013 errno = osif_vdev_sync_op_start(wdev->netdev, &vdev_sync); 2014 if (errno) 2015 return errno; 2016 2017 errno = __wlan_hdd_cfg80211_extscan_set_bssid_hotlist(wiphy, wdev, 2018 data, data_len); 2019 2020 osif_vdev_sync_op_stop(vdev_sync); 2021 2022 return errno; 2023 } 2024 2025 2026 /** 2027 * __wlan_hdd_cfg80211_extscan_set_significant_change() - set significant change 2028 * @wiphy: Pointer to wireless phy 2029 * @wdev: Pointer to wireless device 2030 * @data: Pointer to data 2031 * @data_len: Data length 2032 * 2033 * Return: none 2034 */ 2035 static int 2036 __wlan_hdd_cfg80211_extscan_set_significant_change(struct wiphy *wiphy, 2037 struct wireless_dev *wdev, 2038 const void *data, 2039 int data_len) 2040 { 2041 struct extscan_set_sig_changereq_params *params; 2042 struct net_device *dev = wdev->netdev; 2043 struct hdd_adapter *adapter = WLAN_HDD_GET_PRIV_PTR(dev); 2044 struct hdd_context *hdd_ctx = wiphy_priv(wiphy); 2045 struct nlattr *tb[EXTSCAN_PARAM_MAX + 1]; 2046 struct nlattr *apth; 2047 struct hdd_ext_scan_context *context; 2048 QDF_STATUS status; 2049 uint8_t i; 2050 int id, rem, retval; 2051 unsigned long rc; 2052 2053 hdd_enter_dev(dev); 2054 2055 if (QDF_GLOBAL_FTM_MODE == hdd_get_conparam()) { 2056 hdd_err("Command not allowed in FTM mode"); 2057 return -EPERM; 2058 } 2059 2060 retval = wlan_hdd_validate_context(hdd_ctx); 2061 if (0 != retval) 2062 return -EINVAL; 2063 2064 if (wlan_cfg80211_nla_parse(tb, EXTSCAN_PARAM_MAX, 2065 data, data_len, 2066 wlan_hdd_extscan_config_policy)) { 2067 hdd_err("Invalid ATTR"); 2068 return -EINVAL; 2069 } 2070 2071 params = qdf_mem_malloc(sizeof(*params)); 2072 if (!params) 2073 return -ENOMEM; 2074 2075 /* assume the worst until proven otherwise */ 2076 retval = -EINVAL; 2077 2078 /* Parse and fetch request Id */ 2079 id = QCA_WLAN_VENDOR_ATTR_EXTSCAN_SUBCMD_CONFIG_PARAM_REQUEST_ID; 2080 if (!tb[id]) { 2081 hdd_err("attr request id failed"); 2082 goto fail; 2083 } 2084 2085 params->request_id = nla_get_u32(tb[id]); 2086 hdd_debug("Req Id %d", params->request_id); 2087 2088 /* Parse and fetch RSSI sample size */ 2089 id = QCA_WLAN_VENDOR_ATTR_EXTSCAN_SIGNIFICANT_CHANGE_PARAMS_RSSI_SAMPLE_SIZE; 2090 if (!tb[id]) { 2091 hdd_err("attr RSSI sample size failed"); 2092 goto fail; 2093 } 2094 params->rssi_sample_size = nla_get_u32(tb[id]); 2095 hdd_debug("RSSI sample size %u", params->rssi_sample_size); 2096 2097 /* Parse and fetch lost AP sample size */ 2098 id = QCA_WLAN_VENDOR_ATTR_EXTSCAN_SIGNIFICANT_CHANGE_PARAMS_LOST_AP_SAMPLE_SIZE; 2099 if (!tb[id]) { 2100 hdd_err("attr lost AP sample size failed"); 2101 goto fail; 2102 } 2103 params->lostap_sample_size = nla_get_u32(tb[id]); 2104 hdd_debug("Lost AP sample size %u", params->lostap_sample_size); 2105 2106 /* Parse and fetch AP min breaching */ 2107 id = QCA_WLAN_VENDOR_ATTR_EXTSCAN_SIGNIFICANT_CHANGE_PARAMS_MIN_BREACHING; 2108 if (!tb[id]) { 2109 hdd_err("attr AP min breaching"); 2110 goto fail; 2111 } 2112 params->min_breaching = nla_get_u32(tb[id]); 2113 hdd_debug("AP min breaching %u", params->min_breaching); 2114 2115 /* Parse and fetch number of APs */ 2116 id = QCA_WLAN_VENDOR_ATTR_EXTSCAN_SIGNIFICANT_CHANGE_PARAMS_NUM_AP; 2117 if (!tb[id]) { 2118 hdd_err("attr number of AP failed"); 2119 goto fail; 2120 } 2121 params->num_ap = nla_get_u32(tb[id]); 2122 if (params->num_ap > WLAN_EXTSCAN_MAX_SIGNIFICANT_CHANGE_APS) { 2123 hdd_err("Number of AP %u exceeds max %u", 2124 params->num_ap, 2125 WLAN_EXTSCAN_MAX_SIGNIFICANT_CHANGE_APS); 2126 goto fail; 2127 } 2128 2129 params->vdev_id = adapter->deflink->vdev_id; 2130 hdd_debug("Number of AP %d Vdev Id %d", 2131 params->num_ap, params->vdev_id); 2132 2133 id = QCA_WLAN_VENDOR_ATTR_EXTSCAN_AP_THRESHOLD_PARAM; 2134 if (!tb[id]) { 2135 hdd_err("attr ap threshold failed"); 2136 goto fail; 2137 } 2138 i = 0; 2139 nla_for_each_nested(apth, tb[id], rem) { 2140 2141 if (i == params->num_ap) { 2142 hdd_warn("Ignoring excess AP"); 2143 break; 2144 } 2145 2146 retval = hdd_parse_ap_rssi_threshold(apth, ¶ms->ap[i]); 2147 if (retval) 2148 goto fail; 2149 2150 i++; 2151 } 2152 if (i < params->num_ap) { 2153 hdd_warn("Number of AP %u less than expected %u", 2154 i, params->num_ap); 2155 params->num_ap = i; 2156 } 2157 2158 context = &ext_scan_context; 2159 spin_lock(&context->context_lock); 2160 INIT_COMPLETION(context->response_event); 2161 context->request_id = params->request_id; 2162 spin_unlock(&context->context_lock); 2163 2164 status = sme_set_significant_change(hdd_ctx->mac_handle, params); 2165 if (!QDF_IS_STATUS_SUCCESS(status)) { 2166 hdd_err("sme_set_significant_change failed(err=%d)", status); 2167 retval = qdf_status_to_os_return(status); 2168 goto fail; 2169 } 2170 2171 /* request was sent -- wait for the response */ 2172 rc = wait_for_completion_timeout(&context->response_event, 2173 msecs_to_jiffies(WLAN_WAIT_TIME_EXTSCAN)); 2174 2175 if (!rc) { 2176 hdd_err("sme_set_significant_change timed out"); 2177 retval = -ETIMEDOUT; 2178 } else { 2179 spin_lock(&context->context_lock); 2180 if (context->request_id == params->request_id) 2181 retval = context->response_status; 2182 else 2183 retval = -EINVAL; 2184 spin_unlock(&context->context_lock); 2185 } 2186 hdd_exit(); 2187 2188 fail: 2189 qdf_mem_free(params); 2190 return retval; 2191 } 2192 2193 /** 2194 * wlan_hdd_cfg80211_extscan_set_significant_change() - set significant change 2195 * @wiphy: Pointer to wireless phy 2196 * @wdev: Pointer to wireless device 2197 * @data: Pointer to data 2198 * @data_len: Data length 2199 * 2200 * Return: 0 on success, negative errno on failure 2201 */ 2202 int wlan_hdd_cfg80211_extscan_set_significant_change(struct wiphy *wiphy, 2203 struct wireless_dev *wdev, 2204 const void *data, int data_len) 2205 { 2206 int errno; 2207 struct osif_vdev_sync *vdev_sync; 2208 2209 errno = osif_vdev_sync_op_start(wdev->netdev, &vdev_sync); 2210 if (errno) 2211 return errno; 2212 2213 errno = __wlan_hdd_cfg80211_extscan_set_significant_change(wiphy, wdev, 2214 data, 2215 data_len); 2216 2217 osif_vdev_sync_op_stop(vdev_sync); 2218 2219 return errno; 2220 } 2221 2222 /** 2223 * hdd_extscan_update_dwell_time_limits() - update dwell times 2224 * @req_msg: Pointer to request message 2225 * @bkt_idx: Index of current bucket being processed 2226 * @active_min: minimum active dwell time 2227 * @active_max: maximum active dwell time 2228 * @passive_min: minimum passive dwell time 2229 * @passive_max: maximum passive dwell time 2230 * 2231 * Return: none 2232 */ 2233 static void 2234 hdd_extscan_update_dwell_time_limits(struct wifi_scan_cmd_req_params *req_msg, 2235 uint32_t bkt_idx, uint32_t active_min, 2236 uint32_t active_max, uint32_t passive_min, 2237 uint32_t passive_max) 2238 { 2239 /* update per-bucket dwell times */ 2240 if (req_msg->buckets[bkt_idx].min_dwell_time_active > 2241 active_min) { 2242 req_msg->buckets[bkt_idx].min_dwell_time_active = 2243 active_min; 2244 } 2245 if (req_msg->buckets[bkt_idx].max_dwell_time_active < 2246 active_max) { 2247 req_msg->buckets[bkt_idx].max_dwell_time_active = 2248 active_max; 2249 } 2250 if (req_msg->buckets[bkt_idx].min_dwell_time_passive > 2251 passive_min) { 2252 req_msg->buckets[bkt_idx].min_dwell_time_passive = 2253 passive_min; 2254 } 2255 if (req_msg->buckets[bkt_idx].max_dwell_time_passive < 2256 passive_max) { 2257 req_msg->buckets[bkt_idx].max_dwell_time_passive = 2258 passive_max; 2259 } 2260 /* update dwell-time across all buckets */ 2261 if (req_msg->min_dwell_time_active > 2262 req_msg->buckets[bkt_idx].min_dwell_time_active) { 2263 req_msg->min_dwell_time_active = 2264 req_msg->buckets[bkt_idx].min_dwell_time_active; 2265 } 2266 if (req_msg->max_dwell_time_active < 2267 req_msg->buckets[bkt_idx].max_dwell_time_active) { 2268 req_msg->max_dwell_time_active = 2269 req_msg->buckets[bkt_idx].max_dwell_time_active; 2270 } 2271 if (req_msg->min_dwell_time_passive > 2272 req_msg->buckets[bkt_idx].min_dwell_time_passive) { 2273 req_msg->min_dwell_time_passive = 2274 req_msg->buckets[bkt_idx].min_dwell_time_passive; 2275 } 2276 if (req_msg->max_dwell_time_passive > 2277 req_msg->buckets[bkt_idx].max_dwell_time_passive) { 2278 req_msg->max_dwell_time_passive = 2279 req_msg->buckets[bkt_idx].max_dwell_time_passive; 2280 } 2281 } 2282 2283 /** 2284 * hdd_extscan_channel_max_reached() - channel max reached 2285 * @req: extscan request structure 2286 * @total_channels: total number of channels 2287 * 2288 * Return: true if total channels reached max, false otherwise 2289 */ 2290 static bool 2291 hdd_extscan_channel_max_reached(struct wifi_scan_cmd_req_params *req, 2292 uint8_t total_channels) 2293 { 2294 if (total_channels == WMI_WLAN_EXTSCAN_MAX_CHANNELS) { 2295 hdd_warn("max #of channels %d reached, take only first %d bucket(s)", 2296 total_channels, req->num_buckets); 2297 return true; 2298 } 2299 return false; 2300 } 2301 2302 /** 2303 * hdd_extscan_start_fill_bucket_channel_spec() - fill bucket channel spec 2304 * @hdd_ctx: HDD global context 2305 * @req_msg: Pointer to request structure 2306 * @bucket_attr: pointer to bucket attribute 2307 * 2308 * Return: 0 on success; error number otherwise 2309 */ 2310 static int hdd_extscan_start_fill_bucket_channel_spec( 2311 struct hdd_context *hdd_ctx, 2312 struct wifi_scan_cmd_req_params *req_msg, 2313 struct nlattr *bucket_attr) 2314 { 2315 mac_handle_t mac_handle; 2316 struct nlattr *bucket_tb[EXTSCAN_PARAM_MAX + 1]; 2317 struct nlattr *channel_tb[EXTSCAN_PARAM_MAX + 1]; 2318 struct nlattr *buckets; 2319 struct nlattr *channels; 2320 int id, rem1, rem2; 2321 QDF_STATUS status; 2322 uint8_t bkt_index, j, num_channels, total_channels = 0; 2323 uint32_t expected_buckets; 2324 uint32_t expected_channels; 2325 uint32_t chan_list[CFG_VALID_CHANNEL_LIST_LEN] = {0}; 2326 uint32_t extscan_active_min_chn_time; 2327 uint32_t min_dwell_time_active_bucket; 2328 uint32_t max_dwell_time_active_bucket; 2329 uint32_t min_dwell_time_passive_bucket; 2330 uint32_t max_dwell_time_passive_bucket; 2331 struct wifi_scan_bucket_params *bucket; 2332 struct wifi_scan_channelspec_params *channel; 2333 struct nlattr *channel_attr; 2334 2335 ucfg_extscan_get_active_min_time(hdd_ctx->psoc, 2336 &extscan_active_min_chn_time); 2337 ucfg_extscan_get_active_max_time(hdd_ctx->psoc, 2338 &max_dwell_time_active_bucket); 2339 ucfg_extscan_get_passive_max_time(hdd_ctx->psoc, 2340 &max_dwell_time_passive_bucket); 2341 2342 min_dwell_time_active_bucket = max_dwell_time_active_bucket; 2343 min_dwell_time_passive_bucket = max_dwell_time_passive_bucket; 2344 2345 req_msg->min_dwell_time_active = 2346 req_msg->max_dwell_time_active = max_dwell_time_active_bucket; 2347 2348 req_msg->min_dwell_time_passive = 2349 req_msg->max_dwell_time_passive = max_dwell_time_passive_bucket; 2350 2351 expected_buckets = req_msg->num_buckets; 2352 req_msg->num_buckets = 0; 2353 bkt_index = 0; 2354 2355 mac_handle = hdd_ctx->mac_handle; 2356 nla_for_each_nested(buckets, bucket_attr, rem1) { 2357 2358 if (bkt_index >= expected_buckets) { 2359 hdd_warn("ignoring excess buckets"); 2360 break; 2361 } 2362 2363 if (wlan_cfg80211_nla_parse(bucket_tb, EXTSCAN_PARAM_MAX, 2364 nla_data(buckets), nla_len(buckets), 2365 wlan_hdd_extscan_config_policy)) { 2366 hdd_err("nla_parse failed"); 2367 return -EINVAL; 2368 } 2369 2370 bucket = &req_msg->buckets[bkt_index]; 2371 2372 /* Parse and fetch bucket spec */ 2373 id = QCA_WLAN_VENDOR_ATTR_EXTSCAN_BUCKET_SPEC_INDEX; 2374 if (!bucket_tb[id]) { 2375 hdd_err("attr bucket index failed"); 2376 return -EINVAL; 2377 } 2378 bucket->bucket = nla_get_u8(bucket_tb[id]); 2379 2380 /* Parse and fetch wifi band */ 2381 id = QCA_WLAN_VENDOR_ATTR_EXTSCAN_BUCKET_SPEC_BAND; 2382 if (!bucket_tb[id]) { 2383 hdd_err("attr wifi band failed"); 2384 return -EINVAL; 2385 } 2386 bucket->band = nla_get_u8(bucket_tb[id]); 2387 2388 /* Parse and fetch period */ 2389 id = QCA_WLAN_VENDOR_ATTR_EXTSCAN_BUCKET_SPEC_PERIOD; 2390 if (!bucket_tb[id]) { 2391 hdd_err("attr period failed"); 2392 return -EINVAL; 2393 } 2394 bucket->period = nla_get_u32(bucket_tb[id]); 2395 2396 /* Parse and fetch report events */ 2397 id = QCA_WLAN_VENDOR_ATTR_EXTSCAN_BUCKET_SPEC_REPORT_EVENTS; 2398 if (!bucket_tb[id]) { 2399 hdd_err("attr report events failed"); 2400 return -EINVAL; 2401 } 2402 bucket->report_events = nla_get_u8(bucket_tb[id]); 2403 2404 /* Parse and fetch max period */ 2405 id = QCA_WLAN_VENDOR_ATTR_EXTSCAN_BUCKET_SPEC_MAX_PERIOD; 2406 if (!bucket_tb[id]) { 2407 hdd_err("attr max period failed"); 2408 return -EINVAL; 2409 } 2410 bucket->max_period = nla_get_u32(bucket_tb[id]); 2411 2412 /* Parse and fetch base */ 2413 id = QCA_WLAN_VENDOR_ATTR_EXTSCAN_BUCKET_SPEC_BASE; 2414 if (!bucket_tb[id]) { 2415 hdd_err("attr base failed"); 2416 return -EINVAL; 2417 } 2418 bucket->exponent = nla_get_u32(bucket_tb[id]); 2419 2420 /* Parse and fetch step count */ 2421 id = QCA_WLAN_VENDOR_ATTR_EXTSCAN_BUCKET_SPEC_STEP_COUNT; 2422 if (!bucket_tb[id]) { 2423 hdd_err("attr step count failed"); 2424 return -EINVAL; 2425 } 2426 bucket->step_count = nla_get_u32(bucket_tb[id]); 2427 2428 hdd_debug("Bucket spec Index: %d Wifi band: %d period: %d report events: %d max period: %u base: %u Step count: %u", 2429 bucket->bucket, 2430 bucket->band, 2431 bucket->period, 2432 bucket->report_events, 2433 bucket->max_period, 2434 bucket->exponent, 2435 bucket->step_count); 2436 2437 /* start with known good values for bucket dwell times */ 2438 bucket->min_dwell_time_active = max_dwell_time_active_bucket; 2439 bucket->max_dwell_time_active = max_dwell_time_active_bucket; 2440 bucket->min_dwell_time_passive = max_dwell_time_passive_bucket; 2441 bucket->max_dwell_time_passive = max_dwell_time_passive_bucket; 2442 2443 /* Framework shall pass the channel list if the input 2444 * WiFi band is WMI_WIFI_BAND_UNSPECIFIED. If the 2445 * input WiFi band is specified (any value other than 2446 * WMI_WIFI_BAND_UNSPECIFIED) then driver populates 2447 * the channel list. 2448 */ 2449 if (bucket->band != WMI_WIFI_BAND_UNSPECIFIED) { 2450 if (hdd_extscan_channel_max_reached(req_msg, 2451 total_channels)) 2452 return 0; 2453 2454 num_channels = 0; 2455 hdd_debug("WiFi band is specified, driver to fill channel list"); 2456 status = sme_get_valid_channels_by_band(mac_handle, 2457 bucket->band, 2458 chan_list, 2459 &num_channels); 2460 if (!QDF_IS_STATUS_SUCCESS(status)) { 2461 hdd_err("sme_get_valid_channels_by_band failed (err=%d)", 2462 status); 2463 return -EINVAL; 2464 } 2465 hdd_debug("before trimming, num_channels: %d", 2466 num_channels); 2467 2468 bucket->num_channels = 2469 QDF_MIN(num_channels, 2470 (WMI_WLAN_EXTSCAN_MAX_CHANNELS - 2471 total_channels)); 2472 hdd_debug("Adj Num channels/bucket: %d total_channels: %d", 2473 bucket->num_channels, total_channels); 2474 total_channels += bucket->num_channels; 2475 2476 for (j = 0; j < bucket->num_channels; j++) { 2477 channel = &bucket->channels[j]; 2478 2479 channel->channel = chan_list[j]; 2480 channel->channel_class = 0; 2481 if ((wlan_reg_get_channel_state_for_pwrmode( 2482 hdd_ctx->pdev, chan_list[j], 2483 REG_CURRENT_PWR_MODE)) != 2484 CHANNEL_STATE_ENABLE) { 2485 channel->passive = 1; 2486 channel->dwell_time_ms = 2487 max_dwell_time_passive_bucket; 2488 /* reconfigure per-bucket dwell time */ 2489 if (min_dwell_time_passive_bucket > 2490 channel->dwell_time_ms) { 2491 min_dwell_time_passive_bucket = 2492 channel->dwell_time_ms; 2493 } 2494 if (max_dwell_time_passive_bucket < 2495 channel->dwell_time_ms) { 2496 max_dwell_time_passive_bucket = 2497 channel->dwell_time_ms; 2498 } 2499 2500 } else { 2501 channel->passive = 0; 2502 channel->dwell_time_ms = 2503 max_dwell_time_active_bucket; 2504 /* reconfigure per-bucket dwell times */ 2505 if (min_dwell_time_active_bucket > 2506 channel->dwell_time_ms) { 2507 min_dwell_time_active_bucket = 2508 channel->dwell_time_ms; 2509 } 2510 if (max_dwell_time_active_bucket < 2511 channel->dwell_time_ms) { 2512 max_dwell_time_active_bucket = 2513 channel->dwell_time_ms; 2514 } 2515 2516 } 2517 2518 hdd_debug("Channel: %u Passive: %u Dwell time: %u ms Class: %u", 2519 channel->channel, 2520 channel->passive, 2521 channel->dwell_time_ms, 2522 channel->channel_class); 2523 } 2524 2525 hdd_extscan_update_dwell_time_limits( 2526 req_msg, bkt_index, 2527 min_dwell_time_active_bucket, 2528 max_dwell_time_active_bucket, 2529 min_dwell_time_passive_bucket, 2530 max_dwell_time_passive_bucket); 2531 2532 hdd_debug("bkt_index:%d actv_min:%d actv_max:%d pass_min:%d pass_max:%d", 2533 bkt_index, 2534 bucket->min_dwell_time_active, 2535 bucket->max_dwell_time_active, 2536 bucket->min_dwell_time_passive, 2537 bucket->max_dwell_time_passive); 2538 2539 bkt_index++; 2540 req_msg->num_buckets++; 2541 continue; 2542 } 2543 2544 /* Parse and fetch number of channels */ 2545 id = QCA_WLAN_VENDOR_ATTR_EXTSCAN_BUCKET_SPEC_NUM_CHANNEL_SPECS; 2546 if (!bucket_tb[id]) { 2547 hdd_err("attr num channels failed"); 2548 return -EINVAL; 2549 } 2550 bucket->num_channels = nla_get_u32(bucket_tb[id]); 2551 hdd_debug("before trimming: num channels %d", 2552 bucket->num_channels); 2553 2554 bucket->num_channels = 2555 QDF_MIN(bucket->num_channels, 2556 (WMI_WLAN_EXTSCAN_MAX_CHANNELS - 2557 total_channels)); 2558 hdd_debug("Num channels/bucket: %d total_channels: %d", 2559 bucket->num_channels, total_channels); 2560 2561 if (hdd_extscan_channel_max_reached(req_msg, total_channels)) 2562 return 0; 2563 2564 id = QCA_WLAN_VENDOR_ATTR_EXTSCAN_CHANNEL_SPEC; 2565 channel_attr = bucket_tb[id]; 2566 if (!channel_attr) { 2567 hdd_err("attr channel spec failed"); 2568 return -EINVAL; 2569 } 2570 2571 expected_channels = bucket->num_channels; 2572 bucket->num_channels = 0; 2573 2574 nla_for_each_nested(channels, channel_attr, rem2) { 2575 if ((bucket->num_channels >= expected_channels) || 2576 hdd_extscan_channel_max_reached(req_msg, 2577 total_channels)) 2578 break; 2579 2580 if (wlan_cfg80211_nla_parse(channel_tb, 2581 EXTSCAN_PARAM_MAX, 2582 nla_data(channels), 2583 nla_len(channels), 2584 wlan_hdd_extscan_config_policy)) { 2585 hdd_err("nla_parse failed"); 2586 return -EINVAL; 2587 } 2588 2589 channel = &bucket->channels[bucket->num_channels]; 2590 /* Parse and fetch channel */ 2591 if (!channel_tb[ 2592 QCA_WLAN_VENDOR_ATTR_EXTSCAN_CHANNEL_SPEC_CHANNEL]) { 2593 hdd_err("attr channel failed"); 2594 return -EINVAL; 2595 } 2596 channel->channel = 2597 nla_get_u32(channel_tb[ 2598 QCA_WLAN_VENDOR_ATTR_EXTSCAN_CHANNEL_SPEC_CHANNEL]); 2599 hdd_debug("channel %u", 2600 channel->channel); 2601 2602 /* Parse and fetch dwell time */ 2603 if (!channel_tb[ 2604 QCA_WLAN_VENDOR_ATTR_EXTSCAN_CHANNEL_SPEC_DWELL_TIME]) { 2605 hdd_err("attr dwelltime failed"); 2606 return -EINVAL; 2607 } 2608 channel->dwell_time_ms = 2609 nla_get_u32(channel_tb[ 2610 QCA_WLAN_VENDOR_ATTR_EXTSCAN_CHANNEL_SPEC_DWELL_TIME]); 2611 2612 /* Override dwell time if required */ 2613 if (channel->dwell_time_ms < 2614 extscan_active_min_chn_time || 2615 channel->dwell_time_ms > 2616 max_dwell_time_active_bucket) { 2617 hdd_debug("WiFi band is unspecified, dwellTime:%d", 2618 channel->dwell_time_ms); 2619 2620 if ((wlan_reg_get_channel_state_for_pwrmode( 2621 hdd_ctx->pdev, channel->channel, 2622 REG_CURRENT_PWR_MODE)) != 2623 CHANNEL_STATE_ENABLE) { 2624 channel->dwell_time_ms = 2625 max_dwell_time_passive_bucket; 2626 } else { 2627 channel->dwell_time_ms = 2628 max_dwell_time_active_bucket; 2629 } 2630 } 2631 2632 hdd_debug("New Dwell time %u ms", 2633 channel->dwell_time_ms); 2634 2635 if ((wlan_reg_get_channel_state_for_pwrmode( 2636 hdd_ctx->pdev, channel->channel, 2637 REG_CURRENT_PWR_MODE)) != 2638 CHANNEL_STATE_ENABLE) { 2639 if (min_dwell_time_passive_bucket > 2640 channel->dwell_time_ms) { 2641 min_dwell_time_passive_bucket = 2642 channel->dwell_time_ms; 2643 } 2644 if (max_dwell_time_passive_bucket < 2645 channel->dwell_time_ms) { 2646 max_dwell_time_passive_bucket = 2647 channel->dwell_time_ms; 2648 } 2649 } else { 2650 if (min_dwell_time_active_bucket > 2651 channel->dwell_time_ms) { 2652 min_dwell_time_active_bucket = 2653 channel->dwell_time_ms; 2654 } 2655 if (max_dwell_time_active_bucket < 2656 channel->dwell_time_ms) { 2657 max_dwell_time_active_bucket = 2658 channel->dwell_time_ms; 2659 } 2660 } 2661 2662 /* Parse and fetch channel spec passive */ 2663 if (!channel_tb[ 2664 QCA_WLAN_VENDOR_ATTR_EXTSCAN_CHANNEL_SPEC_PASSIVE]) { 2665 hdd_err("attr channel spec passive failed"); 2666 return -EINVAL; 2667 } 2668 channel->passive = 2669 nla_get_u8(channel_tb[ 2670 QCA_WLAN_VENDOR_ATTR_EXTSCAN_CHANNEL_SPEC_PASSIVE]); 2671 hdd_debug("Chnl spec passive %u", 2672 channel->passive); 2673 /* Override scan type if required */ 2674 if ((wlan_reg_get_channel_state_for_pwrmode( 2675 hdd_ctx->pdev, 2676 channel->channel, 2677 REG_CURRENT_PWR_MODE)) 2678 != CHANNEL_STATE_ENABLE) { 2679 channel->passive = true; 2680 } else { 2681 channel->passive = false; 2682 } 2683 total_channels++; 2684 bucket->num_channels++; 2685 } 2686 2687 if (bucket->num_channels != expected_channels) 2688 hdd_warn("channels: Expected %u got %u", 2689 expected_channels, 2690 bucket->num_channels); 2691 2692 hdd_extscan_update_dwell_time_limits( 2693 req_msg, bkt_index, 2694 min_dwell_time_active_bucket, 2695 max_dwell_time_active_bucket, 2696 min_dwell_time_passive_bucket, 2697 max_dwell_time_passive_bucket); 2698 2699 hdd_debug("bktIndex:%d actv_min:%d actv_max:%d pass_min:%d pass_max:%d", 2700 bkt_index, 2701 bucket->min_dwell_time_active, 2702 bucket->max_dwell_time_active, 2703 bucket->min_dwell_time_passive, 2704 bucket->max_dwell_time_passive); 2705 2706 bkt_index++; 2707 req_msg->num_buckets++; 2708 } 2709 2710 hdd_debug("Global: actv_min:%d actv_max:%d pass_min:%d pass_max:%d", 2711 req_msg->min_dwell_time_active, 2712 req_msg->max_dwell_time_active, 2713 req_msg->min_dwell_time_passive, 2714 req_msg->max_dwell_time_passive); 2715 return 0; 2716 } 2717 2718 /* 2719 * hdd_extscan_map_usr_drv_config_flags() - map userspace to driver config flags 2720 * @config_flags - [input] configuration flags. 2721 * 2722 * This function maps user space received configuration flags to 2723 * driver representation. 2724 * 2725 * Return: configuration flags 2726 */ 2727 static uint32_t hdd_extscan_map_usr_drv_config_flags(uint32_t config_flags) 2728 { 2729 uint32_t configuration_flags = 0; 2730 2731 if (config_flags & EXTSCAN_LP_EXTENDED_BATCHING) 2732 configuration_flags |= EXTSCAN_LP_EXTENDED_BATCHING; 2733 2734 return configuration_flags; 2735 } 2736 2737 /** 2738 * __wlan_hdd_cfg80211_extscan_start() - ext scan start 2739 * @wiphy: Pointer to wireless phy 2740 * @wdev: Pointer to wireless device 2741 * @data: Pointer to data 2742 * @data_len: Length of @data 2743 * 2744 * Return: 0 on success; error number otherwise 2745 */ 2746 static int 2747 __wlan_hdd_cfg80211_extscan_start(struct wiphy *wiphy, 2748 struct wireless_dev *wdev, 2749 const void *data, 2750 int data_len) 2751 { 2752 struct wifi_scan_cmd_req_params *params; 2753 struct net_device *dev = wdev->netdev; 2754 struct hdd_adapter *adapter = WLAN_HDD_GET_PRIV_PTR(dev); 2755 struct hdd_context *hdd_ctx = wiphy_priv(wiphy); 2756 struct nlattr *tb[EXTSCAN_PARAM_MAX + 1]; 2757 struct hdd_ext_scan_context *context; 2758 uint32_t num_buckets; 2759 QDF_STATUS status; 2760 int retval, id; 2761 unsigned long rc; 2762 2763 hdd_enter_dev(dev); 2764 2765 if (QDF_GLOBAL_FTM_MODE == hdd_get_conparam()) { 2766 hdd_err("Command not allowed in FTM mode"); 2767 return -EPERM; 2768 } 2769 2770 if (QDF_NDI_MODE == adapter->device_mode) { 2771 hdd_err("Command not allowed for NDI interface"); 2772 return -EPERM; 2773 } 2774 2775 retval = wlan_hdd_validate_context(hdd_ctx); 2776 if (0 != retval) 2777 return -EINVAL; 2778 2779 if (!ucfg_extscan_get_enable(hdd_ctx->psoc)) { 2780 hdd_err("extscan not supported"); 2781 return -ENOTSUPP; 2782 } 2783 if (wlan_cfg80211_nla_parse(tb, EXTSCAN_PARAM_MAX, data, data_len, 2784 wlan_hdd_extscan_config_policy)) { 2785 hdd_err("Invalid ATTR"); 2786 return -EINVAL; 2787 } 2788 2789 params = qdf_mem_malloc(sizeof(*params)); 2790 if (!params) 2791 return -ENOMEM; 2792 2793 /* assume the worst until proven otherwise */ 2794 retval = -EINVAL; 2795 2796 /* Parse and fetch request Id */ 2797 id = QCA_WLAN_VENDOR_ATTR_EXTSCAN_SUBCMD_CONFIG_PARAM_REQUEST_ID; 2798 if (!tb[id]) { 2799 hdd_err("attr request id failed"); 2800 goto fail; 2801 } 2802 2803 params->request_id = nla_get_u32(tb[id]); 2804 params->vdev_id = adapter->deflink->vdev_id; 2805 2806 /* Parse and fetch base period */ 2807 id = QCA_WLAN_VENDOR_ATTR_EXTSCAN_SCAN_CMD_PARAMS_BASE_PERIOD; 2808 if (!tb[id]) { 2809 hdd_err("attr base period failed"); 2810 goto fail; 2811 } 2812 params->base_period = nla_get_u32(tb[id]); 2813 2814 /* Parse and fetch max AP per scan */ 2815 id = QCA_WLAN_VENDOR_ATTR_EXTSCAN_SCAN_CMD_PARAMS_MAX_AP_PER_SCAN; 2816 if (!tb[id]) { 2817 hdd_err("attr max_ap_per_scan failed"); 2818 goto fail; 2819 } 2820 params->max_ap_per_scan = nla_get_u32(tb[id]); 2821 2822 /* Parse and fetch report threshold percent */ 2823 id = QCA_WLAN_VENDOR_ATTR_EXTSCAN_SCAN_CMD_PARAMS_REPORT_THRESHOLD_PERCENT; 2824 if (!tb[id]) { 2825 hdd_err("attr report_threshold percent failed"); 2826 goto fail; 2827 } 2828 params->report_threshold_percent = nla_get_u8(tb[id]); 2829 2830 /* Parse and fetch report threshold num scans */ 2831 id = QCA_WLAN_VENDOR_ATTR_EXTSCAN_SCAN_CMD_PARAMS_REPORT_THRESHOLD_NUM_SCANS; 2832 if (!tb[id]) { 2833 hdd_err("attr report_threshold num scans failed"); 2834 goto fail; 2835 } 2836 params->report_threshold_num_scans = nla_get_u8(tb[id]); 2837 hdd_debug("Req Id: %d Vdev Id: %d Base Period: %d Max AP per Scan: %d Report Threshold percent: %d Report Threshold num scans: %d", 2838 params->request_id, params->vdev_id, 2839 params->base_period, params->max_ap_per_scan, 2840 params->report_threshold_percent, 2841 params->report_threshold_num_scans); 2842 2843 /* Parse and fetch number of buckets */ 2844 id = QCA_WLAN_VENDOR_ATTR_EXTSCAN_SCAN_CMD_PARAMS_NUM_BUCKETS; 2845 if (!tb[id]) { 2846 hdd_err("attr number of buckets failed"); 2847 goto fail; 2848 } 2849 num_buckets = nla_get_u8(tb[id]); 2850 2851 if (num_buckets > WMI_WLAN_EXTSCAN_MAX_BUCKETS) { 2852 hdd_warn("Exceeded MAX number of buckets: %d", 2853 WMI_WLAN_EXTSCAN_MAX_BUCKETS); 2854 num_buckets = WMI_WLAN_EXTSCAN_MAX_BUCKETS; 2855 } 2856 hdd_debug("Input: Number of Buckets %d", num_buckets); 2857 params->num_buckets = num_buckets; 2858 2859 /* This is optional attribute, if not present set it to 0 */ 2860 id = QCA_WLAN_VENDOR_ATTR_EXTSCAN_CONFIGURATION_FLAGS; 2861 if (!tb[id]) 2862 params->configuration_flags = 0; 2863 else 2864 params->configuration_flags = 2865 hdd_extscan_map_usr_drv_config_flags( 2866 nla_get_u32(tb[id])); 2867 2868 params->extscan_adaptive_dwell_mode = 2869 ucfg_scan_get_extscan_adaptive_dwell_mode(hdd_ctx->psoc); 2870 2871 hdd_debug("Configuration flags: %u", 2872 params->configuration_flags); 2873 2874 /* Parse and fetch number the array of buckets */ 2875 id = QCA_WLAN_VENDOR_ATTR_EXTSCAN_BUCKET_SPEC; 2876 if (!tb[id]) { 2877 hdd_err("attr bucket spec failed"); 2878 goto fail; 2879 } 2880 retval = hdd_extscan_start_fill_bucket_channel_spec(hdd_ctx, params, 2881 tb[id]); 2882 if (retval) 2883 goto fail; 2884 2885 context = &ext_scan_context; 2886 spin_lock(&context->context_lock); 2887 INIT_COMPLETION(context->response_event); 2888 context->request_id = params->request_id; 2889 context->buckets_scanned = 0; 2890 spin_unlock(&context->context_lock); 2891 2892 status = sme_ext_scan_start(hdd_ctx->mac_handle, params); 2893 if (!QDF_IS_STATUS_SUCCESS(status)) { 2894 hdd_err("sme_ext_scan_start failed(err=%d)", status); 2895 retval = qdf_status_to_os_return(status); 2896 goto fail; 2897 } 2898 2899 hdd_ctx->ext_scan_start_since_boot = qdf_get_monotonic_boottime(); 2900 hdd_debug("Timestamp since boot: %llu", 2901 hdd_ctx->ext_scan_start_since_boot); 2902 2903 /* request was sent -- wait for the response */ 2904 rc = wait_for_completion_timeout(&context->response_event, 2905 msecs_to_jiffies(WLAN_WAIT_TIME_EXTSCAN)); 2906 2907 if (!rc) { 2908 hdd_err("sme_ext_scan_start timed out"); 2909 retval = -ETIMEDOUT; 2910 } else { 2911 spin_lock(&context->context_lock); 2912 if (context->request_id == params->request_id) 2913 retval = context->response_status; 2914 else 2915 retval = -EINVAL; 2916 spin_unlock(&context->context_lock); 2917 } 2918 hdd_exit(); 2919 2920 fail: 2921 qdf_mem_free(params); 2922 return retval; 2923 } 2924 2925 /** 2926 * wlan_hdd_cfg80211_extscan_start() - start extscan 2927 * @wiphy: Pointer to wireless phy. 2928 * @wdev: Pointer to wireless device. 2929 * @data: Pointer to input data. 2930 * @data_len: Length of @data. 2931 * 2932 * Return: 0 on success, negative errno on failure 2933 */ 2934 int wlan_hdd_cfg80211_extscan_start(struct wiphy *wiphy, 2935 struct wireless_dev *wdev, 2936 const void *data, int data_len) 2937 { 2938 int errno; 2939 struct osif_vdev_sync *vdev_sync; 2940 2941 errno = osif_vdev_sync_op_start(wdev->netdev, &vdev_sync); 2942 if (errno) 2943 return errno; 2944 2945 errno = __wlan_hdd_cfg80211_extscan_start(wiphy, wdev, data, data_len); 2946 2947 osif_vdev_sync_op_stop(vdev_sync); 2948 2949 return errno; 2950 } 2951 2952 2953 /** 2954 * __wlan_hdd_cfg80211_extscan_stop() - ext scan stop 2955 * @wiphy: Pointer to wireless phy 2956 * @wdev: Pointer to wireless device 2957 * @data: Pointer to data 2958 * @data_len: Data length 2959 * 2960 * Return: none 2961 */ 2962 static int 2963 __wlan_hdd_cfg80211_extscan_stop(struct wiphy *wiphy, 2964 struct wireless_dev *wdev, 2965 const void *data, int data_len) 2966 { 2967 struct extscan_stop_req_params params; 2968 struct net_device *dev = wdev->netdev; 2969 struct hdd_adapter *adapter = WLAN_HDD_GET_PRIV_PTR(dev); 2970 struct hdd_context *hdd_ctx = wiphy_priv(wiphy); 2971 struct nlattr *tb[EXTSCAN_PARAM_MAX + 1]; 2972 struct hdd_ext_scan_context *context; 2973 QDF_STATUS status; 2974 int id, retval; 2975 unsigned long rc; 2976 2977 hdd_enter_dev(dev); 2978 2979 if (QDF_GLOBAL_FTM_MODE == hdd_get_conparam()) { 2980 hdd_err("Command not allowed in FTM mode"); 2981 return -EPERM; 2982 } 2983 2984 retval = wlan_hdd_validate_context(hdd_ctx); 2985 if (0 != retval) 2986 return -EINVAL; 2987 2988 if (!ucfg_extscan_get_enable(hdd_ctx->psoc)) { 2989 hdd_err("extscan not supported"); 2990 return -ENOTSUPP; 2991 } 2992 2993 if (wlan_cfg80211_nla_parse(tb, EXTSCAN_PARAM_MAX, data, data_len, 2994 wlan_hdd_extscan_config_policy)) { 2995 hdd_err("Invalid ATTR"); 2996 return -EINVAL; 2997 } 2998 2999 /* Parse and fetch request Id */ 3000 id = QCA_WLAN_VENDOR_ATTR_EXTSCAN_SUBCMD_CONFIG_PARAM_REQUEST_ID; 3001 if (!tb[id]) { 3002 hdd_err("attr request id failed"); 3003 return -EINVAL; 3004 } 3005 params.request_id = nla_get_u32(tb[id]); 3006 params.vdev_id = adapter->deflink->vdev_id; 3007 hdd_debug("Req Id %d Vdev Id %d", 3008 params.request_id, params.vdev_id); 3009 3010 context = &ext_scan_context; 3011 spin_lock(&context->context_lock); 3012 INIT_COMPLETION(context->response_event); 3013 context->request_id = params.request_id; 3014 spin_unlock(&context->context_lock); 3015 3016 status = sme_ext_scan_stop(hdd_ctx->mac_handle, ¶ms); 3017 if (!QDF_IS_STATUS_SUCCESS(status)) { 3018 hdd_err("sme_ext_scan_stop failed(err=%d)", status); 3019 return qdf_status_to_os_return(status); 3020 } 3021 3022 /* request was sent -- wait for the response */ 3023 rc = wait_for_completion_timeout(&context->response_event, 3024 msecs_to_jiffies(WLAN_WAIT_TIME_EXTSCAN)); 3025 3026 if (!rc) { 3027 hdd_err("sme_ext_scan_stop timed out"); 3028 retval = -ETIMEDOUT; 3029 } else { 3030 spin_lock(&context->context_lock); 3031 if (context->request_id == params.request_id) 3032 retval = context->response_status; 3033 else 3034 retval = -EINVAL; 3035 spin_unlock(&context->context_lock); 3036 } 3037 hdd_exit(); 3038 return retval; 3039 } 3040 3041 /** 3042 * wlan_hdd_cfg80211_extscan_stop() - stop extscan 3043 * @wiphy: Pointer to wireless phy. 3044 * @wdev: Pointer to wireless device. 3045 * @data: Pointer to input data. 3046 * @data_len: Length of @data. 3047 * 3048 * Return: 0 on success, negative errno on failure 3049 */ 3050 int wlan_hdd_cfg80211_extscan_stop(struct wiphy *wiphy, 3051 struct wireless_dev *wdev, 3052 const void *data, int data_len) 3053 { 3054 int errno; 3055 struct osif_vdev_sync *vdev_sync; 3056 3057 errno = osif_vdev_sync_op_start(wdev->netdev, &vdev_sync); 3058 if (errno) 3059 return errno; 3060 3061 errno = __wlan_hdd_cfg80211_extscan_stop(wiphy, wdev, data, data_len); 3062 3063 osif_vdev_sync_op_stop(vdev_sync); 3064 3065 return errno; 3066 } 3067 3068 /** 3069 * __wlan_hdd_cfg80211_extscan_reset_bssid_hotlist() - reset bssid hotlist 3070 * @wiphy: Pointer to wireless phy 3071 * @wdev: Pointer to wireless device 3072 * @data: Pointer to data 3073 * @data_len: Data length 3074 * 3075 * Return: none 3076 */ 3077 static int 3078 __wlan_hdd_cfg80211_extscan_reset_bssid_hotlist(struct wiphy *wiphy, 3079 struct wireless_dev *wdev, 3080 const void *data, 3081 int data_len) 3082 { 3083 struct extscan_bssid_hotlist_reset_params params; 3084 struct net_device *dev = wdev->netdev; 3085 struct hdd_adapter *adapter = WLAN_HDD_GET_PRIV_PTR(dev); 3086 struct hdd_context *hdd_ctx = wiphy_priv(wiphy); 3087 struct nlattr *tb[EXTSCAN_PARAM_MAX + 1]; 3088 struct hdd_ext_scan_context *context; 3089 QDF_STATUS status; 3090 int id, retval; 3091 unsigned long rc; 3092 3093 hdd_enter_dev(dev); 3094 3095 if (QDF_GLOBAL_FTM_MODE == hdd_get_conparam()) { 3096 hdd_err("Command not allowed in FTM mode"); 3097 return -EPERM; 3098 } 3099 3100 retval = wlan_hdd_validate_context(hdd_ctx); 3101 if (0 != retval) 3102 return -EINVAL; 3103 3104 if (!ucfg_extscan_get_enable(hdd_ctx->psoc)) { 3105 hdd_err("extscan not supported"); 3106 return -ENOTSUPP; 3107 } 3108 3109 if (wlan_cfg80211_nla_parse(tb, EXTSCAN_PARAM_MAX, 3110 data, data_len, 3111 wlan_hdd_extscan_config_policy)) { 3112 hdd_err("Invalid ATTR"); 3113 return -EINVAL; 3114 } 3115 3116 /* Parse and fetch request Id */ 3117 id = QCA_WLAN_VENDOR_ATTR_EXTSCAN_SUBCMD_CONFIG_PARAM_REQUEST_ID; 3118 if (!tb[id]) { 3119 hdd_err("attr request id failed"); 3120 return -EINVAL; 3121 } 3122 3123 params.request_id = nla_get_u32(tb[id]); 3124 params.vdev_id = adapter->deflink->vdev_id; 3125 hdd_debug("Req Id %d vdev Id %d", params.request_id, params.vdev_id); 3126 3127 context = &ext_scan_context; 3128 spin_lock(&context->context_lock); 3129 INIT_COMPLETION(context->response_event); 3130 context->request_id = params.request_id; 3131 spin_unlock(&context->context_lock); 3132 3133 status = sme_reset_bss_hotlist(hdd_ctx->mac_handle, ¶ms); 3134 if (!QDF_IS_STATUS_SUCCESS(status)) { 3135 hdd_err("sme_reset_bss_hotlist failed(err=%d)", status); 3136 return qdf_status_to_os_return(status); 3137 } 3138 3139 /* request was sent -- wait for the response */ 3140 rc = wait_for_completion_timeout 3141 (&context->response_event, 3142 msecs_to_jiffies(WLAN_WAIT_TIME_EXTSCAN)); 3143 if (!rc) { 3144 hdd_err("sme_reset_bss_hotlist timed out"); 3145 retval = -ETIMEDOUT; 3146 } else { 3147 spin_lock(&context->context_lock); 3148 if (context->request_id == params.request_id) 3149 retval = context->response_status; 3150 else 3151 retval = -EINVAL; 3152 spin_unlock(&context->context_lock); 3153 } 3154 hdd_exit(); 3155 return retval; 3156 } 3157 3158 /** 3159 * wlan_hdd_cfg80211_extscan_reset_bssid_hotlist() - reset bssid hot list 3160 * @wiphy: Pointer to wireless phy 3161 * @wdev: Pointer to wireless device 3162 * @data: Pointer to data 3163 * @data_len: Data length 3164 * 3165 * Return: 0 on success, negative errno on failure 3166 */ 3167 int wlan_hdd_cfg80211_extscan_reset_bssid_hotlist(struct wiphy *wiphy, 3168 struct wireless_dev *wdev, 3169 const void *data, 3170 int data_len) 3171 { 3172 int errno; 3173 struct osif_vdev_sync *vdev_sync; 3174 3175 errno = osif_vdev_sync_op_start(wdev->netdev, &vdev_sync); 3176 if (errno) 3177 return errno; 3178 3179 errno = __wlan_hdd_cfg80211_extscan_reset_bssid_hotlist(wiphy, wdev, 3180 data, data_len); 3181 3182 osif_vdev_sync_op_stop(vdev_sync); 3183 3184 return errno; 3185 } 3186 3187 /** 3188 * __wlan_hdd_cfg80211_extscan_reset_significant_change() - 3189 * reset significant change 3190 * @wiphy: Pointer to wireless phy 3191 * @wdev: Pointer to wireless device 3192 * @data: Pointer to data 3193 * @data_len: Data length 3194 * 3195 * Return: none 3196 */ 3197 static int 3198 __wlan_hdd_cfg80211_extscan_reset_significant_change(struct wiphy *wiphy, 3199 struct wireless_dev *wdev, 3200 const void *data, 3201 int data_len) 3202 { 3203 struct extscan_capabilities_reset_params params; 3204 struct net_device *dev = wdev->netdev; 3205 struct hdd_adapter *adapter = WLAN_HDD_GET_PRIV_PTR(dev); 3206 struct hdd_context *hdd_ctx = wiphy_priv(wiphy); 3207 struct nlattr *tb[EXTSCAN_PARAM_MAX + 1]; 3208 struct hdd_ext_scan_context *context; 3209 QDF_STATUS status; 3210 int id, retval; 3211 unsigned long rc; 3212 3213 hdd_enter_dev(dev); 3214 3215 if (QDF_GLOBAL_FTM_MODE == hdd_get_conparam()) { 3216 hdd_err("Command not allowed in FTM mode"); 3217 return -EPERM; 3218 } 3219 3220 retval = wlan_hdd_validate_context(hdd_ctx); 3221 if (0 != retval) 3222 return -EINVAL; 3223 3224 if (!ucfg_extscan_get_enable(hdd_ctx->psoc)) { 3225 hdd_err("extscan not supported"); 3226 return -ENOTSUPP; 3227 } 3228 3229 if (wlan_cfg80211_nla_parse(tb, EXTSCAN_PARAM_MAX, data, data_len, 3230 wlan_hdd_extscan_config_policy)) { 3231 hdd_err("Invalid ATTR"); 3232 return -EINVAL; 3233 } 3234 3235 /* Parse and fetch request Id */ 3236 id = QCA_WLAN_VENDOR_ATTR_EXTSCAN_SUBCMD_CONFIG_PARAM_REQUEST_ID; 3237 if (!tb[id]) { 3238 hdd_err("attr request id failed"); 3239 return -EINVAL; 3240 } 3241 3242 params.request_id = nla_get_u32(tb[id]); 3243 params.vdev_id = adapter->deflink->vdev_id; 3244 hdd_debug("Req Id %d Vdev Id %d", params.request_id, params.vdev_id); 3245 3246 context = &ext_scan_context; 3247 spin_lock(&context->context_lock); 3248 INIT_COMPLETION(context->response_event); 3249 context->request_id = params.request_id; 3250 spin_unlock(&context->context_lock); 3251 3252 status = sme_reset_significant_change(hdd_ctx->mac_handle, ¶ms); 3253 if (!QDF_IS_STATUS_SUCCESS(status)) { 3254 hdd_err("sme_reset_significant_change failed(err=%d)", 3255 status); 3256 return -EINVAL; 3257 } 3258 3259 /* request was sent -- wait for the response */ 3260 rc = wait_for_completion_timeout(&context->response_event, 3261 msecs_to_jiffies(WLAN_WAIT_TIME_EXTSCAN)); 3262 3263 if (!rc) { 3264 hdd_err("sme_ResetSignificantChange timed out"); 3265 retval = -ETIMEDOUT; 3266 } else { 3267 spin_lock(&context->context_lock); 3268 if (context->request_id == params.request_id) 3269 retval = context->response_status; 3270 else 3271 retval = -EINVAL; 3272 spin_unlock(&context->context_lock); 3273 } 3274 hdd_exit(); 3275 return retval; 3276 } 3277 3278 /** 3279 * wlan_hdd_cfg80211_extscan_reset_significant_change() - reset significant 3280 * change 3281 * @wiphy: Pointer to wireless phy 3282 * @wdev: Pointer to wireless device 3283 * @data: Pointer to data 3284 * @data_len: Data length 3285 * 3286 * Return: 0 on success, negative errno on failure 3287 */ 3288 int wlan_hdd_cfg80211_extscan_reset_significant_change(struct wiphy *wiphy, 3289 struct wireless_dev *wdev, 3290 const void *data, int data_len) 3291 { 3292 int errno; 3293 struct osif_vdev_sync *vdev_sync; 3294 3295 errno = osif_vdev_sync_op_start(wdev->netdev, &vdev_sync); 3296 if (errno) 3297 return errno; 3298 3299 errno = __wlan_hdd_cfg80211_extscan_reset_significant_change(wiphy, 3300 wdev, 3301 data, 3302 data_len); 3303 3304 osif_vdev_sync_op_stop(vdev_sync); 3305 3306 return errno; 3307 } 3308 3309 3310 /** 3311 * hdd_extscan_epno_fill_network() - epno fill single network 3312 * @network: aggregate network attribute 3313 * @nw: epno network record to be filled 3314 * 3315 * This function takes a single network block NL vendor attribute from 3316 * @network and decodes it into the internal record @nw. 3317 * 3318 * Return: 0 on success, error number otherwise 3319 */ 3320 static int 3321 hdd_extscan_epno_fill_network(struct nlattr *network, 3322 struct wifi_epno_network_params *nw) 3323 { 3324 struct nlattr *tb[QCA_WLAN_VENDOR_ATTR_PNO_MAX + 1]; 3325 int id, ssid_len; 3326 uint8_t *ssid; 3327 3328 if (!network) { 3329 hdd_err("attr network attr failed"); 3330 return -EINVAL; 3331 } 3332 3333 if (wlan_cfg80211_nla_parse(tb, QCA_WLAN_VENDOR_ATTR_PNO_MAX, 3334 nla_data(network), 3335 nla_len(network), 3336 wlan_hdd_pno_config_policy)) { 3337 hdd_err("nla_parse failed"); 3338 return -EINVAL; 3339 } 3340 3341 /* Parse and fetch ssid */ 3342 id = QCA_WLAN_VENDOR_ATTR_PNO_SET_LIST_PARAM_EPNO_NETWORK_SSID; 3343 if (!tb[id]) { 3344 hdd_err("attr network ssid failed"); 3345 return -EINVAL; 3346 } 3347 ssid_len = nla_len(tb[id]); 3348 3349 /* nla_parse will detect overflow but not underflow */ 3350 if (0 == ssid_len) { 3351 hdd_err("zero ssid length"); 3352 return -EINVAL; 3353 } 3354 3355 /* Decrement by 1, don't count null character */ 3356 ssid_len--; 3357 3358 nw->ssid.length = ssid_len; 3359 hdd_debug("network ssid length %d", ssid_len); 3360 ssid = nla_data(tb[id]); 3361 qdf_mem_copy(nw->ssid.ssid, ssid, ssid_len); 3362 hdd_debug("Ssid (" QDF_SSID_FMT ")", 3363 QDF_SSID_REF(nw->ssid.length, nw->ssid.ssid)); 3364 3365 /* Parse and fetch epno flags */ 3366 id = QCA_WLAN_VENDOR_ATTR_PNO_SET_LIST_PARAM_EPNO_NETWORK_FLAGS; 3367 if (!tb[id]) { 3368 hdd_err("attr epno flags failed"); 3369 return -EINVAL; 3370 } 3371 nw->flags = nla_get_u8(tb[id]); 3372 hdd_debug("flags %u", nw->flags); 3373 3374 /* Parse and fetch auth bit */ 3375 id = QCA_WLAN_VENDOR_ATTR_PNO_SET_LIST_PARAM_EPNO_NETWORK_AUTH_BIT; 3376 if (!tb[id]) { 3377 hdd_err("attr auth bit failed"); 3378 return -EINVAL; 3379 } 3380 nw->auth_bit_field = nla_get_u8(tb[id]); 3381 hdd_debug("auth bit %u", nw->auth_bit_field); 3382 3383 return 0; 3384 } 3385 3386 /** 3387 * hdd_extscan_epno_fill_network_list() - epno fill network list 3388 * @req_msg: request message 3389 * @networks: aggregate network list attribute 3390 * 3391 * This function reads the network block NL vendor attributes from 3392 * @networks and fills in the epno request message @req_msg. 3393 * 3394 * Return: 0 on success, error number otherwise 3395 */ 3396 static int 3397 hdd_extscan_epno_fill_network_list(struct wifi_enhanced_pno_params *req_msg, 3398 struct nlattr *networks) 3399 { 3400 struct nlattr *network; 3401 int rem; 3402 uint32_t index; 3403 uint32_t expected_networks; 3404 struct wifi_epno_network_params *nw; 3405 3406 if (!networks) { 3407 hdd_err("attr networks list failed"); 3408 return -EINVAL; 3409 } 3410 3411 expected_networks = req_msg->num_networks; 3412 index = 0; 3413 3414 nla_for_each_nested(network, networks, rem) { 3415 if (index == expected_networks) { 3416 hdd_warn("ignoring excess networks"); 3417 break; 3418 } 3419 3420 nw = &req_msg->networks[index++]; 3421 if (hdd_extscan_epno_fill_network(network, nw)) 3422 return -EINVAL; 3423 } 3424 req_msg->num_networks = index; 3425 return 0; 3426 } 3427 3428 /** 3429 * __wlan_hdd_cfg80211_set_epno_list() - epno set network list 3430 * @wiphy: wiphy 3431 * @wdev: pointer to wireless dev 3432 * @data: data pointer 3433 * @data_len: data length 3434 * 3435 * This function reads the NL vendor attributes from @data and 3436 * fills in the epno request message. 3437 * 3438 * Return: 0 on success, error number otherwise 3439 */ 3440 static int __wlan_hdd_cfg80211_set_epno_list(struct wiphy *wiphy, 3441 struct wireless_dev *wdev, 3442 const void *data, 3443 int data_len) 3444 { 3445 struct wifi_enhanced_pno_params *req_msg; 3446 struct net_device *dev = wdev->netdev; 3447 struct hdd_adapter *adapter = WLAN_HDD_GET_PRIV_PTR(dev); 3448 struct hdd_context *hdd_ctx = wiphy_priv(wiphy); 3449 struct nlattr *tb[QCA_WLAN_VENDOR_ATTR_PNO_MAX + 1]; 3450 struct nlattr *networks; 3451 QDF_STATUS status; 3452 uint32_t num_networks, len; 3453 int id, ret_val; 3454 3455 hdd_enter_dev(dev); 3456 3457 ret_val = wlan_hdd_validate_context(hdd_ctx); 3458 if (ret_val) 3459 return ret_val; 3460 3461 if (!ucfg_extscan_get_enable(hdd_ctx->psoc)) { 3462 hdd_err("extscan not supported"); 3463 return -ENOTSUPP; 3464 } 3465 3466 if (QDF_GLOBAL_FTM_MODE == hdd_get_conparam()) { 3467 hdd_err("Command not allowed in FTM mode"); 3468 return -EPERM; 3469 } 3470 3471 if (wlan_cfg80211_nla_parse(tb, QCA_WLAN_VENDOR_ATTR_PNO_MAX, data, 3472 data_len, wlan_hdd_pno_config_policy)) { 3473 hdd_err("Invalid ATTR"); 3474 return -EINVAL; 3475 } 3476 3477 /* Parse and fetch number of networks */ 3478 id = QCA_WLAN_VENDOR_ATTR_PNO_SET_LIST_PARAM_NUM_NETWORKS; 3479 if (!tb[id]) { 3480 hdd_err("attr num networks failed"); 3481 return -EINVAL; 3482 } 3483 3484 /* 3485 * num_networks is also used as EPNO SET/RESET request. 3486 * if num_networks is zero then it is treated as RESET. 3487 */ 3488 num_networks = nla_get_u32(tb[id]); 3489 3490 if (num_networks > MAX_EPNO_NETWORKS) { 3491 hdd_debug("num of nw: %d exceeded max: %d, resetting to: %d", 3492 num_networks, MAX_EPNO_NETWORKS, MAX_EPNO_NETWORKS); 3493 num_networks = MAX_EPNO_NETWORKS; 3494 } 3495 3496 hdd_debug("num networks %u", num_networks); 3497 len = sizeof(*req_msg) + 3498 (num_networks * sizeof(req_msg->networks[0])); 3499 3500 req_msg = qdf_mem_malloc(len); 3501 if (!req_msg) 3502 return -ENOMEM; 3503 3504 req_msg->num_networks = num_networks; 3505 3506 /* Parse and fetch request Id */ 3507 id = QCA_WLAN_VENDOR_ATTR_PNO_CONFIG_REQUEST_ID; 3508 if (!tb[id]) { 3509 hdd_err("attr request id failed"); 3510 goto fail; 3511 } 3512 req_msg->request_id = nla_get_u32(tb[id]); 3513 hdd_debug("Req Id %u", req_msg->request_id); 3514 3515 req_msg->vdev_id = adapter->deflink->vdev_id; 3516 hdd_debug("Vdev Id %d", req_msg->vdev_id); 3517 3518 if (num_networks) { 3519 /* Parse and fetch min_5ghz_rssi */ 3520 id = QCA_WLAN_VENDOR_ATTR_EPNO_MIN5GHZ_RSSI; 3521 if (!tb[id]) { 3522 hdd_err("min_5ghz_rssi id failed"); 3523 goto fail; 3524 } 3525 req_msg->min_5ghz_rssi = nla_get_u32(tb[id]); 3526 3527 /* Parse and fetch min_24ghz_rssi */ 3528 id = QCA_WLAN_VENDOR_ATTR_EPNO_MIN24GHZ_RSSI; 3529 if (!tb[id]) { 3530 hdd_err("min_24ghz_rssi id failed"); 3531 goto fail; 3532 } 3533 req_msg->min_24ghz_rssi = nla_get_u32(tb[id]); 3534 3535 /* Parse and fetch initial_score_max */ 3536 id = QCA_WLAN_VENDOR_ATTR_EPNO_INITIAL_SCORE_MAX; 3537 if (!tb[id]) { 3538 hdd_err("initial_score_max id failed"); 3539 goto fail; 3540 } 3541 req_msg->initial_score_max = nla_get_u32(tb[id]); 3542 3543 /* Parse and fetch current_connection_bonus */ 3544 id = QCA_WLAN_VENDOR_ATTR_EPNO_CURRENT_CONNECTION_BONUS; 3545 if (!tb[id]) { 3546 hdd_err("current_connection_bonus id failed"); 3547 goto fail; 3548 } 3549 req_msg->current_connection_bonus = nla_get_u32(tb[id]); 3550 3551 /* Parse and fetch same_network_bonus */ 3552 id = QCA_WLAN_VENDOR_ATTR_EPNO_SAME_NETWORK_BONUS; 3553 if (!tb[id]) { 3554 hdd_err("same_network_bonus id failed"); 3555 goto fail; 3556 } 3557 req_msg->same_network_bonus = nla_get_u32(tb[id]); 3558 3559 /* Parse and fetch secure_bonus */ 3560 id = QCA_WLAN_VENDOR_ATTR_EPNO_SECURE_BONUS; 3561 if (!tb[id]) { 3562 hdd_err("secure_bonus id failed"); 3563 goto fail; 3564 } 3565 req_msg->secure_bonus = nla_get_u32(tb[id]); 3566 3567 /* Parse and fetch band_5ghz_bonus */ 3568 id = QCA_WLAN_VENDOR_ATTR_EPNO_BAND5GHZ_BONUS; 3569 if (!tb[id]) { 3570 hdd_err("band_5ghz_bonus id failed"); 3571 goto fail; 3572 } 3573 req_msg->band_5ghz_bonus = nla_get_u32(tb[id]); 3574 3575 hdd_debug("min_5ghz_rssi: %d min_24ghz_rssi: %d", 3576 req_msg->min_5ghz_rssi, 3577 req_msg->min_24ghz_rssi); 3578 hdd_debug("initial_score_max: %d current_connection_bonus:%d", 3579 req_msg->initial_score_max, 3580 req_msg->current_connection_bonus); 3581 hdd_debug("Bonuses same_network: %d secure: %d band_5ghz: %d", 3582 req_msg->same_network_bonus, 3583 req_msg->secure_bonus, 3584 req_msg->band_5ghz_bonus); 3585 3586 id = QCA_WLAN_VENDOR_ATTR_PNO_SET_LIST_PARAM_EPNO_NETWORKS_LIST; 3587 networks = tb[id]; 3588 if (hdd_extscan_epno_fill_network_list(req_msg, networks)) 3589 goto fail; 3590 3591 } 3592 3593 status = sme_set_epno_list(hdd_ctx->mac_handle, req_msg); 3594 if (!QDF_IS_STATUS_SUCCESS(status)) { 3595 hdd_err("sme_set_epno_list failed(err=%d)", status); 3596 goto fail; 3597 } 3598 3599 hdd_exit(); 3600 qdf_mem_free(req_msg); 3601 return 0; 3602 3603 fail: 3604 qdf_mem_free(req_msg); 3605 return -EINVAL; 3606 } 3607 3608 /** 3609 * wlan_hdd_cfg80211_set_epno_list() - epno set network list 3610 * @wiphy: wiphy 3611 * @wdev: pointer to wireless dev 3612 * @data: data pointer 3613 * @data_len: data length 3614 * 3615 * This function reads the NL vendor attributes from %tb and 3616 * fill in the epno request message. 3617 * 3618 * Return: 0 on success, error number otherwise 3619 */ 3620 int wlan_hdd_cfg80211_set_epno_list(struct wiphy *wiphy, 3621 struct wireless_dev *wdev, 3622 const void *data, 3623 int data_len) 3624 { 3625 int errno; 3626 struct osif_vdev_sync *vdev_sync; 3627 3628 errno = osif_vdev_sync_op_start(wdev->netdev, &vdev_sync); 3629 if (errno) 3630 return errno; 3631 3632 errno = __wlan_hdd_cfg80211_set_epno_list(wiphy, wdev, data, data_len); 3633 3634 osif_vdev_sync_op_stop(vdev_sync); 3635 3636 return errno; 3637 } 3638 3639 /** 3640 * hdd_extscan_passpoint_fill_network() - passpoint fill single network 3641 * @network: aggregate network attribute 3642 * @nw: passpoint network record to be filled 3643 * 3644 * This function takes a single network block NL vendor attribute from 3645 * @network and decodes it into the internal record @nw. 3646 * 3647 * Return: 0 on success, error number otherwise 3648 */ 3649 static int 3650 hdd_extscan_passpoint_fill_network(struct nlattr *network, 3651 struct wifi_passpoint_network_param *nw) 3652 { 3653 struct nlattr *tb[QCA_WLAN_VENDOR_ATTR_PNO_MAX + 1]; 3654 int id; 3655 size_t len; 3656 3657 if (!network) { 3658 hdd_err("attr network attr failed"); 3659 return -EINVAL; 3660 } 3661 3662 if (wlan_cfg80211_nla_parse(tb, QCA_WLAN_VENDOR_ATTR_PNO_MAX, 3663 nla_data(network), 3664 nla_len(network), 3665 wlan_hdd_pno_config_policy)) { 3666 hdd_err("nla_parse failed"); 3667 return -EINVAL; 3668 } 3669 3670 /* Parse and fetch identifier */ 3671 id = QCA_WLAN_VENDOR_ATTR_PNO_PASSPOINT_NETWORK_PARAM_ID; 3672 if (!tb[id]) { 3673 hdd_err("attr passpoint id failed"); 3674 return -EINVAL; 3675 } 3676 nw->id = nla_get_u32(tb[id]); 3677 hdd_debug("Id %u", nw->id); 3678 3679 /* Parse and fetch realm */ 3680 id = QCA_WLAN_VENDOR_ATTR_PNO_PASSPOINT_NETWORK_PARAM_REALM; 3681 if (!tb[id]) { 3682 hdd_err("attr realm failed"); 3683 return -EINVAL; 3684 } 3685 len = wlan_cfg80211_nla_strscpy(nw->realm, tb[id], 3686 WMI_PASSPOINT_REALM_LEN); 3687 /* Don't send partial realm to firmware */ 3688 if (len >= WMI_PASSPOINT_REALM_LEN) { 3689 hdd_err("user passed invalid realm, len:%zu", len); 3690 return -EINVAL; 3691 } 3692 3693 hdd_debug("realm: %s", nw->realm); 3694 3695 /* Parse and fetch roaming consortium ids */ 3696 id = QCA_WLAN_VENDOR_ATTR_PNO_PASSPOINT_NETWORK_PARAM_ROAM_CNSRTM_ID; 3697 if (!tb[id]) { 3698 hdd_err("attr roaming consortium ids failed"); 3699 return -EINVAL; 3700 } 3701 nla_memcpy(&nw->roaming_consortium_ids, tb[id], 3702 sizeof(nw->roaming_consortium_ids)); 3703 hdd_debug("roaming consortium ids"); 3704 3705 /* Parse and fetch plmn */ 3706 id = QCA_WLAN_VENDOR_ATTR_PNO_PASSPOINT_NETWORK_PARAM_ROAM_PLMN; 3707 if (!tb[id]) { 3708 hdd_err("attr plmn failed"); 3709 return -EINVAL; 3710 } 3711 nla_memcpy(&nw->plmn, tb[id], 3712 WMI_PASSPOINT_PLMN_LEN); 3713 hdd_debug("plmn %02x:%02x:%02x)", 3714 nw->plmn[0], 3715 nw->plmn[1], 3716 nw->plmn[2]); 3717 3718 return 0; 3719 } 3720 3721 /** 3722 * hdd_extscan_passpoint_fill_networks() - passpoint fill network list 3723 * @req_msg: request message 3724 * @networks: aggregate network list attribute 3725 * 3726 * This function reads the network block NL vendor attributes from 3727 * @networks and fills in the passpoint request message. 3728 * 3729 * Return: 0 on success, error number otherwise 3730 */ 3731 static int 3732 hdd_extscan_passpoint_fill_networks(struct wifi_passpoint_req_param *req_msg, 3733 struct nlattr *networks) 3734 { 3735 struct nlattr *network; 3736 int rem; 3737 uint32_t index; 3738 uint32_t expected_networks; 3739 struct wifi_passpoint_network_param *nw; 3740 3741 if (!networks) { 3742 hdd_err("attr networks list failed"); 3743 return -EINVAL; 3744 } 3745 3746 expected_networks = req_msg->num_networks; 3747 index = 0; 3748 3749 nla_for_each_nested(network, networks, rem) { 3750 if (index == expected_networks) { 3751 hdd_warn("ignoring excess networks"); 3752 break; 3753 } 3754 3755 nw = &req_msg->networks[index++]; 3756 if (hdd_extscan_passpoint_fill_network(network, nw)) 3757 return -EINVAL; 3758 } 3759 req_msg->num_networks = index; 3760 return 0; 3761 } 3762 3763 /** 3764 * __wlan_hdd_cfg80211_set_passpoint_list() - set passpoint network list 3765 * @wiphy: wiphy 3766 * @wdev: pointer to wireless dev 3767 * @data: data pointer 3768 * @data_len: data length 3769 * 3770 * This function reads the NL vendor attributes from %tb and 3771 * fill in the passpoint request message. 3772 * 3773 * Return: 0 on success, error number otherwise 3774 */ 3775 static int __wlan_hdd_cfg80211_set_passpoint_list(struct wiphy *wiphy, 3776 struct wireless_dev *wdev, 3777 const void *data, 3778 int data_len) 3779 { 3780 struct wifi_passpoint_req_param *req_msg; 3781 struct net_device *dev = wdev->netdev; 3782 struct hdd_adapter *adapter = WLAN_HDD_GET_PRIV_PTR(dev); 3783 struct hdd_context *hdd_ctx = wiphy_priv(wiphy); 3784 struct nlattr *tb[QCA_WLAN_VENDOR_ATTR_PNO_MAX + 1]; 3785 struct nlattr *networks; 3786 uint32_t num_networks; 3787 QDF_STATUS status; 3788 int id, ret; 3789 3790 hdd_enter_dev(dev); 3791 3792 ret = wlan_hdd_validate_context(hdd_ctx); 3793 if (ret) 3794 return ret; 3795 3796 if (QDF_GLOBAL_FTM_MODE == hdd_get_conparam()) { 3797 hdd_err("Command not allowed in FTM mode"); 3798 return -EPERM; 3799 } 3800 3801 if (wlan_cfg80211_nla_parse(tb, QCA_WLAN_VENDOR_ATTR_PNO_MAX, data, 3802 data_len, wlan_hdd_pno_config_policy)) { 3803 hdd_err("Invalid ATTR"); 3804 return -EINVAL; 3805 } 3806 3807 /* Parse and fetch number of networks */ 3808 id = QCA_WLAN_VENDOR_ATTR_PNO_PASSPOINT_LIST_PARAM_NUM; 3809 if (!tb[id]) { 3810 hdd_err("attr num networks failed"); 3811 return -EINVAL; 3812 } 3813 num_networks = nla_get_u32(tb[id]); 3814 if (num_networks > SIR_PASSPOINT_LIST_MAX_NETWORKS) { 3815 hdd_err("num networks %u exceeds max %u", 3816 num_networks, SIR_PASSPOINT_LIST_MAX_NETWORKS); 3817 return -EINVAL; 3818 } 3819 3820 hdd_debug("num networks %u", num_networks); 3821 3822 req_msg = qdf_mem_malloc(sizeof(*req_msg) + 3823 (num_networks * sizeof(req_msg->networks[0]))); 3824 if (!req_msg) 3825 return -ENOMEM; 3826 3827 req_msg->num_networks = num_networks; 3828 3829 /* Parse and fetch request Id */ 3830 id = QCA_WLAN_VENDOR_ATTR_EXTSCAN_SUBCMD_CONFIG_PARAM_REQUEST_ID; 3831 if (!tb[id]) { 3832 hdd_err("attr request id failed"); 3833 goto fail; 3834 } 3835 req_msg->request_id = nla_get_u32(tb[id]); 3836 3837 req_msg->vdev_id = adapter->deflink->vdev_id; 3838 hdd_debug("Req Id %u Vdev Id %d", 3839 req_msg->request_id, req_msg->vdev_id); 3840 3841 id = QCA_WLAN_VENDOR_ATTR_PNO_PASSPOINT_LIST_PARAM_NETWORK_ARRAY; 3842 networks = tb[id]; 3843 if (hdd_extscan_passpoint_fill_networks(req_msg, networks)) 3844 goto fail; 3845 3846 status = sme_set_passpoint_list(hdd_ctx->mac_handle, req_msg); 3847 if (!QDF_IS_STATUS_SUCCESS(status)) { 3848 hdd_err("sme_set_passpoint_list failed(err=%d)", status); 3849 goto fail; 3850 } 3851 3852 hdd_exit(); 3853 qdf_mem_free(req_msg); 3854 return 0; 3855 3856 fail: 3857 qdf_mem_free(req_msg); 3858 return -EINVAL; 3859 } 3860 3861 /** 3862 * wlan_hdd_cfg80211_set_passpoint_list() - set passpoint network list 3863 * @wiphy: wiphy 3864 * @wdev: pointer to wireless dev 3865 * @data: data pointer 3866 * @data_len: data length 3867 * 3868 * This function reads the NL vendor attributes from %tb and 3869 * fill in the passpoint request message. 3870 * 3871 * Return: 0 on success, error number otherwise 3872 */ 3873 int wlan_hdd_cfg80211_set_passpoint_list(struct wiphy *wiphy, 3874 struct wireless_dev *wdev, 3875 const void *data, 3876 int data_len) 3877 { 3878 int errno; 3879 struct osif_vdev_sync *vdev_sync; 3880 3881 errno = osif_vdev_sync_op_start(wdev->netdev, &vdev_sync); 3882 if (errno) 3883 return errno; 3884 3885 errno = __wlan_hdd_cfg80211_set_passpoint_list(wiphy, wdev, 3886 data, data_len); 3887 3888 osif_vdev_sync_op_stop(vdev_sync); 3889 3890 return errno; 3891 } 3892 3893 /** 3894 * __wlan_hdd_cfg80211_reset_passpoint_list() - reset passpoint network list 3895 * @wiphy: wiphy 3896 * @wdev: pointer to wireless dev 3897 * @data: data pointer 3898 * @data_len: data length 3899 * 3900 * This function resets passpoint networks list 3901 * 3902 * Return: 0 on success, error number otherwise 3903 */ 3904 static int __wlan_hdd_cfg80211_reset_passpoint_list(struct wiphy *wiphy, 3905 struct wireless_dev *wdev, 3906 const void *data, 3907 int data_len) 3908 { 3909 struct wifi_passpoint_req_param *req_msg; 3910 struct net_device *dev = wdev->netdev; 3911 struct hdd_adapter *adapter = WLAN_HDD_GET_PRIV_PTR(dev); 3912 struct hdd_context *hdd_ctx = wiphy_priv(wiphy); 3913 struct nlattr *tb[QCA_WLAN_VENDOR_ATTR_PNO_MAX + 1]; 3914 QDF_STATUS status; 3915 int id, ret; 3916 3917 hdd_enter_dev(dev); 3918 3919 ret = wlan_hdd_validate_context(hdd_ctx); 3920 if (ret) 3921 return ret; 3922 3923 if (QDF_GLOBAL_FTM_MODE == hdd_get_conparam()) { 3924 hdd_err("Command not allowed in FTM mode"); 3925 return -EPERM; 3926 } 3927 3928 if (wlan_cfg80211_nla_parse(tb, QCA_WLAN_VENDOR_ATTR_PNO_MAX, data, 3929 data_len, wlan_hdd_extscan_config_policy)) { 3930 hdd_err("Invalid ATTR"); 3931 return -EINVAL; 3932 } 3933 3934 req_msg = qdf_mem_malloc(sizeof(*req_msg)); 3935 if (!req_msg) 3936 return -ENOMEM; 3937 3938 /* Parse and fetch request Id */ 3939 id = QCA_WLAN_VENDOR_ATTR_EXTSCAN_SUBCMD_CONFIG_PARAM_REQUEST_ID; 3940 if (!tb[id]) { 3941 hdd_err("attr request id failed"); 3942 goto fail; 3943 } 3944 req_msg->request_id = nla_get_u32(tb[id]); 3945 3946 req_msg->vdev_id = adapter->deflink->vdev_id; 3947 hdd_debug("Req Id %u Vdev Id %d", 3948 req_msg->request_id, req_msg->vdev_id); 3949 3950 status = sme_reset_passpoint_list(hdd_ctx->mac_handle, req_msg); 3951 if (!QDF_IS_STATUS_SUCCESS(status)) { 3952 hdd_err("sme_reset_passpoint_list failed(err=%d)", status); 3953 goto fail; 3954 } 3955 3956 hdd_exit(); 3957 qdf_mem_free(req_msg); 3958 return 0; 3959 3960 fail: 3961 qdf_mem_free(req_msg); 3962 return -EINVAL; 3963 } 3964 3965 /** 3966 * wlan_hdd_cfg80211_reset_passpoint_list() - reset passpoint network list 3967 * @wiphy: wiphy 3968 * @wdev: pointer to wireless dev 3969 * @data: data pointer 3970 * @data_len: data length 3971 * 3972 * This function resets passpoint networks list 3973 * 3974 * Return: 0 on success, error number otherwise 3975 */ 3976 int wlan_hdd_cfg80211_reset_passpoint_list(struct wiphy *wiphy, 3977 struct wireless_dev *wdev, 3978 const void *data, 3979 int data_len) 3980 { 3981 int errno; 3982 struct osif_vdev_sync *vdev_sync; 3983 3984 errno = osif_vdev_sync_op_start(wdev->netdev, &vdev_sync); 3985 if (errno) 3986 return errno; 3987 3988 errno = __wlan_hdd_cfg80211_reset_passpoint_list(wiphy, wdev, 3989 data, data_len); 3990 3991 osif_vdev_sync_op_stop(vdev_sync); 3992 3993 return errno; 3994 } 3995 3996 /** 3997 * wlan_hdd_cfg80211_extscan_init() - Initialize the ExtScan feature 3998 * @hdd_ctx: Global HDD context 3999 * 4000 * Return: none 4001 */ 4002 void wlan_hdd_cfg80211_extscan_init(struct hdd_context *hdd_ctx) 4003 { 4004 init_completion(&ext_scan_context.response_event); 4005 spin_lock_init(&ext_scan_context.context_lock); 4006 } 4007 4008 #endif /* FEATURE_WLAN_EXTSCAN */ 4009