From e85ae55537cede50ba1cf043d3dca773c7431871 Mon Sep 17 00:00:00 2001 From: Abhinav Kumar Date: Wed, 5 Jun 2019 19:02:14 +0530 Subject: [PATCH] qcacld-3.0: Handle BEACON_REPORTING_DO_NOT_RESUME vendor attribute Optionally set by userspace to request the driver not to resume beacon reporting after a pause is completed, when the QCA_WLAN_VENDOR_ATTR_BEACON_REPORTING_OP_TYPE is set to QCA_WLAN_VENDOR_BEACON_REPORTING_OP_START. If this flag is set, the driver will not resume beacon reporting after beacon reporting pause is completed. Userspace has to send QCA_WLAN_VENDOR_BEACON_REPORTING_OP_START command again in order to initiate beacon reporting again. If this flag is set in the recent QCA_WLAN_VENDOR_BEACON_REPORTING_OP_START command, then in the subsequent QCA_WLAN_VENDOR_BEACON_REPORTING_OP_PAUSE event (if any) the QCA_WLAN_VENDOR_ATTR_BEACON_REPORTING_AUTO_RESUMES shall not be set by the driver. Change-Id: I371a218cb513dcb077b7df675c549818c2b657b2 CRs-Fixed: 2466480 --- core/hdd/inc/wlan_hdd_bcn_recv.h | 12 ++-- core/hdd/src/wlan_hdd_bcn_recv.c | 110 +++++++++++++++++++++++-------- core/sme/inc/csr_internal.h | 2 + core/sme/inc/sme_api.h | 23 ++++++- core/sme/src/common/sme_api.c | 34 ++++++++-- 5 files changed, 139 insertions(+), 42 deletions(-) diff --git a/core/hdd/inc/wlan_hdd_bcn_recv.h b/core/hdd/inc/wlan_hdd_bcn_recv.h index cfd6bc65062e..b603ee1f0431 100644 --- a/core/hdd/inc/wlan_hdd_bcn_recv.h +++ b/core/hdd/inc/wlan_hdd_bcn_recv.h @@ -28,19 +28,19 @@ struct wireless_dev; struct wiphy; /** - * wlan_hdd_cfg80211_bcn_rcv_start() - Process bcn recv start ind + * wlan_hdd_cfg80211_bcn_rcv_op() - Process beacon report operations * @wiphy: Pointer to wireless phy * @wdev: Pointer to wireless device * @data: Pointer to data * @data_len: Length of @data * - * Wrapper function of __wlan_hdd_cfg80211_bcn_rcv_start() + * Wrapper function of __wlan_hdd_cfg80211_bcn_rcv_op() * * Return: 0 on success, negative errno on failure */ -int wlan_hdd_cfg80211_bcn_rcv_start(struct wiphy *wiphy, - struct wireless_dev *wdev, - const void *data, int data_len); +int wlan_hdd_cfg80211_bcn_rcv_op(struct wiphy *wiphy, + struct wireless_dev *wdev, + const void *data, int data_len); /** * hdd_beacon_recv_pause_indication()- Send vendor event to user space @@ -64,7 +64,7 @@ void hdd_beacon_recv_pause_indication(hdd_handle_t hdd_handle, .flags = WIPHY_VENDOR_CMD_NEED_WDEV | \ WIPHY_VENDOR_CMD_NEED_NETDEV | \ WIPHY_VENDOR_CMD_NEED_RUNNING, \ - .doit = wlan_hdd_cfg80211_bcn_rcv_start \ + .doit = wlan_hdd_cfg80211_bcn_rcv_op\ }, #define BCN_RECV_FEATURE_VENDOR_EVENTS \ diff --git a/core/hdd/src/wlan_hdd_bcn_recv.c b/core/hdd/src/wlan_hdd_bcn_recv.c index ffe78be9d0bf..3267259a4384 100644 --- a/core/hdd/src/wlan_hdd_bcn_recv.c +++ b/core/hdd/src/wlan_hdd_bcn_recv.c @@ -45,6 +45,8 @@ beacon_reporting_params[QCA_WLAN_VENDOR_ATTR_BEACON_REPORTING_MAX + 1] = { [QCA_WLAN_VENDOR_ATTR_BEACON_REPORTING_ACTIVE_REPORTING] = {.type = NLA_FLAG}, [QCA_WLAN_VENDOR_ATTR_BEACON_REPORTING_PERIOD] = {.type = NLA_U8}, + [QCA_WLAN_VENDOR_ATTR_BEACON_REPORTING_DO_NOT_RESUME] = {.type = + NLA_FLAG}, }; /** @@ -173,13 +175,15 @@ static void hdd_send_bcn_recv_info(hdd_handle_t hdd_handle, * @adapter: Pointer to network adapter * @active_report: Active reporting flag * @nth_value: Beacon report period + * @do_not_resume: beacon reporting resume after a pause is completed * * This function process beacon reporting start operation. */ static int hdd_handle_beacon_reporting_start_op(struct hdd_context *hdd_ctx, struct hdd_adapter *adapter, bool active_report, - uint32_t nth_value) + uint32_t nth_value, + bool do_not_resume) { QDF_STATUS qdf_status = QDF_STATUS_SUCCESS; int errno; @@ -216,9 +220,15 @@ static int hdd_handle_beacon_reporting_start_op(struct hdd_context *hdd_ctx, } /* Handle beacon receive start indication */ qdf_status = sme_handle_bcn_recv_start(hdd_ctx->mac_handle, - adapter->vdev_id, nth_value); + adapter->vdev_id, nth_value, + do_not_resume); if (QDF_IS_STATUS_ERROR(qdf_status)) { hdd_err("bcn rcv start failed with status=%d", qdf_status); + if (sme_register_bcn_report_pe_cb(hdd_ctx->mac_handle, NULL)) + hdd_err("bcn report cb deregistration failed"); + if (sme_register_bcn_recv_pause_ind_cb(hdd_ctx->mac_handle, + NULL)) + hdd_err("bcn pause ind cb deregistration failed"); errno = qdf_status_to_os_return(qdf_status); return errno; } @@ -274,7 +284,7 @@ static int hdd_handle_beacon_reporting_stop_op(struct hdd_context *hdd_ctx, } /** - * __wlan_hdd_cfg80211_bcn_rcv_start() - enable/disable beacon reporting + * __wlan_hdd_cfg80211_bcn_rcv_op() - enable/disable beacon reporting * indication * @wiphy: Pointer to wireless phy * @wdev: Pointer to wireless device @@ -286,9 +296,9 @@ static int hdd_handle_beacon_reporting_stop_op(struct hdd_context *hdd_ctx, * * Return: 0 on success, negative errno on failure */ -static int __wlan_hdd_cfg80211_bcn_rcv_start(struct wiphy *wiphy, - struct wireless_dev *wdev, - const void *data, int data_len) +static int __wlan_hdd_cfg80211_bcn_rcv_op(struct wiphy *wiphy, + struct wireless_dev *wdev, + const void *data, int data_len) { struct hdd_context *hdd_ctx = wiphy_priv(wiphy); struct net_device *dev = wdev->netdev; @@ -296,7 +306,7 @@ static int __wlan_hdd_cfg80211_bcn_rcv_start(struct wiphy *wiphy, struct nlattr *tb[QCA_WLAN_VENDOR_ATTR_BEACON_REPORTING_MAX + 1]; uint32_t bcn_report, nth_value = 1; int errno; - bool active_report; + bool active_report, do_not_resume; hdd_enter_dev(dev); @@ -319,8 +329,9 @@ static int __wlan_hdd_cfg80211_bcn_rcv_start(struct wiphy *wiphy, QCA_WLAN_VENDOR_ATTR_BEACON_REPORTING_MAX, data, data_len, beacon_reporting_params); if (errno) { - hdd_err("Invalid ATTR"); - return -EINVAL; + hdd_err("Failed to parse the beacon reporting params %d", + errno); + return errno; } /* Parse and fetch OP Type */ @@ -328,38 +339,56 @@ static int __wlan_hdd_cfg80211_bcn_rcv_start(struct wiphy *wiphy, hdd_err("attr beacon report OP type failed"); return -EINVAL; } - active_report = - !!tb[QCA_WLAN_VENDOR_ATTR_BEACON_REPORTING_ACTIVE_REPORTING]; - hdd_debug("attr active_report %d", active_report); - bcn_report = nla_get_u8(tb[QCA_WLAN_VENDOR_ATTR_BEACON_REPORTING_OP_TYPE]); hdd_debug("Bcn Report: OP type:%d", bcn_report); - if (tb[QCA_WLAN_VENDOR_ATTR_BEACON_REPORTING_PERIOD]) - nth_value = - nla_get_u8(tb[QCA_WLAN_VENDOR_ATTR_BEACON_REPORTING_PERIOD]); - hdd_debug("Beacon Report: Period: %d", nth_value); - switch (bcn_report) { case QCA_WLAN_VENDOR_BEACON_REPORTING_OP_START: + active_report = + !!tb[QCA_WLAN_VENDOR_ATTR_BEACON_REPORTING_ACTIVE_REPORTING]; + hdd_debug("attr active_report %d", active_report); + + do_not_resume = + !!tb[QCA_WLAN_VENDOR_ATTR_BEACON_REPORTING_DO_NOT_RESUME]; + hdd_debug("Attr beacon report do not resume %d", do_not_resume); + + if (tb[QCA_WLAN_VENDOR_ATTR_BEACON_REPORTING_PERIOD]) + nth_value = + nla_get_u8(tb[QCA_WLAN_VENDOR_ATTR_BEACON_REPORTING_PERIOD]); + hdd_debug("Beacon Report: Period: %d", nth_value); + if (sme_is_beacon_report_started(hdd_ctx->mac_handle, adapter->vdev_id)) { - hdd_debug("Start cmd already in progress"); - return errno; + hdd_debug("Start cmd already in progress, issue the stop to FW, before new start"); + if (hdd_handle_beacon_reporting_stop_op(hdd_ctx, + adapter)) { + hdd_err("Failed to stop the beacon reporting before starting new start"); + return -EAGAIN; + } } errno = hdd_handle_beacon_reporting_start_op(hdd_ctx, adapter, active_report, - nth_value); + nth_value, + do_not_resume); + if (errno) { + hdd_err("Failed to start beacon reporting %d,", errno); + break; + } break; case QCA_WLAN_VENDOR_BEACON_REPORTING_OP_STOP: if (sme_is_beacon_report_started(hdd_ctx->mac_handle, adapter->vdev_id)) { errno = hdd_handle_beacon_reporting_stop_op(hdd_ctx, adapter); + if (errno) { + hdd_err("Failed to stop the beacon report, %d", + errno); + } } else { hdd_err_rl("BCN_RCV_STOP rej as no START CMD active"); + errno = -EINVAL; } break; default: @@ -380,6 +409,7 @@ void hdd_beacon_recv_pause_indication(hdd_handle_t hdd_handle, uint32_t data_len; int flags; uint32_t abort_reason; + bool do_not_resume; if (wlan_hdd_validate_context(hdd_ctx)) return; @@ -402,6 +432,10 @@ void hdd_beacon_recv_pause_indication(hdd_handle_t hdd_handle, return; } + do_not_resume = + sme_is_beacon_reporting_do_not_resume(hdd_ctx->mac_handle, + adapter->vdev_id); + if (is_disconnected) { abort_reason = QCA_WLAN_VENDOR_BEACON_REPORTING_PAUSE_REASON_DISCONNECTED; @@ -411,8 +445,23 @@ void hdd_beacon_recv_pause_indication(hdd_handle_t hdd_handle, hdd_handle_beacon_reporting_stop_op(hdd_ctx, adapter); } else { + /* + * In case of scan, Check that auto resume of beacon reporting + * is allowed or not. + * If not allowed: + * Deregister callbacks and Reset bcn recv start flag in order + * to make sure host should not send beacon report to userspace + * further. + * If Auto resume allowed: + * Send pause indication to userspace and continue sending + * connected AP's beacon to userspace. + */ + if (do_not_resume) + hdd_handle_beacon_reporting_stop_op(hdd_ctx, + adapter); + switch (type) { - case SCAN_EVENT_TYPE_STARTED: + case SCAN_EVENT_TYPE_FOREIGN_CHANNEL: abort_reason = QCA_WLAN_VENDOR_BEACON_REPORTING_PAUSE_REASON_SCAN_STARTED; break; @@ -437,8 +486,13 @@ void hdd_beacon_recv_pause_indication(hdd_handle_t hdd_handle, * Send auto resume flag to user space to specify the driver will * automatically resume reporting beacon events only in case of * pause indication due to scan started. + * If do_not_resume flag is set in the recent + * QCA_WLAN_VENDOR_BEACON_REPORTING_OP_START command, then in the + * subsequent QCA_WLAN_VENDOR_BEACON_REPORTING_OP_PAUSE event (if any) + * the QCA_WLAN_VENDOR_ATTR_BEACON_REPORTING_AUTO_RESUMES shall not be + * set by the driver. */ - if (!is_disconnected) + if (!is_disconnected || !do_not_resume) if (nla_put_flag(vendor_event, QCA_WLAN_VENDOR_ATTR_BEACON_REPORTING_AUTO_RESUMES)) { hdd_err("QCA_WLAN_VENDOR_ATTR put fail"); @@ -449,9 +503,9 @@ void hdd_beacon_recv_pause_indication(hdd_handle_t hdd_handle, cfg80211_vendor_event(vendor_event, flags); } -int wlan_hdd_cfg80211_bcn_rcv_start(struct wiphy *wiphy, - struct wireless_dev *wdev, - const void *data, int data_len) +int wlan_hdd_cfg80211_bcn_rcv_op(struct wiphy *wiphy, + struct wireless_dev *wdev, + const void *data, int data_len) { int errno; struct osif_vdev_sync *vdev_sync; @@ -460,8 +514,8 @@ int wlan_hdd_cfg80211_bcn_rcv_start(struct wiphy *wiphy, if (errno) return errno; - errno = __wlan_hdd_cfg80211_bcn_rcv_start(wiphy, wdev, - data, data_len); + errno = __wlan_hdd_cfg80211_bcn_rcv_op(wiphy, wdev, + data, data_len); osif_vdev_sync_op_stop(vdev_sync); diff --git a/core/sme/inc/csr_internal.h b/core/sme/inc/csr_internal.h index 5fc4d3a9efd7..6cb1746ca586 100644 --- a/core/sme/inc/csr_internal.h +++ b/core/sme/inc/csr_internal.h @@ -567,6 +567,7 @@ struct csr_disconnect_stats { * struct csr_roam_session - CSR per-vdev context * @vdev_id: ID of the vdev for which this entry is applicable * @is_bcn_recv_start: Allow to process bcn recv indication + * @beacon_report_do_not_resume: Do not resume the beacon reporting after scan */ struct csr_roam_session { union { @@ -642,6 +643,7 @@ struct csr_roam_session { qdf_mc_timer_t hTimerRoaming; #ifdef WLAN_BCN_RECV_FEATURE bool is_bcn_recv_start; + bool beacon_report_do_not_resume; #endif /* the roamResult that is used when the roaming timer fires */ eCsrRoamResult roamResult; diff --git a/core/sme/inc/sme_api.h b/core/sme/inc/sme_api.h index 89104f9206ba..9b3d7d61f226 100644 --- a/core/sme/inc/sme_api.h +++ b/core/sme/inc/sme_api.h @@ -1585,6 +1585,7 @@ QDF_STATUS sme_update_mimo_power_save(mac_handle_t mac_handle, * @mac_handle: Opaque handle to the global MAC context * @vdev_id: SME session id * @nth_value: Beacon report period + * @do_not_resume: beacon reporting resume after a pause is completed * * This function remove beacon filter. It allow fw to send * all beacons from connected peer to driver. @@ -1593,7 +1594,8 @@ QDF_STATUS sme_update_mimo_power_save(mac_handle_t mac_handle, */ QDF_STATUS sme_handle_bcn_recv_start(mac_handle_t mac_handle, uint32_t vdev_id, - uint32_t nth_value); + uint32_t nth_value, + bool do_not_resume); /** * sme_is_beacon_report_started() - Check bcn recv started @@ -1607,6 +1609,18 @@ QDF_STATUS sme_handle_bcn_recv_start(mac_handle_t mac_handle, bool sme_is_beacon_report_started(mac_handle_t mac_handle, uint32_t session_id); +/** + * sme_is_beacon_reporting_do_not_resume() - Check auto resume allowed or not + * @mac_handle: Opaque handle to the global MAC context + * @session_id: SME session id + * + * This function is to check auto resume of beacon reporting is allowed or not. + * + * Return: true on success + */ +bool sme_is_beacon_reporting_do_not_resume(mac_handle_t mac_handle, + uint32_t session_id); + /** * stop_beacon_report() - To stop beacon report * @mac_handle: Opaque handle to the global MAC context @@ -1625,6 +1639,13 @@ bool sme_is_beacon_report_started(mac_handle_t mac_handle, return true; } +static inline +bool sme_is_beacon_reporting_do_not_resume(mac_handle_t mac_handle, + uint32_t session_id) +{ + return false; +} + static inline void sme_stop_beacon_report(mac_handle_t mac_handle, uint32_t session_id) diff --git a/core/sme/src/common/sme_api.c b/core/sme/src/common/sme_api.c index 62baeced640f..fc18b498caed 100644 --- a/core/sme/src/common/sme_api.c +++ b/core/sme/src/common/sme_api.c @@ -12634,7 +12634,8 @@ QDF_STATUS sme_update_mimo_power_save(mac_handle_t mac_handle, #ifdef WLAN_BCN_RECV_FEATURE QDF_STATUS sme_handle_bcn_recv_start(mac_handle_t mac_handle, - uint32_t vdev_id, uint32_t nth_value) + uint32_t vdev_id, uint32_t nth_value, + bool do_not_resume) { struct mac_context *mac_ctx = MAC_CONTEXT(mac_handle); struct csr_roam_session *session; @@ -12660,6 +12661,7 @@ QDF_STATUS sme_handle_bcn_recv_start(mac_handle_t mac_handle, return QDF_STATUS_SUCCESS; } session->is_bcn_recv_start = true; + session->beacon_report_do_not_resume = do_not_resume; sme_release_global_lock(&mac_ctx->sme); } @@ -12676,6 +12678,7 @@ QDF_STATUS sme_handle_bcn_recv_start(mac_handle_t mac_handle, status = sme_acquire_global_lock(&mac_ctx->sme); if (QDF_IS_STATUS_SUCCESS(status)) { session->is_bcn_recv_start = false; + session->beacon_report_do_not_resume = false; sme_release_global_lock(&mac_ctx->sme); } sme_err("WMI_VDEV_PARAM_NTH_BEACON_TO_HOST %d", ret); @@ -12692,16 +12695,12 @@ void sme_stop_beacon_report(mac_handle_t mac_handle, uint32_t session_id) QDF_STATUS status; int ret; - if (!CSR_IS_SESSION_VALID(mac_ctx, session_id)) { - sme_err("CSR session not valid: %d", session_id); - return; - } - session = CSR_GET_SESSION(mac_ctx, session_id); if (!session) { sme_err("vdev_id %d not found", session_id); return; } + ret = sme_cli_set_command(session_id, WMI_VDEV_PARAM_NTH_BEACON_TO_HOST, 0, VDEV_CMD); @@ -12710,6 +12709,7 @@ void sme_stop_beacon_report(mac_handle_t mac_handle, uint32_t session_id) status = sme_acquire_global_lock(&mac_ctx->sme); if (QDF_IS_STATUS_SUCCESS(status)) { session->is_bcn_recv_start = false; + session->beacon_report_do_not_resume = false; sme_release_global_lock(&mac_ctx->sme); } } @@ -12719,18 +12719,38 @@ bool sme_is_beacon_report_started(mac_handle_t mac_handle, uint32_t session_id) struct mac_context *mac_ctx = MAC_CONTEXT(mac_handle); struct csr_roam_session *session; + session = CSR_GET_SESSION(mac_ctx, session_id); + if (!session) { + sme_err("vdev_id %d not found", session_id); + return false; + } + if (!CSR_IS_SESSION_VALID(mac_ctx, session_id)) { sme_err("CSR session not valid: %d", session_id); return false; } + return session->is_bcn_recv_start; +} + +bool sme_is_beacon_reporting_do_not_resume(mac_handle_t mac_handle, + uint32_t session_id) +{ + struct mac_context *mac_ctx = MAC_CONTEXT(mac_handle); + struct csr_roam_session *session; + session = CSR_GET_SESSION(mac_ctx, session_id); if (!session) { sme_err("vdev_id %d not found", session_id); return false; } - return session->is_bcn_recv_start; + if (!CSR_IS_SESSION_VALID(mac_ctx, session_id)) { + sme_err("CSR session not valid: %d", session_id); + return false; + } + + return session->beacon_report_do_not_resume; } #endif