1 /* 2 * Copyright (c) 2019-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_bcn_recv.c 22 * Feature for receiving beacons of connected AP and sending select 23 * params to upper layer via vendor event 24 */ 25 26 #include <wlan_hdd_includes.h> 27 #include <net/cfg80211.h> 28 #include "wlan_osif_priv.h" 29 #include "qdf_trace.h" 30 #include "wlan_hdd_main.h" 31 #include "osif_sync.h" 32 #include "wlan_hdd_bcn_recv.h" 33 #include <linux/limits.h> 34 #include <wlan_hdd_object_manager.h> 35 36 #define SET_BIT(value, mask) ((value) |= (1 << (mask))) 37 38 #define BOOTTIME QCA_WLAN_VENDOR_ATTR_BEACON_REPORTING_BOOTTIME_WHEN_RECEIVED 39 40 #ifndef CHAR_BIT 41 #define CHAR_BIT 8 /* Normally in <limits.h> */ 42 #endif 43 44 const struct nla_policy 45 beacon_reporting_params_policy 46 [QCA_WLAN_VENDOR_ATTR_BEACON_REPORTING_MAX + 1] = { 47 [QCA_WLAN_VENDOR_ATTR_BEACON_REPORTING_OP_TYPE] = {.type = NLA_U8}, 48 [QCA_WLAN_VENDOR_ATTR_BEACON_REPORTING_ACTIVE_REPORTING] = {.type = 49 NLA_FLAG}, 50 [QCA_WLAN_VENDOR_ATTR_BEACON_REPORTING_PERIOD] = {.type = NLA_U8}, 51 [QCA_WLAN_VENDOR_ATTR_BEACON_REPORTING_DO_NOT_RESUME] = {.type = 52 NLA_FLAG}, 53 }; 54 55 /** 56 * get_beacon_report_data_len() - Calculate length for beacon 57 * report to allocate skb buffer 58 * @report: beacon report structure 59 * 60 * Return: skb buffer length 61 */ 62 static get_beacon_report_data_len(struct wlan_beacon_report * report)63 int get_beacon_report_data_len(struct wlan_beacon_report *report) 64 { 65 uint32_t data_len = NLMSG_HDRLEN; 66 67 /* QCA_WLAN_VENDOR_ATTR_BEACON_REPORTING_OP_TYPE */ 68 data_len += nla_total_size(sizeof(u32)); 69 70 /* QCA_WLAN_VENDOR_ATTR_BEACON_REPORTING_SSID */ 71 data_len += nla_total_size(report->ssid.length); 72 73 /* QCA_WLAN_VENDOR_ATTR_BEACON_REPORTING_BSSID */ 74 data_len += nla_total_size(ETH_ALEN); 75 76 /* QCA_WLAN_VENDOR_ATTR_BEACON_REPORTING_FREQ */ 77 data_len += nla_total_size(sizeof(u32)); 78 79 /* QCA_WLAN_VENDOR_ATTR_BEACON_REPORTING_BI */ 80 data_len += nla_total_size(sizeof(u16)); 81 82 /* QCA_WLAN_VENDOR_ATTR_BEACON_REPORTING_TSF */ 83 data_len += nla_total_size(sizeof(uint64_t)); 84 85 /* QCA_WLAN_VENDOR_ATTR_BEACON_REPORTING_BOOTTIME_WHEN_RECEIVED */ 86 data_len += nla_total_size(sizeof(uint64_t)); 87 88 return data_len; 89 } 90 91 /** 92 * get_pause_ind_data_len() - Calculate skb buffer length 93 * @is_disconnected: Connection state 94 * 95 * Calculate length for pause indication to allocate skb buffer 96 * 97 * Return: skb buffer length 98 */ get_pause_ind_data_len(bool is_disconnected)99 static int get_pause_ind_data_len(bool is_disconnected) 100 { 101 uint32_t data_len = NLMSG_HDRLEN; 102 103 /* QCA_WLAN_VENDOR_ATTR_BEACON_REPORTING_OP_TYPE */ 104 data_len += nla_total_size(sizeof(u32)); 105 106 /* QCA_WLAN_VENDOR_ATTR_BEACON_REPORTING_PAUSE_REASON */ 107 data_len += nla_total_size(sizeof(u32)); 108 109 /* QCA_WLAN_VENDOR_ATTR_BEACON_REPORTING_AUTO_RESUMES */ 110 if (!is_disconnected) 111 data_len += nla_total_size(sizeof(u8)); 112 113 return data_len; 114 } 115 116 /** 117 * hdd_send_bcn_recv_info() - Send beacon info to userspace for 118 * connected AP 119 * @hdd_handle: hdd_handle to get hdd_adapter 120 * @beacon_report: Required beacon report 121 * 122 * Send beacon info to userspace for connected AP through a vendor event: 123 * QCA_NL80211_VENDOR_SUBCMD_BEACON_REPORTING. 124 */ hdd_send_bcn_recv_info(hdd_handle_t hdd_handle,struct wlan_beacon_report * beacon_report)125 static QDF_STATUS hdd_send_bcn_recv_info(hdd_handle_t hdd_handle, 126 struct wlan_beacon_report 127 *beacon_report) 128 { 129 struct sk_buff *vendor_event; 130 struct hdd_context *hdd_ctx = hdd_handle_to_context(hdd_handle); 131 uint32_t data_len; 132 int flags = cds_get_gfp_flags(); 133 struct hdd_adapter *adapter; 134 struct wlan_hdd_link_info *link_info; 135 enum qca_nl80211_vendor_subcmds_index index = 136 QCA_NL80211_VENDOR_SUBCMD_BEACON_REPORTING_INDEX; 137 138 if (wlan_hdd_validate_context(hdd_ctx)) 139 return QDF_STATUS_E_FAILURE; 140 141 data_len = get_beacon_report_data_len(beacon_report); 142 143 link_info = hdd_get_link_info_by_vdev(hdd_ctx, beacon_report->vdev_id); 144 if (!link_info || hdd_validate_adapter(link_info->adapter)) 145 return QDF_STATUS_E_FAILURE; 146 147 adapter = link_info->adapter; 148 vendor_event = wlan_cfg80211_vendor_event_alloc(hdd_ctx->wiphy, 149 &adapter->wdev, 150 data_len, index, flags); 151 if (!vendor_event) { 152 hdd_err("wlan_cfg80211_vendor_event_alloc failed"); 153 return QDF_STATUS_E_FAILURE; 154 } 155 156 if (nla_put_u32(vendor_event, 157 QCA_WLAN_VENDOR_ATTR_BEACON_REPORTING_OP_TYPE, 158 QCA_WLAN_VENDOR_BEACON_REPORTING_OP_BEACON_INFO) || 159 nla_put(vendor_event, QCA_WLAN_VENDOR_ATTR_BEACON_REPORTING_SSID, 160 beacon_report->ssid.length, beacon_report->ssid.ssid) || 161 nla_put(vendor_event, QCA_WLAN_VENDOR_ATTR_BEACON_REPORTING_BSSID, 162 ETH_ALEN, beacon_report->bssid.bytes) || 163 nla_put_u32(vendor_event, 164 QCA_WLAN_VENDOR_ATTR_BEACON_REPORTING_FREQ, 165 beacon_report->frequency) || 166 nla_put_u16(vendor_event, 167 QCA_WLAN_VENDOR_ATTR_BEACON_REPORTING_BI, 168 beacon_report->beacon_interval) || 169 wlan_cfg80211_nla_put_u64(vendor_event, 170 QCA_WLAN_VENDOR_ATTR_BEACON_REPORTING_TSF, 171 beacon_report->time_stamp) || 172 wlan_cfg80211_nla_put_u64(vendor_event, BOOTTIME, 173 beacon_report->boot_time)) { 174 hdd_err("QCA_WLAN_VENDOR_ATTR put fail"); 175 wlan_cfg80211_vendor_free_skb(vendor_event); 176 return QDF_STATUS_E_FAILURE; 177 } 178 179 wlan_cfg80211_vendor_event(vendor_event, flags); 180 return QDF_STATUS_SUCCESS; 181 } 182 183 /** 184 * hdd_handle_beacon_reporting_start_op() - Process bcn recv start op 185 * @hdd_ctx: Pointer to hdd context 186 * @adapter: Pointer to network adapter 187 * @active_report: Active reporting flag 188 * @nth_value: Beacon report period 189 * @do_not_resume: beacon reporting resume after a pause is completed 190 * 191 * This function process beacon reporting start operation. 192 */ hdd_handle_beacon_reporting_start_op(struct hdd_context * hdd_ctx,struct hdd_adapter * adapter,bool active_report,uint32_t nth_value,bool do_not_resume)193 static int hdd_handle_beacon_reporting_start_op(struct hdd_context *hdd_ctx, 194 struct hdd_adapter *adapter, 195 bool active_report, 196 uint32_t nth_value, 197 bool do_not_resume) 198 { 199 QDF_STATUS qdf_status = QDF_STATUS_SUCCESS; 200 int errno; 201 uint32_t mask = 0; 202 203 if (active_report) { 204 /* Register beacon report callback */ 205 qdf_status = 206 sme_register_bcn_report_pe_cb(hdd_ctx->mac_handle, 207 hdd_send_bcn_recv_info); 208 if (QDF_IS_STATUS_ERROR(qdf_status)) { 209 hdd_err("bcn recv info cb reg failed = %d", qdf_status); 210 errno = qdf_status_to_os_return(qdf_status); 211 return errno; 212 } 213 214 /* Register pause indication callback */ 215 qdf_status = 216 sme_register_bcn_recv_pause_ind_cb(hdd_ctx->mac_handle, 217 hdd_beacon_recv_pause_indication); 218 if (QDF_IS_STATUS_ERROR(qdf_status)) { 219 hdd_err("pause_ind_cb reg failed = %d", qdf_status); 220 errno = qdf_status_to_os_return(qdf_status); 221 return errno; 222 } 223 /* Update Beacon report period in case of active reporting */ 224 nth_value = 1; 225 /* 226 * Set MSB which indicates fw to don't wakeup host in wow 227 * mode in case of active beacon report. 228 */ 229 mask = (sizeof(uint32_t) * CHAR_BIT) - 1; 230 SET_BIT(nth_value, mask); 231 } 232 /* Handle beacon receive start indication */ 233 qdf_status = sme_handle_bcn_recv_start(hdd_ctx->mac_handle, 234 adapter->deflink->vdev_id, 235 nth_value, do_not_resume); 236 if (QDF_IS_STATUS_ERROR(qdf_status)) { 237 hdd_err("bcn rcv start failed with status=%d", qdf_status); 238 if (sme_register_bcn_report_pe_cb(hdd_ctx->mac_handle, NULL)) 239 hdd_err("bcn report cb deregistration failed"); 240 if (sme_register_bcn_recv_pause_ind_cb(hdd_ctx->mac_handle, 241 NULL)) 242 hdd_err("bcn pause ind cb deregistration failed"); 243 errno = qdf_status_to_os_return(qdf_status); 244 return errno; 245 } 246 247 errno = qdf_status_to_os_return(qdf_status); 248 249 return errno; 250 } 251 252 /** 253 * hdd_handle_beacon_reporting_stop_op() - Process bcn recv stop op 254 * @hdd_ctx: Pointer to hdd context 255 * @adapter: Pointer to network adapter 256 * 257 * This function process beacon reporting stop operation. 258 */ hdd_handle_beacon_reporting_stop_op(struct hdd_context * hdd_ctx,struct hdd_adapter * adapter)259 static int hdd_handle_beacon_reporting_stop_op(struct hdd_context *hdd_ctx, 260 struct hdd_adapter *adapter) 261 { 262 QDF_STATUS qdf_status = QDF_STATUS_SUCCESS; 263 int errno; 264 265 /* Reset bcn recv start flag */ 266 sme_stop_beacon_report(hdd_ctx->mac_handle, adapter->deflink->vdev_id); 267 268 /* Deregister beacon report callback */ 269 qdf_status = sme_register_bcn_report_pe_cb(hdd_ctx->mac_handle, NULL); 270 if (QDF_IS_STATUS_ERROR(qdf_status)) { 271 hdd_err("Callback de-registration failed = %d", qdf_status); 272 errno = qdf_status_to_os_return(qdf_status); 273 return errno; 274 } 275 276 /* Deregister pause indication callback */ 277 qdf_status = sme_register_bcn_recv_pause_ind_cb(hdd_ctx->mac_handle, 278 NULL); 279 if (QDF_IS_STATUS_ERROR(qdf_status)) { 280 hdd_err("scan even deregister failed = %d", qdf_status); 281 errno = qdf_status_to_os_return(qdf_status); 282 return errno; 283 } 284 285 if (hdd_cm_is_vdev_associated(adapter->deflink)) 286 /* Add beacon filter */ 287 if (hdd_add_beacon_filter(adapter)) { 288 hdd_err("Beacon filter addition failed"); 289 return -EINVAL; 290 } 291 292 errno = qdf_status_to_os_return(qdf_status); 293 294 return errno; 295 } 296 297 /** 298 * __wlan_hdd_cfg80211_bcn_rcv_op() - enable/disable beacon reporting 299 * indication 300 * @wiphy: Pointer to wireless phy 301 * @wdev: Pointer to wireless device 302 * @data: Pointer to data 303 * @data_len: Length of @data 304 * 305 * This function is used to enable/disable asynchronous beacon 306 * reporting feature using vendor commands. 307 * 308 * Return: 0 on success, negative errno on failure 309 */ __wlan_hdd_cfg80211_bcn_rcv_op(struct wiphy * wiphy,struct wireless_dev * wdev,const void * data,int data_len)310 static int __wlan_hdd_cfg80211_bcn_rcv_op(struct wiphy *wiphy, 311 struct wireless_dev *wdev, 312 const void *data, int data_len) 313 { 314 struct hdd_context *hdd_ctx = wiphy_priv(wiphy); 315 struct net_device *dev = wdev->netdev; 316 struct hdd_adapter *adapter = WLAN_HDD_GET_PRIV_PTR(dev); 317 struct nlattr *tb[QCA_WLAN_VENDOR_ATTR_BEACON_REPORTING_MAX + 1]; 318 uint32_t bcn_report, nth_value = 1; 319 int errno; 320 bool active_report, do_not_resume; 321 struct wlan_objmgr_vdev *vdev; 322 enum scm_scan_status scan_req_status; 323 324 hdd_enter_dev(dev); 325 326 if (QDF_GLOBAL_FTM_MODE == hdd_get_conparam()) { 327 hdd_err("Command not allowed in FTM mode"); 328 return -EPERM; 329 } 330 331 errno = hdd_validate_adapter(adapter); 332 if (errno) 333 return errno; 334 335 if (adapter->device_mode != QDF_STA_MODE) { 336 hdd_err("Command not allowed as device not in STA mode"); 337 return -EINVAL; 338 } 339 340 if (!hdd_cm_is_vdev_associated(adapter->deflink)) { 341 hdd_err("STA not in connected state"); 342 return -EINVAL; 343 } 344 345 vdev = hdd_objmgr_get_vdev_by_user(adapter->deflink, WLAN_OSIF_SCAN_ID); 346 if (!vdev) 347 return -EINVAL; 348 349 scan_req_status = ucfg_scan_get_pdev_status(wlan_vdev_get_pdev(vdev)); 350 wlan_objmgr_vdev_release_ref(vdev, WLAN_OSIF_SCAN_ID); 351 352 if (scan_req_status != SCAN_NOT_IN_PROGRESS) { 353 hdd_debug("Scan in progress: %d, bcn rpt start OP not allowed", 354 scan_req_status); 355 return -EBUSY; 356 } 357 358 errno = 359 wlan_cfg80211_nla_parse(tb, 360 QCA_WLAN_VENDOR_ATTR_BEACON_REPORTING_MAX, 361 data, 362 data_len, beacon_reporting_params_policy); 363 if (errno) { 364 hdd_err("Failed to parse the beacon reporting params %d", 365 errno); 366 return errno; 367 } 368 369 /* Parse and fetch OP Type */ 370 if (!tb[QCA_WLAN_VENDOR_ATTR_BEACON_REPORTING_OP_TYPE]) { 371 hdd_err("attr beacon report OP type failed"); 372 return -EINVAL; 373 } 374 bcn_report = 375 nla_get_u8(tb[QCA_WLAN_VENDOR_ATTR_BEACON_REPORTING_OP_TYPE]); 376 hdd_debug("Bcn Report: OP type:%d", bcn_report); 377 378 switch (bcn_report) { 379 case QCA_WLAN_VENDOR_BEACON_REPORTING_OP_START: 380 active_report = 381 !!tb[QCA_WLAN_VENDOR_ATTR_BEACON_REPORTING_ACTIVE_REPORTING]; 382 hdd_debug("attr active_report %d", active_report); 383 384 do_not_resume = 385 !!tb[QCA_WLAN_VENDOR_ATTR_BEACON_REPORTING_DO_NOT_RESUME]; 386 hdd_debug("Attr beacon report do not resume %d", do_not_resume); 387 388 if (tb[QCA_WLAN_VENDOR_ATTR_BEACON_REPORTING_PERIOD]) 389 nth_value = 390 nla_get_u8(tb[QCA_WLAN_VENDOR_ATTR_BEACON_REPORTING_PERIOD]); 391 hdd_debug("Beacon Report: Period: %d", nth_value); 392 393 if (sme_is_beacon_report_started(hdd_ctx->mac_handle, 394 adapter->deflink->vdev_id)) { 395 hdd_debug("Start cmd already in progress, issue the stop to FW, before new start"); 396 if (hdd_handle_beacon_reporting_stop_op(hdd_ctx, 397 adapter)) { 398 hdd_err("Failed to stop the beacon reporting before starting new start"); 399 return -EAGAIN; 400 } 401 } 402 errno = hdd_handle_beacon_reporting_start_op(hdd_ctx, 403 adapter, 404 active_report, 405 nth_value, 406 do_not_resume); 407 if (errno) { 408 hdd_err("Failed to start beacon reporting %d,", errno); 409 break; 410 } 411 break; 412 case QCA_WLAN_VENDOR_BEACON_REPORTING_OP_STOP: 413 if (sme_is_beacon_report_started(hdd_ctx->mac_handle, 414 adapter->deflink->vdev_id)) { 415 errno = hdd_handle_beacon_reporting_stop_op(hdd_ctx, 416 adapter); 417 if (errno) { 418 hdd_err("Failed to stop the beacon report, %d", 419 errno); 420 } 421 } else { 422 hdd_err_rl("BCN_RCV_STOP rej as no START CMD active"); 423 errno = -EINVAL; 424 } 425 break; 426 default: 427 hdd_debug("Invalid bcn report type %d", bcn_report); 428 } 429 430 return errno; 431 } 432 hdd_beacon_recv_pause_indication(hdd_handle_t hdd_handle,uint8_t vdev_id,enum scan_event_type type,bool is_disconnected)433 void hdd_beacon_recv_pause_indication(hdd_handle_t hdd_handle, 434 uint8_t vdev_id, 435 enum scan_event_type type, 436 bool is_disconnected) 437 { 438 struct hdd_context *hdd_ctx = hdd_handle_to_context(hdd_handle); 439 struct hdd_adapter *adapter; 440 struct sk_buff *vendor_event; 441 uint32_t data_len; 442 int flags; 443 uint32_t abort_reason; 444 bool do_not_resume; 445 struct wlan_hdd_link_info *link_info; 446 447 if (wlan_hdd_validate_context(hdd_ctx)) 448 return; 449 450 link_info = hdd_get_link_info_by_vdev(hdd_ctx, vdev_id); 451 if (!link_info || hdd_validate_adapter(link_info->adapter)) 452 return; 453 454 adapter = link_info->adapter; 455 data_len = get_pause_ind_data_len(is_disconnected); 456 flags = cds_get_gfp_flags(); 457 458 vendor_event = 459 wlan_cfg80211_vendor_event_alloc( 460 hdd_ctx->wiphy, &(adapter->wdev), 461 data_len, 462 QCA_NL80211_VENDOR_SUBCMD_BEACON_REPORTING_INDEX, 463 flags); 464 if (!vendor_event) { 465 hdd_err("wlan_cfg80211_vendor_event_alloc failed"); 466 return; 467 } 468 469 do_not_resume = 470 sme_is_beacon_reporting_do_not_resume(hdd_ctx->mac_handle, 471 link_info->vdev_id); 472 473 if (is_disconnected) { 474 abort_reason = 475 QCA_WLAN_VENDOR_BEACON_REPORTING_PAUSE_REASON_DISCONNECTED; 476 /* Deregister callbacks and Reset bcn recv start flag */ 477 if (sme_is_beacon_report_started(hdd_ctx->mac_handle, 478 link_info->vdev_id)) 479 hdd_handle_beacon_reporting_stop_op(hdd_ctx, adapter); 480 } else { 481 /* 482 * In case of scan, Check that auto resume of beacon reporting 483 * is allowed or not. 484 * If not allowed: 485 * Deregister callbacks and Reset bcn recv start flag in order 486 * to make sure host should not send beacon report to userspace 487 * further. 488 * If Auto resume allowed: 489 * Send pause indication to userspace and continue sending 490 * connected AP's beacon to userspace. 491 */ 492 if (do_not_resume) 493 hdd_handle_beacon_reporting_stop_op(hdd_ctx, adapter); 494 495 switch (type) { 496 case SCAN_EVENT_TYPE_STARTED: 497 abort_reason = 498 QCA_WLAN_VENDOR_BEACON_REPORTING_PAUSE_REASON_SCAN_STARTED; 499 break; 500 default: 501 abort_reason = 502 QCA_WLAN_VENDOR_BEACON_REPORTING_PAUSE_REASON_UNSPECIFIED; 503 } 504 } 505 /* Send vendor event to user space to inform ABORT */ 506 if (nla_put_u32(vendor_event, 507 QCA_WLAN_VENDOR_ATTR_BEACON_REPORTING_OP_TYPE, 508 QCA_WLAN_VENDOR_BEACON_REPORTING_OP_PAUSE) || 509 nla_put_u32(vendor_event, 510 QCA_WLAN_VENDOR_ATTR_BEACON_REPORTING_PAUSE_REASON, 511 abort_reason)) { 512 hdd_err("QCA_WLAN_VENDOR_ATTR put fail"); 513 wlan_cfg80211_vendor_free_skb(vendor_event); 514 return; 515 } 516 517 /* 518 * Send auto resume flag to user space to specify the driver will 519 * automatically resume reporting beacon events only in case of 520 * pause indication due to scan started. 521 * If do_not_resume flag is set in the recent 522 * QCA_WLAN_VENDOR_BEACON_REPORTING_OP_START command, then in the 523 * subsequent QCA_WLAN_VENDOR_BEACON_REPORTING_OP_PAUSE event (if any) 524 * the QCA_WLAN_VENDOR_ATTR_BEACON_REPORTING_AUTO_RESUMES shall not be 525 * set by the driver. 526 */ 527 if (!is_disconnected && !do_not_resume) 528 if (nla_put_flag(vendor_event, 529 QCA_WLAN_VENDOR_ATTR_BEACON_REPORTING_AUTO_RESUMES)) { 530 hdd_err("QCA_WLAN_VENDOR_ATTR put fail"); 531 wlan_cfg80211_vendor_free_skb(vendor_event); 532 return; 533 } 534 535 wlan_cfg80211_vendor_event(vendor_event, flags); 536 } 537 wlan_hdd_cfg80211_bcn_rcv_op(struct wiphy * wiphy,struct wireless_dev * wdev,const void * data,int data_len)538 int wlan_hdd_cfg80211_bcn_rcv_op(struct wiphy *wiphy, 539 struct wireless_dev *wdev, 540 const void *data, int data_len) 541 { 542 int errno; 543 struct osif_vdev_sync *vdev_sync; 544 545 errno = osif_vdev_sync_op_start(wdev->netdev, &vdev_sync); 546 if (errno) 547 return errno; 548 549 errno = __wlan_hdd_cfg80211_bcn_rcv_op(wiphy, wdev, 550 data, data_len); 551 552 osif_vdev_sync_op_stop(vdev_sync); 553 554 return errno; 555 } 556