summaryrefslogtreecommitdiff
path: root/qcwcn
diff options
context:
space:
mode:
authorVinay Gannevaram <vganneva@codeaurora.org>2019-02-15 19:16:31 +0530
committerKumar Anand <kumaranand@google.com>2019-05-23 18:22:05 +0000
commitdceeae89168333edbda8676581a1820ac3b95a58 (patch)
tree68c94bc913e2250e7b40ad2dd353b71457924432 /qcwcn
parent5291a581560317dd6b1a1b50edbc7889684957d5 (diff)
downloadwlan-dceeae89168333edbda8676581a1820ac3b95a58.tar.gz
WIFIHAL: Support to send nl requests through wifihal
Added support in wifihal to send nl messages on behalf of its clients. Since netadmin capabilities are given to wifihal, it is used as bridge to send nl messages to kernel Added support for clients to register for nl events. CRs-Fixed: 2424237 Bug: 131618408 Bug: 28340421 Test: Regression test Change-Id: If8b62733e1d298804e0be98918eb875fc52a4ad1 Signed-off-by: Srinivas Girigowda <quic_sgirigow@quicinc.com>
Diffstat (limited to 'qcwcn')
-rw-r--r--qcwcn/wifi_hal/Android.mk26
-rw-r--r--qcwcn/wifi_hal/common.h10
-rw-r--r--qcwcn/wifi_hal/list.cpp76
-rw-r--r--qcwcn/wifi_hal/list.h62
-rw-r--r--qcwcn/wifi_hal/wifi_hal.cpp583
-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.cpp59
-rw-r--r--qcwcn/wifi_hal/wifilogger_diag.h5
10 files changed, 1293 insertions, 8 deletions
diff --git a/qcwcn/wifi_hal/Android.mk b/qcwcn/wifi_hal/Android.mk
index 639ccdb..bb31fe7 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.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..0417398
--- /dev/null
+++ b/qcwcn/wifi_hal/list.h
@@ -0,0 +1,62 @@
+/* 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))
+
+#endif
diff --git a/qcwcn/wifi_hal/wifi_hal.cpp b/qcwcn/wifi_hal/wifi_hal.cpp
index 198ab01..5fc3007 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) {
@@ -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;
if (info->cmd_sock != 0) {
nl_socket_free(info->cmd_sock);
@@ -834,6 +966,18 @@ 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(reg, &info->monitor_sockets, list) {
+ if(reg) {
+ free(reg);
+ }
+ }
+
if (info->interfaces) {
for (int i = 0; i < info->num_interfaces; i++)
free(info->interfaces[i]);
@@ -901,6 +1045,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 +1402,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 +1444,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 +1456,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 +1478,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 +1522,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..2e01fe0 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)
{
@@ -2568,7 +2570,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 +2590,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