blob: df015ac40a5fc84d473626af50fdc7c90d0b0bee [file] [log] [blame]
/*
* Copyright (c) 2015-2017 The Linux Foundation. All rights reserved.
*
* Previously licensed under the ISC license by Qualcomm Atheros, Inc.
*
*
* Permission to use, copy, modify, and/or distribute this software for
* any purpose with or without fee is hereby granted, provided that the
* above copyright notice and this permission notice appear in all
* copies.
*
* THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL
* WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED
* WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE
* AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL
* DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR
* PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER
* TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
* PERFORMANCE OF THIS SOFTWARE.
*/
/*
* This file was originally distributed by Qualcomm Atheros, Inc.
* under proprietary terms before Copyright ownership was assigned
* to the Linux Foundation.
*/
#ifdef FEATURE_OEM_DATA_SUPPORT
/*================================================================================
\file wlan_hdd_oemdata.c
\brief Linux Wireless Extensions for oem data req/rsp
$Id: wlan_hdd_oemdata.c,v 1.34 2010/04/15 01:49:23 -- VINAY
Copyright (C) Qualcomm Inc.
================================================================================*/
#include <linux/version.h>
#include <linux/module.h>
#include <linux/kernel.h>
#include <linux/init.h>
#include <linux/wireless.h>
#include <wlan_hdd_includes.h>
#include <net/arp.h>
#include <vos_sched.h>
#include "qwlan_version.h"
static struct hdd_context_s *pHddCtx;
/*---------------------------------------------------------------------------------------------
\brief hdd_OemDataReqCallback() -
This function also reports the results to the user space
\return - eHalStatus enumeration
-----------------------------------------------------------------------------------------------*/
static eHalStatus hdd_OemDataReqCallback(tHalHandle hHal,
void *pContext,
tANI_U32 oemDataReqID,
eOemDataReqStatus oemDataReqStatus)
{
eHalStatus status = eHAL_STATUS_SUCCESS;
struct net_device *dev = (struct net_device *) pContext;
union iwreq_data wrqu;
char buffer[IW_CUSTOM_MAX+1];
memset(&wrqu, '\0', sizeof(wrqu));
memset(buffer, '\0', sizeof(buffer));
//now if the status is success, then send an event up
//so that the application can request for the data
//else no need to send the event up
if(oemDataReqStatus == eOEM_DATA_REQ_FAILURE)
{
snprintf(buffer, IW_CUSTOM_MAX, "QCOM: OEM-DATA-REQ-FAILED");
hddLog(LOGW, "%s: oem data req %d failed", __func__, oemDataReqID);
}
else if(oemDataReqStatus == eOEM_DATA_REQ_INVALID_MODE)
{
snprintf(buffer, IW_CUSTOM_MAX, "QCOM: OEM-DATA-REQ-INVALID-MODE");
hddLog(LOGW, "%s: oem data req %d failed because the driver is in invalid mode (IBSS|BTAMP|AP)", __func__, oemDataReqID);
}
else
{
snprintf(buffer, IW_CUSTOM_MAX, "QCOM: OEM-DATA-REQ-SUCCESS");
//everything went alright
}
wrqu.data.pointer = buffer;
wrqu.data.length = strlen(buffer);
wireless_send_event(dev, IWEVCUSTOM, &wrqu, buffer);
return status;
}
/**--------------------------------------------------------------------------------------------
\brief __iw_get_oem_data_rsp() -
This function gets the oem data response. This invokes
the respective sme functionality. Function for handling the oem data rsp
IOCTL
\param - dev - Pointer to the net device
- info - Pointer to the iw_oem_data_req
- wrqu - Pointer to the iwreq data
- extra - Pointer to the data
\return - 0 for success, non zero for failure
-----------------------------------------------------------------------------------------------*/
int __iw_get_oem_data_rsp(
struct net_device *dev,
struct iw_request_info *info,
union iwreq_data *wrqu,
char *extra)
{
int rc = 0;
eHalStatus status;
struct iw_oem_data_rsp* pHddOemDataRsp;
tOemDataRsp* pSmeOemDataRsp;
hdd_adapter_t *pAdapter;
hdd_context_t *pHddCtx;
ENTER();
pAdapter = (netdev_priv(dev));
if (NULL == pAdapter)
{
VOS_TRACE(VOS_MODULE_ID_HDD, VOS_TRACE_LEVEL_ERROR,
"%s: Adapter is NULL",__func__);
return -EINVAL;
}
pHddCtx = WLAN_HDD_GET_CTX(pAdapter);
rc = wlan_hdd_validate_context(pHddCtx);
if (0 != rc)
{
return rc;
}
do
{
//get the oem data response from sme
status = sme_getOemDataRsp(WLAN_HDD_GET_HAL_CTX(pAdapter), &pSmeOemDataRsp);
if (status != eHAL_STATUS_SUCCESS)
{
hddLog(LOGE, "%s: failed in sme_getOemDataRsp", __func__);
rc = -EIO;
break;
}
else
{
if (pSmeOemDataRsp != NULL)
{
pHddOemDataRsp = (struct iw_oem_data_rsp*)(extra);
vos_mem_copy(pHddOemDataRsp->oemDataRsp, pSmeOemDataRsp->oemDataRsp, OEM_DATA_RSP_SIZE);
}
else
{
hddLog(LOGE, "%s: pSmeOemDataRsp = NULL", __func__);
rc = -EIO;
break;
}
}
} while(0);
EXIT();
return rc;
}
int iw_get_oem_data_rsp(
struct net_device *dev,
struct iw_request_info *info,
union iwreq_data *wrqu,
char *extra)
{
int ret;
vos_ssr_protect(__func__);
ret = __iw_get_oem_data_rsp(dev, info, wrqu, extra);
vos_ssr_unprotect(__func__);
return ret;
}
/**--------------------------------------------------------------------------------------------
\brief __iw_set_oem_data_req() -
This function sets the oem data req configuration. This invokes
the respective sme oem data req functionality. Function for
handling the set IOCTL for the oem data req configuration
\param - dev - Pointer to the net device
- info - Pointer to the iw_oem_data_req
- wrqu - Pointer to the iwreq data
- extra - Pointer to the data
\return - 0 for success, non zero for failure
-----------------------------------------------------------------------------------------------*/
int __iw_set_oem_data_req(
struct net_device *dev,
struct iw_request_info *info,
union iwreq_data *wrqu,
char *extra)
{
int rc = 0;
eHalStatus status = eHAL_STATUS_SUCCESS;
struct iw_oem_data_req *pOemDataReq = NULL;
tOemDataReqConfig oemDataReqConfig;
tANI_U32 oemDataReqID = 0;
hdd_adapter_t *pAdapter;
hdd_context_t *pHddCtx;
hdd_wext_state_t *pwextBuf;
ENTER();
if (!capable(CAP_NET_ADMIN))
{
VOS_TRACE(VOS_MODULE_ID_HDD, VOS_TRACE_LEVEL_ERROR,
FL("permission check failed"));
return -EPERM;
}
pAdapter = (netdev_priv(dev));
if (NULL == pAdapter)
{
VOS_TRACE(VOS_MODULE_ID_HDD, VOS_TRACE_LEVEL_ERROR,
"%s: Adapter is NULL",__func__);
return -EINVAL;
}
pHddCtx = WLAN_HDD_GET_CTX(pAdapter);
rc = wlan_hdd_validate_context(pHddCtx);
if (0 != rc)
{
return rc;
}
pwextBuf = WLAN_HDD_GET_WEXT_STATE_PTR(pAdapter);
if (NULL == pwextBuf)
{
VOS_TRACE(VOS_MODULE_ID_HDD, VOS_TRACE_LEVEL_ERROR,
"%s: pwextBuf is NULL",__func__);
return -EINVAL;
}
if (pHddCtx->isPnoEnable)
{
VOS_TRACE( VOS_MODULE_ID_HDD, VOS_TRACE_LEVEL_INFO,
FL("pno scan in progress"));
return -EBUSY;
}
do
{
if (NULL != wrqu->data.pointer)
{
pOemDataReq = (struct iw_oem_data_req *)wrqu->data.pointer;
}
if (pOemDataReq == NULL)
{
hddLog(LOGE, "in %s oemDataReq == NULL", __func__);
rc = -EIO;
break;
}
vos_mem_zero(&oemDataReqConfig, sizeof(tOemDataReqConfig));
if (copy_from_user((&oemDataReqConfig)->oemDataReq,
pOemDataReq->oemDataReq, OEM_DATA_REQ_SIZE))
{
VOS_TRACE(VOS_MODULE_ID_HDD, VOS_TRACE_LEVEL_FATAL,
"%s: copy_from_user() failed!", __func__);
rc = -EFAULT;
break;
}
status = sme_OemDataReq(WLAN_HDD_GET_HAL_CTX(pAdapter),
pAdapter->sessionId,
&oemDataReqConfig,
&oemDataReqID,
&hdd_OemDataReqCallback,
dev);
if (status != eHAL_STATUS_SUCCESS)
{
VOS_TRACE(VOS_MODULE_ID_HDD, VOS_TRACE_LEVEL_ERROR,
"%s: sme_OemDataReq status %d", __func__, status);
rc = -EFAULT;
break;
}
pwextBuf->oemDataReqID = oemDataReqID;
pwextBuf->oemDataReqInProgress = TRUE;
} while(0);
EXIT();
return rc;
}
int iw_set_oem_data_req(
struct net_device *dev,
struct iw_request_info *info,
union iwreq_data *wrqu,
char *extra)
{
int ret;
vos_ssr_protect(__func__);
ret = __iw_set_oem_data_req(dev, info, wrqu, extra);
vos_ssr_unprotect(__func__);
return ret;
}
/**---------------------------------------------------------------------------
\brief iw_get_oem_data_cap()
This function gets the capability information for OEM Data Request
and Response.
\param - dev - Pointer to the net device
- info - Pointer to the t_iw_oem_data_cap
- wrqu - Pointer to the iwreq data
- extra - Pointer to the data
\return - 0 for success, non zero for failure
----------------------------------------------------------------------------*/
int iw_get_oem_data_cap(
struct net_device *dev,
struct iw_request_info *info,
union iwreq_data *wrqu,
char *extra)
{
eHalStatus status;
t_iw_oem_data_cap oemDataCap;
t_iw_oem_data_cap *pHddOemDataCap;
hdd_adapter_t *pAdapter = netdev_priv(dev);
hdd_context_t *pHddContext;
hdd_config_t *pConfig;
tANI_U32 numChannels;
tANI_U8 chanList[OEM_CAP_MAX_NUM_CHANNELS];
tANI_U32 i;
int ret;
ENTER();
if (!pAdapter)
{
VOS_TRACE(VOS_MODULE_ID_HDD, VOS_TRACE_LEVEL_ERROR,
"%s:Invalid context, pAdapter is null", __func__);
return -EINVAL;
}
pHddContext = WLAN_HDD_GET_CTX(pAdapter);
ret = wlan_hdd_validate_context(pHddContext);
if (0 != ret)
return ret;
pConfig = pHddContext->cfg_ini;
do
{
vos_mem_zero(&oemDataCap, sizeof(oemDataCap));
strlcpy(oemDataCap.oem_target_signature, OEM_TARGET_SIGNATURE,
OEM_TARGET_SIGNATURE_LEN);
oemDataCap.oem_target_type = TARGET_TYPE_PRONTO;
oemDataCap.oem_fw_version = 0;
oemDataCap.driver_version.major = QWLAN_VERSION_MAJOR;
oemDataCap.driver_version.minor = QWLAN_VERSION_MINOR;
oemDataCap.driver_version.patch = QWLAN_VERSION_PATCH;
oemDataCap.driver_version.build = QWLAN_VERSION_BUILD;
oemDataCap.allowed_dwell_time_min = pConfig->nNeighborScanMinChanTime;
oemDataCap.allowed_dwell_time_max = pConfig->nNeighborScanMaxChanTime;
oemDataCap.curr_dwell_time_min =
sme_getNeighborScanMinChanTime(pHddContext->hHal);
oemDataCap.curr_dwell_time_max =
sme_getNeighborScanMaxChanTime(pHddContext->hHal);
oemDataCap.supported_bands = pConfig->nBandCapability;
/* request for max num of channels */
numChannels = WNI_CFG_VALID_CHANNEL_LIST_LEN;
status = sme_GetCfgValidChannels(pHddContext->hHal,
&chanList[0],
&numChannels);
if (eHAL_STATUS_SUCCESS != status)
{
VOS_TRACE(VOS_MODULE_ID_HDD, VOS_TRACE_LEVEL_ERROR,
"%s:failed to get valid channel list", __func__);
return -ENOENT;
}
else
{
/* make sure num channels is not more than chan list array */
if (numChannels > OEM_CAP_MAX_NUM_CHANNELS)
{
VOS_TRACE(VOS_MODULE_ID_HDD, VOS_TRACE_LEVEL_ERROR,
"%s:Num of channels(%d) more than length(%d) of chanlist",
__func__, numChannels, OEM_CAP_MAX_NUM_CHANNELS);
return -ENOMEM;
}
oemDataCap.num_channels = numChannels;
for (i = 0; i < numChannels; i++)
{
oemDataCap.channel_list[i] = chanList[i];
}
}
pHddOemDataCap = (t_iw_oem_data_cap *)(extra);
vos_mem_copy(pHddOemDataCap, &oemDataCap, sizeof(*pHddOemDataCap));
} while (0);
EXIT();
return 0;
}
/**---------------------------------------------------------------------------
\brief send_oem_reg_rsp_nlink_msg() - send oem registration response
This function sends oem message to registered application process
\param -
- none
\return - none
--------------------------------------------------------------------------*/
static void send_oem_reg_rsp_nlink_msg(void)
{
struct sk_buff *skb;
struct nlmsghdr *nlh;
tAniMsgHdr *aniHdr;
tANI_U8 *buf;
tANI_U8 *numInterfaces;
tANI_U8 *deviceMode;
tANI_U8 *vdevId;
hdd_adapter_list_node_t *pAdapterNode = NULL;
hdd_adapter_list_node_t *pNext = NULL;
hdd_adapter_t *pAdapter = NULL;
VOS_STATUS status = 0;
/* OEM message is always to a specific process and cannot be a broadcast */
if (pHddCtx->oem_pid == 0)
{
VOS_TRACE(VOS_MODULE_ID_HDD, VOS_TRACE_LEVEL_ERROR,
"%s: invalid dest pid", __func__);
return;
}
skb = alloc_skb(NLMSG_SPACE(WLAN_NL_MAX_PAYLOAD), GFP_KERNEL);
if (skb == NULL)
{
VOS_TRACE(VOS_MODULE_ID_HDD, VOS_TRACE_LEVEL_ERROR,
"%s: alloc_skb failed", __func__);
return;
}
nlh = (struct nlmsghdr *)skb->data;
nlh->nlmsg_pid = 0; /* from kernel */
nlh->nlmsg_flags = 0;
nlh->nlmsg_seq = 0;
nlh->nlmsg_type = WLAN_NL_MSG_OEM;
aniHdr = NLMSG_DATA(nlh);
aniHdr->type = ANI_MSG_APP_REG_RSP;
/* Fill message body:
* First byte will be number of interfaces, followed by
* two bytes for each interfaces
* - one byte for device mode
* - one byte for vdev id
*/
buf = (char *) ((char *)aniHdr + sizeof(tAniMsgHdr));
numInterfaces = buf++;
*numInterfaces = 0;
/* Iterate through each of the adapters and fill device mode and vdev id */
status = hdd_get_front_adapter(pHddCtx, &pAdapterNode);
while ((VOS_STATUS_SUCCESS == status) && pAdapterNode)
{
pAdapter = pAdapterNode->pAdapter;
if (pAdapter)
{
deviceMode = buf++;
vdevId = buf++;
*deviceMode = pAdapter->device_mode;
*vdevId = pAdapter->sessionId;
(*numInterfaces)++;
VOS_TRACE(VOS_MODULE_ID_HDD, VOS_TRACE_LEVEL_INFO,
"%s: numInterfaces: %d, deviceMode: %d, vdevId: %d",
__func__, *numInterfaces, *deviceMode, *vdevId);
}
status = hdd_get_next_adapter(pHddCtx, pAdapterNode, &pNext);
pAdapterNode = pNext;
}
aniHdr->length = sizeof(tANI_U8) + (*numInterfaces) * 2 * sizeof(tANI_U8);
nlh->nlmsg_len = NLMSG_LENGTH((sizeof(tAniMsgHdr) + aniHdr->length));
skb_put(skb, NLMSG_SPACE((sizeof(tAniMsgHdr) + aniHdr->length)));
VOS_TRACE(VOS_MODULE_ID_HDD, VOS_TRACE_LEVEL_INFO,
"%s: sending App Reg Response length (%d) to process pid (%d)",
__func__, aniHdr->length, pHddCtx->oem_pid);
(void)nl_srv_ucast(skb, pHddCtx->oem_pid, MSG_DONTWAIT);
return;
}
/**---------------------------------------------------------------------------
\brief send_oem_err_rsp_nlink_msg() - send oem error response
This function sends error response to oem app
\param -
- app_pid - PID of oem application process
\return - none
--------------------------------------------------------------------------*/
static void send_oem_err_rsp_nlink_msg(v_SINT_t app_pid, tANI_U8 error_code)
{
struct sk_buff *skb;
struct nlmsghdr *nlh;
tAniMsgHdr *aniHdr;
tANI_U8 *buf;
skb = alloc_skb(NLMSG_SPACE(WLAN_NL_MAX_PAYLOAD), GFP_KERNEL);
if (skb == NULL)
{
VOS_TRACE(VOS_MODULE_ID_HDD, VOS_TRACE_LEVEL_ERROR,
"%s: alloc_skb failed", __func__);
return;
}
nlh = (struct nlmsghdr *)skb->data;
nlh->nlmsg_pid = 0; /* from kernel */
nlh->nlmsg_flags = 0;
nlh->nlmsg_seq = 0;
nlh->nlmsg_type = WLAN_NL_MSG_OEM;
aniHdr = NLMSG_DATA(nlh);
aniHdr->type = ANI_MSG_OEM_ERROR;
aniHdr->length = sizeof(tANI_U8);
nlh->nlmsg_len = NLMSG_LENGTH(sizeof(tAniMsgHdr) + aniHdr->length);
/* message body will contain one byte of error code */
buf = (char *) ((char *) aniHdr + sizeof(tAniMsgHdr));
*buf = error_code;
skb_put(skb, NLMSG_SPACE(sizeof(tAniMsgHdr) + aniHdr->length));
VOS_TRACE(VOS_MODULE_ID_HDD, VOS_TRACE_LEVEL_INFO,
"%s: sending oem error response to process pid (%d)",
__func__, app_pid);
(void)nl_srv_ucast(skb, app_pid, MSG_DONTWAIT);
return;
}
/**---------------------------------------------------------------------------
\brief send_oem_data_rsp_msg() - send oem data response
This function sends oem data rsp message to registered application process
over the netlink socket.
\param -
- oemDataRsp - Pointer to OEM Data Response struct
\return - 0 for success, non zero for failure
--------------------------------------------------------------------------*/
void send_oem_data_rsp_msg(tANI_U32 length, tANI_U8 *oemDataRsp)
{
struct sk_buff *skb;
struct nlmsghdr *nlh;
tAniMsgHdr *aniHdr;
tANI_U8 *oemData;
/* OEM message is always to a specific process and cannot be a broadcast */
if (pHddCtx->oem_pid == 0)
{
VOS_TRACE(VOS_MODULE_ID_HDD, VOS_TRACE_LEVEL_ERROR,
"%s: invalid dest pid", __func__);
return;
}
if (length > NEW_OEM_DATA_RSP_SIZE)
{
VOS_TRACE(VOS_MODULE_ID_HDD, VOS_TRACE_LEVEL_ERROR,
"%s: invalid length of Oem Data response", __func__);
return;
}
skb = alloc_skb(NLMSG_SPACE(sizeof(tAniMsgHdr) + length),
GFP_KERNEL);
if (skb == NULL)
{
VOS_TRACE(VOS_MODULE_ID_HDD, VOS_TRACE_LEVEL_ERROR,
"%s: alloc_skb failed", __func__);
return;
}
nlh = (struct nlmsghdr *)skb->data;
nlh->nlmsg_pid = 0; /* from kernel */
nlh->nlmsg_flags = 0;
nlh->nlmsg_seq = 0;
nlh->nlmsg_type = WLAN_NL_MSG_OEM;
aniHdr = NLMSG_DATA(nlh);
aniHdr->type = ANI_MSG_OEM_DATA_RSP;
aniHdr->length = length;
nlh->nlmsg_len = NLMSG_LENGTH((sizeof(tAniMsgHdr) + aniHdr->length));
oemData = (tANI_U8 *) ((char *)aniHdr + sizeof(tAniMsgHdr));
vos_mem_copy(oemData, oemDataRsp, length);
skb_put(skb, NLMSG_SPACE((sizeof(tAniMsgHdr) + aniHdr->length)));
VOS_TRACE(VOS_MODULE_ID_HDD, VOS_TRACE_LEVEL_INFO,
"%s: sending Oem Data Response of len (%d) to process pid (%d)",
__func__, length, pHddCtx->oem_pid);
(void)nl_srv_ucast(skb, pHddCtx->oem_pid, MSG_DONTWAIT);
return;
}
/**---------------------------------------------------------------------------
\brief oem_process_channel_info_req_msg() - process oem channel_info request
This function responds with channel info to oem process
\param -
- numOfChannels - number of channels
- chanList - channel list
\return - 0 for success, non zero for failure
--------------------------------------------------------------------------*/
static int oem_process_channel_info_req_msg(int numOfChannels, char *chanList)
{
struct sk_buff *skb;
struct nlmsghdr *nlh;
tAniMsgHdr *aniHdr;
tHddChannelInfo *pHddChanInfo;
tHddChannelInfo hddChanInfo;
tANI_U8 chanId;
tANI_U32 reg_info_1;
tANI_U32 reg_info_2;
eHalStatus status = eHAL_STATUS_FAILURE;
int i;
tANI_U8 *buf;
/* OEM message is always to a specific process and cannot be a broadcast */
if (pHddCtx->oem_pid == 0)
{
VOS_TRACE(VOS_MODULE_ID_HDD, VOS_TRACE_LEVEL_ERROR,
"%s: invalid dest pid", __func__);
return -1;
}
skb = alloc_skb(NLMSG_SPACE(sizeof(tAniMsgHdr) + sizeof(tANI_U8) +
numOfChannels * sizeof(tHddChannelInfo)), GFP_KERNEL);
if (skb == NULL)
{
VOS_TRACE(VOS_MODULE_ID_HDD, VOS_TRACE_LEVEL_ERROR,
"%s: alloc_skb failed", __func__);
return -1;
}
nlh = (struct nlmsghdr *)skb->data;
nlh->nlmsg_pid = 0; /* from kernel */
nlh->nlmsg_flags = 0;
nlh->nlmsg_seq = 0;
nlh->nlmsg_type = WLAN_NL_MSG_OEM;
aniHdr = NLMSG_DATA(nlh);
aniHdr->type = ANI_MSG_CHANNEL_INFO_RSP;
aniHdr->length = sizeof(tANI_U8) + numOfChannels * sizeof(tHddChannelInfo);
nlh->nlmsg_len = NLMSG_LENGTH((sizeof(tAniMsgHdr) + aniHdr->length));
/* First byte of message body will have num of channels */
buf = (char *) ((char *)aniHdr + sizeof(tAniMsgHdr));
*buf++ = numOfChannels;
/* Next follows channel info struct for each channel id.
* If chan id is wrong or SME returns failure for a channel
* then fill in 0 in channel info for that particular channel
*/
for (i = 0 ; i < numOfChannels; i++)
{
pHddChanInfo = (tHddChannelInfo *) ((char *) buf +
i * sizeof(tHddChannelInfo));
chanId = chanList[i];
status = sme_getRegInfo(pHddCtx->hHal, chanId,
&reg_info_1, &reg_info_2);
if (eHAL_STATUS_SUCCESS == status)
{
/* band center freq1, and freq2 depends on peer's capability
* and at this time we might not be associated on the given
* channel, so fill freq1=mhz, and freq2=0
*/
hddChanInfo.chan_id = chanId;
hddChanInfo.reserved0 = 0;
hddChanInfo.mhz = vos_chan_to_freq(chanId);
hddChanInfo.band_center_freq1 = hddChanInfo.mhz;
hddChanInfo.band_center_freq2 = 0;
/* set only DFS flag in info, rest of the fields will be filled in
* by the OEM App
*/
hddChanInfo.info = 0;
if (NV_CHANNEL_DFS == vos_nv_getChannelEnabledState(chanId))
hddChanInfo.info |= (1 << WLAN_HAL_CHAN_FLAG_DFS);
hddChanInfo.reg_info_1 = reg_info_1;
hddChanInfo.reg_info_2 = reg_info_2;
}
else
{
/* chanId passed to sme_getRegInfo is not valid, fill in zeros
* in channel info struct
*/
VOS_TRACE(VOS_MODULE_ID_HDD, VOS_TRACE_LEVEL_INFO,
"%s: sme_getRegInfo failed for chan (%d), return info 0",
__func__, chanId);
hddChanInfo.chan_id = chanId;
hddChanInfo.reserved0 = 0;
hddChanInfo.mhz = 0;
hddChanInfo.band_center_freq1 = 0;
hddChanInfo.band_center_freq2 = 0;
hddChanInfo.info = 0;
hddChanInfo.reg_info_1 = 0;
hddChanInfo.reg_info_2 = 0;
}
vos_mem_copy(pHddChanInfo, &hddChanInfo, sizeof(tHddChannelInfo));
}
skb_put(skb, NLMSG_SPACE((sizeof(tAniMsgHdr) + aniHdr->length)));
VOS_TRACE(VOS_MODULE_ID_HDD, VOS_TRACE_LEVEL_INFO,
"%s: sending channel info resp for num channels (%d) to pid (%d)",
__func__, numOfChannels, pHddCtx->oem_pid);
(void)nl_srv_ucast(skb, pHddCtx->oem_pid, MSG_DONTWAIT);
return 0;
}
/**---------------------------------------------------------------------------
\brief oem_process_data_req_msg() - process oem data request
This function sends oem message to SME
\param -
- oemDataLen - Length to OEM Data buffer
- oemData - Pointer to OEM Data buffer
\return - eHalStatus enumeration
--------------------------------------------------------------------------*/
void oem_process_data_req_msg(int oemDataLen, char *oemData)
{
tOemDataReqNewConfig oemDataReqNewConfig;
hdd_adapter_t *pAdapter = NULL;
/* for now, STA interface only */
pAdapter = hdd_get_adapter(pHddCtx, WLAN_HDD_INFRA_STATION);
if (!pAdapter)
{
VOS_TRACE(VOS_MODULE_ID_HDD, VOS_TRACE_LEVEL_ERROR,
"%s: No adapter for STA mode", __func__);
return;
}
if (!oemData)
{
VOS_TRACE(VOS_MODULE_ID_HDD, VOS_TRACE_LEVEL_ERROR,
"%s: oemData is null", __func__);
return;
}
vos_mem_zero(&oemDataReqNewConfig, sizeof(tOemDataReqNewConfig));
vos_mem_copy(&oemDataReqNewConfig.selfMacAddr,
pAdapter->macAddressCurrent.bytes, sizeof(tSirMacAddr));
vos_mem_copy(&oemDataReqNewConfig.oemDataReqNew, oemData, oemDataLen);
VOS_TRACE(VOS_MODULE_ID_HDD, VOS_TRACE_LEVEL_INFO,
"selfMacAddr: " MAC_ADDRESS_STR" ",
MAC_ADDR_ARRAY(oemDataReqNewConfig.selfMacAddr));
sme_OemDataReqNew(pHddCtx->hHal,
&oemDataReqNewConfig);
}
/*
* Callback function invoked by Netlink service for all netlink
* messages (from user space) addressed to WLAN_NL_MSG_OEM
*/
/**
* oem_msg_callback() - callback invoked by netlink service
* @skb: skb with netlink message
*
* This function gets invoked by netlink service when a message
* is received from user space addressed to WLAN_NL_MSG_OEM
*
* Return: zero on success
* On error, error number will be returned.
*/
static int oem_msg_callback(struct sk_buff *skb)
{
struct nlmsghdr *nlh;
tAniMsgHdr *msg_hdr;
int ret;
char *sign_str = NULL;
char* aniMsgBody;
tANI_U32 *oemMsgSubType;
nlh = (struct nlmsghdr *)skb->data;
if (!nlh) {
hddLog(LOGE, FL("Netlink header null"));
return -EPERM;
}
ret = wlan_hdd_validate_context(pHddCtx);
if (0 != ret) {
hddLog(LOGE, FL("HDD context is not valid"));
return ret;
}
msg_hdr = NLMSG_DATA(nlh);
if (!msg_hdr) {
hddLog(LOGE, FL("Message header null"));
send_oem_err_rsp_nlink_msg(nlh->nlmsg_pid, OEM_ERR_NULL_MESSAGE_HEADER);
return -EPERM;
}
if (nlh->nlmsg_len < NLMSG_LENGTH(sizeof(tAniMsgHdr) + msg_hdr->length)) {
hddLog(LOGE, FL("Invalid nl msg len, nlh->nlmsg_len (%d), msg_hdr->len (%d)"),
nlh->nlmsg_len, msg_hdr->length);
send_oem_err_rsp_nlink_msg(nlh->nlmsg_pid,
OEM_ERR_INVALID_MESSAGE_LENGTH);
return -EPERM;
}
hddLog(LOG1, FL("Received App msg type: %d"), msg_hdr->type);
switch (msg_hdr->type) {
case ANI_MSG_APP_REG_REQ:
/* Registration request is only allowed for Qualcomm Application */
hddLog(LOG1, FL("Received App Req Req from App process pid(%d), len(%d)"),
nlh->nlmsg_pid, msg_hdr->length);
sign_str = (char *)((char *)msg_hdr + sizeof(tAniMsgHdr));
if ((OEM_APP_SIGNATURE_LEN == msg_hdr->length) &&
(0 == strncmp(sign_str, OEM_APP_SIGNATURE_STR,
OEM_APP_SIGNATURE_LEN))) {
hddLog(LOG1, FL("Valid App Req Req from oem app process pid(%d)"),
nlh->nlmsg_pid);
pHddCtx->oem_app_registered = TRUE;
pHddCtx->oem_pid = nlh->nlmsg_pid;
send_oem_reg_rsp_nlink_msg();
} else {
hddLog(LOGE, FL("Invalid signature in App Reg Request from pid(%d)"),
nlh->nlmsg_pid);
send_oem_err_rsp_nlink_msg(nlh->nlmsg_pid,
OEM_ERR_INVALID_SIGNATURE);
return -EPERM;
}
break;
case ANI_MSG_OEM_DATA_REQ:
hddLog(LOG1, FL("Received Oem Data Request length(%d) from pid: %d"),
msg_hdr->length, nlh->nlmsg_pid);
if ((!pHddCtx->oem_app_registered) ||
(nlh->nlmsg_pid != pHddCtx->oem_pid)) {
/* either oem app is not registered yet or pid is different */
hddLog(LOGE, FL("OEM DataReq: app not registered(%d) or incorrect pid(%d)"),
pHddCtx->oem_app_registered, nlh->nlmsg_pid);
send_oem_err_rsp_nlink_msg(nlh->nlmsg_pid,
OEM_ERR_APP_NOT_REGISTERED);
return -EPERM;
}
if ((!msg_hdr->length) || (OEM_DATA_REQ_SIZE < msg_hdr->length)) {
hddLog(LOGE, FL("Invalid length (%d) in Oem Data Request"),
msg_hdr->length);
send_oem_err_rsp_nlink_msg(nlh->nlmsg_pid,
OEM_ERR_INVALID_MESSAGE_LENGTH);
return -EPERM;
}
aniMsgBody = (char *)((char *)msg_hdr + sizeof(tAniMsgHdr));
oemMsgSubType = (tANI_U32*) aniMsgBody;
hddLog(LOG1, FL("oemMsgSubType: 0x%x"), *oemMsgSubType);
oem_process_data_req_msg(msg_hdr->length,
(char *) ((char *)msg_hdr +
sizeof(tAniMsgHdr)));
break;
case ANI_MSG_CHANNEL_INFO_REQ:
hddLog(LOG1,
FL("Received channel info request, num channel(%d) from pid: %d"),
msg_hdr->length, nlh->nlmsg_pid);
if ((!pHddCtx->oem_app_registered) ||
(nlh->nlmsg_pid != pHddCtx->oem_pid)) {
/* either oem app is not registered yet or pid is different */
hddLog(LOGE,
FL("Chan InfoReq: app not registered(%d) or incorrect pid(%d)"),
pHddCtx->oem_app_registered, nlh->nlmsg_pid);
send_oem_err_rsp_nlink_msg(nlh->nlmsg_pid,
OEM_ERR_APP_NOT_REGISTERED);
return -EPERM;
}
/* message length contains list of channel ids */
if ((!msg_hdr->length) ||
(WNI_CFG_VALID_CHANNEL_LIST_LEN < msg_hdr->length)) {
hddLog(LOGE,
FL("Invalid length (%d) in channel info request"),
msg_hdr->length);
send_oem_err_rsp_nlink_msg(nlh->nlmsg_pid,
OEM_ERR_INVALID_MESSAGE_LENGTH);
return -EPERM;
}
oem_process_channel_info_req_msg(msg_hdr->length,
(char *)((char*)msg_hdr + sizeof(tAniMsgHdr)));
break;
default:
hddLog(LOGE,
FL("Received Invalid message type (%d), length (%d)"),
msg_hdr->type, msg_hdr->length);
send_oem_err_rsp_nlink_msg(nlh->nlmsg_pid,
OEM_ERR_INVALID_MESSAGE_TYPE);
return -EPERM;
}
return 0;
}
static int __oem_msg_callback(struct sk_buff *skb)
{
int ret;
vos_ssr_protect(__func__);
ret = oem_msg_callback(skb);
vos_ssr_unprotect(__func__);
return ret;
}
/**---------------------------------------------------------------------------
\brief oem_activate_service() - Activate oem message handler
This function registers a handler to receive netlink message from
an OEM application process.
\param -
- pAdapter - pointer to HDD adapter
\return - 0 for success, non zero for failure
--------------------------------------------------------------------------*/
int oem_activate_service(void *pAdapter)
{
pHddCtx = (struct hdd_context_s*) pAdapter;
/* Register the msg handler for msgs addressed to WLAN_NL_MSG_OEM */
nl_srv_register(WLAN_NL_MSG_OEM, __oem_msg_callback);
return 0;
}
/**---------------------------------------------------------------------------
\brief oem_deactivate_service() - Deactivate oem message handler
This function unregisters a handler to receive netlink message from
an OEM application process.
\return - none
--------------------------------------------------------------------------*/
void oem_deactivate_service()
{
/* unregister the msg handler for msgs addressed to WLAN_NL_MSG_OEM */
nl_srv_unregister(WLAN_NL_MSG_OEM, __oem_msg_callback);
}
#endif