qcacld-3.0: Process get_cu_for_each_subbw driver command

Host parse newely added vendor command
QCA_NL80211_VENDOR_SUBCMD_CONNECTED_CHANNEL_STATS and trigger
scan to get connected channel stats from FW.

On scan done host sends scan done indication to upper layer
via QCA_NL80211_VENDOR_SUBCMD_CONNECTED_CHANNEL_STATS vendor
command.

Change-Id: I7a4727b66003f6ee96645c5078d1f922b2f18cec
CRs-Fixed: 3461106
This commit is contained in:
abhinav kumar
2023-04-06 16:56:05 +05:30
committed by Madan Koyyalamudi
parent 2fae80a3e1
commit 62b5a049d6
11 changed files with 492 additions and 2 deletions

View File

@@ -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

View File

@@ -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;

View File

@@ -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

View File

@@ -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

View File

@@ -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

View File

@@ -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)
{

View File

@@ -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)

View File

@@ -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

View File

@@ -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)

View File

@@ -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

View File

@@ -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