summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorXin Li <delphij@google.com>2019-10-25 10:28:01 -0700
committerXin Li <delphij@google.com>2019-10-25 10:28:01 -0700
commit2dd444c395c7cceaae8fc9b681cbec1af67ce23b (patch)
tree09a382c89d58ac170687b86f24f3ebc3f80698b6
parent180ce9e724d5a2097da24af214b2d4dc12a34f51 (diff)
parente66c67c549e9f29fafbe4d8e9098fc59cbd63ae8 (diff)
downloadwlan-2dd444c395c7cceaae8fc9b681cbec1af67ce23b.tar.gz
Merge Coral/Flame into AOSP master
Bug: 141248619 Change-Id: I9976a12048a8be199082a2200540f4a899fd3e4f Merged-In: I911b1a53ec46f39cc7597c2a31f59669db4f0699
-rw-r--r--qcwcn/wifi_hal/Android.mk26
-rw-r--r--qcwcn/wifi_hal/common.cpp2
-rw-r--r--qcwcn/wifi_hal/common.h10
-rw-r--r--qcwcn/wifi_hal/list.cpp76
-rw-r--r--qcwcn/wifi_hal/list.h72
-rw-r--r--qcwcn/wifi_hal/wifi_hal.cpp586
-rw-r--r--qcwcn/wifi_hal/wifi_hal_ctrl/wifi_hal_ctrl.c234
-rw-r--r--qcwcn/wifi_hal/wifi_hal_ctrl/wifi_hal_ctrl.h225
-rwxr-xr-xqcwcn/wifi_hal/wifihal_internal.h21
-rw-r--r--qcwcn/wifi_hal/wifilogger_diag.cpp121
-rw-r--r--qcwcn/wifi_hal/wifilogger_diag.h5
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(&reg->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 *)&reg->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(&reg->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 *)&reg->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(&reg->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 *)&reg->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 *)&reg->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