diff --git a/core/hdd/src/wlan_hdd_bcn_recv.c b/core/hdd/src/wlan_hdd_bcn_recv.c index dc65934452bb..0447ac6e937d 100644 --- a/core/hdd/src/wlan_hdd_bcn_recv.c +++ b/core/hdd/src/wlan_hdd_bcn_recv.c @@ -76,6 +76,92 @@ int get_beacon_report_data_len(struct wlan_beacon_report *report) return data_len; } +/** + * get_pause_ind_data_len() - Calculate skb buffer length + * @report: Required beacon report + * + * Calculate length for pause indication to allocate skb buffer + * + * Return: skb buffer length + */ +static int get_pause_ind_data_len(void) +{ + uint32_t data_len = NLMSG_HDRLEN; + + /* QCA_WLAN_VENDOR_ATTR_BEACON_REPORTING_OP_TYPE */ + data_len += nla_total_size(sizeof(u32)); + + /* QCA_WLAN_VENDOR_ATTR_BEACON_REPORTING_PAUSE_REASON */ + data_len += nla_total_size(sizeof(u32)); + + return data_len; +} + +/** + * hdd_beacon_recv_pause_indication()- Send vendor event to user space + * to inform SCAN started indication + * @hdd_handle: hdd handler + * @vdev_id: vdev id + * @type: scan event type + * + * Return: None + */ +static void hdd_beacon_recv_pause_indication(hdd_handle_t hdd_handle, + uint8_t vdev_id, + enum scan_event_type type) +{ + struct hdd_context *hdd_ctx = hdd_handle_to_context(hdd_handle); + struct hdd_adapter *adapter; + struct sk_buff *vendor_event; + uint32_t data_len; + int flags; + uint32_t abort_reason; + + if (wlan_hdd_validate_context(hdd_ctx)) + return; + + adapter = hdd_get_adapter_by_vdev(hdd_ctx, vdev_id); + if (hdd_validate_adapter(adapter)) + return; + + data_len = get_pause_ind_data_len(); + flags = cds_get_gfp_flags(); + + vendor_event = + cfg80211_vendor_event_alloc( + hdd_ctx->wiphy, NULL, + data_len, + QCA_NL80211_VENDOR_SUBCMD_BEACON_REPORTING_INDEX, + flags); + if (!vendor_event) { + hdd_err("cfg80211_vendor_event_alloc failed"); + return; + } + + switch (type) { + case SCAN_EVENT_TYPE_STARTED: + abort_reason = + QCA_WLAN_VENDOR_BEACON_REPORTING_PAUSE_REASON_SCAN_STARTED; + break; + default: + abort_reason = + QCA_WLAN_VENDOR_BEACON_REPORTING_PAUSE_REASON_UNSPECIFIED; + } + /* Send vendor event to user space to inform ABORT */ + if (nla_put_u32(vendor_event, + QCA_WLAN_VENDOR_ATTR_BEACON_REPORTING_OP_TYPE, + QCA_WLAN_VENDOR_BEACON_REPORTING_OP_PAUSE) || + nla_put_u32(vendor_event, + QCA_WLAN_VENDOR_ATTR_BEACON_REPORTING_PAUSE_REASON, + abort_reason)) { + hdd_err("QCA_WLAN_VENDOR_ATTR put fail"); + kfree_skb(vendor_event); + return; + } + + cfg80211_vendor_event(vendor_event, flags); +} + /** * hdd_send_bcn_recv_info() - Send beacon info to userspace for * connected AP @@ -211,6 +297,16 @@ static int __wlan_hdd_cfg80211_bcn_rcv_start(struct wiphy *wiphy, return errno; } } + qdf_status = + sme_register_bcn_recv_pause_ind_cb(hdd_ctx->mac_handle, + hdd_beacon_recv_pause_indication); + if (QDF_IS_STATUS_ERROR(qdf_status)) { + hdd_err("bcn_recv_abort_ind cb reg failed = %d", + qdf_status); + errno = qdf_status_to_os_return(qdf_status); + return errno; + } + qdf_status = sme_handle_bcn_recv_start(hdd_ctx->mac_handle, adapter->vdev_id); diff --git a/core/sme/inc/sme_api.h b/core/sme/inc/sme_api.h index d43becdff09f..e1eed1106453 100644 --- a/core/sme/inc/sme_api.h +++ b/core/sme/inc/sme_api.h @@ -3455,4 +3455,27 @@ sme_get_mws_coex_info(mac_handle_t mac_handle, uint32_t vdev_id, void *context); #endif /* WLAN_MWS_INFO_DEBUGFS */ +#ifdef WLAN_BCN_RECV_FEATURE +/** + * sme_register_bcn_recv_pause_ind_cb() - Register pause ind cb + * mac_handle: man handler + * cb: callback function to HDD + * + * This function register HDD callback in order to indicate beacon + * receive pause indication to userspace. + * + * return QDF_STATUS of cb registration + */ +QDF_STATUS sme_register_bcn_recv_pause_ind_cb(mac_handle_t mac_handle, + beacon_pause_cb cb); + +#else +static inline +QDF_STATUS sme_register_bcn_recv_pause_ind_cb(mac_handle_t mac_handle, + beacon_pause_cb cb) +{ + return QDF_STATUS_SUCCESS; +} +#endif + #endif /* #if !defined( __SME_API_H ) */ diff --git a/core/sme/inc/sme_internal.h b/core/sme/inc/sme_internal.h index 6d6802ccf17c..827acdeb9ca1 100644 --- a/core/sme/inc/sme_internal.h +++ b/core/sme/inc/sme_internal.h @@ -265,6 +265,16 @@ typedef void (*hidden_ssid_cb)(hdd_handle_t hdd_handle, typedef void (*beacon_report_cb)(hdd_handle_t hdd_handle, struct wlan_beacon_report *beacon_report); +/** + * beacon_pause_cb : scan start callback fun + * @hdd_handler: HDD handler + * @vdev_id: vdev id + * @type: scan event type + */ +typedef void (*beacon_pause_cb)(hdd_handle_t hdd_handle, + uint8_t vdev_id, + enum scan_event_type type); + #ifdef WLAN_FEATURE_MOTION_DETECTION typedef QDF_STATUS (*md_host_evt_cb)(void *hdd_ctx, struct sir_md_evt *event); #endif /* WLAN_FEATURE_MOTION_DETECTION */ @@ -374,6 +384,7 @@ struct sme_context { #ifdef WLAN_BCN_RECV_FEATURE beacon_report_cb beacon_report_cb; + beacon_pause_cb beacon_pause_cb; #endif }; diff --git a/core/sme/src/common/sme_api.c b/core/sme/src/common/sme_api.c index 8ba26dfdf96a..b7d8dd62fd0b 100644 --- a/core/sme/src/common/sme_api.c +++ b/core/sme/src/common/sme_api.c @@ -15526,3 +15526,67 @@ sme_get_mws_coex_info(mac_handle_t mac_handle, uint32_t vdev_id, return status; } #endif /* WLAN_MWS_INFO_DEBUGFS */ + +#ifdef WLAN_BCN_RECV_FEATURE +/** + * sme_scan_event_handler() - Scan complete event handler + * @vdev: vdev obj manager + * @event: scan event + * @arg: arg of scan event + * + * This function is getting called after Host receive scan start + * + * Return: None + */ +static void sme_scan_event_handler(struct wlan_objmgr_vdev *vdev, + struct scan_event *event, + void *arg) +{ + struct mac_context *mac = arg; + struct csr_roam_session *session; + + if (!mac) { + sme_err("Invalid mac context"); + return; + } + + if (!CSR_IS_SESSION_VALID(mac, vdev->vdev_objmgr.vdev_id)) { + sme_err("Invalid vdev_id: %d", vdev->vdev_objmgr.vdev_id); + return; + } + + session = CSR_GET_SESSION(mac, vdev->vdev_objmgr.vdev_id); + + if (event->type == SCAN_EVENT_TYPE_STARTED) { + if (mac->sme.beacon_pause_cb) + mac->sme.beacon_pause_cb(mac->hdd_handle, + vdev->vdev_objmgr.vdev_id, event->type); + } +} + +QDF_STATUS sme_register_bcn_recv_pause_ind_cb(mac_handle_t mac_handle, + beacon_pause_cb cb) +{ + QDF_STATUS status; + struct mac_context *mac = MAC_CONTEXT(mac_handle); + + if (!mac) { + sme_err("Invalid mac context"); + return QDF_STATUS_E_NOMEM; + } + + status = sme_acquire_global_lock(&mac->sme); + if (QDF_IS_STATUS_SUCCESS(status)) { + mac->sme.beacon_pause_cb = cb; + sme_release_global_lock(&mac->sme); + } + + /* scan event registration */ + status = ucfg_scan_register_event_handler(mac->pdev, + sme_scan_event_handler, mac); + if (QDF_IS_STATUS_ERROR(status)) + sme_err("scan event register failed "); + + return status; +} +#endif