summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--core/cdf/src/i_cdf_util.h5
-rw-r--r--core/hdd/inc/wlan_hdd_oemdata.h20
-rw-r--r--core/hdd/src/wlan_hdd_oemdata.c317
-rw-r--r--core/sme/inc/sme_api.h19
-rw-r--r--core/sme/src/common/sme_api.c54
-rw-r--r--core/utils/ptt/inc/wlan_ptt_sock_svc.h4
6 files changed, 354 insertions, 65 deletions
diff --git a/core/cdf/src/i_cdf_util.h b/core/cdf/src/i_cdf_util.h
index 1ca6b1d6e421..80ab1ae7ddf8 100644
--- a/core/cdf/src/i_cdf_util.h
+++ b/core/cdf/src/i_cdf_util.h
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2014-2015 The Linux Foundation. All rights reserved.
+ * Copyright (c) 2014-2016 The Linux Foundation. All rights reserved.
*
* Previously licensed under the ISC license by Qualcomm Atheros, Inc.
*
@@ -74,6 +74,9 @@ static inline int __cdf_status_to_os_return(CDF_STATUS status)
return -EALREADY;
case CDF_STATUS_E_NOMEM:
return -ENOMEM;
+ case CDF_STATUS_E_FAILURE:
+ case CDF_STATUS_E_INVAL:
+ return -EINVAL;
default:
return -EPERM;
}
diff --git a/core/hdd/inc/wlan_hdd_oemdata.h b/core/hdd/inc/wlan_hdd_oemdata.h
index 82ea3e18263c..2acf25590a88 100644
--- a/core/hdd/inc/wlan_hdd_oemdata.h
+++ b/core/hdd/inc/wlan_hdd_oemdata.h
@@ -154,6 +154,26 @@ typedef struct cdf_packed {
tHddChannelInfo peer_chan_info;
} tPeerStatusInfo;
+/**
+ * enum oem_capability_mask - mask field for userspace client capabilities
+ * @OEM_CAP_RM_FTMRR: FTM range report mask bit
+ * @OEM_CAP_RM_LCI: LCI capability mask bit
+ */
+enum oem_capability_mask {
+ OEM_CAP_RM_FTMRR = (1 << (0)),
+ OEM_CAP_RM_LCI = (1 << (1)),
+};
+
+/**
+ * struct oem_get_capability_rsp - capabilites set by userspace and target.
+ * @target_cap: target capabilities
+ * @client_capabilities: capabilities set by userspace via set request
+ */
+struct oem_get_capability_rsp {
+ t_iw_oem_data_cap target_cap;
+ struct sme_oem_capability cap;
+};
+
void hdd_send_peer_status_ind_to_oem_app(struct cdf_mac_addr *peerMac,
uint8_t peerStatus,
uint8_t peerTimingMeasCap,
diff --git a/core/hdd/src/wlan_hdd_oemdata.c b/core/hdd/src/wlan_hdd_oemdata.c
index e23412ac0dff..52c74fefcca1 100644
--- a/core/hdd/src/wlan_hdd_oemdata.c
+++ b/core/hdd/src/wlan_hdd_oemdata.c
@@ -44,10 +44,82 @@
#include "qwlan_version.h"
#include "cds_utils.h"
#include "wma.h"
+#include "sme_api.h"
static struct hdd_context_s *p_hdd_ctx;
/**
+ * populate_oem_data_cap() - populate oem capabilities
+ * @adapter: device adapter
+ * @data_cap: pointer to populate the capabilities
+ *
+ * Return: error code
+ */
+static int populate_oem_data_cap(hdd_adapter_t *adapter,
+ t_iw_oem_data_cap *data_cap)
+{
+ CDF_STATUS status = CDF_STATUS_E_FAILURE;
+ struct hdd_config *config;
+ uint32_t num_chan;
+ uint8_t *chan_list;
+ hdd_context_t *hdd_ctx = adapter->pHddCtx;
+
+ config = hdd_ctx->config;
+ if (!config) {
+ hdd_err("HDD configuration is null");
+ return -EINVAL;
+ }
+ chan_list = cdf_mem_malloc(sizeof(uint8_t) * OEM_CAP_MAX_NUM_CHANNELS);
+ if (NULL == chan_list) {
+ hdd_err("Memory allocation failed");
+ return -ENOMEM;
+ }
+
+ strlcpy(data_cap->oem_target_signature, OEM_TARGET_SIGNATURE,
+ OEM_TARGET_SIGNATURE_LEN);
+ data_cap->oem_target_type = hdd_ctx->target_type;
+ data_cap->oem_fw_version = hdd_ctx->target_fw_version;
+ data_cap->driver_version.major = QWLAN_VERSION_MAJOR;
+ data_cap->driver_version.minor = QWLAN_VERSION_MINOR;
+ data_cap->driver_version.patch = QWLAN_VERSION_PATCH;
+ data_cap->driver_version.build = QWLAN_VERSION_BUILD;
+ data_cap->allowed_dwell_time_min = config->nNeighborScanMinChanTime;
+ data_cap->allowed_dwell_time_max = config->nNeighborScanMaxChanTime;
+ data_cap->curr_dwell_time_min =
+ sme_get_neighbor_scan_min_chan_time(hdd_ctx->hHal,
+ adapter->sessionId);
+ data_cap->curr_dwell_time_max =
+ sme_get_neighbor_scan_max_chan_time(hdd_ctx->hHal,
+ adapter->sessionId);
+ data_cap->supported_bands = config->nBandCapability;
+
+ /* request for max num of channels */
+ num_chan = WNI_CFG_VALID_CHANNEL_LIST_LEN;
+ status = sme_get_cfg_valid_channels(hdd_ctx->hHal,
+ &chan_list[0], &num_chan);
+ if (CDF_STATUS_SUCCESS != status) {
+ hdd_err("failed to get valid channel list, status: %d", status);
+ cdf_mem_free(chan_list);
+ return -EINVAL;
+ }
+
+ /* make sure num channels is not more than chan list array */
+ if (num_chan > OEM_CAP_MAX_NUM_CHANNELS) {
+ hdd_err("Num of channels-%d > length-%d of chan_list",
+ num_chan, OEM_CAP_MAX_NUM_CHANNELS);
+ cdf_mem_free(chan_list);
+ return -ENOMEM;
+ }
+
+ data_cap->num_channels = num_chan;
+ cdf_mem_copy(data_cap->channel_list, chan_list,
+ sizeof(uint8_t) * num_chan);
+
+ cdf_mem_free(chan_list);
+ return 0;
+}
+
+/**
* iw_get_oem_data_cap() - Get OEM Data Capabilities
* @dev: net device upon which the request was received
* @info: ioctl request information
@@ -63,15 +135,11 @@ int iw_get_oem_data_cap(struct net_device *dev,
struct iw_request_info *info,
union iwreq_data *wrqu, char *extra)
{
- CDF_STATUS status;
- t_iw_oem_data_cap oemDataCap;
+ int status;
+ t_iw_oem_data_cap oemDataCap = { {0} };
t_iw_oem_data_cap *pHddOemDataCap;
hdd_adapter_t *pAdapter = (netdev_priv(dev));
hdd_context_t *pHddContext;
- struct hdd_config *pConfig;
- uint32_t numChannels;
- uint8_t chanList[OEM_CAP_MAX_NUM_CHANNELS];
- uint32_t i;
int ret;
ENTER();
@@ -81,65 +149,12 @@ int iw_get_oem_data_cap(struct net_device *dev,
if (0 != ret)
return ret;
- pConfig = pHddContext->config;
- if (!pConfig) {
- CDF_TRACE(CDF_MODULE_ID_HDD, CDF_TRACE_LEVEL_ERROR,
- "%s:HDD configuration is null", __func__);
- return -ENOENT;
- }
-
- do {
- cdf_mem_zero(&oemDataCap, sizeof(oemDataCap));
- strlcpy(oemDataCap.oem_target_signature, OEM_TARGET_SIGNATURE,
- OEM_TARGET_SIGNATURE_LEN);
- oemDataCap.oem_target_type = pHddContext->target_type;
- oemDataCap.oem_fw_version = pHddContext->target_fw_version;
- 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_get_neighbor_scan_min_chan_time(pHddContext->hHal,
- pAdapter->sessionId);
- oemDataCap.curr_dwell_time_max =
- sme_get_neighbor_scan_max_chan_time(pHddContext->hHal,
- pAdapter->sessionId);
- oemDataCap.supported_bands = pConfig->nBandCapability;
-
- /* request for max num of channels */
- numChannels = WNI_CFG_VALID_CHANNEL_LIST_LEN;
- status = sme_get_cfg_valid_channels(pHddContext->hHal,
- &chanList[0], &numChannels);
- if (CDF_STATUS_SUCCESS != status) {
- CDF_TRACE(CDF_MODULE_ID_HDD, CDF_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) {
- CDF_TRACE(CDF_MODULE_ID_HDD,
- CDF_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];
- }
- }
+ status = populate_oem_data_cap(pAdapter, &oemDataCap);
+ if (!status)
+ return status;
- pHddOemDataCap = (t_iw_oem_data_cap *) (extra);
- cdf_mem_copy(pHddOemDataCap, &oemDataCap,
- sizeof(*pHddOemDataCap));
- } while (0);
+ pHddOemDataCap = (t_iw_oem_data_cap *) (extra);
+ *pHddOemDataCap = oemDataCap;
EXIT();
return 0;
@@ -511,6 +526,132 @@ static int oem_process_channel_info_req_msg(int numOfChannels, char *chanList)
}
/**
+ * oem_process_set_cap_req_msg() - process oem set capability request
+ * @oem_cap_len: Length of OEM capability
+ * @oem_cap: Pointer to OEM capability buffer
+ * @app_pid: process ID, to which rsp message is to be sent
+ *
+ * This function sends oem message to SME
+ *
+ * Return: error code
+ */
+static int oem_process_set_cap_req_msg(int oem_cap_len,
+ char *oem_cap, int32_t app_pid)
+{
+ CDF_STATUS status;
+ int error_code;
+ struct sk_buff *skb;
+ struct nlmsghdr *nlh;
+ tAniMsgHdr *ani_hdr;
+ uint8_t *buf;
+
+ if (!oem_cap) {
+ hdd_err("oem_cap is null");
+ return -EINVAL;
+ }
+
+ status = sme_oem_update_capability(p_hdd_ctx->hHal,
+ (struct sme_oem_capability *)oem_cap);
+ if (!CDF_IS_STATUS_SUCCESS(status))
+ hdd_err("error updating rm capability, status: %d", status);
+ error_code = cdf_status_to_os_return(status);
+
+ skb = alloc_skb(NLMSG_SPACE(WLAN_NL_MAX_PAYLOAD), GFP_KERNEL);
+ if (skb == NULL) {
+ hdd_err("alloc_skb failed");
+ return -ENOMEM;
+ }
+
+ 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;
+ ani_hdr = NLMSG_DATA(nlh);
+ ani_hdr->type = ANI_MSG_SET_OEM_CAP_RSP;
+ /* 64 bit alignment */
+ ani_hdr->length = sizeof(error_code);
+ nlh->nlmsg_len = NLMSG_LENGTH(sizeof(tAniMsgHdr) + ani_hdr->length);
+
+ /* message body will contain only status code */
+ buf = (char *)((char *)ani_hdr + sizeof(tAniMsgHdr));
+ cdf_mem_copy(buf, &error_code, ani_hdr->length);
+
+ skb_put(skb, NLMSG_SPACE(sizeof(tAniMsgHdr) + ani_hdr->length));
+
+ hdd_info("sending oem response to process pid %d", app_pid);
+
+ (void)nl_srv_ucast(skb, app_pid, MSG_DONTWAIT);
+
+ return error_code;
+}
+
+/**
+ * oem_process_get_cap_req_msg() - process oem get capability request
+ *
+ * This function process the get capability request from OEM and responds
+ * with the capability.
+ *
+ * Return: error code
+ */
+static int oem_process_get_cap_req_msg(void)
+{
+ int error_code;
+ struct oem_get_capability_rsp *cap_rsp;
+ t_iw_oem_data_cap data_cap = { {0} };
+ struct sme_oem_capability oem_cap;
+ hdd_adapter_t *adapter;
+ struct sk_buff *skb;
+ struct nlmsghdr *nlh;
+ tAniMsgHdr *ani_hdr;
+ uint8_t *buf;
+
+ /* for now, STA interface only */
+ adapter = hdd_get_adapter(p_hdd_ctx, WLAN_HDD_INFRA_STATION);
+ if (!adapter) {
+ hdd_err("No adapter for STA mode");
+ return -EINVAL;
+ }
+
+ error_code = populate_oem_data_cap(adapter, &data_cap);
+ if (0 != error_code)
+ return error_code;
+
+ skb = alloc_skb(NLMSG_SPACE(sizeof(tAniMsgHdr) + sizeof(*cap_rsp)),
+ GFP_KERNEL);
+ if (skb == NULL) {
+ hdd_err("alloc_skb failed");
+ return -ENOMEM;
+ }
+
+ 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;
+ ani_hdr = NLMSG_DATA(nlh);
+ ani_hdr->type = ANI_MSG_GET_OEM_CAP_RSP;
+
+ ani_hdr->length = sizeof(*cap_rsp);
+ nlh->nlmsg_len = NLMSG_LENGTH((sizeof(tAniMsgHdr) + ani_hdr->length));
+
+ buf = (char *)((char *)ani_hdr + sizeof(tAniMsgHdr));
+ cdf_mem_copy(buf, &data_cap, sizeof(data_cap));
+
+ buf = (char *) buf + sizeof(data_cap);
+ cdf_mem_zero(&oem_cap, sizeof(oem_cap));
+ sme_oem_get_capability(p_hdd_ctx->hHal, &oem_cap);
+ cdf_mem_copy(buf, &oem_cap, sizeof(oem_cap));
+
+ skb_put(skb, NLMSG_SPACE((sizeof(tAniMsgHdr) + ani_hdr->length)));
+ hdd_info("send rsp to oem-pid:%d for get_capability",
+ p_hdd_ctx->oem_pid);
+
+ (void)nl_srv_ucast(skb, p_hdd_ctx->oem_pid, MSG_DONTWAIT);
+ return 0;
+}
+
+/**
* hdd_send_peer_status_ind_to_oem_app() -
* Function to send peer status to a registered application
* @peerMac: MAC address of peer
@@ -768,6 +909,54 @@ static int oem_msg_callback(struct sk_buff *skb)
sizeof(tAniMsgHdr)));
break;
+ case ANI_MSG_SET_OEM_CAP_REQ:
+ hdd_info("Received set oem capability req of length:%d from pid: %d",
+ msg_hdr->length, nlh->nlmsg_pid);
+
+ if ((!p_hdd_ctx->oem_app_registered) ||
+ (nlh->nlmsg_pid != p_hdd_ctx->oem_pid)) {
+ /* oem app is not registered yet or pid is different */
+ hdd_err("set_oem_capability : app not registered(%d) or incorrect pid(%d)",
+ p_hdd_ctx->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) ||
+ (sizeof(struct sme_oem_capability) < msg_hdr->length)) {
+ hdd_err("Invalid length (%d) in set_oem_capability",
+ msg_hdr->length);
+ send_oem_err_rsp_nlink_msg(nlh->nlmsg_pid,
+ OEM_ERR_INVALID_MESSAGE_LENGTH);
+ return -EPERM;
+ }
+
+ oem_process_set_cap_req_msg(msg_hdr->length,
+ (char *)((char *)msg_hdr +
+ sizeof(tAniMsgHdr)),
+ nlh->nlmsg_pid);
+ break;
+
+ case ANI_MSG_GET_OEM_CAP_REQ:
+ hdd_info("Rcvd get oem capability req of length:%d from pid: %d",
+ msg_hdr->length, nlh->nlmsg_pid);
+
+ if ((!p_hdd_ctx->oem_app_registered) ||
+ (nlh->nlmsg_pid != p_hdd_ctx->oem_pid)) {
+ /* oem app is not registered yet or pid is different */
+ hdd_err("get_oem_capability : app not registered(%d) or incorrect pid(%d)",
+ p_hdd_ctx->oem_app_registered,
+ nlh->nlmsg_pid);
+ send_oem_err_rsp_nlink_msg(nlh->nlmsg_pid,
+ OEM_ERR_APP_NOT_REGISTERED);
+ return -EPERM;
+ }
+
+ oem_process_get_cap_req_msg();
+ break;
+
default:
CDF_TRACE(CDF_MODULE_ID_HDD, CDF_TRACE_LEVEL_ERROR,
"%s: Received Invalid message type (%d), length (%d)",
diff --git a/core/sme/inc/sme_api.h b/core/sme/inc/sme_api.h
index 49850aae7cb2..fd35a0a99627 100644
--- a/core/sme/inc/sme_api.h
+++ b/core/sme/inc/sme_api.h
@@ -187,6 +187,21 @@ typedef enum {
SME_BI_DIR = 2,
} sme_tspec_dir_type;
+/**
+ * struct sme_oem_capability - OEM capability to be exchanged between host
+ * and userspace
+ * @ftm_rr: FTM range report capability bit
+ * @lci_capability: LCI capability bit
+ * @reserved1: reserved
+ * @reserved2: reserved
+ */
+struct sme_oem_capability {
+ uint32_t ftm_rr:1;
+ uint32_t lci_capability:1;
+ uint32_t reserved1:30;
+ uint32_t reserved2;
+};
+
/*-------------------------------------------------------------------------
Function declarations and documenation
------------------------------------------------------------------------*/
@@ -442,6 +457,10 @@ CDF_STATUS sme_oem_data_req(tHalHandle hHal,
uint8_t sessionId,
tOemDataReqConfig *,
uint32_t *pOemDataReqID);
+CDF_STATUS sme_oem_update_capability(tHalHandle hHal,
+ struct sme_oem_capability *cap);
+CDF_STATUS sme_oem_get_capability(tHalHandle hHal,
+ struct sme_oem_capability *cap);
#endif /*FEATURE_OEM_DATA_SUPPORT */
CDF_STATUS sme_roam_update_apwpsie(tHalHandle, uint8_t sessionId,
tSirAPWPSIEs * pAPWPSIES);
diff --git a/core/sme/src/common/sme_api.c b/core/sme/src/common/sme_api.c
index e2607e99d0c8..4a8f998aef5d 100644
--- a/core/sme/src/common/sme_api.c
+++ b/core/sme/src/common/sme_api.c
@@ -4402,6 +4402,60 @@ CDF_STATUS sme_register_oem_data_rsp_callback(tHalHandle h_hal,
#endif
/**
+ * sme_oem_update_capability() - update UMAC's oem related capability.
+ * @hal: Handle returned by mac_open
+ * @oem_cap: pointer to oem_capability
+ *
+ * This function updates OEM capability to UMAC. Currently RTT
+ * related capabilities are updated. More capabilities can be
+ * added in future.
+ *
+ * Return: CDF_STATUS
+ */
+CDF_STATUS sme_oem_update_capability(tHalHandle hal,
+ struct sme_oem_capability *cap)
+{
+ CDF_STATUS status = CDF_STATUS_SUCCESS;
+ tpAniSirGlobal pmac = PMAC_STRUCT(hal);
+ uint8_t *bytes;
+
+ bytes = pmac->rrm.rrmSmeContext.rrmConfig.rm_capability;
+
+ if (cap->ftm_rr)
+ bytes[4] |= RM_CAP_FTM_RANGE_REPORT;
+ if (cap->lci_capability)
+ bytes[4] |= RM_CAP_CIVIC_LOC_MEASUREMENT;
+
+ return status;
+}
+
+/**
+ * sme_oem_get_capability() - get oem capability
+ * @hal: Handle returned by mac_open
+ * @oem_cap: pointer to oem_capability
+ *
+ * This function is used to get the OEM capability from UMAC.
+ * Currently RTT related capabilities are received. More
+ * capabilities can be added in future.
+ *
+ * Return: CDF_STATUS
+ */
+CDF_STATUS sme_oem_get_capability(tHalHandle hal,
+ struct sme_oem_capability *cap)
+{
+ CDF_STATUS status = CDF_STATUS_SUCCESS;
+ tpAniSirGlobal pmac = PMAC_STRUCT(hal);
+ uint8_t *bytes;
+
+ bytes = pmac->rrm.rrmSmeContext.rrmConfig.rm_capability;
+
+ cap->ftm_rr = bytes[4] & RM_CAP_FTM_RANGE_REPORT;
+ cap->lci_capability = bytes[4] & RM_CAP_CIVIC_LOC_MEASUREMENT;
+
+ return status;
+}
+
+/**
* sme_register_ftm_msg_processor() - registers hdd ftm message processor
* function to MAC/SYS
*
diff --git a/core/utils/ptt/inc/wlan_ptt_sock_svc.h b/core/utils/ptt/inc/wlan_ptt_sock_svc.h
index 121fcbac7579..a328d8ecc3d0 100644
--- a/core/utils/ptt/inc/wlan_ptt_sock_svc.h
+++ b/core/utils/ptt/inc/wlan_ptt_sock_svc.h
@@ -66,6 +66,10 @@
#define ANI_MSG_CHANNEL_INFO_RSP (ANI_DRIVER_MSG_START + 5)
#define ANI_MSG_OEM_ERROR (ANI_DRIVER_MSG_START + 6)
#define ANI_MSG_PEER_STATUS_IND (ANI_DRIVER_MSG_START + 7)
+#define ANI_MSG_SET_OEM_CAP_REQ (ANI_DRIVER_MSG_START + 8)
+#define ANI_MSG_SET_OEM_CAP_RSP (ANI_DRIVER_MSG_START + 9)
+#define ANI_MSG_GET_OEM_CAP_REQ (ANI_DRIVER_MSG_START + 10)
+#define ANI_MSG_GET_OEM_CAP_RSP (ANI_DRIVER_MSG_START + 11)
#define ANI_MAX_RADIOS 3
#define ANI_NL_MSG_OK 0