Commit 4c3054c5 authored by Yingying Tang's avatar Yingying Tang Committed by Madan Mohan Koyyalamudi
Browse files

Qcacld-2.0: Add support to get station's RSSI when hostapd is started

Host send request message to firmware and get all stations' RSSI
information when hostapd is started.

Change-Id: I3c6795dfb29e769fc4d1cd1b2c60eeb95f6eadf5
CRs-Fixed: 912576
parent 440cb71e
......@@ -182,6 +182,9 @@ typedef struct
#define WE_WOWL_DEL_PTRN 2
#define MAX_VAR_ARGS 7
#define QCSAP_IOCTL_PRIV_GET_RSSI (SIOCIWFIRSTPRIV + 29)
#define QCSAP_IOCTL_PRIV_GET_SOFTAP_LINK_SPEED (SIOCIWFIRSTPRIV + 31)
#define QCSAP_IOCTL_MAX_STR_LEN 1024
......
......@@ -275,6 +275,8 @@ struct statsContext
struct completion completion;
hdd_adapter_t *pAdapter;
unsigned int magic;
union iwreq_data *wrqu;
char *extra;
};
struct linkspeedContext
......
......@@ -4605,6 +4605,251 @@ int iw_get_softap_linkspeed(struct net_device *dev,
}
/**
* hdd_get_rssi_cb() - get station's rssi callback
* @sta_rssi: pointer of rssi information
* @context: get rssi callback context
*
* This function will fill rssi information to hostapd
* adapter
*
*/
void hdd_get_rssi_cb(struct sir_rssi_resp *sta_rssi, void *context)
{
struct statsContext *get_rssi_context;
struct sir_rssi_info *rssi_info;
uint8_t peer_num;
int i;
int buf = 0;
int length = 0;
char *rssi_info_output;
union iwreq_data *wrqu;
if ((NULL == sta_rssi) || (NULL == context)) {
hddLog(VOS_TRACE_LEVEL_ERROR,
"%s: Bad param, sta_rssi [%p] context [%p]",
__func__, sta_rssi, context);
return;
}
spin_lock(&hdd_context_lock);
/*
* there is a race condition that exists between this callback
* function and the caller since the caller could time out either
* before or while this code is executing. we use a spinlock to
* serialize these actions
*/
get_rssi_context = context;
if (RSSI_CONTEXT_MAGIC !=
get_rssi_context->magic) {
/*
* the caller presumably timed out so there is nothing
* we can do
*/
spin_unlock(&hdd_context_lock);
hddLog(VOS_TRACE_LEVEL_WARN,
"%s: Invalid context, magic [%08x]",
__func__,
get_rssi_context->magic);
return;
}
rssi_info_output = get_rssi_context->extra;
wrqu = get_rssi_context->wrqu;
peer_num = sta_rssi->count;
rssi_info = sta_rssi->info;
get_rssi_context->magic = 0;
hddLog(LOG1, "%s : %d peers", __func__, peer_num);
/*
* The iwpriv tool default print is before mac addr and rssi.
* Add '\n' before first rssi item to align the frist rssi item
* with others
*
* wlan getRSSI:
* [macaddr1] [rssi1]
* [macaddr2] [rssi2]
* [macaddr3] [rssi3]
*/
length = scnprintf((rssi_info_output), WE_MAX_STR_LEN, "\n");
for (i = 0; i < peer_num; i++) {
buf = scnprintf
(
(rssi_info_output + length), WE_MAX_STR_LEN - length,
"[%pM] [%d]\n",
rssi_info[i].peer_macaddr,
rssi_info[i].rssi
);
length += buf;
}
wrqu->data.length = length + 1;
/* notify the caller */
complete(&get_rssi_context->completion);
/* serialization is complete */
spin_unlock(&hdd_context_lock);
}
/**
* wlan_hdd_get_peer_rssi() - get station's rssi
* @adapter: hostapd interface
* @macaddress: iwpriv request information
* @wrqu: iwpriv command parameter
* @extra
*
* This function will call sme_get_rssi to get rssi
*
* Return: 0 on success, otherwise error value
*/
static int wlan_hdd_get_peer_rssi(hdd_adapter_t *adapter,
v_MACADDR_t macaddress,
char *extra,
union iwreq_data *wrqu)
{
eHalStatus hstatus;
unsigned long rc;
struct statsContext context;
struct sir_rssi_req rssi_req;
if (NULL == adapter) {
hddLog(VOS_TRACE_LEVEL_ERROR, "%s: pAdapter is NULL",
__func__);
return -EFAULT;
}
init_completion(&context.completion);
context.magic = RSSI_CONTEXT_MAGIC;
context.extra = extra;
context.wrqu = wrqu;
vos_mem_copy(&(rssi_req.peer_macaddr), &macaddress,
VOS_MAC_ADDR_SIZE);
rssi_req.sessionId = adapter->sessionId;
hstatus = sme_get_rssi(WLAN_HDD_GET_HAL_CTX(adapter),
rssi_req,
&context,
hdd_get_rssi_cb);
if (eHAL_STATUS_SUCCESS != hstatus) {
hddLog(VOS_TRACE_LEVEL_ERROR,
"%s: Unable to retrieve statistics for rssi",
__func__);
rc = -EFAULT;
} else {
rc = wait_for_completion_timeout(&context.completion,
msecs_to_jiffies(WLAN_WAIT_TIME_STATS));
if (!rc) {
hddLog(VOS_TRACE_LEVEL_ERROR,
"%s: SME timed out while retrieving rssi",
__func__);
}
}
/*
* either we never sent a request, we sent a request and received a
* response or we sent a request and timed out. if we never sent a
* request or if we sent a request and got a response, we want to
* clear the magic out of paranoia. if we timed out there is a
* race condition such that the callback function could be
* executing at the same time we are. of primary concern is if the
* callback function had already verified the "magic" but had not
* yet set the completion variable when a timeout occurred. we
* serialize these activities by invalidating the magic while
* holding a shared spinlock which will cause us to block if the
* callback is currently executing
*/
spin_lock(&hdd_context_lock);
context.magic = 0;
spin_unlock(&hdd_context_lock);
return rc;
}
/**
* __iw_get_peer_rssi() - get station's rssi
* @dev: net device
* @info: iwpriv request information
* @wrqu: iwpriv command parameter
* @extra
*
* This function will call wlan_hdd_get_peer_rssi
* to get rssi
*
* Return: 0 on success, otherwise error value
*/
static int
__iw_get_peer_rssi(struct net_device *dev, struct iw_request_info *info,
union iwreq_data *wrqu, char *extra)
{
hdd_adapter_t *adapter = (netdev_priv(dev));
hdd_context_t *hddctx;
char macaddrarray[18];
v_MACADDR_t macaddress = VOS_MAC_ADDR_BROADCAST_INITIALIZER;
VOS_STATUS status = VOS_STATUS_E_FAILURE;
int ret;
ENTER();
hddctx = WLAN_HDD_GET_CTX(adapter);
ret = wlan_hdd_validate_context(hddctx);
if (0 != ret)
return ret;
hddLog(VOS_TRACE_LEVEL_INFO, "%s wrqu->data.length= %d",
__func__, wrqu->data.length);
if (wrqu->data.length >= MAC_ADDRESS_STR_LEN - 1) {
if (copy_from_user(macaddrarray,
wrqu->data.pointer, MAC_ADDRESS_STR_LEN - 1)) {
hddLog(LOG1, "%s: failed to copy data to user buffer",
__func__);
return -EFAULT;
}
macaddrarray[MAC_ADDRESS_STR_LEN - 1] = '\0';
hddLog(LOG1, "%s, %s",
__func__, macaddrarray);
status = hdd_string_to_hex(macaddrarray,
MAC_ADDRESS_STR_LEN, macaddress.bytes );
if (!VOS_IS_STATUS_SUCCESS(status)) {
hddLog(VOS_TRACE_LEVEL_ERROR,
FL("String to Hex conversion Failed"));
}
}
return wlan_hdd_get_peer_rssi(adapter, macaddress, extra, wrqu);
}
/**
* iw_get_peer_rssi() - get station's rssi
* @dev: net device
* @info: iwpriv request information
* @wrqu: iwpriv command parameter
* @extra
*
* This function will call __iw_get_peer_rssi
*
* Return: 0 on success, otherwise error value
*/
static int
iw_get_peer_rssi(struct net_device *dev, struct iw_request_info *info,
union iwreq_data *wrqu, char *extra)
{
int ret;
vos_ssr_protect(__func__);
ret = __iw_get_peer_rssi(dev, info, wrqu, extra);
vos_ssr_unprotect(__func__);
return ret;
}
static const iw_handler hostapd_handler[] =
{
(iw_handler) NULL, /* SIOCSIWCOMMIT */
......@@ -4922,7 +5167,9 @@ static const struct iw_priv_args hostapd_private_args[] = {
{ QCSAP_IOCTL_PRIV_GET_SOFTAP_LINK_SPEED,
IW_PRIV_TYPE_CHAR | 18,
IW_PRIV_TYPE_CHAR | 5, "getLinkSpeed" },
{ QCSAP_IOCTL_PRIV_GET_RSSI,
IW_PRIV_TYPE_CHAR | 18,
IW_PRIV_TYPE_CHAR | WE_MAX_STR_LEN, "getRSSI" },
{ QCSAP_IOCTL_PRIV_SET_THREE_INT_GET_NONE,
IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 3, 0, "" },
/* handlers for sub-ioctl */
......@@ -5053,6 +5300,7 @@ static const iw_handler hostapd_private[] = {
[QCSAP_IOCTL_GET_CHANNEL_LIST - SIOCIWFIRSTPRIV] = iw_softap_get_channel_list,
[QCSAP_IOCTL_GET_STA_INFO - SIOCIWFIRSTPRIV] = iw_softap_get_sta_info,
[QCSAP_IOCTL_PRIV_GET_SOFTAP_LINK_SPEED - SIOCIWFIRSTPRIV] = iw_get_softap_linkspeed,
[QCSAP_IOCTL_PRIV_GET_RSSI - SIOCIWFIRSTPRIV] = iw_get_peer_rssi,
[QCSAP_IOCTL_SET_TX_POWER - SIOCIWFIRSTPRIV] = iw_softap_set_tx_power,
[QCSAP_IOCTL_SET_MAX_TX_POWER - SIOCIWFIRSTPRIV] = iw_softap_set_max_tx_power,
[QCSAP_IOCTL_DATAPATH_SNAP_SHOT - SIOCIWFIRSTPRIV] = iw_display_data_path_snapshot,
......
......@@ -4865,6 +4865,45 @@ typedef struct sSirLinkSpeedInfo
tANI_U32 estLinkSpeed; //Linkspeed from firmware
} tSirLinkSpeedInfo, *tpSirLinkSpeedInfo;
/*
* struct sir_rssi_req - rssi request struct
* @peer_macaddr: MAC address
* @sessionId: vdev id
*
* rssi request message's struct
*/
struct sir_rssi_req {
v_MACADDR_t peer_macaddr;
uint8_t sessionId;
};
/*
* struct sir_rssi_info - rssi information struct
* @peer_macaddr: MAC address
* @rssi: rssi
*
* a station's rssi information
*/
struct sir_rssi_info {
tSirMacAddr peer_macaddr;
int8_t rssi;
};
/*
* struct sir_rssi_info - all peers rssi information struct
* @count: peer's number
* @info: rssi information
*
* all station's rssi information
*/
struct sir_rssi_resp {
uint8_t count;
struct sir_rssi_info info[0];
};
typedef struct sSirAddPeriodicTxPtrn
{
/* MAC Address for the adapter */
......
......@@ -415,6 +415,7 @@ enum eWniMsgTypes
#endif
eWNI_SME_TSF_EVENT,
eWNI_SME_GET_RSSI_IND,
eWNI_SME_MSG_TYPES_END
};
......
......@@ -647,6 +647,9 @@ typedef struct sSirMbMsgP2p
#define SIR_HAL_BEACON_TX_SUCCESS_IND (SIR_HAL_ITC_MSG_TYPES_BEGIN + 242)
#define SIR_HAL_DFS_RADAR_IND (SIR_HAL_ITC_MSG_TYPES_BEGIN + 243)
#define SIR_HAL_GET_RSSI (SIR_HAL_ITC_MSG_TYPES_BEGIN + 244)
#define SIR_HAL_INIT_THERMAL_INFO_CMD (SIR_HAL_ITC_MSG_TYPES_BEGIN + 248)
#define SIR_HAL_SET_THERMAL_LEVEL (SIR_HAL_ITC_MSG_TYPES_BEGIN + 249)
......
......@@ -1941,6 +1941,102 @@ static int wma_link_speed_event_handler(void *handle, u_int8_t *cmd_param_info,
return 0;
}
 
/**
* wma_handle_sta_rssi() - handle rssi information in
* peer stats
* @num_peer_stats: peer number
* @peer_stats: peer stats received from firmware
* @peer_macaddr: the specified mac address
* @sapaddr: sap mac address
*
* This function will send eWNI_SME_GET_RSSI_IND
* to sme with stations' rssi information
*
*/
static void wma_handle_sta_rssi(uint32_t num_peer_stats,
wmi_peer_stats *peer_stats,
v_MACADDR_t peer_macaddr,
uint8_t *sapaddr)
{
VOS_STATUS vos_status = VOS_STATUS_SUCCESS;
wmi_mac_addr temp_addr;
struct sir_rssi_resp *sta_rssi;
vos_msg_t sme_msg = {0};
uint32_t i = 0;
uint32_t j = 0;
if (!vos_is_macaddr_broadcast(&peer_macaddr)) {
WMI_CHAR_ARRAY_TO_MAC_ADDR(peer_macaddr.bytes, &temp_addr);
for (i = 0; i < num_peer_stats; i++) {
if ((((temp_addr.mac_addr47to32) & 0x0000ffff) ==
((peer_stats->peer_macaddr.mac_addr47to32) &
0x0000ffff))
&&(temp_addr.mac_addr31to0 ==
peer_stats->peer_macaddr.mac_addr31to0)) {
break;
}
peer_stats = peer_stats + 1;
}
sta_rssi = vos_mem_malloc(sizeof(*sta_rssi) +
sizeof(sta_rssi->info[0]));
if (NULL == sta_rssi) {
WMA_LOGE("%s: Memory allocation failed.", __func__);
return;
}
if (i < num_peer_stats) {
sta_rssi->count = 1;
WMI_MAC_ADDR_TO_CHAR_ARRAY(&(peer_stats->peer_macaddr),
sta_rssi->info[0].peer_macaddr);
sta_rssi->info[0].rssi =
peer_stats->peer_rssi;
} else {
WMA_LOGE("%s: no match mac address", __func__);
sta_rssi->count = 0;
}
} else {
sta_rssi = vos_mem_malloc(sizeof(*sta_rssi) +
num_peer_stats * sizeof(sta_rssi->info[0]));
if (NULL == sta_rssi) {
WMA_LOGE("%s: Memory allocation failed.", __func__);
return;
}
sta_rssi->count = num_peer_stats;
for (i = 0; i < num_peer_stats; i++) {
WMI_MAC_ADDR_TO_CHAR_ARRAY(&(peer_stats->peer_macaddr),
sta_rssi->info[j].peer_macaddr);
sta_rssi->info[j].rssi = peer_stats->peer_rssi;
if (TRUE == vos_mem_compare(
sta_rssi->info[j].peer_macaddr,
sapaddr, VOS_MAC_ADDR_SIZE)) {
sta_rssi->count = sta_rssi->count - 1;
} else {
j++;
}
peer_stats = peer_stats + 1;
}
WMA_LOGD("WDA send peer num %d", sta_rssi->count);
}
sme_msg.type = eWNI_SME_GET_RSSI_IND;
sme_msg.bodyptr = sta_rssi;
sme_msg.bodyval = 0;
vos_status = vos_mq_post_message(VOS_MODULE_ID_SME, &sme_msg);
if (!VOS_IS_STATUS_SUCCESS(vos_status) ) {
WMA_LOGE("%s: Fail to post get rssi msg", __func__);
vos_mem_free(sta_rssi);
}
return;
}
static void wma_fw_stats_ind(tp_wma_handle wma, u_int8_t *buf)
{
wmi_stats_event_fixed_param *event = (wmi_stats_event_fixed_param *)buf;
......@@ -1971,11 +2067,23 @@ static void wma_fw_stats_ind(tp_wma_handle wma, u_int8_t *buf)
}
}
 
WMA_LOGD("WDA receive peer num %d",
event->num_peer_stats);
if (event->num_peer_stats > 0) {
for (i = 0; i < event->num_peer_stats; i++) {
peer_stats = (wmi_peer_stats *)temp;
wma_update_peer_stats(wma, peer_stats);
temp += sizeof(wmi_peer_stats);
WMA_LOGD("update get rssi %d",
wma->get_sta_rssi);
if (wma->get_sta_rssi == TRUE) {
wma_handle_sta_rssi(event->num_peer_stats,
(wmi_peer_stats *)temp,
wma->peer_macaddr,
wma->myaddr);
} else {
for (i = 0; i < event->num_peer_stats; i++) {
peer_stats = (wmi_peer_stats *)temp;
wma_update_peer_stats(wma, peer_stats);
temp += sizeof(wmi_peer_stats);
}
}
}
 
......@@ -10172,6 +10280,63 @@ VOS_STATUS wma_get_link_speed(WMA_HANDLE handle,
}
 
 
/**
* wma_get_rssi() - get station's rssi
* @handle: wma interface
* @prssi_req: get rssi request information
*
* This function will send WMI_REQUEST_STATS_CMDID
* to wmi
*
* Return: 0 on success, otherwise error value
*/
static VOS_STATUS wma_get_rssi(WMA_HANDLE handle,
struct sir_rssi_req *prssi_req)
{
tp_wma_handle wma_handle = (tp_wma_handle)handle;
wmi_request_stats_cmd_fixed_param *cmd;
wmi_buf_t wmi_buf;
uint32_t len;
uint8_t *buf_ptr;
if (!wma_handle || !wma_handle->wmi_handle) {
WMA_LOGE("%s: WMA is closed, can not issue get rssi",
__func__);
return VOS_STATUS_E_INVAL;
}
len = sizeof(wmi_request_stats_cmd_fixed_param);
wmi_buf = wmi_buf_alloc(wma_handle->wmi_handle, len);
if (!wmi_buf) {
WMA_LOGE("%s: wmi_buf_alloc failed", __func__);
return VOS_STATUS_E_NOMEM;
}
buf_ptr = (uint8_t *)wmi_buf_data(wmi_buf);
cmd = (wmi_request_stats_cmd_fixed_param *)buf_ptr;
WMITLV_SET_HDR(&cmd->tlv_header,
WMITLV_TAG_STRUC_wmi_request_stats_cmd_fixed_param,
WMITLV_GET_STRUCT_TLVLEN(wmi_request_stats_cmd_fixed_param));
cmd->stats_id = WMI_REQUEST_PEER_STAT;
cmd->vdev_id = prssi_req->sessionId;
wma_handle->get_sta_rssi = TRUE;
if (wmi_unified_cmd_send(wma_handle->wmi_handle, wmi_buf, len,
WMI_REQUEST_STATS_CMDID)) {
WMA_LOGE("Failed to send host stats request to fw");
wmi_buf_free(wmi_buf);
return VOS_STATUS_E_FAILURE;
}
vos_mem_copy(&(wma_handle->peer_macaddr),
&(prssi_req->peer_macaddr),
VOS_MAC_ADDR_SIZE);
return VOS_STATUS_SUCCESS;
}
static int
wmi_unified_pdev_set_param(wmi_unified_t wmi_handle, WMI_PDEV_PARAM param_id,
u_int32_t param_value)
......@@ -17646,6 +17811,7 @@ static void wma_get_stats_req(WMA_HANDLE handle,
 
node->fw_stats_set = 0;
node->stats_rsp = pGetPEStatsRspParams;
wma_handle->get_sta_rssi = FALSE;
cmd = (wmi_request_stats_cmd_fixed_param *)wmi_buf_data(buf);
WMITLV_SET_HDR(&cmd->tlv_header,
WMITLV_TAG_STRUC_wmi_request_stats_cmd_fixed_param,
......@@ -22043,6 +22209,10 @@ VOS_STATUS wma_mc_process_msg(v_VOID_t *vos_context, vos_msg_t *msg)
wma_get_link_speed(wma_handle, msg->bodyptr);
vos_mem_free(msg->bodyptr);
break;
case WDA_GET_RSSI:
wma_get_rssi(wma_handle, msg->bodyptr);
vos_mem_free(msg->bodyptr);
break;
case WDA_MODEM_POWER_STATE_IND:
wma_notify_modem_power_state(wma_handle,
(tSirModemPowerStateInd *)msg->bodyptr);
......
......@@ -655,6 +655,8 @@ typedef struct {
v_BOOL_t ptrn_match_enable_all_vdev;
void* pGetRssiReq;
v_S7_t first_rssi;
bool get_sta_rssi;
v_MACADDR_t peer_macaddr;
t_thermal_mgmt thermal_mgmt_info;
v_BOOL_t roam_offload_enabled;
t_wma_roam_preauth_chan_state_t roam_preauth_scan_state;
......
......@@ -159,6 +159,9 @@ typedef struct tagSmeStruct
/* linkspeed callback */
void (*pLinkSpeedIndCb) (tSirLinkSpeedInfo *indParam, void *pDevContext);
void *pLinkSpeedCbContext;
/* get rssi callback */
void (*pget_rssi_ind_cb) (struct sir_rssi_resp *param, void *pcontext);
void *pget_rssi_cb_context;
#ifdef FEATURE_WLAN_EXTSCAN
void (*pExtScanIndCb) (void *, const tANI_U16, void *);
#endif /* FEATURE_WLAN_EXTSCAN */
......
......@@ -3726,6 +3726,11 @@ eHalStatus sme_GetLinkSpeed(tHalHandle hHal,tSirLinkSpeedInfo *lsReq,void *plsCo
void (*pCallbackfn)(tSirLinkSpeedInfo *indParam, void *pContext) );
#endif
eHalStatus sme_get_rssi(tHalHandle hal, struct sir_rssi_req req,
void *context,
void (*callbackfn)(struct sir_rssi_resp *param,
void *pcontext));
/*----------------------------------------------------------------------------
\fn sme_ModifyAddIE
\brief This function sends msg to updates the additional IE buffers in PE
......
......@@ -2763,6 +2763,12 @@ eHalStatus sme_ProcessMsg(tHalHandle hHal, vos_msg_t* pMsg)
vos_mem_free(pMsg->bodyptr);
}
break;
case eWNI_SME_GET_RSSI_IND:
if (pMac->sme.pget_rssi_ind_cb)
pMac->sme.pget_rssi_ind_cb(pMsg->bodyptr,
pMac->sme.pget_rssi_cb_context);
vos_mem_free(pMsg->bodyptr);
break;
case eWNI_SME_CSA_OFFLOAD_EVENT:
if (pMsg->bodyptr)
{
......@@ -11286,8 +11292,69 @@ eHalStatus sme_GetLinkSpeed(tHalHandle hHal, tSirLinkSpeedInfo *lsReq, void *pls
}
return(status);
}
#endif /* QCA_WIFI_2_0 */
#endif /* FEATURE_WLAN_TDLS */
/**
* sme_get_rssi() - get station's rssi
* @hal: hal interface