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