diff options
| -rw-r--r-- | core/cdf/src/i_cdf_util.h | 5 | ||||
| -rw-r--r-- | core/hdd/inc/wlan_hdd_oemdata.h | 20 | ||||
| -rw-r--r-- | core/hdd/src/wlan_hdd_oemdata.c | 317 | ||||
| -rw-r--r-- | core/sme/inc/sme_api.h | 19 | ||||
| -rw-r--r-- | core/sme/src/common/sme_api.c | 54 | ||||
| -rw-r--r-- | core/utils/ptt/inc/wlan_ptt_sock_svc.h | 4 |
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 |
