diff --git a/components/mlme/core/inc/wlan_mlme_main.h b/components/mlme/core/inc/wlan_mlme_main.h index 144b17267e..cbbecc0e77 100644 --- a/components/mlme/core/inc/wlan_mlme_main.h +++ b/components/mlme/core/inc/wlan_mlme_main.h @@ -126,6 +126,7 @@ struct peer_disconnect_stats_param { * @rso_rx_ops: Roam Rx ops to receive roam offload events from firmware * @wfa_testcmd: WFA config tx ops to send to FW * @disconnect_stats_param: Peer disconnect stats related params for SAP case + * @scan_requester_id: mlme scan requester id */ struct wlan_mlme_psoc_ext_obj { struct wlan_mlme_cfg cfg; @@ -133,6 +134,7 @@ struct wlan_mlme_psoc_ext_obj { struct wlan_cm_roam_rx_ops rso_rx_ops; struct wlan_mlme_wfa_cmd wfa_testcmd; struct peer_disconnect_stats_param disconnect_stats_param; + wlan_scan_requester scan_requester_id; }; /** @@ -921,6 +923,17 @@ struct wlan_mlme_nss_chains *mlme_get_dynamic_vdev_config( */ uint32_t mlme_get_vdev_he_ops(struct wlan_objmgr_psoc *psoc, uint8_t vdev_id); +/** + * mlme_connected_chan_stats_request() - process connected channel stats + * request + * @psoc: pointer to psoc object + * @vdev_id: Vdev id + * + * Return: none + */ +void mlme_connected_chan_stats_request(struct wlan_objmgr_psoc *psoc, + uint8_t vdev_id); + /** * mlme_get_ini_vdev_config() - get the vdev ini config params * @vdev: vdev pointer diff --git a/components/mlme/core/src/wlan_mlme_main.c b/components/mlme/core/src/wlan_mlme_main.c index b109887959..2154db7f6f 100644 --- a/components/mlme/core/src/wlan_mlme_main.c +++ b/components/mlme/core/src/wlan_mlme_main.c @@ -34,9 +34,15 @@ #include "wifi_pos_ucfg_i.h" #include "wlan_mlo_mgr_sta.h" #include "twt/core/src/wlan_twt_cfg.h" +#include "wlan_scan_api.h" +#include "wlan_mlme_vdev_mgr_interface.h" #define NUM_OF_SOUNDING_DIMENSIONS 1 /*Nss - 1, (Nss = 2 for 2x2)*/ +/* Time to passive scan dwell for scan to get channel stats, in milliseconds */ +#define MLME_GET_CHAN_STATS_PASSIVE_SCAN_TIME 40 +#define MLME_GET_CHAN_STATS_WIDE_BAND_PASSIVE_SCAN_TIME 110 + struct wlan_mlme_psoc_ext_obj *mlme_get_psoc_ext_obj_fl( struct wlan_objmgr_psoc *psoc, const char *func, uint32_t line) @@ -59,6 +65,258 @@ struct wlan_mlme_nss_chains *mlme_get_dynamic_vdev_config( return &mlme_priv->dynamic_cfg; } +/* Buffer len size to consider the 4 char freq, and a space, Total 5 */ +#define MLME_CHAN_WEIGHT_CHAR_LEN 5 +#define MLME_MAX_CHAN_TO_PRINT 39 + +/** + * mlme_fill_freq_in_scan_start_request() - Fill frequencies in scan req + * @vdev: vdev common object + * @req: pointer to scan request + * + * Return: QDF_STATUS + */ +static QDF_STATUS +mlme_fill_freq_in_scan_start_request(struct wlan_objmgr_vdev *vdev, + struct scan_start_request *req) +{ + const struct bonded_channel_freq *range; + struct mlme_legacy_priv *mlme_priv; + enum phy_ch_width associated_ch_width; + uint8_t i; + struct chan_list *scan_chan_list; + uint16_t first_freq, operation_chan_freq; + char *chan_buff = NULL; + uint32_t buff_len, buff_num = 0, chan_count = 0; + + mlme_priv = wlan_vdev_mlme_get_ext_hdl(vdev); + if (!mlme_priv) + return QDF_STATUS_E_FAILURE; + + operation_chan_freq = wlan_get_operation_chan_freq(vdev); + associated_ch_width = mlme_priv->connect_info.ch_width_orig; + if (associated_ch_width == CH_WIDTH_INVALID) { + mlme_debug("vdev %d : Invalid associated ch width for freq %d", + req->scan_req.vdev_id, operation_chan_freq); + return QDF_STATUS_E_FAILURE; + } + + req->scan_req.dwell_time_passive = + MLME_GET_CHAN_STATS_PASSIVE_SCAN_TIME; + req->scan_req.dwell_time_passive_6g = + MLME_GET_CHAN_STATS_PASSIVE_SCAN_TIME; + + if (associated_ch_width == CH_WIDTH_20MHZ) { + mlme_debug("vdev %d :Trigger scan for associated freq %d bw %d", + req->scan_req.vdev_id, operation_chan_freq, + associated_ch_width); + req->scan_req.chan_list.num_chan = 1; + req->scan_req.chan_list.chan[0].freq = operation_chan_freq; + return QDF_STATUS_SUCCESS; + } + + range = wlan_reg_get_bonded_chan_entry(operation_chan_freq, + associated_ch_width, 0); + if (!range) { + mlme_debug("vdev %d: Invalid freq range for freq: %d bw: %d", + req->scan_req.vdev_id, operation_chan_freq, + associated_ch_width); + return QDF_STATUS_E_FAILURE; + } + + scan_chan_list = qdf_mem_malloc(sizeof(*scan_chan_list)); + if (!scan_chan_list) + return QDF_STATUS_E_NOMEM; + + scan_chan_list->num_chan = 0; + first_freq = range->start_freq; + for (; first_freq <= range->end_freq; first_freq += BW_20_MHZ) { + scan_chan_list->chan[scan_chan_list->num_chan].freq = + first_freq; + scan_chan_list->num_chan++; + } + + req->scan_req.chan_list.num_chan = scan_chan_list->num_chan; + + mlme_debug("vdev %d : freq %d bw %d, range [%d-%d], Total freq %d", + req->scan_req.vdev_id, operation_chan_freq, + associated_ch_width, range->start_freq, + range->end_freq, req->scan_req.chan_list.num_chan); + + buff_len = (QDF_MIN(req->scan_req.chan_list.num_chan, + MLME_MAX_CHAN_TO_PRINT) * MLME_CHAN_WEIGHT_CHAR_LEN) + 1; + + chan_buff = qdf_mem_malloc(buff_len); + if (!chan_buff) { + qdf_mem_free(scan_chan_list); + return QDF_STATUS_E_NOMEM; + } + for (i = 0; i < req->scan_req.chan_list.num_chan; i++) { + req->scan_req.chan_list.chan[i].freq = + scan_chan_list->chan[i].freq; + buff_num += qdf_scnprintf(chan_buff + buff_num, + buff_len - buff_num, " %d", + req->scan_req.chan_list.chan[i].freq); + chan_count++; + if (chan_count >= MLME_MAX_CHAN_TO_PRINT) { + mlme_debug("Freq list: %s", chan_buff); + buff_num = 0; + chan_count = 0; + } + } + + if (buff_num) + mlme_debug("Freq list: %s", chan_buff); + + qdf_mem_free(chan_buff); + qdf_mem_free(scan_chan_list); + + return QDF_STATUS_SUCCESS; +} + +/** + * mlme_fill_freq_in_wide_scan_start_request() - Fill frequencies in wide band + * scan req + * @vdev: vdev common object + * @req: pointer to scan request + * + * Return: QDF_STATUS + */ +static QDF_STATUS +mlme_fill_freq_in_wide_scan_start_request(struct wlan_objmgr_vdev *vdev, + struct scan_start_request *req) +{ + const struct bonded_channel_freq *range; + struct mlme_legacy_priv *mlme_priv; + enum phy_ch_width associated_ch_width; + qdf_freq_t operation_chan_freq; + + mlme_priv = wlan_vdev_mlme_get_ext_hdl(vdev); + if (!mlme_priv) + return QDF_STATUS_E_FAILURE; + + operation_chan_freq = wlan_get_operation_chan_freq(vdev); + associated_ch_width = mlme_priv->connect_info.ch_width_orig; + + if (associated_ch_width == CH_WIDTH_INVALID) { + mlme_debug("vdev %d :Invalid assoc ch width, freq %d", + req->scan_req.vdev_id, operation_chan_freq); + return QDF_STATUS_E_FAILURE; + } + + if (associated_ch_width == CH_WIDTH_320MHZ) { + range = wlan_reg_get_bonded_chan_entry(operation_chan_freq, + associated_ch_width, 0); + if (!range) { + mlme_debug("vdev %d : range is null for freq %d", + req->scan_req.vdev_id, operation_chan_freq); + return QDF_STATUS_E_FAILURE; + } + + mlme_debug("vdev %d :trigger wide band scan for freq %d bw %d, range [%d-%d], total freq %d", + req->scan_req.vdev_id, operation_chan_freq, + associated_ch_width, range->start_freq, + range->end_freq, req->scan_req.chan_list.num_chan); + + + req->scan_req.chan_list.num_chan = 2; + req->scan_req.chan_list.chan[0].freq = range->start_freq; + req->scan_req.chan_list.chan[1].freq = range->end_freq; + } else { + mlme_debug("vdev %d : trigger wide band scan for freq %d bw %d", + req->scan_req.vdev_id, operation_chan_freq, + associated_ch_width); + req->scan_req.chan_list.num_chan = 1; + req->scan_req.chan_list.chan[0].freq = operation_chan_freq; + } + + req->scan_req.dwell_time_passive = + MLME_GET_CHAN_STATS_WIDE_BAND_PASSIVE_SCAN_TIME; + req->scan_req.dwell_time_passive_6g = + MLME_GET_CHAN_STATS_WIDE_BAND_PASSIVE_SCAN_TIME; + + req->scan_req.scan_f_wide_band = true; + /* + * FW report CCA busy for each possible 20Mhz subbands of the + * wideband scan channel if below flag is true + */ + req->scan_req.scan_f_report_cca_busy_for_each_20mhz = true; + + return QDF_STATUS_SUCCESS; +} + +void mlme_connected_chan_stats_request(struct wlan_objmgr_psoc *psoc, + uint8_t vdev_id) +{ + struct wlan_mlme_psoc_ext_obj *mlme_obj; + QDF_STATUS status; + struct wlan_objmgr_vdev *vdev; + struct scan_start_request *req; + + mlme_obj = mlme_get_psoc_ext_obj(psoc); + if (!mlme_obj) { + mlme_debug("vdev %d : NULL mlme psoc object", vdev_id); + return; + } + + vdev = wlan_objmgr_get_vdev_by_id_from_psoc(psoc, vdev_id, + WLAN_MLME_NB_ID); + if (!vdev) { + mlme_debug("vdev %d : NULL vdev object", vdev_id); + return; + } + + req = qdf_mem_malloc(sizeof(*req)); + if (!req) { + wlan_objmgr_vdev_release_ref(vdev, WLAN_MLME_NB_ID); + return; + } + + status = wlan_scan_init_default_params(vdev, req); + if (QDF_IS_STATUS_ERROR(status)) + goto release; + + req->scan_req.scan_id = wlan_scan_get_scan_id(psoc); + req->scan_req.scan_req_id = mlme_obj->scan_requester_id; + req->scan_req.vdev_id = wlan_vdev_get_id(vdev); + + req->scan_req.scan_type = SCAN_TYPE_DEFAULT; + + /* Fill channel list as per fw capability */ + if (wlan_psoc_nif_fw_ext2_cap_get(psoc, + WLAN_CCA_BUSY_INFO_FOREACH_20MHZ)) { + status = mlme_fill_freq_in_wide_scan_start_request(vdev, req); + if (QDF_IS_STATUS_ERROR(status)) + goto release; + } else { + status = mlme_fill_freq_in_scan_start_request(vdev, req); + if (QDF_IS_STATUS_ERROR(status)) + goto release; + } + + /* disable adatptive dwell time */ + req->scan_req.adaptive_dwell_time_mode = SCAN_DWELL_MODE_STATIC; + /* to disable early 6Ghz scan bail out */ + req->scan_req.min_dwell_time_6g = 0; + /* passive scan for CCA measurement */ + req->scan_req.scan_f_passive = true; + /* Fw pause home channel when scan channel is same as home channel */ + req->scan_req.scan_f_pause_home_channel = true; + + status = wlan_scan_start(req); + if (QDF_IS_STATUS_ERROR(status)) { + mlme_debug("vdev %d :Failed to send scan req, status %d", + req->scan_req.vdev_id, status); + goto release; + } + + wlan_objmgr_vdev_release_ref(vdev, WLAN_MLME_NB_ID); + return; +release: + qdf_mem_free(req); + wlan_objmgr_vdev_release_ref(vdev, WLAN_MLME_NB_ID); +} + uint32_t mlme_get_vdev_he_ops(struct wlan_objmgr_psoc *psoc, uint8_t vdev_id) { struct vdev_mlme_obj *mlme_obj; diff --git a/components/mlme/core/src/wlan_mlme_vdev_mgr_interface.c b/components/mlme/core/src/wlan_mlme_vdev_mgr_interface.c index de3c10892b..7834ad5905 100644 --- a/components/mlme/core/src/wlan_mlme_vdev_mgr_interface.c +++ b/components/mlme/core/src/wlan_mlme_vdev_mgr_interface.c @@ -1680,6 +1680,47 @@ vdevmgr_vdev_stop_rsp_handle(struct vdev_mlme_obj *vdev_mlme, return wma_vdev_stop_resp_handler(vdev_mlme, rsp); } +/** + * psoc_mlme_ext_hdl_enable() - to enable mlme ext param handler + * @psoc: psoc object + * + * Return: QDF_STATUS + */ +static QDF_STATUS psoc_mlme_ext_hdl_enable(struct wlan_objmgr_psoc *psoc) +{ + struct wlan_mlme_psoc_ext_obj *mlme_obj; + + mlme_obj = mlme_get_psoc_ext_obj(psoc); + if (!mlme_obj) + return QDF_STATUS_E_FAILURE; + + mlme_obj->scan_requester_id = + wlan_scan_register_requester(psoc, "MLME_EXT", + wlan_mlme_chan_stats_scan_event_cb, + NULL); + + return QDF_STATUS_SUCCESS; +} + +/** + * psoc_mlme_ext_hdl_disable() - to disable mlme ext param handler + * @psoc: psoc object + * + * Return: QDF_STATUS + */ +static QDF_STATUS psoc_mlme_ext_hdl_disable(struct wlan_objmgr_psoc *psoc) +{ + struct wlan_mlme_psoc_ext_obj *mlme_obj; + + mlme_obj = mlme_get_psoc_ext_obj(psoc); + if (!mlme_obj) + return QDF_STATUS_E_FAILURE; + + wlan_scan_unregister_requester(psoc, mlme_obj->scan_requester_id); + + return QDF_STATUS_SUCCESS; +} + /** * psoc_mlme_ext_hdl_create() - Create mlme legacy priv object * @psoc_mlme: psoc mlme object @@ -2085,6 +2126,8 @@ static struct mlme_ext_ops ext_ops = { .mlme_cm_ext_vdev_down_req_cb = cm_send_vdev_down_req, .mlme_cm_ext_reassoc_req_cb = cm_handle_reassoc_req, .mlme_cm_ext_roam_start_ind_cb = cm_handle_roam_start, + .mlme_psoc_ext_hdl_enable = psoc_mlme_ext_hdl_enable, + .mlme_psoc_ext_hdl_disable = psoc_mlme_ext_hdl_disable, #ifdef WLAN_FEATURE_DYNAMIC_MAC_ADDR_UPDATE .mlme_vdev_send_set_mac_addr = vdevmgr_mlme_vdev_send_set_mac_addr, #endif diff --git a/components/mlme/dispatcher/inc/wlan_mlme_api.h b/components/mlme/dispatcher/inc/wlan_mlme_api.h index 3e9edcbdb0..4ef0c1eb11 100644 --- a/components/mlme/dispatcher/inc/wlan_mlme_api.h +++ b/components/mlme/dispatcher/inc/wlan_mlme_api.h @@ -1059,6 +1059,18 @@ QDF_STATUS mlme_update_tgt_he_caps_in_cfg(struct wlan_objmgr_psoc *psoc, enum phy_ch_width wlan_mlme_convert_vht_op_bw_to_phy_ch_width( uint8_t channel_width); +/** + * wlan_mlme_chan_stats_scan_event_cb() - process connected channel stats + * scan event + * @vdev: pointer to vdev object + * @event: scan event definition + * @arg: scan argument + * + * Return: none + */ +void wlan_mlme_chan_stats_scan_event_cb(struct wlan_objmgr_vdev *vdev, + struct scan_event *event, void *arg); + #ifdef WLAN_FEATURE_11BE /** * mlme_update_tgt_eht_caps_in_cfg() - Update tgt eht cap in mlme component diff --git a/components/mlme/dispatcher/inc/wlan_mlme_ucfg_api.h b/components/mlme/dispatcher/inc/wlan_mlme_ucfg_api.h index feb724998c..5fef7ce955 100644 --- a/components/mlme/dispatcher/inc/wlan_mlme_ucfg_api.h +++ b/components/mlme/dispatcher/inc/wlan_mlme_ucfg_api.h @@ -4589,6 +4589,17 @@ QDF_STATUS ucfg_mlme_set_vdev_traffic_low_latency(struct wlan_objmgr_psoc *psoc, uint8_t vdev_id, bool set); +/** + * ucfg_mlme_connected_chan_stats_request() - process connected channel stats + * request + * @psoc: pointer to psoc object + * @vdev_id: Vdev id + * + * Return: none + */ +void ucfg_mlme_connected_chan_stats_request(struct wlan_objmgr_psoc *psoc, + uint8_t vdev_id); + /** * ucfg_mlme_set_vdev_traffic_high_throughput() - Set/clear vdev high * throughput config diff --git a/components/mlme/dispatcher/src/wlan_mlme_api.c b/components/mlme/dispatcher/src/wlan_mlme_api.c index 06dfdfd0ce..c4023d2b23 100644 --- a/components/mlme/dispatcher/src/wlan_mlme_api.c +++ b/components/mlme/dispatcher/src/wlan_mlme_api.c @@ -6671,6 +6671,17 @@ void wlan_mlme_get_feature_info(struct wlan_objmgr_psoc *psoc, } #endif +void wlan_mlme_chan_stats_scan_event_cb(struct wlan_objmgr_vdev *vdev, + struct scan_event *event, void *arg) +{ + bool success = false; + + if (!util_is_scan_completed(event, &success)) + return; + + mlme_send_scan_done_complete_cb(event->vdev_id); +} + enum phy_ch_width wlan_mlme_convert_vht_op_bw_to_phy_ch_width( uint8_t channel_width) { diff --git a/components/mlme/dispatcher/src/wlan_mlme_ucfg_api.c b/components/mlme/dispatcher/src/wlan_mlme_ucfg_api.c index 8c8a13a392..200810f73f 100644 --- a/components/mlme/dispatcher/src/wlan_mlme_ucfg_api.c +++ b/components/mlme/dispatcher/src/wlan_mlme_ucfg_api.c @@ -1,6 +1,6 @@ /* * Copyright (c) 2018-2021 The Linux Foundation. All rights reserved. - * Copyright (c) 2022 Qualcomm Innovation Center, Inc. All rights reserved. + * Copyright (c) 2022-2023 Qualcomm Innovation Center, Inc. All rights reserved. * * Permission to use, copy, modify, and/or distribute this software for * any purpose with or without fee is hereby granted, provided that the @@ -367,6 +367,12 @@ ucfg_mlme_set_vdev_traffic_type(struct wlan_objmgr_psoc *psoc, return status; } +void ucfg_mlme_connected_chan_stats_request(struct wlan_objmgr_psoc *psoc, + uint8_t vdev_id) +{ + mlme_connected_chan_stats_request(psoc, vdev_id); +} + QDF_STATUS ucfg_mlme_set_vdev_traffic_low_latency(struct wlan_objmgr_psoc *psoc, uint8_t vdev_id, bool set) diff --git a/core/hdd/src/wlan_hdd_cfg80211.c b/core/hdd/src/wlan_hdd_cfg80211.c index 703eadbfb0..c9e7031426 100644 --- a/core/hdd/src/wlan_hdd_cfg80211.c +++ b/core/hdd/src/wlan_hdd_cfg80211.c @@ -1575,6 +1575,13 @@ static const struct nl80211_vendor_cmd_info wlan_hdd_cfg80211_vendor_events[] = QCA_NL80211_VENDOR_SUBCMD_STATS_EXT }, #endif /* WLAN_FEATURE_STATS_EXT */ + [QCA_NL80211_VENDOR_SUBCMD_CONNECTED_CHANNEL_STATS_INDEX] = { + .vendor_id = + QCA_NL80211_VENDOR_ID, + .subcmd = + QCA_NL80211_VENDOR_SUBCMD_CONNECTED_CHANNEL_STATS + }, + #ifdef FEATURE_WLAN_EXTSCAN [QCA_NL80211_VENDOR_SUBCMD_EXTSCAN_START_INDEX] = { .vendor_id = @@ -18500,6 +18507,18 @@ const struct wiphy_vendor_command hdd_wiphy_vendor_commands[] = { vendor_command_policy(VENDOR_CMD_RAW_DATA, 0) }, #endif + + { + .info.vendor_id = QCA_NL80211_VENDOR_ID, + .info.subcmd = + QCA_NL80211_VENDOR_SUBCMD_CONNECTED_CHANNEL_STATS, + .flags = WIPHY_VENDOR_CMD_NEED_WDEV | + WIPHY_VENDOR_CMD_NEED_NETDEV | + WIPHY_VENDOR_CMD_NEED_RUNNING, + .doit = wlan_hdd_cfg80211_connected_chan_stats_req, + vendor_command_policy(VENDOR_CMD_RAW_DATA, 0) + }, + FEATURE_EXTSCAN_VENDOR_COMMANDS FEATURE_LL_STATS_VENDOR_COMMANDS diff --git a/core/hdd/src/wlan_hdd_main.c b/core/hdd/src/wlan_hdd_main.c index 5378453a5e..017df01608 100644 --- a/core/hdd/src/wlan_hdd_main.c +++ b/core/hdd/src/wlan_hdd_main.c @@ -17633,10 +17633,55 @@ static void wlan_hdd_state_ctrl_param_destroy(void) #endif /* WLAN_CTRL_NAME */ +/** + * hdd_send_scan_done_complete_cb() - API to send scan done indication to upper + * layer + * @vdev_id: vdev id + * + * Return: none + */ +static void hdd_send_scan_done_complete_cb(uint8_t vdev_id) +{ + struct hdd_context *hdd_ctx; + struct hdd_adapter *adapter; + struct sk_buff *vendor_event; + uint32_t len; + + hdd_ctx = cds_get_context(QDF_MODULE_ID_HDD); + if (!hdd_ctx) { + hdd_err("Invalid hdd context"); + return; + } + adapter = hdd_get_adapter_by_vdev(hdd_ctx, vdev_id); + if (!adapter) { + hdd_err("No adapter found for vdev id:%d", vdev_id); + return; + } + + len = NLMSG_HDRLEN; + vendor_event = + wlan_cfg80211_vendor_event_alloc( + hdd_ctx->wiphy, &adapter->wdev, len, + QCA_NL80211_VENDOR_SUBCMD_CONNECTED_CHANNEL_STATS_INDEX, + GFP_KERNEL); + + if (!vendor_event) { + hdd_err("wlan_cfg80211_vendor_event_alloc failed"); + return; + } + + hdd_debug("sending scan done ind to upper layer for vdev_id:%d", + vdev_id); + wlan_cfg80211_vendor_event(vendor_event, GFP_KERNEL); +} + struct osif_vdev_mgr_ops osif_vdev_mgrlegacy_ops = { #ifdef WLAN_FEATURE_DYNAMIC_MAC_ADDR_UPDATE - .osif_vdev_mgr_set_mac_addr_response = hdd_set_mac_addr_event_cb + .osif_vdev_mgr_set_mac_addr_response = hdd_set_mac_addr_event_cb, #endif + .osif_vdev_mgr_send_scan_done_complete_cb = + hdd_send_scan_done_complete_cb, + }; static QDF_STATUS hdd_vdev_mgr_register_cb(void) diff --git a/core/hdd/src/wlan_hdd_stats.c b/core/hdd/src/wlan_hdd_stats.c index 2d561a6ef1..162a8f27c0 100644 --- a/core/hdd/src/wlan_hdd_stats.c +++ b/core/hdd/src/wlan_hdd_stats.c @@ -3942,6 +3942,63 @@ static QDF_STATUS wlan_hdd_stats_request_needed(struct hdd_adapter *adapter) } #endif /* WLAN_FEATURE_LINK_LAYER_STATS */ +/** + * __wlan_hdd_cfg80211_connected_chan_stats_request() - stats request for + * currently connected channel + * @wiphy: Pointer to wiphy + * @wdev: Pointer to wdev + * @data: Pointer to data + * @data_len: Data length + * + * Return: int + */ +static int +__wlan_hdd_cfg80211_connected_chan_stats_request(struct wiphy *wiphy, + struct wireless_dev *wdev, + const void *data, + int data_len) +{ + struct net_device *dev = wdev->netdev; + struct hdd_adapter *adapter = WLAN_HDD_GET_PRIV_PTR(dev); + struct hdd_context *hdd_ctx = wiphy_priv(wiphy); + bool is_vdev_connected; + enum QDF_OPMODE mode; + + is_vdev_connected = hdd_cm_is_vdev_connected(adapter); + mode = adapter->device_mode; + if (mode == QDF_STA_MODE && is_vdev_connected) { + ucfg_mlme_connected_chan_stats_request(hdd_ctx->psoc, + adapter->deflink->vdev_id); + } else { + hdd_debug("vdev %d: reject chan stats req, mode:%d, conn:%d", + adapter->deflink->vdev_id, mode, is_vdev_connected); + return -EINVAL; + } + + return 0; +} + +int wlan_hdd_cfg80211_connected_chan_stats_req(struct wiphy *wiphy, + struct wireless_dev *wdev, + const void *data, + int data_len) +{ + int errno; + struct osif_vdev_sync *vdev_sync; + + errno = osif_vdev_sync_op_start(wdev->netdev, &vdev_sync); + if (errno) + return errno; + + errno = __wlan_hdd_cfg80211_connected_chan_stats_request(wiphy, wdev, + data, + data_len); + + osif_vdev_sync_op_stop(vdev_sync); + + return errno; +} + #ifdef WLAN_FEATURE_STATS_EXT /** * __wlan_hdd_cfg80211_stats_ext_request() - ext stats request diff --git a/core/hdd/src/wlan_hdd_stats.h b/core/hdd/src/wlan_hdd_stats.h index d62bc93cf7..e070eac4c7 100644 --- a/core/hdd/src/wlan_hdd_stats.h +++ b/core/hdd/src/wlan_hdd_stats.h @@ -333,6 +333,21 @@ int wlan_hdd_cfg80211_stats_ext_request(struct wiphy *wiphy, #endif /* End of WLAN_FEATURE_STATS_EXT */ +/** + * wlan_hdd_cfg80211_connected_chan_stats_req() - get currently connected + * channel statistics from driver/firmware + * @wiphy: Pointer to wiphy + * @wdev: Pointer to wdev + * @data: Pointer to data + * @data_len: Data length + * + * Return: int + */ +int wlan_hdd_cfg80211_connected_chan_stats_req(struct wiphy *wiphy, + struct wireless_dev *wdev, + const void *data, + int data_len); + /** * wlan_hdd_cfg80211_get_station() - get station statistics * @wiphy: Pointer to wiphy