From 922724f2db16965eabcfa0f8a44a570f767671e3 Mon Sep 17 00:00:00 2001 From: Naveen Rawat Date: Fri, 17 Mar 2017 19:35:46 -0700 Subject: [PATCH] qcacmn: Implement WIFI_POS commands Implement following commands for WIFI_POS: 1) ANI_MSG_APP_REG_REQ 2) ANI_MSG_CHANNEL_INFO_REQ 3) ANI_MSG_SET_OEM_CAP_REQ 4) ANI_MSG_GET_OEM_CAP_REQ 5) ANI_MSG_OEM_DATA_REQ 6) ANI_MSG_PEER_STATUS_IND Change-Id: I7e3b502660b169f4cdb654cb5f433446a24d2421 CRs-Fixed: 2003488 --- os_if/linux/wifi_pos/src/os_if_wifi_pos.c | 235 ++++++++++++++- target_if/wifi_pos/src/target_if_wifi_pos.c | 35 ++- umac/wifi_pos/inc/wifi_pos_api.h | 49 +++ umac/wifi_pos/src/wifi_pos_api.c | 53 ++++ umac/wifi_pos/src/wifi_pos_main.c | 297 ++++++++++++++++++- umac/wifi_pos/src/wifi_pos_oem_interface_i.h | 41 +++ umac/wifi_pos/src/wifi_pos_ucfg.c | 37 ++- umac/wifi_pos/src/wifi_pos_ucfg_i.h | 3 +- umac/wifi_pos/src/wifi_pos_utils.c | 38 --- umac/wifi_pos/src/wifi_pos_utils_i.h | 81 +++-- 10 files changed, 776 insertions(+), 93 deletions(-) diff --git a/os_if/linux/wifi_pos/src/os_if_wifi_pos.c b/os_if/linux/wifi_pos/src/os_if_wifi_pos.c index e88c106042..2fbdc3d049 100644 --- a/os_if/linux/wifi_pos/src/os_if_wifi_pos.c +++ b/os_if/linux/wifi_pos/src/os_if_wifi_pos.c @@ -37,10 +37,126 @@ #include "os_if_wifi_pos.h" #include "wifi_pos_api.h" #include "wlan_cfg80211.h" +#include "wlan_objmgr_psoc_obj.h" #ifdef CNSS_GENL #include #endif +/** + * os_if_wifi_pos_send_rsp() - send oem registration response + * + * This function sends oem message to registered application process + * + * Return: none + */ +static void os_if_wifi_pos_send_rsp(uint32_t pid, uint32_t rsp_msg_type, + uint32_t buf_len, uint8_t *buf) +{ + tAniMsgHdr *aniHdr; + struct sk_buff *skb; + struct nlmsghdr *nlh; + + /* OEM msg is always to a specific process and cannot be a broadcast */ + if (pid == 0) { + cfg80211_err("invalid dest pid"); + return; + } + + skb = alloc_skb(NLMSG_SPACE(sizeof(tAniMsgHdr) + buf_len), GFP_ATOMIC); + if (skb == NULL) { + cfg80211_alert("alloc_skb failed"); + 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; + nlh->nlmsg_len = NLMSG_LENGTH(sizeof(tAniMsgHdr) + buf_len); + + aniHdr = NLMSG_DATA(nlh); + aniHdr->type = rsp_msg_type; + qdf_mem_copy(&aniHdr[1], buf, buf_len); + aniHdr->length = buf_len; + + skb_put(skb, NLMSG_SPACE(sizeof(tAniMsgHdr) + buf_len)); + cfg80211_debug("sending oem rsp: type: %d len(%d) to pid (%d)", + rsp_msg_type, buf_len, pid); + nl_srv_ucast_oem(skb, pid, MSG_DONTWAIT); +} + +#ifdef CNSS_GENL +static int wifi_pos_parse_req(const void *data, int len, int pid, + struct wifi_pos_req_msg *req) +{ + tAniMsgHdr *msg_hdr; + struct nlattr *tb[CLD80211_ATTR_MAX + 1]; + + if (nla_parse(tb, CLD80211_ATTR_MAX, data, len, NULL)) { + cfg80211_err("invalid data in request"); + return OEM_ERR_INVALID_MESSAGE_TYPE; + } + + if (!tb[CLD80211_ATTR_DATA]) { + cfg80211_err("CLD80211_ATTR_DATA not present"); + return OEM_ERR_INVALID_MESSAGE_TYPE; + } + + msg_hdr = (tAniMsgHdr *)nla_data(tb[CLD80211_ATTR_DATA]); + if (!msg_hdr) { + cfg80211_err("msg_hdr null"); + return OEM_ERR_NULL_MESSAGE_HEADER; + } + + req->msg_type = msg_hdr->type; + req->buf_len = msg_hdr->length; + req->buf = (uint8_t *)&msg_hdr[1]; + req->pid = pid; + + if (tb[CLD80211_ATTR_META_DATA]) { + req->field_info_buf = (struct wifi_pos_field_info *) + nla_data(tb[CLD80211_ATTR_META_DATA]); + req->field_info_buf_len = nla_len(tb[CLD80211_ATTR_META_DATA]); + } + + return 0; +} +#else +static int wifi_pos_parse_req(struct sk_buff *skb, struct wifi_pos_req_msg *req) +{ + /* SKB->data contains NL msg */ + /* NLMSG_DATA(nlh) contains ANI msg */ + struct nlmsghdr *nlh; + tAniMsgHdr *msg_hdr; + + nlh = (struct nlmsghdr *)skb->data; + if (!nlh) { + cfg80211_err("Netlink header null"); + return OEM_ERR_NULL_MESSAGE_HEADER; + } + + msg_hdr = NLMSG_DATA(nlh); + if (!msg_hdr) { + cfg80211_err("Message header null"); + return OEM_ERR_NULL_MESSAGE_HEADER; + } + + if (nlh->nlmsg_len < NLMSG_LENGTH(sizeof(*msg_hdr) + msg_hdr->length)) { + cfg80211_err("nlmsg_len(%d) and animsg_len(%d) mis-match", + nlh->nlmsg_len, msg_hdr->length); + return OEM_ERR_INVALID_MESSAGE_LENGTH; + } + + req->msg_type = msg_hdr->type; + req->buf_len = msg_hdr->length; + req->buf = (uint8_t *)&msg_hdr[1]; + req->pid = nlh->nlmsg_pid; + + return 0; +} +#endif + /** * os_if_wifi_pos_callback() - callback registered with NL service socket to * process wifi pos request @@ -52,26 +168,70 @@ static void os_if_wifi_pos_callback(const void *data, int data_len, void *ctx, int pid) { + uint8_t err; QDF_STATUS status; struct wifi_pos_req_msg req = {0}; struct wlan_objmgr_psoc *psoc = wifi_pos_get_psoc(); + cfg80211_debug("enter: pid %d", pid); if (!psoc) { cfg80211_err("global psoc object not registered yet."); return; } wlan_objmgr_psoc_get_ref(psoc, WLAN_WIFI_POS_ID); + err = wifi_pos_parse_req(data, data_len, pid, &req); + if (err) { + os_if_wifi_pos_send_rsp(wifi_pos_get_app_pid(psoc), + ANI_MSG_OEM_ERROR, sizeof(err), &err); + status = QDF_STATUS_E_INVAL; + goto release_psoc_ref; + } - /* implemention is TBD */ - status = ucfg_wifi_pos_process_req(psoc, &req, NULL); + status = ucfg_wifi_pos_process_req(psoc, &req, os_if_wifi_pos_send_rsp); if (QDF_IS_STATUS_ERROR(status)) cfg80211_err("ucfg_wifi_pos_process_req failed. status: %d", status); +release_psoc_ref: wlan_objmgr_psoc_release_ref(psoc, WLAN_WIFI_POS_ID); } +#else +static int os_if_wifi_pos_callback(struct sk_buff *skb) +{ + uint8_t err; + QDF_STATUS status; + struct wifi_pos_req_msg req = {0}; + struct wlan_objmgr_psoc *psoc = wifi_pos_get_psoc(); + cfg80211_debug("enter"); + if (!psoc) { + cfg80211_err("global psoc object not registered yet."); + return -EINVAL; + } + + wlan_objmgr_psoc_get_ref(psoc, WLAN_WIFI_POS_ID); + err = wifi_pos_parse_req(skb, &req); + if (err) { + os_if_wifi_pos_send_rsp(wifi_pos_get_app_pid(psoc), + ANI_MSG_OEM_ERROR, sizeof(err), &err); + status = QDF_STATUS_E_INVAL; + goto release_psoc_ref; + } + + status = ucfg_wifi_pos_process_req(psoc, &req, os_if_wifi_pos_send_rsp); + if (QDF_IS_STATUS_ERROR(status)) + cfg80211_err("ucfg_wifi_pos_process_req failed. status: %d", + status); + +release_psoc_ref: + wlan_objmgr_psoc_release_ref(psoc, WLAN_WIFI_POS_ID); + + return qdf_status_to_os_return(status); +} +#endif + +#ifdef CNSS_GENL int os_if_wifi_pos_register_nl(void) { int ret = register_cld_cmd_cb(WLAN_NL_MSG_OEM, @@ -81,7 +241,14 @@ int os_if_wifi_pos_register_nl(void) return ret; } +#else +int os_if_wifi_pos_register_nl(void) +{ + return nl_srv_register(WLAN_NL_MSG_OEM, os_if_wifi_pos_callback); +} +#endif /* CNSS_GENL */ +#ifdef CNSS_GENL int os_if_wifi_pos_deregister_nl(void) { int ret = deregister_cld_cmd_cb(WLAN_NL_MSG_OEM); @@ -91,16 +258,11 @@ int os_if_wifi_pos_deregister_nl(void) return ret; } #else -int os_if_wifi_pos_register_nl(void) -{ - return 0; -} - int os_if_wifi_pos_deregister_nl(void) { return 0; } -#endif +#endif /* CNSS_GENL */ void os_if_wifi_pos_send_peer_status(struct qdf_mac_addr *peer_mac, uint8_t peer_status, @@ -109,7 +271,62 @@ void os_if_wifi_pos_send_peer_status(struct qdf_mac_addr *peer_mac, struct wifi_pos_ch_info *chan_info, enum tQDF_ADAPTER_MODE dev_mode) { - /* implemention TBD */ + struct wlan_objmgr_psoc *psoc = wifi_pos_get_psoc(); + struct wmi_pos_peer_status_info *peer_info; + + if (!psoc) { + cfg80211_err("global wifi_pos psoc object not registered"); + return; + } + + if (!wifi_pos_is_app_registered(psoc) || + wifi_pos_get_app_pid(psoc) == 0) { + cfg80211_err("app is not registered or pid is invalid"); + return; + } + + peer_info = qdf_mem_malloc(sizeof(*peer_info)); + if (!peer_info) { + cfg80211_alert("malloc failed"); + return; + } + qdf_mem_copy(peer_info->peer_mac_addr, peer_mac->bytes, + sizeof(peer_mac->bytes)); + peer_info->peer_status = peer_status; + peer_info->vdev_id = session_id; + peer_info->peer_capability = peer_timing_meas_cap; + peer_info->reserved0 = 0; + /* Set 0th bit of reserved0 for STA mode */ + if (QDF_STA_MODE == dev_mode) + peer_info->reserved0 |= 0x01; + + if (chan_info) { + peer_info->peer_chan_info.chan_id = chan_info->chan_id; + peer_info->peer_chan_info.reserved0 = 0; + peer_info->peer_chan_info.mhz = chan_info->mhz; + peer_info->peer_chan_info.band_center_freq1 = + chan_info->band_center_freq1; + peer_info->peer_chan_info.band_center_freq2 = + chan_info->band_center_freq2; + peer_info->peer_chan_info.info = chan_info->info; + peer_info->peer_chan_info.reg_info_1 = chan_info->reg_info_1; + peer_info->peer_chan_info.reg_info_2 = chan_info->reg_info_2; + } + + os_if_wifi_pos_send_rsp(wifi_pos_get_app_pid(psoc), + ANI_MSG_PEER_STATUS_IND, + sizeof(*peer_info), (uint8_t *)peer_info); + return; +} + +void os_if_wifi_pos_set_ftm_cap(struct wlan_objmgr_psoc *psoc, uint32_t val) +{ + if (!psoc) { + cfg80211_err("psoc is null"); + return; + } + + wifi_pos_set_ftm_cap(psoc, val); } int os_if_wifi_pos_populate_caps(struct wlan_objmgr_psoc *psoc, diff --git a/target_if/wifi_pos/src/target_if_wifi_pos.c b/target_if/wifi_pos/src/target_if_wifi_pos.c index a9b7fa711c..e540852a1c 100644 --- a/target_if/wifi_pos/src/target_if_wifi_pos.c +++ b/target_if/wifi_pos/src/target_if_wifi_pos.c @@ -49,17 +49,44 @@ static int wifi_pos_oem_rsp_ev_handler(ol_scn_t scn, uint8_t *data_buf, uint32_t data_len) { - struct oem_data_rsp *oem_rsp = NULL; - struct wlan_objmgr_psoc *psoc = NULL; + int ret; + struct oem_data_rsp oem_rsp = {0}; + struct wifi_pos_psoc_priv_obj *wifi_pos_psoc; + struct wlan_objmgr_psoc *psoc = wifi_pos_get_psoc(); struct wlan_lmac_if_wifi_pos_rx_ops *wifi_pos_rx_ops = NULL; + WMI_OEM_RESPONSE_EVENTID_param_tlvs *param_buf = + (WMI_OEM_RESPONSE_EVENTID_param_tlvs *)data_buf; + if (!psoc) { + wifi_pos_err("psoc is null"); + return QDF_STATUS_NOT_INITIALIZED; + } + wifi_pos_psoc = wifi_pos_get_psoc_priv_obj(psoc); + if (!wifi_pos_psoc) { + wifi_pos_err("wifi_pos_psoc is null"); + return QDF_STATUS_NOT_INITIALIZED; + } + qdf_spin_lock_bh(&wifi_pos_psoc->wifi_pos_lock); + wlan_objmgr_psoc_get_ref(psoc, WLAN_WIFI_POS_ID); + + wifi_pos_rx_ops = target_if_wifi_pos_get_rxops(psoc); /* this will be implemented later */ if (!wifi_pos_rx_ops || !wifi_pos_rx_ops->oem_rsp_event_rx) { wifi_pos_err("lmac callbacks not registered"); - return QDF_STATUS_NOT_INITIALIZED; + ret = QDF_STATUS_NOT_INITIALIZED; + goto release_psoc_ref; } - return wifi_pos_rx_ops->oem_rsp_event_rx(psoc, oem_rsp); + oem_rsp.rsp_len = param_buf->num_data; + oem_rsp.data = param_buf->data; + + ret = wifi_pos_rx_ops->oem_rsp_event_rx(psoc, &oem_rsp); + +release_psoc_ref: + wlan_objmgr_psoc_release_ref(psoc, WLAN_WIFI_POS_ID); + qdf_spin_unlock_bh(&wifi_pos_psoc->wifi_pos_lock); + + return ret; } /** diff --git a/umac/wifi_pos/inc/wifi_pos_api.h b/umac/wifi_pos/inc/wifi_pos_api.h index c551d8d530..6a25d8b106 100644 --- a/umac/wifi_pos/inc/wifi_pos_api.h +++ b/umac/wifi_pos/inc/wifi_pos_api.h @@ -34,6 +34,8 @@ /* Include files */ #include "qdf_types.h" +#include "qdf_status.h" +#include "qdf_trace.h" /* forward reference */ struct wlan_objmgr_psoc; @@ -134,6 +136,19 @@ struct wifi_pos_req_msg { uint32_t field_info_buf_len; }; +/** + * ucfg_wifi_pos_process_req: ucfg API to be called from HDD/OS_IF to process a + * wifi_pos request from userspace + * @psoc: pointer to psoc object + * @req: wifi_pos request msg + * @send_rsp_cb: callback pointer required to send msg to userspace + * + * Return: status of operation + */ +QDF_STATUS ucfg_wifi_pos_process_req(struct wlan_objmgr_psoc *psoc, + struct wifi_pos_req_msg *req, + void (*send_rsp_cb)(uint32_t, uint32_t, uint32_t, uint8_t *)); + /** * wifi_pos_init: initializes WIFI POS component, called by dispatcher init * @@ -276,6 +291,40 @@ void wifi_pos_set_current_dwell_time_max(struct wlan_objmgr_psoc *psoc, QDF_STATUS wifi_pos_populate_caps(struct wlan_objmgr_psoc *psoc, struct wifi_pos_driver_caps *caps); +/** + * wifi_pos_set_ftm_cap: API to set fine timing measurement caps + * @psoc: psoc object + * @val: value to set + * + * Return: None + */ +void wifi_pos_set_ftm_cap(struct wlan_objmgr_psoc *psoc, uint32_t val); + +/** + * wifi_pos_get_app_pid: returns oem app pid. + * @psoc: pointer to psoc object + * + * Return: oem app pid + */ +uint32_t wifi_pos_get_app_pid(struct wlan_objmgr_psoc *psoc); + +/** + * wifi_pos_is_app_registered: indicates if oem app is registered. + * @psoc: pointer to psoc object + * + * Return: true if app is registered, false otherwise + */ +bool wifi_pos_is_app_registered(struct wlan_objmgr_psoc *psoc); + +/** + * wifi_pos_get_psoc: API to get global PSOC object + * + * Since request from userspace is not associated with any vdev/pdev/psoc, this + * API is used to get global psoc object. + * Return: global psoc object. + */ +struct wlan_objmgr_psoc *wifi_pos_get_psoc(void); + #else static inline QDF_STATUS wifi_pos_init(void) { diff --git a/umac/wifi_pos/src/wifi_pos_api.c b/umac/wifi_pos/src/wifi_pos_api.c index 9a7fd8cb41..1abe5adef7 100644 --- a/umac/wifi_pos/src/wifi_pos_api.c +++ b/umac/wifi_pos/src/wifi_pos_api.c @@ -204,3 +204,56 @@ void wifi_pos_set_current_dwell_time_min(struct wlan_objmgr_psoc *psoc, wifi_pos_psoc->current_dwell_time_max = val; qdf_spin_unlock_bh(&wifi_pos_psoc->wifi_pos_lock); } + +void wifi_pos_set_ftm_cap(struct wlan_objmgr_psoc *psoc, uint32_t val) +{ + struct wifi_pos_psoc_priv_obj *wifi_pos_psoc = + wifi_pos_get_psoc_priv_obj(psoc); + + if (!wifi_pos_psoc) { + wifi_pos_alert("unable to get wifi_pos psoc obj"); + return; + } + + qdf_spin_lock_bh(&wifi_pos_psoc->wifi_pos_lock); + wifi_pos_psoc->fine_time_meas_cap = val; + qdf_spin_unlock_bh(&wifi_pos_psoc->wifi_pos_lock); +} + +uint32_t wifi_pos_get_app_pid(struct wlan_objmgr_psoc *psoc) +{ + uint32_t app_pid; + struct wifi_pos_psoc_priv_obj *wifi_pos_psoc = + wifi_pos_get_psoc_priv_obj(psoc); + + if (!wifi_pos_psoc) { + wifi_pos_err("wifi_pos priv obj is null"); + return 0; + } + + qdf_spin_lock_bh(&wifi_pos_psoc->wifi_pos_lock); + app_pid = wifi_pos_psoc->app_pid; + qdf_spin_unlock_bh(&wifi_pos_psoc->wifi_pos_lock); + + return app_pid; + +} + +bool wifi_pos_is_app_registered(struct wlan_objmgr_psoc *psoc) +{ + bool is_app_registered; + struct wifi_pos_psoc_priv_obj *wifi_pos_psoc = + wifi_pos_get_psoc_priv_obj(psoc); + + if (!wifi_pos_psoc) { + wifi_pos_err("wifi_pos priv obj is null"); + return false; + } + + qdf_spin_lock_bh(&wifi_pos_psoc->wifi_pos_lock); + is_app_registered = wifi_pos_psoc->is_app_registered; + qdf_spin_unlock_bh(&wifi_pos_psoc->wifi_pos_lock); + + return is_app_registered; +} + diff --git a/umac/wifi_pos/src/wifi_pos_main.c b/umac/wifi_pos/src/wifi_pos_main.c index 88565d0911..1c15452a4f 100644 --- a/umac/wifi_pos/src/wifi_pos_main.c +++ b/umac/wifi_pos/src/wifi_pos_main.c @@ -31,7 +31,7 @@ * wifi positioning to initialize and de-initialize the component. */ #include "target_if_wifi_pos.h" -#include "os_if_wifi_pos.h" +#include "wifi_pos_oem_interface_i.h" #include "wifi_pos_utils_i.h" #include "wifi_pos_api.h" #include "wifi_pos_main_i.h" @@ -39,6 +39,9 @@ #include "wlan_objmgr_cmn.h" #include "wlan_objmgr_global_obj.h" #include "wlan_objmgr_psoc_obj.h" +#include "wlan_objmgr_pdev_obj.h" +#include "wlan_objmgr_vdev_obj.h" +#include "wlan_ptt_sock_svc.h" #ifdef UMAC_REG_COMPONENT /* enable this when regulatory component gets merged */ @@ -47,6 +50,15 @@ struct regulatory_channel; #endif +/* + * obj mgr api to iterate over vdevs does not provide a direct array or vdevs, + * rather takes a callback that is called for every vdev. wifi pos needs to + * store device mode and vdev id of all active vdevs and provide this info to + * user space as part of APP registration response. due to this, vdev_idx is + * used to identify how many vdevs have been populated by obj manager API. + */ +static uint32_t vdev_idx; + /** * wifi_pos_get_tlv_support: indicates if firmware supports TLV wifi pos msg * @psoc: psoc object @@ -59,6 +71,263 @@ static bool wifi_pos_get_tlv_support(struct wlan_objmgr_psoc *psoc) return true; } +static int wifi_pos_process_data_req(struct wlan_objmgr_psoc *psoc, + struct wifi_pos_req_msg *req) +{ + uint8_t idx; + uint32_t sub_type = 0; + uint32_t channel_mhz = 0; + void *pdev_id = NULL; + uint32_t offset; + struct oem_data_req data_req; + struct wlan_lmac_if_wifi_pos_tx_ops *tx_ops; + + wifi_pos_debug("Received data req pid(%d), len(%d)", + req->pid, req->buf_len); + + /* look for fields */ + if (req->field_info_buf) + for (idx = 0; idx < req->field_info_buf->count; idx++) { + offset = req->field_info_buf->fields[idx].offset; + /* + * replace following reads with read_api based on + * length + */ + if (req->field_info_buf->fields[idx].id == + WMIRTT_FIELD_ID_oem_data_sub_type) { + sub_type = *((uint32_t *)&req->buf[offset]); + continue; + } + + if (req->field_info_buf->fields[idx].id == + WMIRTT_FIELD_ID_channel_mhz) { + channel_mhz = *((uint32_t *)&req->buf[offset]); + continue; + } + + if (req->field_info_buf->fields[idx].id == + WMIRTT_FIELD_ID_pdev) { + pdev_id = &req->buf[offset]; + continue; + } + } + + switch (sub_type) { + case TARGET_OEM_CAPABILITY_REQ: + /* TBD */ + break; + case TARGET_OEM_CONFIGURE_LCR: + /* TBD */ + break; + case TARGET_OEM_CONFIGURE_LCI: + /* TBD */ + break; + case TARGET_OEM_MEASUREMENT_REQ: + /* TBD */ + break; + case TARGET_OEM_CONFIGURE_FTMRR: + /* TBD */ + break; + case TARGET_OEM_CONFIGURE_WRU: + /* TBD */ + break; + default: + wifi_pos_debug("invalid sub type or not passed"); + /* + * this is legacy MCL operation. pass whole msg to firmware as + * it is. + */ + tx_ops = target_if_wifi_pos_get_txops(psoc); + data_req.data_len = req->buf_len; + data_req.data = req->buf; + tx_ops->data_req_tx(psoc, &data_req); + break; + } + + return 0; +} + +static int wifi_pos_process_set_cap_req(struct wlan_objmgr_psoc *psoc, + struct wifi_pos_req_msg *req) +{ + int error_code; + struct wifi_pos_psoc_priv_obj *wifi_pos_obj = + wifi_pos_get_psoc_priv_obj(psoc); + struct wifi_pos_user_defined_caps *caps = + (struct wifi_pos_user_defined_caps *)req->buf; + + wifi_pos_debug("Received set cap req pid(%d), len(%d)", + req->pid, req->buf_len); + + wifi_pos_obj->ftm_rr = caps->ftm_rr; + wifi_pos_obj->lci_capability = caps->lci_capability; + error_code = qdf_status_to_os_return(QDF_STATUS_SUCCESS); + wifi_pos_obj->wifi_pos_send_rsp(wifi_pos_obj->app_pid, + ANI_MSG_SET_OEM_CAP_RSP, + sizeof(error_code), + (uint8_t *)&error_code); + + return 0; +} + +static int wifi_pos_process_get_cap_req(struct wlan_objmgr_psoc *psoc, + struct wifi_pos_req_msg *req) +{ + struct wifi_pos_oem_get_cap_rsp cap_rsp = { { {0} } }; + struct wifi_pos_psoc_priv_obj *wifi_pos_obj = + wifi_pos_get_psoc_priv_obj(psoc); + + wifi_pos_debug("Received get cap req pid(%d), len(%d)", + req->pid, req->buf_len); + + wifi_pos_populate_caps(psoc, &cap_rsp.driver_cap); + cap_rsp.user_defined_cap.ftm_rr = wifi_pos_obj->ftm_rr; + cap_rsp.user_defined_cap.lci_capability = wifi_pos_obj->lci_capability; + wifi_pos_obj->wifi_pos_send_rsp(wifi_pos_obj->app_pid, + ANI_MSG_GET_OEM_CAP_RSP, + sizeof(cap_rsp), + (uint8_t *)&cap_rsp); + + return 0; +} + +static int wifi_pos_process_ch_info_req(struct wlan_objmgr_psoc *psoc, + struct wifi_pos_req_msg *req) +{ + uint8_t idx; + uint8_t *buf; + uint32_t len; + uint8_t *channels = req->buf; + uint32_t num_ch = req->buf_len; + struct wifi_pos_ch_info_rsp *ch_info; + struct wifi_pos_psoc_priv_obj *wifi_pos_obj = + wifi_pos_get_psoc_priv_obj(psoc); + + wifi_pos_debug("Received ch info req pid(%d), len(%d)", + req->pid, req->buf_len); + + len = sizeof(uint8_t) + sizeof(struct wifi_pos_ch_info_rsp) * num_ch; + buf = qdf_mem_malloc(len); + if (!buf) { + wifi_pos_alert("malloc failed"); + return -ENOMEM; + } + + /* First byte of message body will have num of channels */ + buf[0] = num_ch; + ch_info = (struct wifi_pos_ch_info_rsp *)&buf[1]; + for (idx = 0; idx < num_ch; idx++) { + ch_info[idx].chan_id = channels[idx]; + ch_info[idx].reserved0 = 0; +#ifdef UMAC_REG_COMPONENT + /* + * please note that this is feature macro temp and will go away + * once regulatory component gets merged: + * identify regulatory API to get following information + */ + ch_info[idx].mhz = cds_chan_to_freq(channels[idx]); + ch_info[idx].band_center_freq1 = ch_info[idx].mhz; +#endif + ch_info[idx].band_center_freq2 = 0; + ch_info[idx].info = 0; +#ifdef UMAC_REG_COMPONENT + /* + * please note that this is feature macro temp and will go away + * once regulatory component gets merged: + * identify regulatory API to replace update_channel_bw_info + * and to get following information + */ + if (CHANNEL_STATE_DFS == cds_get_channel_state(channels[idx])) + WMI_SET_CHANNEL_FLAG(&ch_info[idx], WMI_CHAN_FLAG_DFS); +#endif + ch_info[idx].reg_info_1 = 0; + ch_info[idx].reg_info_2 = 0; + } + + wifi_pos_obj->wifi_pos_send_rsp(wifi_pos_obj->app_pid, + ANI_MSG_CHANNEL_INFO_RSP, + len, buf); + qdf_mem_free(buf); + return 0; +} + +static void wifi_pos_populate_vdev_info(struct wlan_objmgr_psoc *psoc, + void *vdev, void *arg) +{ + struct app_reg_rsp_vdev_info *vdev_info = arg; + + wlan_vdev_obj_lock(vdev); + vdev_info[vdev_idx].dev_mode = wlan_vdev_mlme_get_opmode(vdev); + vdev_info[vdev_idx].vdev_id = wlan_vdev_get_id(vdev); + wlan_vdev_obj_unlock(vdev); + vdev_idx++; +} + +static int wifi_pos_process_app_reg_req(struct wlan_objmgr_psoc *psoc, + struct wifi_pos_req_msg *req) +{ + int ret = 0; + uint8_t err = 0; + uint32_t rsp_len; + char *sign_str = NULL; + struct wifi_app_reg_rsp *app_reg_rsp; + struct app_reg_rsp_vdev_info vdevs_info[WLAN_UMAC_PSOC_MAX_VDEVS] + = { { 0 } }; + struct wifi_pos_psoc_priv_obj *wifi_pos_obj = + wifi_pos_get_psoc_priv_obj(psoc); + + wifi_pos_err("Received App Req Req pid(%d), len(%d)", + req->pid, req->buf_len); + + sign_str = (char *)req->buf; + /* Registration request is only allowed for Qualcomm Application */ + if ((OEM_APP_SIGNATURE_LEN != req->buf_len) || + (strncmp(sign_str, OEM_APP_SIGNATURE_STR, + OEM_APP_SIGNATURE_LEN))) { + wifi_pos_err("Invalid signature pid(%d)", req->pid); + ret = -EPERM; + err = OEM_ERR_INVALID_SIGNATURE; + goto app_reg_failed; + } + + wifi_pos_debug("Valid App Req Req from pid(%d)", req->pid); + wifi_pos_obj->is_app_registered = true; + wifi_pos_obj->app_pid = req->pid; + + vdev_idx = 0; + wlan_objmgr_iterate_obj_list(psoc, WLAN_VDEV_OP, + wifi_pos_populate_vdev_info, + vdevs_info, 1, WLAN_WIFI_POS_ID); + rsp_len = (sizeof(struct app_reg_rsp_vdev_info) * vdev_idx) + + sizeof(uint8_t); + app_reg_rsp = qdf_mem_malloc(rsp_len); + if (!app_reg_rsp) { + wifi_pos_alert("malloc failed"); + ret = -ENOMEM; + err = OEM_ERR_NULL_CONTEXT; + goto app_reg_failed; + } + + app_reg_rsp->num_inf = vdev_idx; + qdf_mem_copy(&app_reg_rsp->vdevs, vdevs_info, + sizeof(struct app_reg_rsp_vdev_info) * vdev_idx); + if (!vdev_idx) + wifi_pos_debug("no active vdev"); + + vdev_idx = 0; + wifi_pos_obj->wifi_pos_send_rsp(req->pid, ANI_MSG_APP_REG_RSP, + rsp_len, (uint8_t *)app_reg_rsp); + + qdf_mem_free(app_reg_rsp); + return ret; + +app_reg_failed: + + wifi_pos_obj->wifi_pos_send_rsp(req->pid, ANI_MSG_OEM_ERROR, + sizeof(err), &err); + return ret; +} + /** * wifi_pos_tlv_callback: wifi pos msg handler registered for TLV type req * @wmi_msg: wmi type request msg @@ -68,9 +337,23 @@ static bool wifi_pos_get_tlv_support(struct wlan_objmgr_psoc *psoc) static QDF_STATUS wifi_pos_tlv_callback(struct wlan_objmgr_psoc *psoc, struct wifi_pos_req_msg *req) { - /* actual implementation of cmds start here */ - /* TBD - decide if ANI_MSG_OEM_DATA_REQ goest to MC thread or not */ - return QDF_STATUS_SUCCESS; + wifi_pos_debug("enter: msg_type: %d", req->msg_type); + switch (req->msg_type) { + case ANI_MSG_APP_REG_REQ: + return wifi_pos_process_app_reg_req(psoc, req); + case ANI_MSG_OEM_DATA_REQ: + return wifi_pos_process_data_req(psoc, req); + case ANI_MSG_CHANNEL_INFO_REQ: + return wifi_pos_process_ch_info_req(psoc, req); + case ANI_MSG_SET_OEM_CAP_REQ: + return wifi_pos_process_set_cap_req(psoc, req); + case ANI_MSG_GET_OEM_CAP_REQ: + return wifi_pos_process_get_cap_req(psoc, req); + default: + wifi_pos_err("invalid request type"); + break; + } + return 0; } /** @@ -190,8 +473,10 @@ int wifi_pos_oem_rsp_handler(struct wlan_objmgr_psoc *psoc, wifi_pos_debug("sending oem data rsp, len: %d to pid: %d", oem_rsp->rsp_len, wifi_pos_obj->app_pid); - wifi_pos_obj->wifi_pos_send_rsp(psoc, ANI_MSG_OEM_DATA_RSP, - oem_rsp->rsp_len, oem_rsp->data); + wifi_pos_obj->wifi_pos_send_rsp(wifi_pos_obj->app_pid, + ANI_MSG_OEM_DATA_RSP, + oem_rsp->rsp_len, + oem_rsp->data); return 0; } diff --git a/umac/wifi_pos/src/wifi_pos_oem_interface_i.h b/umac/wifi_pos/src/wifi_pos_oem_interface_i.h index 2080d7dfce..94b6e15205 100644 --- a/umac/wifi_pos/src/wifi_pos_oem_interface_i.h +++ b/umac/wifi_pos/src/wifi_pos_oem_interface_i.h @@ -22,4 +22,45 @@ #ifndef _WIFI_POS_OEM_INTERFACE_H_ #define _WIFI_POS_OEM_INTERFACE_H_ +/* Include files */ +#include "qdf_types.h" +#include "qdf_status.h" +#include "wlan_objmgr_cmn.h" + +#define TARGET_OEM_CAPABILITY_REQ 0x01 +#define TARGET_OEM_CAPABILITY_RSP 0x02 +#define TARGET_OEM_MEASUREMENT_REQ 0x03 +#define TARGET_OEM_MEASUREMENT_RSP 0x04 +#define TARGET_OEM_ERROR_REPORT_RSP 0x05 +#define TARGET_OEM_NAN_MEAS_REQ 0x06 +#define TARGET_OEM_NAN_MEAS_RSP 0x07 +#define TARGET_OEM_NAN_PEER_INFO 0x08 +#define TARGET_OEM_CONFIGURE_LCR 0x09 +#define TARGET_OEM_CONFIGURE_LCI 0x0A +#define TARGET_OEM_CONFIGURE_WRU 0x80 +#define TARGET_OEM_CONFIGURE_FTMRR 0x81 + +struct wifi_pos_field { + uint32_t id; + uint32_t offset; + uint32_t length; +}; + +struct wifi_pos_field_info { + uint32_t count; + struct wifi_pos_field fields[1]; +}; + +/** + * enum WMIRTT_FIELD_ID - identifies which field is being specified + * @WMIRTT_FIELD_ID_oem_data_sub_type: oem data req sub type + * @WMIRTT_FIELD_ID_channel_mhz: channel mhz info + * @WMIRTT_FIELD_ID_pdev: pdev info + */ +enum WMIRTT_FIELD_ID { + WMIRTT_FIELD_ID_oem_data_sub_type, + WMIRTT_FIELD_ID_channel_mhz, + WMIRTT_FIELD_ID_pdev, +}; + #endif diff --git a/umac/wifi_pos/src/wifi_pos_ucfg.c b/umac/wifi_pos/src/wifi_pos_ucfg.c index 7752ee344f..2c4074898a 100644 --- a/umac/wifi_pos/src/wifi_pos_ucfg.c +++ b/umac/wifi_pos/src/wifi_pos_ucfg.c @@ -23,22 +23,51 @@ #include "wifi_pos_utils_i.h" #include "wifi_pos_api.h" #include "wifi_pos_ucfg_i.h" +#include "wlan_ptt_sock_svc.h" QDF_STATUS ucfg_wifi_pos_process_req(struct wlan_objmgr_psoc *psoc, struct wifi_pos_req_msg *req, - void (*send_rsp_cb)(uint32_t *, - uint32_t, uint32_t, uint8_t *)) + void (*send_rsp_cb)(uint32_t, uint32_t, uint32_t, uint8_t *)) { + uint8_t err; + uint32_t app_pid; + QDF_STATUS status; + bool is_app_registered; struct wifi_pos_psoc_priv_obj *wifi_pos_psoc_obj = wifi_pos_get_psoc_priv_obj(psoc); + wifi_pos_debug("enter"); + if (!wifi_pos_psoc_obj) { wifi_pos_err("wifi_pos_psoc_obj is null"); return QDF_STATUS_E_NULL_VALUE; } - /* assign callback pointer to be called for rsp or error */ + qdf_spin_lock_bh(&wifi_pos_psoc_obj->wifi_pos_lock); wifi_pos_psoc_obj->wifi_pos_send_rsp = send_rsp_cb; + is_app_registered = wifi_pos_psoc_obj->is_app_registered; + app_pid = wifi_pos_psoc_obj->app_pid; + if (!wifi_pos_psoc_obj->wifi_pos_req_handler) { + wifi_pos_err("wifi_pos_psoc_obj->wifi_pos_req_handler is null"); + err = OEM_ERR_NULL_CONTEXT; + send_rsp_cb(app_pid, ANI_MSG_OEM_ERROR, sizeof(err), &err); + status = QDF_STATUS_E_NULL_VALUE; + goto unlock_and_exit; + } - return wifi_pos_psoc_obj->wifi_pos_req_handler(psoc, req); + if (req->msg_type != ANI_MSG_APP_REG_REQ && + (!is_app_registered || app_pid != req->pid)) { + wifi_pos_err("requesting app is not registered, app_registered: %d, requesting pid: %d, stored pid: %d", + is_app_registered, req->pid, app_pid); + err = OEM_ERR_APP_NOT_REGISTERED; + send_rsp_cb(app_pid, ANI_MSG_OEM_ERROR, sizeof(err), &err); + status = QDF_STATUS_E_INVAL; + goto unlock_and_exit; + } + + status = wifi_pos_psoc_obj->wifi_pos_req_handler(psoc, req); + +unlock_and_exit: + qdf_spin_unlock_bh(&wifi_pos_psoc_obj->wifi_pos_lock); + return status; } diff --git a/umac/wifi_pos/src/wifi_pos_ucfg_i.h b/umac/wifi_pos/src/wifi_pos_ucfg_i.h index fe614ed8ec..a5dd1f4f87 100644 --- a/umac/wifi_pos/src/wifi_pos_ucfg_i.h +++ b/umac/wifi_pos/src/wifi_pos_ucfg_i.h @@ -42,7 +42,6 @@ struct wifi_pos_req_msg; */ QDF_STATUS ucfg_wifi_pos_process_req(struct wlan_objmgr_psoc *psoc, struct wifi_pos_req_msg *req, - void (*send_rsp_cb)(struct wlan_objmgr_psoc *, - uint32_t, uint32_t, uint8_t *)); + void (*send_rsp_cb)(uint32_t, uint32_t, uint32_t, uint8_t *)); #endif /* _WIFI_POS_UCFG_H_ */ diff --git a/umac/wifi_pos/src/wifi_pos_utils.c b/umac/wifi_pos/src/wifi_pos_utils.c index 63cc03aa95..4f3f74d592 100644 --- a/umac/wifi_pos/src/wifi_pos_utils.c +++ b/umac/wifi_pos/src/wifi_pos_utils.c @@ -74,41 +74,3 @@ struct wifi_pos_psoc_priv_obj *wifi_pos_get_psoc_priv_obj( return obj; } - -bool wifi_pos_is_app_registered(struct wlan_objmgr_psoc *psoc) -{ - struct wifi_pos_psoc_priv_obj *obj; - - if (!psoc) { - wifi_pos_err("psoc is null"); - return false; - } - - obj = wifi_pos_get_psoc_priv_obj(psoc); - - if (!obj) { - wifi_pos_err("wifi_pos priv obj is null"); - return false; - } - - return obj->is_app_registered; -} - -uint32_t wifi_pos_get_app_pid(struct wlan_objmgr_psoc *psoc) -{ - struct wifi_pos_psoc_priv_obj *obj; - - if (!psoc) { - wifi_pos_err("psoc is null"); - return 0; - } - - obj = wifi_pos_get_psoc_priv_obj(psoc); - - if (!obj) { - wifi_pos_err("wifi_pos priv obj is null"); - return 0; - } - - return obj->app_pid; -} diff --git a/umac/wifi_pos/src/wifi_pos_utils_i.h b/umac/wifi_pos/src/wifi_pos_utils_i.h index 6c95dafb9b..19b57c06b9 100644 --- a/umac/wifi_pos/src/wifi_pos_utils_i.h +++ b/umac/wifi_pos/src/wifi_pos_utils_i.h @@ -41,6 +41,7 @@ #include "qdf_trace.h" struct wlan_objmgr_psoc; +struct wifi_pos_req_msg; #define wifi_pos_log(level, args...) \ QDF_TRACE(QDF_MODULE_ID_WIFIPOS, level, ## args) @@ -70,6 +71,28 @@ struct wlan_objmgr_psoc; #define OEM_DATA_RSP_SIZE 1724 #endif +/** + * struct app_reg_rsp_vdev_info - vdev info struct + * @dev_mode: device mode + * @vdev_id: vdev id + * + */ +struct qdf_packed app_reg_rsp_vdev_info { + uint8_t dev_mode; + uint8_t vdev_id; +}; + +/** + * struct wifi_app_reg_rsp - app registration response struct + * @num_inf: number of interfaces active + * @vdevs: array indicating all active vdev's information + * + */ +struct qdf_packed wifi_app_reg_rsp { + uint8_t num_inf; + struct app_reg_rsp_vdev_info vdevs[1]; +}; + /** * struct oem_data_req - data request to be sent to firmware * @data_len: len of data @@ -93,7 +116,7 @@ struct oem_data_rsp { }; /** - * typedef wifi_pos_driver_version - Driver version identifier (w.x.y.z) + * struct wifi_pos_driver_version - Driver version identifier (w.x.y.z) * @major: Version ID major number * @minor: Version ID minor number * @patch: Version ID patch number @@ -134,13 +157,29 @@ struct qdf_packed wifi_pos_driver_caps { uint8_t channel_list[OEM_CAP_MAX_NUM_CHANNELS]; }; -struct wifi_pos_req_msg { - uint32_t msg_type; - uint32_t pid; - uint8_t *buf; - uint32_t buf_len; - struct wifi_pos_field_info *field_info_buf; - uint32_t field_info_buf_len; +/** + * struct wifi_pos_user_defined_caps - 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 wifi_pos_user_defined_caps { + uint32_t ftm_rr:1; + uint32_t lci_capability:1; + uint32_t reserved1:30; + uint32_t reserved2; +}; + +/** + * struct wifi_pos_oem_get_cap_rsp - capabilites set by userspace and target. + * @driver_cap: target capabilities + * @user_defined_cap: capabilities set by userspace via set request + */ +struct qdf_packed wifi_pos_oem_get_cap_rsp { + struct wifi_pos_driver_caps driver_cap; + struct wifi_pos_user_defined_caps user_defined_cap; }; /** @@ -184,9 +223,7 @@ struct wifi_pos_psoc_priv_obj { QDF_STATUS (*wifi_pos_req_handler)(struct wlan_objmgr_psoc *psoc, struct wifi_pos_req_msg *req); - void (*wifi_pos_send_rsp)(struct wlan_objmgr_psoc *psoc, - uint32_t rsp_msg_type, uint32_t buf_len, - uint8_t *buf); + void (*wifi_pos_send_rsp)(uint32_t, uint32_t, uint32_t, uint8_t *); }; /** @@ -235,14 +272,6 @@ void wifi_pos_clear_psoc(void); QDF_STATUS wifi_pos_populate_caps(struct wlan_objmgr_psoc *psoc, struct wifi_pos_driver_caps *caps); -/** - * wifi_pos_is_app_registered: indicates if oem app is registered. - * @psoc: pointer to psoc object - * - * Return: true if app is registered, false otherwise - */ -bool wifi_pos_is_app_registered(struct wlan_objmgr_psoc *psoc); - /** * wifi_pos_get_app_pid: returns oem app pid. * @psoc: pointer to psoc object @@ -252,20 +281,12 @@ bool wifi_pos_is_app_registered(struct wlan_objmgr_psoc *psoc); uint32_t wifi_pos_get_app_pid(struct wlan_objmgr_psoc *psoc); /** - * wifi_pos_lock: acquires wifi_pos lock + * wifi_pos_is_app_registered: indicates if oem app is registered. * @psoc: pointer to psoc object * - * Return: None + * Return: true if app is registered, false otherwise */ -void wifi_pos_lock(struct wlan_objmgr_psoc *psoc); - -/** - * wifi_pos_unlock: releases wifi_pos lock - * @psoc: pointer to psoc object - * - * Return: None - */ -void wifi_pos_unlock(struct wlan_objmgr_psoc *psoc); +bool wifi_pos_is_app_registered(struct wlan_objmgr_psoc *psoc); #endif /* _WIFI_POS_UTILS_H_ */ #endif /* WIFI_POS_CONVERGED */