diff options
author | Xin Li <delphij@google.com> | 2019-10-25 10:28:01 -0700 |
---|---|---|
committer | Xin Li <delphij@google.com> | 2019-10-25 10:28:01 -0700 |
commit | 2dd444c395c7cceaae8fc9b681cbec1af67ce23b (patch) | |
tree | 09a382c89d58ac170687b86f24f3ebc3f80698b6 | |
parent | 180ce9e724d5a2097da24af214b2d4dc12a34f51 (diff) | |
parent | e66c67c549e9f29fafbe4d8e9098fc59cbd63ae8 (diff) | |
download | wlan-2dd444c395c7cceaae8fc9b681cbec1af67ce23b.tar.gz |
Merge Coral/Flame into AOSP master
Bug: 141248619
Change-Id: I9976a12048a8be199082a2200540f4a899fd3e4f
Merged-In: I911b1a53ec46f39cc7597c2a31f59669db4f0699
-rw-r--r-- | qcwcn/wifi_hal/Android.mk | 26 | ||||
-rw-r--r-- | qcwcn/wifi_hal/common.cpp | 2 | ||||
-rw-r--r-- | qcwcn/wifi_hal/common.h | 10 | ||||
-rw-r--r-- | qcwcn/wifi_hal/list.cpp | 76 | ||||
-rw-r--r-- | qcwcn/wifi_hal/list.h | 72 | ||||
-rw-r--r-- | qcwcn/wifi_hal/wifi_hal.cpp | 586 | ||||
-rw-r--r-- | qcwcn/wifi_hal/wifi_hal_ctrl/wifi_hal_ctrl.c | 234 | ||||
-rw-r--r-- | qcwcn/wifi_hal/wifi_hal_ctrl/wifi_hal_ctrl.h | 225 | ||||
-rwxr-xr-x | qcwcn/wifi_hal/wifihal_internal.h | 21 | ||||
-rw-r--r-- | qcwcn/wifi_hal/wifilogger_diag.cpp | 121 | ||||
-rw-r--r-- | qcwcn/wifi_hal/wifilogger_diag.h | 5 |
11 files changed, 1343 insertions, 35 deletions
diff --git a/qcwcn/wifi_hal/Android.mk b/qcwcn/wifi_hal/Android.mk index 857f156..0b76f66 100644 --- a/qcwcn/wifi_hal/Android.mk +++ b/qcwcn/wifi_hal/Android.mk @@ -14,6 +14,25 @@ LOCAL_PATH := $(call my-dir) +# Control APIs used by clients to communicate with HAL. +# ============================================================ +include $(CLEAR_VARS) + +LOCAL_CFLAGS := -Wno-unused-parameter +LOCAL_CFLAGS += -Wall -Werror +LOCAL_MODULE := libwifi-hal-ctrl +LOCAL_VENDOR_MODULE := true +LOCAL_C_INCLUDES := $(LOCAL_PATH)/wifi_hal_ctrl +LOCAL_SRC_FILES := wifi_hal_ctrl/wifi_hal_ctrl.c +LOCAL_HEADER_LIBRARIES := libcutils_headers +include $(BUILD_SHARED_LIBRARY) + +include $(CLEAR_VARS) +LOCAL_MODULE := libwifi-hal-ctrl_headers +LOCAL_EXPORT_C_INCLUDE_DIRS := $(LOCAL_PATH)/wifi_hal_ctrl +LOCAL_HEADER_LIBRARIES := libcutils_headers +include $(BUILD_HEADER_LIBRARY) + # Make the HAL library # ============================================================ include $(CLEAR_VARS) @@ -41,6 +60,7 @@ LOCAL_C_INCLUDES += \ $(TARGET_OUT_HEADERS)/cld80211-lib LOCAL_SRC_FILES := \ + list.cpp \ wifi_hal.cpp \ common.cpp \ cpp_bindings.cpp \ @@ -76,7 +96,7 @@ LOCAL_SHARED_LIBRARIES += libnl_2 LOCAL_C_INCLUDES += external/libnl-headers endif -LOCAL_HEADER_LIBRARIES := libcutils_headers libutils_headers +LOCAL_HEADER_LIBRARIES := libcutils_headers libutils_headers libwifi-hal-ctrl_headers include $(BUILD_STATIC_LIBRARY) @@ -106,6 +126,7 @@ LOCAL_C_INCLUDES += \ $(TARGET_OUT_HEADERS)/cld80211-lib LOCAL_SRC_FILES := \ + list.cpp \ wifi_hal.cpp \ common.cpp \ cpp_bindings.cpp \ @@ -134,6 +155,7 @@ LOCAL_VENDOR_MODULE := true LOCAL_CLANG := true LOCAL_SHARED_LIBRARIES += libnetutils liblog LOCAL_SHARED_LIBRARIES += libdl libwpa_client libcld80211 +LOCAL_SHARED_LIBRARIES += libwifi-hal-ctrl ifneq ($(wildcard external/libnl),) LOCAL_SHARED_LIBRARIES += libnl @@ -143,5 +165,5 @@ LOCAL_SHARED_LIBRARIES += libnl_2 LOCAL_C_INCLUDES += external/libnl-headers endif -LOCAL_HEADER_LIBRARIES := libcutils_headers libutils_headers +LOCAL_HEADER_LIBRARIES := libcutils_headers libutils_headers libwifi-hal-ctrl_headers include $(BUILD_SHARED_LIBRARY) diff --git a/qcwcn/wifi_hal/common.cpp b/qcwcn/wifi_hal/common.cpp index c54577c..3d72e76 100644 --- a/qcwcn/wifi_hal/common.cpp +++ b/qcwcn/wifi_hal/common.cpp @@ -420,6 +420,8 @@ wifi_error mapKernelErrortoWifiHalError(int kern_err) return WIFI_ERROR_OUT_OF_MEMORY; case -EBUSY: return WIFI_ERROR_BUSY; + case -ENOBUFS: + return WIFI_ERROR_TOO_MANY_REQUESTS; } return WIFI_ERROR_UNKNOWN; } diff --git a/qcwcn/wifi_hal/common.h b/qcwcn/wifi_hal/common.h index 759ae01..0ed5a81 100644 --- a/qcwcn/wifi_hal/common.h +++ b/qcwcn/wifi_hal/common.h @@ -27,6 +27,7 @@ #include <fcntl.h> #include <inttypes.h> #include <sys/socket.h> +#include <sys/un.h> #include <netlink/genl/genl.h> #include <netlink/genl/family.h> #include <netlink/genl/ctrl.h> @@ -53,6 +54,8 @@ #define DEFAULT_EVENT_CB_SIZE (64) #define NUM_RING_BUFS 5 +#define WIFI_HAL_CTRL_IFACE "/dev/socket/wifihal/wifihal_ctrlsock" + #define MAC_ADDR_ARRAY(a) (a)[0], (a)[1], (a)[2], (a)[3], (a)[4], (a)[5] #define MAC_ADDR_STR "%02x:%02x:%02x:%02x:%02x:%02x" #define BIT(x) (1 << (x)) @@ -105,11 +108,18 @@ struct gscan_event_handlers_s; struct rssi_monitor_event_handler_s; struct cld80211_ctx; +struct ctrl_sock { + int s; + struct sockaddr_un local; +}; + typedef struct hal_info_s { struct nl_sock *cmd_sock; // command socket object struct nl_sock *event_sock; // event socket object struct nl_sock *user_sock; // user socket object + struct ctrl_sock wifihal_ctrl_sock; // ctrl sock object + struct list_head monitor_sockets; // list of monitor sockets int nl80211_family_id; // family id for 80211 driver bool in_event_loop; // Indicates that event loop is active diff --git a/qcwcn/wifi_hal/list.cpp b/qcwcn/wifi_hal/list.cpp new file mode 100644 index 0000000..966da2e --- /dev/null +++ b/qcwcn/wifi_hal/list.cpp @@ -0,0 +1,76 @@ +/* Copyright (c) 2019 The Linux Foundation. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * * Neither the name of The Linux Foundation nor the names of its + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS + * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR + * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, + * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE + * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN + * IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#include <stdlib.h> +#include "list.h" + +void INITIALISE_LIST(struct list_head *list) +{ + list->next = list; + list->prev = list; +} + +void list_add(struct list_head *latest, + struct list_head *prev, struct list_head *next) +{ + next->prev = latest; + latest->next = next; + latest->prev = prev; + prev->next = latest; +} + +void add_to_list(struct list_head *latest, struct list_head *head) +{ + list_add(latest, head, head->next); +} + +void list_add_tail(struct list_head *latest, struct list_head *head) +{ + list_add(latest, head->prev, head); +} + +void list_del(struct list_head *prev, struct list_head *next) +{ + next->prev = prev; + prev->next = next; +} + +void del_from_list(struct list_head *record) +{ + list_del(record->prev, record->next); + record->next = NULL; + record->prev = NULL; +} + +void replace_in_list(struct list_head *old, struct list_head *latest) +{ + latest->next = old->next; + latest->next->prev = latest; + latest->prev = old->prev; + latest->prev->next = latest; +} diff --git a/qcwcn/wifi_hal/list.h b/qcwcn/wifi_hal/list.h new file mode 100644 index 0000000..90d344c --- /dev/null +++ b/qcwcn/wifi_hal/list.h @@ -0,0 +1,72 @@ +/* Copyright (c) 2019 The Linux Foundation. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * * Neither the name of The Linux Foundation nor the names of its + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS + * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR + * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, + * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE + * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN + * IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#ifndef _WIFIHAL_LIST_H_ +#define _WIFIHAL_LIST_H_ + +struct list_head { + struct list_head *next, *prev; +}; + +void INITIALISE_LIST(struct list_head *list); +void list_add(struct list_head *latest, struct list_head *prev, + struct list_head *next); +void add_to_list(struct list_head *latest, struct list_head *head); +void list_add_tail(struct list_head *latest, struct list_head *head); +void list_del(struct list_head *prev, struct list_head *next); +void del_from_list(struct list_head *record); +void replace_in_list(struct list_head *old, struct list_head *latest); + +#define list_for_each(ref, head) \ + for (ref = (head)->next; ref->next, ref != (head); ref = ref->next) + +#define offset_of(type, member) ((char *)&((type *)0)->member) + +#define container_of(ptr, type, member) ({ \ + const typeof(((type *)0)->member) *__mptr = (ptr); \ + (type *)((char *)__mptr - offset_of(type, member)); }) + +#define list_entry(ptr, type, member) \ + container_of(ptr, type, member) + +#define list_for_each_entry(ref, head, member) \ + for (ref = list_entry((head)->next, typeof(*ref), member); \ + ref->member.next, &ref->member != (head); \ + ref = list_entry(ref->member.next, typeof(*ref), member)) + +#define list_for_each_entry_safe(pos, n, head, member) \ + for (pos = list_entry((head)->next, typeof(*pos), member), \ + n = list_entry(pos->member.next, typeof(*pos), member); \ + &pos->member != (head); \ + pos = n, n = list_entry(n->member.next, typeof(*n), member)) + +#define list_for_each_safe(pos, n, head) \ + for (pos = (head)->next, n = pos->next; pos != (head); \ + pos = n, n = pos->next) + +#endif diff --git a/qcwcn/wifi_hal/wifi_hal.cpp b/qcwcn/wifi_hal/wifi_hal.cpp index 198ab01..cb82885 100644 --- a/qcwcn/wifi_hal/wifi_hal.cpp +++ b/qcwcn/wifi_hal/wifi_hal.cpp @@ -41,6 +41,7 @@ #include <cld80211_lib.h> #include <sys/types.h> +#include "list.h" #include <unistd.h> #include "sync.h" @@ -48,6 +49,7 @@ #define LOG_TAG "WifiHAL" #include "wifi_hal.h" +#include "wifi_hal_ctrl.h" #include "common.h" #include "cpp_bindings.h" #include "ifaceeventhandler.h" @@ -73,6 +75,19 @@ #define POLL_DRIVER_DURATION_US (100000) #define POLL_DRIVER_MAX_TIME_MS (10000) +static int attach_monitor_sock(wifi_handle handle, wifihal_ctrl_req_t *ctrl_msg); + +static int dettach_monitor_sock(wifi_handle handle, wifihal_ctrl_req_t *ctrl_msg); + +static int register_monitor_sock(wifi_handle handle, wifihal_ctrl_req_t *ctrl_msg, int attach); + +static int send_nl_data(wifi_handle handle, wifihal_ctrl_req_t *ctrl_msg); + +static int internal_pollin_handler(wifi_handle handle, struct nl_sock *sock); + +static void internal_event_handler_app(wifi_handle handle, int events, + struct ctrl_sock *sock); + static void internal_event_handler(wifi_handle handle, int events, struct nl_sock *sock); static int internal_valid_message_handler(nl_msg *msg, void *arg); @@ -135,6 +150,105 @@ static nl_sock * wifi_create_nl_socket(int port, int protocol) return sock; } +void wifi_create_ctrl_socket(hal_info *info) +{ +#ifdef ANDROID + struct group *grp_wifi; + gid_t gid_wifi; + struct passwd *pwd_system; + uid_t uid_system; +#endif + + int flags; + + info->wifihal_ctrl_sock.s = socket(PF_UNIX, SOCK_DGRAM, 0); + + if (info->wifihal_ctrl_sock.s < 0) { + ALOGE("socket(PF_UNIX): %s", strerror(errno)); + return; + } + memset(&info->wifihal_ctrl_sock.local, 0, sizeof(info->wifihal_ctrl_sock.local)); + + info->wifihal_ctrl_sock.local.sun_family = AF_UNIX; + + snprintf(info->wifihal_ctrl_sock.local.sun_path, + sizeof(info->wifihal_ctrl_sock.local.sun_path), "%s", WIFI_HAL_CTRL_IFACE); + + if (bind(info->wifihal_ctrl_sock.s, (struct sockaddr *) &info->wifihal_ctrl_sock.local, + sizeof(info->wifihal_ctrl_sock.local)) < 0) { + ALOGD("ctrl_iface bind(PF_UNIX) failed: %s", + strerror(errno)); + if (connect(info->wifihal_ctrl_sock.s, (struct sockaddr *) &info->wifihal_ctrl_sock.local, + sizeof(info->wifihal_ctrl_sock.local)) < 0) { + ALOGD("ctrl_iface exists, but does not" + " allow connections - assuming it was left" + "over from forced program termination"); + if (unlink(info->wifihal_ctrl_sock.local.sun_path) < 0) { + ALOGE("Could not unlink existing ctrl_iface socket '%s': %s", + info->wifihal_ctrl_sock.local.sun_path, strerror(errno)); + goto out; + + } + if (bind(info->wifihal_ctrl_sock.s , + (struct sockaddr *) &info->wifihal_ctrl_sock.local, + sizeof(info->wifihal_ctrl_sock.local)) < 0) { + ALOGE("wifihal-ctrl-iface-init: bind(PF_UNIX): %s", + strerror(errno)); + goto out; + } + ALOGD("Successfully replaced leftover " + "ctrl_iface socket '%s'", info->wifihal_ctrl_sock.local.sun_path); + } else { + ALOGI("ctrl_iface exists and seems to " + "be in use - cannot override it"); + ALOGI("Delete '%s' manually if it is " + "not used anymore", info->wifihal_ctrl_sock.local.sun_path); + goto out; + } + } + + /* + * Make socket non-blocking so that we don't hang forever if + * target dies unexpectedly. + */ + +#ifdef ANDROID + if (chmod(info->wifihal_ctrl_sock.local.sun_path, S_IRWXU | S_IRWXG) < 0) + { + ALOGE("Failed to give permissions: %s", strerror(errno)); + } + + /* Set group even if we do not have privileges to change owner */ + grp_wifi = getgrnam("wifi"); + gid_wifi = grp_wifi ? grp_wifi->gr_gid : 0; + pwd_system = getpwnam("system"); + uid_system = pwd_system ? pwd_system->pw_uid : 0; + if (!gid_wifi || !uid_system) { + ALOGE("Failed to get grp ids"); + unlink(info->wifihal_ctrl_sock.local.sun_path); + goto out; + } + chown(info->wifihal_ctrl_sock.local.sun_path, -1, gid_wifi); + chown(info->wifihal_ctrl_sock.local.sun_path, uid_system, gid_wifi); +#endif + + flags = fcntl(info->wifihal_ctrl_sock.s, F_GETFL); + if (flags >= 0) { + flags |= O_NONBLOCK; + if (fcntl(info->wifihal_ctrl_sock.s, F_SETFL, flags) < 0) { + ALOGI("fcntl(ctrl, O_NONBLOCK): %s", + strerror(errno)); + /* Not fatal, continue on.*/ + } + } + return; + +out: + close(info->wifihal_ctrl_sock.s); + info->wifihal_ctrl_sock.s = 0; + return; +} + int ack_handler(struct nl_msg *msg, void *arg) { int *err = (int *)arg; @@ -471,6 +585,7 @@ static void cld80211lib_cleanup(hal_info *info) cld80211_remove_mcast_group(info->cldctx, "per_pkt_stats"); cld80211_remove_mcast_group(info->cldctx, "diag_events"); cld80211_remove_mcast_group(info->cldctx, "fatal_events"); + cld80211_remove_mcast_group(info->cldctx, "oem_msgs"); exit_cld80211_recv(info->cldctx); cld80211_deinit(info->cldctx); info->cldctx = NULL; @@ -584,6 +699,13 @@ wifi_error wifi_initialize(wifi_handle *handle) wifi_add_membership(*handle, "regulatory"); wifi_add_membership(*handle, "vendor"); + info->wifihal_ctrl_sock.s = 0; + + wifi_create_ctrl_socket(info); + + //! Initailise the monitoring clients list + INITIALISE_LIST(&info->monitor_sockets); + info->cldctx = cld80211_init(); if (info->cldctx != NULL) { info->user_sock = info->cldctx->sock; @@ -618,6 +740,15 @@ wifi_error wifi_initialize(wifi_handle *handle) ALOGE("Failed to add mcast group fatal_events :%d", status); goto cld80211_cleanup; } + + if(info->wifihal_ctrl_sock.s > 0) + { + status = cld80211_add_mcast_group(info->cldctx, "oem_msgs"); + if (status) { + ALOGE("Failed to add mcast group oem_msgs :%d", status); + goto cld80211_cleanup; + } + } } else { ret = wifi_init_user_sock(info); if (ret != WIFI_SUCCESS) { @@ -687,7 +818,7 @@ wifi_error wifi_initialize(wifi_handle *handle) } ALOGV("%s: hardware version type %d", __func__, info->pkt_log_ver); } else { - ALOGE("Failed to get supported logger feature set: %d", ret); + ALOGE("Failed to get firmware version: %d", ret); } ret = get_firmware_bus_max_size_supported(iface_handle); @@ -826,6 +957,7 @@ static void internal_cleaned_up_handler(wifi_handle handle) { hal_info *info = getHalInfo(handle); wifi_cleaned_up_handler cleaned_up_handler = info->cleaned_up_handler; + wifihal_mon_sock_t *reg, *tmp; if (info->cmd_sock != 0) { nl_socket_free(info->cmd_sock); @@ -834,6 +966,19 @@ static void internal_cleaned_up_handler(wifi_handle handle) info->event_sock = NULL; } + if (info->wifihal_ctrl_sock.s != 0) { + close(info->wifihal_ctrl_sock.s); + unlink(info->wifihal_ctrl_sock.local.sun_path); + info->wifihal_ctrl_sock.s = 0; + } + + list_for_each_entry_safe(reg, tmp, &info->monitor_sockets, list) { + del_from_list(®->list); + if(reg) { + free(reg); + } + } + if (info->interfaces) { for (int i = 0; i < info->num_interfaces; i++) free(info->interfaces[i]); @@ -901,6 +1046,352 @@ void wifi_cleanup(wifi_handle handle, wifi_cleaned_up_handler handler) ALOGI("Sent msg on exit sock to unblock poll()"); } + + +static int validate_cld80211_msg(nlmsghdr *nlh, int family, int cmd) +{ + //! Enhance this API + struct genlmsghdr *hdr; + hdr = (genlmsghdr *)nlmsg_data(nlh); + + if(hdr->cmd == WLAN_NL_MSG_OEM) + { + ALOGV("%s: FAMILY ID : %d ,NL CMD : %d received", __FUNCTION__, + nlh->nlmsg_type, hdr->cmd); + + //! Update pid with the wifihal pid + nlh->nlmsg_pid = getpid(); + return 0; + } + else + { + ALOGE("%s: NL CMD : %d received is not allowed", __FUNCTION__, hdr->cmd); + return -1; + } +} + + +static int validate_genl_msg(nlmsghdr *nlh, int family, int cmd) +{ + //! Enhance this API + struct genlmsghdr *hdr; + hdr = (genlmsghdr *)nlmsg_data(nlh); + + if(hdr->cmd == NL80211_CMD_FRAME || + hdr->cmd == NL80211_CMD_REGISTER_ACTION) + { + ALOGV("%s: FAMILY ID : %d ,NL CMD : %d received", __FUNCTION__, + nlh->nlmsg_type, hdr->cmd); + return 0; + } + else + { + ALOGE("%s: NL CMD : %d received is not allowed", __FUNCTION__, hdr->cmd); + return -1; + } +} + +static int send_nl_data(wifi_handle handle, wifihal_ctrl_req_t *ctrl_msg) +{ + hal_info *info = getHalInfo(handle); + struct nl_msg *msg = NULL; + int retval = -1; + + //! attach monitor socket if it was not it the list + if(ctrl_msg->monsock_len) + { + retval = attach_monitor_sock(handle, ctrl_msg); + if(retval) + goto nl_out; + } + + msg = nlmsg_alloc(); + if (!msg) + { + ALOGE("%s: Memory allocation failed \n", __FUNCTION__); + goto nl_out; + } + + memcpy((char *)msg->nm_nlh, (char *)ctrl_msg->data, ctrl_msg->data_len); + + if(ctrl_msg->family_name == GENERIC_NL_FAMILY) + { + //! Before sending the received gennlmsg to kernel, + //! better to have checks for allowed commands + retval = validate_genl_msg(msg->nm_nlh, ctrl_msg->family_name, ctrl_msg->cmd_id); + if (retval < 0) + goto nl_out; + + retval = nl_send_auto_complete(info->event_sock, msg); /* send message */ + if (retval < 0) + { + ALOGE("%s: nl_send_auto_complete - failed : %d \n", __FUNCTION__, retval); + goto nl_out; + } + + retval = internal_pollin_handler(handle, info->event_sock); + } + else if (ctrl_msg->family_name == CLD80211_FAMILY) + { + if (info->cldctx != NULL) + { + //! Before sending the received cld80211 msg to kernel, + //! better to have checks for allowed commands + retval = validate_cld80211_msg(msg->nm_nlh, ctrl_msg->family_name, ctrl_msg->cmd_id); + if (retval < 0) + goto nl_out; + + retval = cld80211_send_msg(info->cldctx, msg); + if (retval != 0) + { + ALOGE("%s: send cld80211 message - failed\n", __FUNCTION__); + goto nl_out; + } + ALOGD("%s: sent cld80211 message for pid %d\n", __FUNCTION__, getpid()); + } + else + { + ALOGE("%s: cld80211 ctx not present \n", __FUNCTION__); + } + } + else + { + ALOGE("%s: Unknown family name : %d \n", __FUNCTION__, ctrl_msg->family_name); + retval = -1; + } +nl_out: + if (msg) + { + nlmsg_free(msg); + } + return retval; +} + +static int register_monitor_sock(wifi_handle handle, wifihal_ctrl_req_t *ctrl_msg, int attach) +{ + hal_info *info = getHalInfo(handle); + + wifihal_mon_sock_t *reg, *nreg; + char *match = NULL; + unsigned int match_len = 0; + unsigned int type; + + //! For Register Action frames, compare the match length and match buffer. + //! For other registrations such as oem messages, + //! diag messages check for respective commands + + if((ctrl_msg->family_name == GENERIC_NL_FAMILY) && + (ctrl_msg->cmd_id == NL80211_CMD_REGISTER_ACTION)) + { + struct genlmsghdr *genlh; + struct nlmsghdr *nlh = (struct nlmsghdr *)ctrl_msg->data; + genlh = (struct genlmsghdr *)nlmsg_data(nlh); + struct nlattr *nlattrs[NL80211_ATTR_MAX + 1]; + + nla_parse(nlattrs, NL80211_ATTR_MAX, genlmsg_attrdata(genlh, 0), + genlmsg_attrlen(genlh, 0), NULL); + + if (!nlattrs[NL80211_ATTR_FRAME_TYPE]) + { + ALOGD("No Valid frame type"); + } + else + { + type = nla_get_u16(nlattrs[NL80211_ATTR_FRAME_TYPE]); + } + if (!nlattrs[NL80211_ATTR_FRAME_MATCH]) + { + ALOGE("No Frame Match"); + return -1; + } + else + { + match_len = nla_len(nlattrs[NL80211_ATTR_FRAME_MATCH]); + match = (char *)nla_data(nlattrs[NL80211_ATTR_FRAME_MATCH]); + + list_for_each_entry(reg, &info->monitor_sockets, list) { + + if(reg == NULL) + break; + + int mlen = min(match_len, reg->match_len); + + if (reg->match_len == 0) + continue; + + if (memcmp(reg->match, match, mlen) == 0) { + + if((ctrl_msg->monsock_len == reg->monsock_len) && + (memcmp((char *)®->monsock, (char *)&ctrl_msg->monsock, ctrl_msg->monsock_len) == 0)) + { + if(attach) + { + ALOGE(" %s :Action frame already registered for this client ", __FUNCTION__); + return -2; + } + else + { + del_from_list(®->list); + free(reg); + return 0; + } + } + else + { + //! when action frame registered for other client, + //! you can't attach or dettach for new client + ALOGE(" %s :Action frame registered for other client ", __FUNCTION__); + return -2; + } + } + } + } + } + else + { + list_for_each_entry(reg, &info->monitor_sockets, list) { + + //! Checking for monitor sock in the list : + + //! For attach request : + //! if sock is not present, then it is a new entry , so add to list. + //! if sock is present, and cmd_id does not match, add another entry to list. + //! if sock is present, and cmd_id matches, return 0. + + //! For dettach req : + //! if sock is not present, return error -2. + //! if sock is present, and cmd_id does not match, return error -2. + //! if sock is present, and cmd_id matches, delete entry and return 0. + if(reg == NULL) + break; + + if (ctrl_msg->monsock_len != reg->monsock_len) + continue; + + if (memcmp((char *)®->monsock, (char *)&ctrl_msg->monsock, ctrl_msg->monsock_len) == 0) { + + if((reg->family_name == ctrl_msg->family_name) && (reg->cmd_id == ctrl_msg->cmd_id)) + { + if(!attach) + { + del_from_list(®->list); + free(reg); + } + return 0; + } + } + } + } + + if(attach) + { + nreg = (wifihal_mon_sock_t *)malloc(sizeof(*reg) + match_len); + if (!nreg) + return -1; + + memset((char *)nreg, 0, sizeof(*reg) + match_len); + nreg->family_name = ctrl_msg->family_name; + nreg->cmd_id = ctrl_msg->cmd_id; + nreg->monsock_len = ctrl_msg->monsock_len; + memcpy((char *)&nreg->monsock, (char *)&ctrl_msg->monsock, ctrl_msg->monsock_len); + + if(match_len && match) + { + nreg->match_len = match_len; + memcpy(nreg->match, match, match_len); + } + add_to_list(&nreg->list, &info->monitor_sockets); + } + else + { + //! Not attached, so cant be dettached + ALOGE("%s: Dettaching the unregistered socket \n", __FUNCTION__); + return -2; + } + + return 0; +} + +static int attach_monitor_sock(wifi_handle handle, wifihal_ctrl_req_t *ctrl_msg) +{ + return register_monitor_sock(handle, ctrl_msg, 1); +} + +static int dettach_monitor_sock(wifi_handle handle, wifihal_ctrl_req_t *ctrl_msg) +{ + return register_monitor_sock(handle, ctrl_msg, 0); +} + +static int internal_pollin_handler_app(wifi_handle handle, struct ctrl_sock *sock) +{ + int retval = -1; + int res; + struct sockaddr_un from; + socklen_t fromlen = sizeof(from); + wifihal_ctrl_req_t *ctrl_msg; + wifihal_ctrl_sync_rsp_t ctrl_reply; + + ctrl_msg = (wifihal_ctrl_req_t *)malloc(DEFAULT_PAGE_SIZE); + if(ctrl_msg == NULL) + { + ALOGE ("Memory allocation failure"); + return -1; + } + + memset((char *)ctrl_msg, 0, DEFAULT_PAGE_SIZE); + + res = recvfrom(sock->s, (char *)ctrl_msg, DEFAULT_PAGE_SIZE, 0, + (struct sockaddr *)&from, &fromlen); + if (res < 0) { + ALOGE("recvfrom(ctrl_iface): %s", + strerror(errno)); + if(ctrl_msg) + free(ctrl_msg); + + return 0; + } + switch(ctrl_msg->ctrl_cmd) + { + case WIFIHAL_CTRL_MONITOR_ATTACH: + retval = attach_monitor_sock(handle, ctrl_msg); + break; + case WIFIHAL_CTRL_MONITOR_DETTACH: + retval = dettach_monitor_sock(handle, ctrl_msg); + break; + case WIFIHAL_CTRL_SEND_NL_DATA: + retval = send_nl_data(handle, ctrl_msg); + break; + default: + break; + } + + ctrl_reply.ctrl_cmd = ctrl_msg->ctrl_cmd; + ctrl_reply.family_name = ctrl_msg->family_name; + ctrl_reply.cmd_id = ctrl_msg->cmd_id; + ctrl_reply.status = retval; + + if(ctrl_msg) + free(ctrl_msg); + + if (sendto(sock->s, (char *)&ctrl_reply, sizeof(ctrl_reply), 0, (struct sockaddr *)&from, + fromlen) < 0) { + int _errno = errno; + ALOGE("socket send failed : %d",_errno); + + if (_errno == ENOBUFS || _errno == EAGAIN) { + /* + * The socket send buffer could be full. This + * may happen if client programs are not + * receiving their pending messages. Close and + * reopen the socket as a workaround to avoid + * getting stuck being unable to send any new + * responses. + */ + } + } + return res; +} + static int internal_pollin_handler(wifi_handle handle, struct nl_sock *sock) { struct nl_cb *cb = nl_socket_get_cb(sock); @@ -912,6 +1403,22 @@ static int internal_pollin_handler(wifi_handle handle, struct nl_sock *sock) return res; } +static void internal_event_handler_app(wifi_handle handle, int events, + struct ctrl_sock *sock) +{ + if (events & POLLERR) { + ALOGE("Error reading from wifi_hal ctrl socket"); + internal_pollin_handler_app(handle, sock); + } else if (events & POLLHUP) { + ALOGE("Remote side hung up"); + } else if (events & POLLIN) { + //ALOGI("Found some events!!!"); + internal_pollin_handler_app(handle, sock); + } else { + ALOGE("Unknown event - %0x", events); + } +} + static void internal_event_handler(wifi_handle handle, int events, struct nl_sock *sock) { @@ -938,8 +1445,8 @@ void wifi_event_loop(wifi_handle handle) info->in_event_loop = true; } - pollfd pfd[3]; - memset(&pfd, 0, 3*sizeof(pfd[0])); + pollfd pfd[4]; + memset(&pfd, 0, 4*sizeof(pfd[0])); pfd[0].fd = nl_socket_get_fd(info->event_sock); pfd[0].events = POLLIN; @@ -950,14 +1457,19 @@ void wifi_event_loop(wifi_handle handle) pfd[2].fd = info->exit_sockets[1]; pfd[2].events = POLLIN; + if(info->wifihal_ctrl_sock.s > 0) { + pfd[3].fd = info->wifihal_ctrl_sock.s ; + pfd[3].events = POLLIN; + } /* TODO: Add support for timeouts */ do { pfd[0].revents = 0; pfd[1].revents = 0; pfd[2].revents = 0; + pfd[3].revents = 0; //ALOGI("Polling sockets"); - int result = poll(pfd, 3, -1); + int result = poll(pfd, 4, -1); if (result < 0) { ALOGE("Error polling socket"); } else { @@ -967,6 +1479,9 @@ void wifi_event_loop(wifi_handle handle) if (pfd[1].revents & (POLLIN | POLLHUP | POLLERR)) { internal_event_handler(handle, pfd[1].revents, info->user_sock); } + if ((info->wifihal_ctrl_sock.s > 0) && (pfd[3].revents & (POLLIN | POLLHUP | POLLERR))) { + internal_event_handler_app(handle, pfd[3].revents, &info->wifihal_ctrl_sock); + } } rb_timerhandler(info); } while (!info->clean_up); @@ -1008,7 +1523,68 @@ static int internal_valid_message_handler(nl_msg *msg, void *arg) ALOGI("event received %s, vendor_id = 0x%0x, subcmd = 0x%0x", event.get_cmdString(), vendor_id, subcmd); } - } else { + } + else if((info->wifihal_ctrl_sock.s > 0) && (cmd == NL80211_CMD_FRAME)) + { + struct genlmsghdr *genlh; + struct nlmsghdr *nlh = nlmsg_hdr(msg); + genlh = (struct genlmsghdr *)nlmsg_data(nlh); + struct nlattr *nlattrs[NL80211_ATTR_MAX + 1]; + + wifihal_ctrl_event_t *ctrl_evt; + char *buff; + wifihal_mon_sock_t *reg; + + nla_parse(nlattrs, NL80211_ATTR_MAX, genlmsg_attrdata(genlh, 0), + genlmsg_attrlen(genlh, 0), NULL); + + if (!nlattrs[NL80211_ATTR_FRAME]) + { + ALOGD("No Frame body"); + return WIFI_SUCCESS; + } + + ctrl_evt = (wifihal_ctrl_event_t *)malloc(DEFAULT_PAGE_SIZE); + if(ctrl_evt == NULL) + { + ALOGE("Memory allocation failure"); + return -1; + } + memset((char *)ctrl_evt, 0, DEFAULT_PAGE_SIZE); + ctrl_evt->family_name = GENERIC_NL_FAMILY; + ctrl_evt->cmd_id = cmd; + ctrl_evt->data_len = msg->nm_nlh->nlmsg_len; + memcpy(ctrl_evt->data, (char *)msg->nm_nlh, ctrl_evt->data_len); + + + buff = (char *)nla_data(nlattrs[NL80211_ATTR_FRAME]) + 24; //! Size of Wlan80211FrameHeader + + list_for_each_entry(reg, &info->monitor_sockets, list) { + + if(reg == NULL) + break; + + if (memcmp(reg->match, buff, reg->match_len)) + continue; + + /* found match! */ + /* Indicate the received Action frame to respective client */ + if (sendto(info->wifihal_ctrl_sock.s, (char *)ctrl_evt, + sizeof(*ctrl_evt) + ctrl_evt->data_len, + 0, (struct sockaddr *)®->monsock, reg->monsock_len) < 0) + { + int _errno = errno; + ALOGE("socket send failed : %d",_errno); + + if (_errno == ENOBUFS || _errno == EAGAIN) { + } + } + + } + free(ctrl_evt); + } + + else { ALOGV("event received %s", event.get_cmdString()); } diff --git a/qcwcn/wifi_hal/wifi_hal_ctrl/wifi_hal_ctrl.c b/qcwcn/wifi_hal/wifi_hal_ctrl/wifi_hal_ctrl.c new file mode 100644 index 0000000..61834fc --- /dev/null +++ b/qcwcn/wifi_hal/wifi_hal_ctrl/wifi_hal_ctrl.c @@ -0,0 +1,234 @@ +/* + * Copyright (c) 2019 The Linux Foundation. All rights reserved. + * + * wpa_supplicant/hostapd control interface library + * Copyright (c) 2004-2006, Jouni Malinen <j@w1.fi> + * + * This software may be distributed under the terms of the BSD license. + * redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * 3. Neither the name(s) of the above-listed copyright holder(s) nor the + * names of its contributors may be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#include "wifi_hal_ctrl.h" + +struct wifihal_ctrl * wifihal_ctrl_open2(const char *ctrl_path, + const char *cli_path) +{ + struct wifihal_ctrl *ctrl; + static int counter = 0; + int retval; + size_t res; + int tries = 0; + int flags; +#ifdef ANDROID + struct group *grp_wifi; + gid_t gid_wifi; + struct passwd *pwd_system; + uid_t uid_system; +#endif + + if (ctrl_path == NULL) + return NULL; + + ctrl = malloc(sizeof(*ctrl)); + if (ctrl == NULL) { + return NULL; + } + + memset(ctrl, 0, sizeof(*ctrl)); + ctrl->s = socket(PF_UNIX, SOCK_DGRAM, 0); + if (ctrl->s < 0) { + free(ctrl); + return NULL; + } + + ctrl->local.sun_family = AF_UNIX; + +try_again: + if (cli_path && cli_path[0] == '/') { + res = strlcpy(ctrl->local.sun_path, cli_path, + sizeof(ctrl->local.sun_path)); + + if (res >= sizeof(ctrl->local.sun_path)) { + close(ctrl->s); + free(ctrl); + return NULL; + } + + } else { + counter++; + retval = snprintf(ctrl->local.sun_path, + sizeof(ctrl->local.sun_path), + CONFIG_CTRL_IFACE_CLIENT_DIR "/" + CONFIG_CTRL_IFACE_CLIENT_PREFIX "%d-%d", + (int) getpid(), counter); + } + tries++; + if (bind(ctrl->s, (struct sockaddr *) &ctrl->local, + sizeof(ctrl->local)) < 0) { + if (errno == EADDRINUSE && tries < 2) { + /* + * getpid() returns unique identifier for this instance + * of wifihal_ctrl, so the existing socket file must have + * been left by unclean termination of an earlier run. + * Remove the file and try again. + */ + unlink(ctrl->local.sun_path); + goto try_again; + } + close(ctrl->s); + free(ctrl); + return NULL; + } + +#ifdef ANDROID + chmod(ctrl->local.sun_path, S_IRWXU | S_IRWXG ); + + /* Set group even if we do not have privileges to change owner */ + grp_wifi = getgrnam("wifi"); + gid_wifi = grp_wifi ? grp_wifi->gr_gid : 0; + pwd_system = getpwnam("system"); + uid_system = pwd_system ? pwd_system->pw_uid : 0; + if (!gid_wifi || !uid_system) { + close(ctrl->s); + unlink(ctrl->local.sun_path); + free(ctrl); + return NULL; + } + chown(ctrl->local.sun_path, -1, gid_wifi); + chown(ctrl->local.sun_path, uid_system, gid_wifi); + + + if (*ctrl_path != '/') { + free(ctrl); + return NULL; + } +#endif /* ANDROID */ + + ctrl->dest.sun_family = AF_UNIX; + res = strlcpy(ctrl->dest.sun_path, ctrl_path, + sizeof(ctrl->dest.sun_path)); + if (res >= sizeof(ctrl->dest.sun_path)) { + close(ctrl->s); + free(ctrl); + return NULL; + } + if (connect(ctrl->s, (struct sockaddr *) &ctrl->dest, + sizeof(ctrl->dest)) < 0) { + close(ctrl->s); + unlink(ctrl->local.sun_path); + free(ctrl); + return NULL; + } + /* + * Make socket non-blocking so that we don't hang forever if + * target dies unexpectedly. + */ + flags = fcntl(ctrl->s, F_GETFL); + if (flags >= 0) { + flags |= O_NONBLOCK; + if (fcntl(ctrl->s, F_SETFL, flags) < 0) { + perror("fcntl(ctrl->s, O_NONBLOCK)"); + /* Not fatal, continue on.*/ + } + } + return ctrl; +} + +struct wifihal_ctrl * wifihal_ctrl_open(const char *ctrl_path) +{ + return wifihal_ctrl_open2(ctrl_path, NULL); +} + +void wifihal_ctrl_close(struct wifihal_ctrl *ctrl) +{ + if (ctrl == NULL) + return; + unlink(ctrl->local.sun_path); + if (ctrl->s >= 0) + close(ctrl->s); + free(ctrl); +} + +int wifihal_ctrl_request(struct wifihal_ctrl *ctrl, const char *cmd, size_t cmd_len, + char *reply, size_t *reply_len) +{ + struct timeval tv; + int counter = 0, res; + fd_set rfds; + const char *_cmd; + size_t _cmd_len; + char *cmd_buf = NULL; + + _cmd = cmd; + _cmd_len = cmd_len; + + errno = 0; +retry_send: + if (sendto(ctrl->s, _cmd, _cmd_len, 0, (struct sockaddr *)&ctrl->dest, sizeof(ctrl->dest)) < 0) { + if (errno == EAGAIN || errno == EBUSY || errno == EWOULDBLOCK) + { + /* + * Must be a non-blocking socket... Try for a bit + * longer before giving up. + */ + if(counter == 5) { + goto send_err; + } else { + counter++; + } + sleep(1); + goto retry_send; + } + send_err: + free(cmd_buf); + return -1; + } + free(cmd_buf); + + for (;;) { + tv.tv_sec = 10; + tv.tv_usec = 0; + FD_ZERO(&rfds); + FD_SET(ctrl->s, &rfds); + res = select(ctrl->s + 1, &rfds, NULL, NULL, &tv); + if (res < 0 && errno == EINTR) + continue; + if (res < 0) + return res; + if (FD_ISSET(ctrl->s, &rfds)) { + res = recv(ctrl->s, reply, *reply_len, 0); + if (res < 0) + return res; + *reply_len = res; + break; + } else { + return -2; + } + } + return 0; +} diff --git a/qcwcn/wifi_hal/wifi_hal_ctrl/wifi_hal_ctrl.h b/qcwcn/wifi_hal/wifi_hal_ctrl/wifi_hal_ctrl.h new file mode 100644 index 0000000..dbfba56 --- /dev/null +++ b/qcwcn/wifi_hal/wifi_hal_ctrl/wifi_hal_ctrl.h @@ -0,0 +1,225 @@ +/* + * Copyright (c) 2019 The Linux Foundation. All rights reserved. + * + * wpa_supplicant/hostapd control interface library + * Copyright (c) 2004-2006, Jouni Malinen <j@w1.fi> + * + * This software may be distributed under the terms of the BSD license. + * redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * 3. Neither the name(s) of the above-listed copyright holder(s) nor the + * names of its contributors may be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#ifndef WIFIHAL_CTRL_H +#define WIFIHAL_CTRL_H + +#include <sys/un.h> +#include <unistd.h> +#include <fcntl.h> + +#include "stdlib.h" + +#ifdef ANDROID +#include <dirent.h> +#include <grp.h> +#include <pwd.h> +#include <sys/stat.h> +#include <sys/types.h> +#include <cutils/sockets.h> +#endif /* ANDROID */ + +#ifdef __cplusplus +extern "C" { +#endif + +/** + * struct wifihal_ctrl - Internal structure for control interface library + * + * This structure is used by the clients to interface with WiFi Hal + * library to store internal data. Programs using the library should not touch + * this data directly. They can only use the pointer to the data structure as + * an identifier for the control interface connection and use this as one of + * the arguments for most of the control interface library functions. + */ + +struct wifihal_ctrl { + int s; + struct sockaddr_un local; + struct sockaddr_un dest; +}; + +#ifndef CONFIG_CTRL_IFACE_CLIENT_DIR +#define CONFIG_CTRL_IFACE_CLIENT_DIR "/dev/socket/wifihal" +#endif /* CONFIG_CTRL_IFACE_CLIENT_DIR */ +#ifndef CONFIG_CTRL_IFACE_CLIENT_PREFIX +#define CONFIG_CTRL_IFACE_CLIENT_PREFIX "wifihal_ctrl_cli_" +#endif /* CONFIG_CTRL_IFACE_CLIENT_PREFIX */ + +#define DEFAULT_PAGE_SIZE 4096 + +enum nl_family_type +{ + //! gen netlink family + GENERIC_NL_FAMILY = 1, + //! Cld80211 family + CLD80211_FAMILY +}; + + +enum wifihal_ctrl_cmd +{ + /** attach monitor sock */ + WIFIHAL_CTRL_MONITOR_ATTACH, + /** dettach monitor sock */ + WIFIHAL_CTRL_MONITOR_DETTACH, + /** Send data over Netlink Sock */ + WIFIHAL_CTRL_SEND_NL_DATA, +}; + +//! WIFIHAL Control Request +typedef struct wifihal_ctrl_req_s { + //! ctrl command + uint32_t ctrl_cmd; + //! Family name + uint32_t family_name; + //! command ID + uint32_t cmd_id; + //! monitor sock len + uint32_t monsock_len; + //! monitor sock + struct sockaddr_un monsock; + //! data buff length + uint32_t data_len; + //! reserved + uint32_t reserved[4]; + //! data + char data[0]; +}wifihal_ctrl_req_t; + + +//! WIFIHAL Sync Response +typedef struct wifihal_ctrl_sync_rsp_s { + //! ctrl command + uint32_t ctrl_cmd; + //! Family name + uint32_t family_name; + //! command ID + uint32_t cmd_id; + //! status for the request + int status; + //! reserved + uint32_t reserved[4]; +}wifihal_ctrl_sync_rsp_t; + +//! WIFIHAL Async Response +typedef struct wifihal_ctrl_event_s { + //! Family name + uint32_t family_name; + //! command ID + uint32_t cmd_id; + //! data buff length + uint32_t data_len; + //! reserved + uint32_t reserved; + //! data + char data[0]; +}wifihal_ctrl_event_t; + +/* WiFi Hal control interface access */ + +/** + * wifihal_ctrl_open - Open a control interface to WiFi-Hal + * @ctrl_path: Path for UNIX domain sockets; ignored if UDP sockets are used. + * Returns: Pointer to abstract control interface data or %NULL on failure + * + * This function is used to open a control interface to WiFi-Hal. + * ctrl_path is usually /var/run/wifihal. This path + * is configured in WiFi-Hal and other programs using the control + * interface need to use matching path configuration. + */ +struct wifihal_ctrl * wifihal_ctrl_open(const char *ctrl_path); + +/** + * wifihal_ctrl_open2 - Open a control interface to wifihal + * @ctrl_path: Path for UNIX domain sockets; ignored if UDP sockets are used. + * @cli_path: Path for client UNIX domain sockets; ignored if UDP socket + * is used. + * Returns: Pointer to abstract control interface data or %NULL on failure + * + * This function is used to open a control interface to wifihal + * when the socket path for client need to be specified explicitly. Default + * ctrl_path is usually /var/run/wifihal and client + * socket path is /tmp. + */ +struct wifihal_ctrl * wifihal_ctrl_open2(const char *ctrl_path, const char *cli_path); + + +/** + * wifihal_ctrl_close - Close a control interface to wifihal + * @ctrl: Control interface data from wifihal_ctrl_open() + * + * This function is used to close a control interface. + */ +void wifihal_ctrl_close(struct wifihal_ctrl *ctrl); + + +/** + * wifihal_ctrl_request - Send a command to wifihal + * @ctrl: Control interface data from wifihal_ctrl_open() + * @cmd: Command; usually, ASCII text, e.g., "PING" + * @cmd_len: Length of the cmd in bytes + * @reply: Buffer for the response + * @reply_len: Reply buffer length + * @msg_cb: Callback function for unsolicited messages or %NULL if not used + * Returns: 0 on success, -1 on error (send or receive failed), -2 on timeout + * + * This function is used to send commands to wifihal. Received + * response will be written to reply and reply_len is set to the actual length + * of the reply. This function will block for up to two seconds while waiting + * for the reply. If unsolicited messages are received, the blocking time may + * be longer. + * + * msg_cb can be used to register a callback function that will be called for + * unsolicited messages received while waiting for the command response. These + * messages may be received if wifihal_ctrl_request() is called at the same time as + * wifihal is sending such a message. + * FIXME : Change the comment below. + * This can happen only if + * the program has used wpa_ctrl_attach() to register itself as a monitor for + * event messages. Alternatively to msg_cb, programs can register two control + * interface connections and use one of them for commands and the other one for + * receiving event messages, in other words, call wpa_ctrl_attach() only for + * the control interface connection that will be used for event messages. + */ +int wifihal_ctrl_request(struct wifihal_ctrl *ctrl, const char *cmd, size_t cmd_len, + char *reply, size_t *reply_len); + + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/qcwcn/wifi_hal/wifihal_internal.h b/qcwcn/wifi_hal/wifihal_internal.h index 986b151..5cc78c3 100755 --- a/qcwcn/wifi_hal/wifihal_internal.h +++ b/qcwcn/wifi_hal/wifihal_internal.h @@ -35,6 +35,8 @@ */ #include "wifi_hal.h" +#include "list.h" +#include "sys/un.h" #define WIFIHAL_LOWI_MAJOR_VERSION 2 #define WIFIHAL_LOWI_MINOR_VERSION 1 @@ -45,6 +47,25 @@ #define DUAL_SIDED_RANGING_SUPPORED 0x00000002 #define GSCAN_SUPPORTED 0x00000004 +typedef struct wifihal_mon_sock_s { + + struct list_head list; + //! Family name + uint32_t family_name; + //! command ID + uint32_t cmd_id; + //! monitor sock len + uint32_t monsock_len; + //! monitor sock + struct sockaddr_un monsock; + //! match buff length + uint32_t match_len; + //! reserved byte + uint32_t reserved[4]; + //! match buff + char match[0]; +} wifihal_mon_sock_t; + /* * This structure is a table of function pointers to the functions * used by the wifihal to interface with LOWI diff --git a/qcwcn/wifi_hal/wifilogger_diag.cpp b/qcwcn/wifi_hal/wifilogger_diag.cpp index 4dd9810..436a42b 100644 --- a/qcwcn/wifi_hal/wifilogger_diag.cpp +++ b/qcwcn/wifi_hal/wifilogger_diag.cpp @@ -44,6 +44,8 @@ #include "wifilogger_diag.h" #include "wifilogger_vendor_tag_defs.h" #include "pkt_stats.h" +#include <errno.h> +#include "wifi_hal_ctrl.h" static uint32_t get_le32(const uint8_t *pos) { @@ -2463,52 +2465,62 @@ static wifi_error parse_stats_record_v1(hal_info *info, static wifi_error parse_stats(hal_info *info, u8 *data, u32 buflen) { wh_pktlog_hdr_t *pkt_stats_header; - wh_pktlog_hdr_v2_t *pkt_stats_header_t; + wh_pktlog_hdr_v2_t *pkt_stats_header_v2_t; wifi_error status = WIFI_SUCCESS; do { + u32 record_len; + if (buflen < sizeof(wh_pktlog_hdr_t)) { status = WIFI_ERROR_INVALID_ARGS; break; } pkt_stats_header = (wh_pktlog_hdr_t *)data; + pkt_stats_header_v2_t = (wh_pktlog_hdr_v2_t *)data; - if (buflen < (sizeof(wh_pktlog_hdr_t) + pkt_stats_header->size)) { + if (info->pkt_log_ver == PKT_LOG_V2) { + if (buflen < sizeof(wh_pktlog_hdr_v2_t)) { + status = WIFI_ERROR_INVALID_ARGS; + break; + } + record_len = (sizeof(wh_pktlog_hdr_v2_t) + pkt_stats_header_v2_t->size); + } else { + if (pkt_stats_header->flags & PKT_INFO_FLG_PKT_DUMP_V2){ + if (buflen < sizeof(wh_pktlog_hdr_v2_t)) { + status = WIFI_ERROR_INVALID_ARGS; + break; + } + record_len = (sizeof(wh_pktlog_hdr_v2_t) + pkt_stats_header_v2_t->size); + } else { + record_len = (sizeof(wh_pktlog_hdr_t) + pkt_stats_header->size); + } + } + + if (buflen < record_len) { status = WIFI_ERROR_INVALID_ARGS; break; } /* Pkt_log_V2 based packet parsing */ if (info->pkt_log_ver == PKT_LOG_V2) { - pkt_stats_header_t = (wh_pktlog_hdr_v2_t *)data; - status = parse_stats_record_v2(info, pkt_stats_header_t); - if (status != WIFI_SUCCESS) { - ALOGE("Failed to parse the stats type : %d", - pkt_stats_header_t->log_type); - return status; - } + status = parse_stats_record_v2(info, pkt_stats_header_v2_t); + if (status != WIFI_SUCCESS) { + ALOGE("Failed to parse the stats type : %d", + pkt_stats_header_v2_t->log_type); + return status; + } /* Pkt_log_V1 based packet parsing */ } else { - status = parse_stats_record_v1(info, pkt_stats_header); - if (status != WIFI_SUCCESS) { - ALOGE("Failed to parse the stats type : %d", + status = parse_stats_record_v1(info, pkt_stats_header); + if (status != WIFI_SUCCESS) { + ALOGE("Failed to parse the stats type : %d", pkt_stats_header->log_type); - return status; - } + return status; + } } + data += record_len; + buflen -= record_len; - if (info->pkt_log_ver == PKT_LOG_V2) { - data += (sizeof(wh_pktlog_hdr_v2_t) + pkt_stats_header->size); - buflen -= (sizeof(wh_pktlog_hdr_v2_t) + pkt_stats_header->size); - } else { - if (pkt_stats_header->flags & PKT_INFO_FLG_PKT_DUMP_V2){ - data += (sizeof(wh_pktlog_hdr_v2_t) + pkt_stats_header->size); - buflen -= (sizeof(wh_pktlog_hdr_v2_t) + pkt_stats_header->size); - } else { - data += (sizeof(wh_pktlog_hdr_t) + pkt_stats_header->size); - buflen -= (sizeof(wh_pktlog_hdr_t) + pkt_stats_header->size); - } - } } while (buflen > 0); return status; @@ -2568,7 +2580,9 @@ wifi_error diag_message_handler(hal_info *info, nl_msg *msg) genlh = (struct genlmsghdr *)nlmsg_data(nlh); if (genlh->cmd == ANI_NL_MSG_PUMAC || genlh->cmd == ANI_NL_MSG_LOG || - genlh->cmd == ANI_NL_MSG_CNSS_DIAG) { + genlh->cmd == ANI_NL_MSG_CNSS_DIAG || + genlh->cmd == WLAN_NL_MSG_OEM) + { cmd = genlh->cmd; int result = nla_parse(attrs, CLD80211_ATTR_MAX, genlmsg_attrdata(genlh, 0), genlmsg_attrlen(genlh, 0), NULL); @@ -2586,6 +2600,59 @@ wifi_error diag_message_handler(hal_info *info, nl_msg *msg) ALOGE("Invalid data received from driver"); return WIFI_SUCCESS; } + if((info->wifihal_ctrl_sock.s > 0) && (genlh->cmd == WLAN_NL_MSG_OEM)) { + wifihal_ctrl_event_t *ctrl_evt; + wifihal_mon_sock_t *reg; + + ctrl_evt = (wifihal_ctrl_event_t *)malloc(sizeof(*ctrl_evt) + nlh->nlmsg_len); + + if(ctrl_evt == NULL) + { + ALOGE("Memory allocation failure"); + return WIFI_ERROR_OUT_OF_MEMORY; + } + memset((char *)ctrl_evt, 0, sizeof(*ctrl_evt) + nlh->nlmsg_len); + + ctrl_evt->family_name = CLD80211_FAMILY; + ctrl_evt->cmd_id = WLAN_NL_MSG_OEM; + ctrl_evt->data_len = nlh->nlmsg_len; + memcpy(ctrl_evt->data, (char *)nlh, ctrl_evt->data_len); + + //! Send oem data to all the registered clients + + list_for_each_entry(reg, &info->monitor_sockets, list) { + + if(reg == NULL) + break; + + if (reg->family_name != CLD80211_FAMILY || reg->cmd_id != WLAN_NL_MSG_OEM) + continue; + + /* found match! */ + /* Indicate the received OEM msg to respective client + it is responsibility of the registered client to check + the oem_msg is meant for them or not based on oem_msg sub type */ + if (sendto(info->wifihal_ctrl_sock.s, (char *)ctrl_evt, + sizeof(*ctrl_evt) + ctrl_evt->data_len, 0, + (struct sockaddr *)®->monsock, reg->monsock_len) < 0) + { + int _errno = errno; + ALOGE("socket send failed : %d",_errno); + + if (_errno == ENOBUFS || _errno == EAGAIN) { + /* + * The socket send buffer could be full. This + * may happen if client programs are not + * receiving their pending messages. Close and + * reopen the socket as a workaround to avoid + * getting stuck being unable to send any new + * responses. + */ + } + } + } + free(ctrl_evt); + } } } else { wnl = (tAniNlHdr *)nlmsg_hdr(msg); diff --git a/qcwcn/wifi_hal/wifilogger_diag.h b/qcwcn/wifi_hal/wifilogger_diag.h index 24ad1eb..fc23cb7 100644 --- a/qcwcn/wifi_hal/wifilogger_diag.h +++ b/qcwcn/wifi_hal/wifilogger_diag.h @@ -104,7 +104,10 @@ typedef struct { }__attribute__((packed)) dbglog_slot; typedef enum eAniNlModuleTypes { - ANI_NL_MSG_PUMAC = ANI_NL_MSG_BASE + 0x01, + ANI_NL_MSG_PUMAC = ANI_NL_MSG_BASE + 0x01,// PTT Socket App + ANI_NL_MSG_PTT = ANI_NL_MSG_BASE + 0x07,// Quarky GUI + WLAN_NL_MSG_BTC, + WLAN_NL_MSG_OEM, ANI_NL_MSG_CNSS_DIAG = ANI_NL_MSG_BASE + 0x0B, ANI_NL_MSG_LOG, ANI_NL_MSG_MAX |