summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--CleanSpec.mk49
-rw-r--r--METADATA3
-rw-r--r--OWNERS4
-rw-r--r--synadhd/Android.mk3
-rw-r--r--synadhd/config/Android.mk30
-rw-r--r--synadhd/config/config-syna.mk21
-rw-r--r--synadhd/config/p2p_supplicant_overlay.conf5
-rw-r--r--synadhd/config/wpa_supplicant_overlay.conf5
-rwxr-xr-xsynadhd/wifi_hal/Android.mk69
-rwxr-xr-xsynadhd/wifi_hal/common.cpp309
-rwxr-xr-xsynadhd/wifi_hal/common.h550
-rwxr-xr-xsynadhd/wifi_hal/cpp_bindings.cpp792
-rwxr-xr-xsynadhd/wifi_hal/cpp_bindings.h384
-rwxr-xr-xsynadhd/wifi_hal/gscan.cpp2010
-rw-r--r--synadhd/wifi_hal/link_layer_stats.cpp303
-rwxr-xr-xsynadhd/wifi_hal/nan.cpp5443
-rw-r--r--synadhd/wifi_hal/rtt.cpp812
-rwxr-xr-xsynadhd/wifi_hal/syna_version.h1
-rw-r--r--synadhd/wifi_hal/sync.h71
-rwxr-xr-xsynadhd/wifi_hal/twt.cpp947
-rwxr-xr-xsynadhd/wifi_hal/wifi_hal.cpp3053
-rwxr-xr-xsynadhd/wifi_hal/wifi_logger.cpp2831
-rw-r--r--synadhd/wifi_hal/wifi_offload.cpp268
-rw-r--r--synadhd/wpa_supplicant_8_lib/Android.mk81
-rw-r--r--synadhd/wpa_supplicant_8_lib/MODULE_LICENSE_BSD0
-rw-r--r--synadhd/wpa_supplicant_8_lib/NOTICE43
-rw-r--r--synadhd/wpa_supplicant_8_lib/driver_cmd_nl80211.c215
-rw-r--r--synadhd/wpa_supplicant_8_lib/driver_cmd_wext.c396
-rw-r--r--synadhd/wpa_supplicant_8_lib/driver_cmd_wext.h37
29 files changed, 18735 insertions, 0 deletions
diff --git a/CleanSpec.mk b/CleanSpec.mk
new file mode 100644
index 0000000..b84e1b6
--- /dev/null
+++ b/CleanSpec.mk
@@ -0,0 +1,49 @@
+# Copyright (C) 2007 The Android Open Source Project
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+#
+
+# If you don't need to do a full clean build but would like to touch
+# a file or delete some intermediate files, add a clean step to the end
+# of the list. These steps will only be run once, if they haven't been
+# run before.
+#
+# E.g.:
+# $(call add-clean-step, touch -c external/sqlite/sqlite3.h)
+# $(call add-clean-step, rm -rf $(PRODUCT_OUT)/obj/STATIC_LIBRARIES/libz_intermediates)
+#
+# Always use "touch -c" and "rm -f" or "rm -rf" to gracefully deal with
+# files that are missing or have been moved.
+#
+# Use $(PRODUCT_OUT) to get to the "out/target/product/blah/" directory.
+# Use $(OUT_DIR) to refer to the "out" directory.
+#
+# If you need to re-do something that's already mentioned, just copy
+# the command and add it to the bottom of the list. E.g., if a change
+# that you made last week required touching a file and a change you
+# made today requires touching the same file, just copy the old
+# touch step and add it to the end of the list.
+#
+# ************************************************
+# NEWER CLEAN STEPS MUST BE AT THE END OF THE LIST
+# ************************************************
+
+# For example:
+#$(call add-clean-step, rm -rf $(OUT_DIR)/target/common/obj/APPS/AndroidTests_intermediates)
+#$(call add-clean-step, rm -rf $(OUT_DIR)/target/common/obj/JAVA_LIBRARIES/core_intermediates)
+#$(call add-clean-step, find $(OUT_DIR) -type f -name "IGTalkSession*" -print0 | xargs -0 rm -f)
+#$(call add-clean-step, rm -rf $(PRODUCT_OUT)/data/*)
+
+# ************************************************
+# NEWER CLEAN STEPS MUST BE AT THE END OF THE LIST
+# ************************************************
diff --git a/METADATA b/METADATA
new file mode 100644
index 0000000..d97975c
--- /dev/null
+++ b/METADATA
@@ -0,0 +1,3 @@
+third_party {
+ license_type: NOTICE
+}
diff --git a/OWNERS b/OWNERS
new file mode 100644
index 0000000..dd590d3
--- /dev/null
+++ b/OWNERS
@@ -0,0 +1,4 @@
+arabawy@google.com
+etancohen@google.com
+kumachang@google.com
+wangroger@google.com
diff --git a/synadhd/Android.mk b/synadhd/Android.mk
new file mode 100644
index 0000000..1a52017
--- /dev/null
+++ b/synadhd/Android.mk
@@ -0,0 +1,3 @@
+ifeq ($(BOARD_WLAN_DEVICE),synadhd)
+ include $(call all-subdir-makefiles)
+endif
diff --git a/synadhd/config/Android.mk b/synadhd/config/Android.mk
new file mode 100644
index 0000000..8c3b13f
--- /dev/null
+++ b/synadhd/config/Android.mk
@@ -0,0 +1,30 @@
+#
+# Copyright (C) 2008 The Android Open Source Project
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+#
+LOCAL_PATH := $(call my-dir)
+
+########################
+
+WIFI_DRIVER_SOCKET_IFACE := wlan0
+ifeq ($(strip $(WPA_SUPPLICANT_VERSION)),VER_0_8_X)
+ include external/wpa_supplicant_8/wpa_supplicant/wpa_supplicant_conf.mk
+else
+ifeq ($(strip $(WPA_SUPPLICANT_VERSION)),VER_0_6_X)
+ include external/wpa_supplicant_6/wpa_supplicant/wpa_supplicant_conf.mk
+else
+ include external/wpa_supplicant/wpa_supplicant_conf.mk
+endif
+endif
+#######################
diff --git a/synadhd/config/config-syna.mk b/synadhd/config/config-syna.mk
new file mode 100644
index 0000000..df3d66f
--- /dev/null
+++ b/synadhd/config/config-syna.mk
@@ -0,0 +1,21 @@
+#
+# Copyright (C) 2008 The Android Open Source Project
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+#
+
+########################
+PRODUCT_COPY_FILES += \
+ hardware/synaptics/wlan/synadhd/config/wpa_supplicant_overlay.conf:$(TARGET_COPY_OUT_VENDOR)/etc/wifi/wpa_supplicant_overlay.conf \
+ hardware/synaptics/wlan/synadhd/config/p2p_supplicant_overlay.conf:$(TARGET_COPY_OUT_VENDOR)/etc/wifi/p2p_supplicant_overlay.conf
+########################
diff --git a/synadhd/config/p2p_supplicant_overlay.conf b/synadhd/config/p2p_supplicant_overlay.conf
new file mode 100644
index 0000000..e44c477
--- /dev/null
+++ b/synadhd/config/p2p_supplicant_overlay.conf
@@ -0,0 +1,5 @@
+disable_scan_offload=1
+wowlan_triggers=any
+p2p_no_go_freq=5170-5740
+p2p_search_delay=0
+no_ctrl_interface= \ No newline at end of file
diff --git a/synadhd/config/wpa_supplicant_overlay.conf b/synadhd/config/wpa_supplicant_overlay.conf
new file mode 100644
index 0000000..740792b
--- /dev/null
+++ b/synadhd/config/wpa_supplicant_overlay.conf
@@ -0,0 +1,5 @@
+disable_scan_offload=1
+wowlan_triggers=any
+p2p_disabled=1
+filter_rssi=-75
+no_ctrl_interface= \ No newline at end of file
diff --git a/synadhd/wifi_hal/Android.mk b/synadhd/wifi_hal/Android.mk
new file mode 100755
index 0000000..a3dc4a3
--- /dev/null
+++ b/synadhd/wifi_hal/Android.mk
@@ -0,0 +1,69 @@
+# Copyright (C) 2011 The Android Open Source Project
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+LOCAL_PATH := $(call my-dir)
+
+# Make the HAL library
+# ============================================================
+include $(CLEAR_VARS)
+
+LOCAL_CFLAGS := \
+ -Wall \
+ -Werror \
+ -Wno-format \
+ -Wno-reorder \
+ -Wno-unused-function \
+ -Wno-unused-parameter \
+ -Wno-unused-private-field \
+ -Wno-unused-variable \
+ -Wno-unused-parameter
+
+LOCAL_C_INCLUDES += \
+ external/libnl/include \
+ $(call include-path-for, libhardware_legacy)/hardware_legacy \
+ external/wpa_supplicant_8/src/drivers
+
+LOCAL_C_INCLUDES += \
+ external/boringssl/include \
+ external/boringssl/src/crypto/digest \
+ external/boringssl/src/crypto/evp/
+
+LOCAL_HEADER_LIBRARIES := libutils_headers liblog_headers
+
+ifneq ($(wildcard vendor/google/libraries/GoogleWifiConfigLib),)
+LOCAL_SHARED_LIBRARIES += \
+ google_wifi_firmware_config_version_c_wrapper
+LOCAL_CFLAGS += -DGOOGLE_WIFI_FW_CONFIG_VERSION_C_WRAPPER
+#only for pixel feature
+LOCAL_CFLAGS += -DRING_DUMP
+endif
+
+LOCAL_SRC_FILES := \
+ wifi_hal.cpp \
+ rtt.cpp \
+ common.cpp \
+ cpp_bindings.cpp \
+ gscan.cpp \
+ nan.cpp \
+ link_layer_stats.cpp \
+ wifi_logger.cpp \
+ wifi_offload.cpp \
+ twt.cpp
+
+LOCAL_MODULE := libwifi-hal-syna
+LOCAL_LICENSE_KINDS := SPDX-license-identifier-Apache-2.0
+LOCAL_LICENSE_CONDITIONS := notice
+LOCAL_PROPRIETARY_MODULE := true
+
+include $(BUILD_STATIC_LIBRARY)
diff --git a/synadhd/wifi_hal/common.cpp b/synadhd/wifi_hal/common.cpp
new file mode 100755
index 0000000..5a9d5ab
--- /dev/null
+++ b/synadhd/wifi_hal/common.cpp
@@ -0,0 +1,309 @@
+/*
+ * Copyright (C) 2017 The Android Open Source Project
+ *
+ * Portions copyright (C) 2017 Broadcom Limited
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <stdint.h>
+#include <fcntl.h>
+#include <sys/socket.h>
+#include <netlink/genl/genl.h>
+#include <netlink/genl/family.h>
+#include <netlink/genl/ctrl.h>
+#include <linux/rtnetlink.h>
+#include <netpacket/packet.h>
+#include <linux/filter.h>
+#include <linux/errqueue.h>
+
+#include <linux/pkt_sched.h>
+#include <netlink/object-api.h>
+#include <netlink/netlink.h>
+#include <netlink/socket.h>
+#include <netlink/handlers.h>
+
+#include "wifi_hal.h"
+#include "common.h"
+#include "cpp_bindings.h"
+
+/* test mode flag for halutil only */
+bool halutil_mode = false;
+interface_info *getIfaceInfo(wifi_interface_handle handle)
+{
+ return (interface_info *)handle;
+}
+
+wifi_handle getWifiHandle(wifi_interface_handle handle)
+{
+ return getIfaceInfo(handle)->handle;
+}
+
+hal_info *getHalInfo(wifi_handle handle)
+{
+ return (hal_info *)handle;
+}
+
+hal_info *getHalInfo(wifi_interface_handle handle)
+{
+ return getHalInfo(getWifiHandle(handle));
+}
+
+wifi_handle getWifiHandle(hal_info *info)
+{
+ return (wifi_handle)info;
+}
+
+wifi_interface_handle getIfaceHandle(interface_info *info)
+{
+ return (wifi_interface_handle)info;
+}
+
+wifi_error wifi_register_handler(wifi_handle handle, int cmd, nl_recvmsg_msg_cb_t func, void *arg)
+{
+ hal_info *info = (hal_info *)handle;
+
+ /* TODO: check for multiple handlers? */
+ pthread_mutex_lock(&info->cb_lock);
+
+ wifi_error result = WIFI_ERROR_OUT_OF_MEMORY;
+
+ if (info->num_event_cb < info->alloc_event_cb) {
+ info->event_cb[info->num_event_cb].nl_cmd = cmd;
+ info->event_cb[info->num_event_cb].vendor_id = 0;
+ info->event_cb[info->num_event_cb].vendor_subcmd = 0;
+ info->event_cb[info->num_event_cb].cb_func = func;
+ info->event_cb[info->num_event_cb].cb_arg = arg;
+ ALOGV("Successfully added event handler %p:%p for command %d at %d",
+ arg, func, cmd, info->num_event_cb);
+ info->num_event_cb++;
+ result = WIFI_SUCCESS;
+ }
+
+ pthread_mutex_unlock(&info->cb_lock);
+ return result;
+}
+
+wifi_error wifi_register_vendor_handler(wifi_handle handle,
+ uint32_t id, int subcmd, nl_recvmsg_msg_cb_t func, void *arg)
+{
+ hal_info *info = (hal_info *)handle;
+
+ /* TODO: check for multiple handlers? */
+ pthread_mutex_lock(&info->cb_lock);
+
+ wifi_error result = WIFI_ERROR_OUT_OF_MEMORY;
+
+ if (info->num_event_cb < info->alloc_event_cb) {
+ /* To avoid an unwanted duplication of the record, find first.
+ * Update it if the same record is already exist.
+ * KEY => [nl_cmd, vendor_id, vendor_subcmd]
+ */
+ int i = 0;
+ bool is_update = false;
+ for (i = 0; i < info->num_event_cb; i++) {
+ if ((info->event_cb[i].nl_cmd == NL80211_CMD_VENDOR) &&
+ (info->event_cb[i].vendor_id == id) &&
+ (info->event_cb[i].vendor_subcmd == subcmd)) {
+ is_update = true;
+ break;
+ }
+ }
+
+ if (is_update) {
+ info->event_cb[i].cb_func = func;
+ info->event_cb[i].cb_arg = arg;
+ } else {
+ info->event_cb[info->num_event_cb].nl_cmd = NL80211_CMD_VENDOR;
+ info->event_cb[info->num_event_cb].vendor_id = id;
+ info->event_cb[info->num_event_cb].vendor_subcmd = subcmd;
+ info->event_cb[info->num_event_cb].cb_func = func;
+ info->event_cb[info->num_event_cb].cb_arg = arg;
+ info->num_event_cb++;
+ }
+ ALOGI("%s ""event handler %p:%p for vendor 0x%0x and subcmd 0x%0x at %d",
+ is_update ? "Updated" : "Added", arg, func, id, subcmd, info->num_event_cb);
+ result = WIFI_SUCCESS;
+ }
+
+ pthread_mutex_unlock(&info->cb_lock);
+ return result;
+}
+
+void wifi_unregister_handler(wifi_handle handle, int cmd)
+{
+ hal_info *info = (hal_info *)handle;
+
+ if (cmd == NL80211_CMD_VENDOR) {
+ ALOGE("Must use wifi_unregister_vendor_handler to remove vendor handlers");
+ return;
+ }
+
+ pthread_mutex_lock(&info->cb_lock);
+
+ for (int i = 0; i < info->num_event_cb; i++) {
+ if (info->event_cb[i].nl_cmd == cmd) {
+ ALOGV("Successfully removed event handler %p:%p for cmd = 0x%0x from %d",
+ info->event_cb[i].cb_arg, info->event_cb[i].cb_func, cmd, i);
+
+ memmove(&info->event_cb[i], &info->event_cb[i+1],
+ (info->num_event_cb - i - 1) * sizeof(cb_info));
+ info->num_event_cb--;
+ break;
+ }
+ }
+
+ pthread_mutex_unlock(&info->cb_lock);
+}
+
+void wifi_unregister_vendor_handler_without_lock(wifi_handle handle, uint32_t id, int subcmd)
+{
+ hal_info *info = (hal_info *)handle;
+
+ for (int i = 0; i < info->num_event_cb; i++) {
+ if (info->event_cb[i].nl_cmd == NL80211_CMD_VENDOR
+ && info->event_cb[i].vendor_id == id
+ && info->event_cb[i].vendor_subcmd == subcmd) {
+ ALOGI("Successfully removed event handler %p:%p for vendor 0x%0x, subcmd 0x%0x from %d",
+ info->event_cb[i].cb_arg, info->event_cb[i].cb_func, id, subcmd, i);
+ memmove(&info->event_cb[i], &info->event_cb[i+1],
+ (info->num_event_cb - i - 1) * sizeof(cb_info));
+ info->num_event_cb--;
+ break;
+ }
+ }
+}
+
+void wifi_unregister_vendor_handler(wifi_handle handle, uint32_t id, int subcmd)
+{
+ hal_info *info = (hal_info *)handle;
+
+ pthread_mutex_lock(&info->cb_lock);
+ wifi_unregister_vendor_handler_without_lock(handle, id, subcmd);
+ pthread_mutex_unlock(&info->cb_lock);
+}
+
+wifi_error wifi_register_cmd(wifi_handle handle, int id, WifiCommand *cmd)
+{
+ hal_info *info = (hal_info *)handle;
+
+ ALOGV("registering command %d", id);
+
+ wifi_error result = WIFI_ERROR_OUT_OF_MEMORY;
+
+ if (info->num_cmd < info->alloc_cmd) {
+ info->cmd[info->num_cmd].id = id;
+ info->cmd[info->num_cmd].cmd = cmd;
+ ALOGV("Successfully added command %d: %p at %d", id, cmd, info->num_cmd);
+ info->num_cmd++;
+ result = WIFI_SUCCESS;
+ } else {
+ ALOGE("Failed to add command %d: %p at %d, reached max limit %d",
+ id, cmd, info->num_cmd, info->alloc_cmd);
+ }
+
+ return result;
+}
+
+WifiCommand *wifi_unregister_cmd(wifi_handle handle, int id)
+{
+ hal_info *info = (hal_info *)handle;
+
+ ALOGV("un-registering command %d", id);
+
+ WifiCommand *cmd = NULL;
+
+ for (int i = 0; i < info->num_cmd; i++) {
+ if (info->cmd[i].id == id) {
+ cmd = info->cmd[i].cmd;
+ memmove(&info->cmd[i], &info->cmd[i+1], (info->num_cmd - i - 1) * sizeof(cmd_info));
+ info->num_cmd--;
+ ALOGV("Successfully removed command %d: %p from %d", id, cmd, i);
+ break;
+ }
+ }
+
+ if (!cmd) {
+ ALOGI("Failed to remove command %d: %p", id, cmd);
+ }
+
+ return cmd;
+}
+
+WifiCommand *wifi_get_cmd(wifi_handle handle, int id)
+{
+ hal_info *info = (hal_info *)handle;
+
+ WifiCommand *cmd = NULL;
+
+ for (int i = 0; i < info->num_cmd; i++) {
+ if (info->cmd[i].id == id) {
+ cmd = info->cmd[i].cmd;
+ break;
+ }
+ }
+
+ return cmd;
+}
+
+void wifi_unregister_cmd(wifi_handle handle, WifiCommand *cmd)
+{
+ hal_info *info = (hal_info *)handle;
+
+ for (int i = 0; i < info->num_cmd; i++) {
+ if (info->cmd[i].cmd == cmd) {
+ int id = info->cmd[i].id;
+ memmove(&info->cmd[i], &info->cmd[i+1], (info->num_cmd - i - 1) * sizeof(cmd_info));
+ info->num_cmd--;
+ ALOGV("Successfully removed command %d: %p from %d", id, cmd, i);
+ break;
+ }
+ }
+}
+
+wifi_error wifi_cancel_cmd(wifi_request_id id, wifi_interface_handle iface)
+{
+ wifi_handle handle = getWifiHandle(iface);
+
+ WifiCommand *cmd = wifi_unregister_cmd(handle, id);
+ ALOGV("Cancel WifiCommand = %p", cmd);
+ if (cmd) {
+ cmd->cancel();
+ cmd->releaseRef();
+ return WIFI_SUCCESS;
+ }
+
+ return WIFI_ERROR_INVALID_ARGS;
+}
+
+wifi_error wifi_get_cancel_cmd(wifi_request_id id, wifi_interface_handle iface)
+{
+ wifi_handle handle = getWifiHandle(iface);
+ WifiCommand *cmd = wifi_get_cmd(handle, id);
+ ALOGV("Get Cancel WifiCommand = %p", cmd);
+ if (cmd) {
+ cmd->cancel();
+ cmd->releaseRef();
+ return WIFI_SUCCESS;
+ }
+
+ return WIFI_ERROR_INVALID_ARGS;
+}
+void set_hautil_mode(bool util_mode)
+{
+ halutil_mode = util_mode;
+}
+bool get_halutil_mode()
+{
+ return halutil_mode;
+}
diff --git a/synadhd/wifi_hal/common.h b/synadhd/wifi_hal/common.h
new file mode 100755
index 0000000..ebf6cb3
--- /dev/null
+++ b/synadhd/wifi_hal/common.h
@@ -0,0 +1,550 @@
+/*
+ * Copyright (C) 2017 The Android Open Source Project
+ *
+ * Portions copyright (C) 2017 Broadcom Limited
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "wifi_hal.h"
+
+#ifndef __WIFI_HAL_COMMON_H__
+#define __WIFI_HAL_COMMON_H__
+
+#define LOG_TAG "WifiHAL"
+
+#include <log/log.h>
+#include "nl80211_copy.h"
+#include "sync.h"
+
+#define SOCKET_BUFFER_SIZE (32768U)
+#define RECV_BUF_SIZE (4096)
+#define DEFAULT_EVENT_CB_SIZE (64)
+#define DEFAULT_CMD_SIZE (64)
+#define DOT11_OUI_LEN 3
+#define DOT11_MAX_SSID_LEN 32
+
+#define ETHERTYPE_IP 0x0800 /* IP */
+#define ETHERTYPE_IPV6 0x86dd /* IP protocol version 6 */
+#define MAX_PROBE_RESP_IE_LEN 2048
+/*
+ Vendor OUI - This is a unique identifier that identifies organization. Lets
+ code Android specific functions with Google OUI; although vendors can do more
+ with their own OUI's as well.
+ */
+
+const uint32_t GOOGLE_OUI = 0x001A11;
+const uint32_t BRCM_OUI = 0x001018;
+/* TODO: define vendor OUI here */
+
+
+#define MAC2STR(a) (a)[0], (a)[1], (a)[2], (a)[3], (a)[4], (a)[5]
+#define MACSTR "%02x:%02x:%02x:%02x:%02x:%02x"
+
+#define NMR2STR(a) (a)[0], (a)[1], (a)[2], (a)[3], (a)[4], (a)[5], (a)[6], (a)[7]
+#define NMRSTR "%02x:%02x:%02x:%02x:%02x:%02x:%02x:%02x"
+#define NAN_MASTER_RANK_LEN 8
+#define NAN_SCID_INFO_LEN 16
+
+#define SAR_CONFIG_SCENARIO_COUNT 100
+#define MAX_NUM_RADIOS 3
+#define MAX_CMD_RESP_BUF_LEN 8192
+
+/*
+ This enum defines ranges for various commands; commands themselves
+ can be defined in respective feature headers; i.e. find gscan command
+ definitions in gscan.cpp
+ */
+
+typedef int (*nl_recvmsg_msg_cb_t)(struct nl_msg *msg, void *arg);
+typedef enum {
+ /* don't use 0 as a valid subcommand */
+ VENDOR_NL80211_SUBCMD_UNSPECIFIED,
+
+ /* define all vendor startup commands between 0x0 and 0x0FFF */
+ VENDOR_NL80211_SUBCMD_RANGE_START = 0x0001,
+ VENDOR_NL80211_SUBCMD_RANGE_END = 0x0FFF,
+
+ /* define all GScan related commands between 0x1000 and 0x10FF */
+ ANDROID_NL80211_SUBCMD_GSCAN_RANGE_START = 0x1000,
+ ANDROID_NL80211_SUBCMD_GSCAN_RANGE_END = 0x10FF,
+
+ /* define all NearbyDiscovery related commands between 0x1100 and 0x11FF */
+ ANDROID_NL80211_SUBCMD_NBD_RANGE_START = 0x1100,
+ ANDROID_NL80211_SUBCMD_NBD_RANGE_END = 0x11FF,
+
+ /* define all RTT related commands between 0x1100 and 0x11FF */
+ ANDROID_NL80211_SUBCMD_RTT_RANGE_START = 0x1100,
+ ANDROID_NL80211_SUBCMD_RTT_RANGE_END = 0x11FF,
+
+ ANDROID_NL80211_SUBCMD_LSTATS_RANGE_START = 0x1200,
+ ANDROID_NL80211_SUBCMD_LSTATS_RANGE_END = 0x12FF,
+
+ /* define all Logger related commands between 0x1400 and 0x14FF */
+ ANDROID_NL80211_SUBCMD_DEBUG_RANGE_START = 0x1400,
+ ANDROID_NL80211_SUBCMD_DEBUG_RANGE_END = 0x14FF,
+
+ /* define all wifi offload related commands between 0x1600 and 0x16FF */
+ ANDROID_NL80211_SUBCMD_WIFI_OFFLOAD_RANGE_START = 0x1600,
+ ANDROID_NL80211_SUBCMD_WIFI_OFFLOAD_RANGE_END = 0x16FF,
+
+ /* define all NAN related commands between 0x1700 and 0x17FF */
+ ANDROID_NL80211_SUBCMD_NAN_RANGE_START = 0x1700,
+ ANDROID_NL80211_SUBCMD_NAN_RANGE_END = 0x17FF,
+
+ /* define all Android Packet Filter related commands between 0x1800 and 0x18FF */
+ ANDROID_NL80211_SUBCMD_PKT_FILTER_RANGE_START = 0x1800,
+ ANDROID_NL80211_SUBCMD_PKT_FILTER_RANGE_END = 0x18FF,
+
+ /* define all tx power related commands between 0x1900 and 0x1910 */
+ ANDROID_NL80211_SUBCMD_TX_POWER_RANGE_START = 0x1900,
+ ANDROID_NL80211_SUBCMD_TX_POWER_RANGE_END = 0x1910,
+
+ /* define all thermal mode related commands between 0x1920 and 0x192F */
+ ANDROID_NL80211_SUBCMD_MITIGATION_RANGE_START = 0x1920,
+ ANDROID_NL80211_SUBCMD_MITIGATION_RANGE_END = 0x192F,
+
+ /* define all DSCP related commands between 0x2000 and 0x20FF */
+ ANDROID_NL80211_SUBCMD_DSCP_RANGE_START = 0x2000,
+ ANDROID_NL80211_SUBCMD_DSCP_RANGE_END = 0x20FF,
+
+ /* define all Channel Avoidance related commands between 0x2100 and 0x211F */
+ ANDROID_NL80211_SUBCMD_CHAVOID_RANGE_START = 0x2100,
+ ANDROID_NL80211_SUBCMD_CHAVOID_RANGE_END = 0x211F,
+
+ /* define all OTA Download related commands between 0x2120 and 0x212F */
+ ANDROID_NL80211_SUBCMD_OTA_DOWNLOAD_START = 0x2120,
+ ANDROID_NL80211_SUBCMD_OTA_DOWNLOAD_END = 0x212F,
+
+ /* define all VOIP mode config related commands between 0x2130 and 0x213F */
+ ANDROID_NL80211_SUBCMD_VIOP_MODE_START = 0x2130,
+ ANDROID_NL80211_SUBCMD_VIOP_MODE_END = 0x213F,
+
+ /* define all TWT related commands between 0x2140 and 0x214F */
+ ANDROID_NL80211_SUBCMD_TWT_START = 0x2140,
+ ANDROID_NL80211_SUBCMD_TWT_END = 0x214F,
+
+ /* define all Usable Channel related commands between 0x2150 and 0x215F */
+ ANDROID_NL80211_SUBCMD_USABLE_CHANNEL_START = 0x2150,
+ ANDROID_NL80211_SUBCMD_USABLE_CHANNEL_END = 0x215F,
+
+ /* define all init/deinit related commands between 0x2160 and 0x216F */
+ ANDROID_NL80211_SUBCMD_INIT_DEINIT_RANGE_START = 0x2160,
+ ANDROID_NL80211_SUBCMD_INIT_DEINIT_RANGE_END = 0x216F,
+
+ /* This is reserved for future usage */
+
+} ANDROID_VENDOR_SUB_COMMAND;
+
+typedef enum {
+
+ GSCAN_SUBCMD_GET_CAPABILITIES = ANDROID_NL80211_SUBCMD_GSCAN_RANGE_START,
+
+ GSCAN_SUBCMD_SET_CONFIG, /* 0x1001 */
+
+ GSCAN_SUBCMD_SET_SCAN_CONFIG, /* 0x1002 */
+ GSCAN_SUBCMD_ENABLE_GSCAN, /* 0x1003 */
+ GSCAN_SUBCMD_GET_SCAN_RESULTS, /* 0x1004 */
+ GSCAN_SUBCMD_SCAN_RESULTS, /* 0x1005 */
+
+ GSCAN_SUBCMD_SET_HOTLIST, /* 0x1006 */
+
+ GSCAN_SUBCMD_SET_SIGNIFICANT_CHANGE_CONFIG, /* 0x1007 */
+ GSCAN_SUBCMD_ENABLE_FULL_SCAN_RESULTS, /* 0x1008 */
+ GSCAN_SUBCMD_GET_CHANNEL_LIST, /* 0x1009 */
+
+ WIFI_SUBCMD_GET_FEATURE_SET, /* 0x100A */
+ WIFI_SUBCMD_GET_FEATURE_SET_MATRIX, /* 0x100B */
+ WIFI_SUBCMD_SET_PNO_RANDOM_MAC_OUI, /* 0x100C */
+ WIFI_SUBCMD_NODFS_SET, /* 0x100D */
+ WIFI_SUBCMD_SET_COUNTRY_CODE, /* 0x100E */
+ /* Add more sub commands here */
+ GSCAN_SUBCMD_SET_EPNO_SSID, /* 0x100F */
+
+ WIFI_SUBCMD_SET_SSID_WHITE_LIST, /* 0x1010 */
+ WIFI_SUBCMD_SET_ROAM_PARAMS, /* 0x1011 */
+ WIFI_SUBCMD_ENABLE_LAZY_ROAM, /* 0x1012 */
+ WIFI_SUBCMD_SET_BSSID_PREF, /* 0x1013 */
+ WIFI_SUBCMD_SET_BSSID_BLACKLIST, /* 0x1014 */
+
+ GSCAN_SUBCMD_ANQPO_CONFIG, /* 0x1015 */
+ WIFI_SUBCMD_SET_RSSI_MONITOR, /* 0x1016 */
+ WIFI_SUBCMD_CONFIG_ND_OFFLOAD, /* 0x1017 */
+ WIFI_SUBCMD_CONFIG_TCPACK_SUP, /* 0x1018 */
+ WIFI_SUBCMD_FW_ROAM_POLICY, /* 0x1019 */
+ WIFI_SUBCMD_ROAM_CAPABILITY, /* 0x101a */
+ WIFI_SUBCMD_SET_LATENCY_MODE, /* 0x101b */
+ WIFI_SUBCMD_SET_MULTISTA_PRIMARY_CONNECTION, /* 0x101c */
+ WIFI_SUBCMD_SET_MULTISTA_USE_CASE, /* 0x101d */
+ WIFI_SUBCMD_SET_DTIM_CONFIG, /* 0x101e */
+ WIFI_SUBCMD_CONFIG_INDOOR_STATE,
+
+ GSCAN_SUBCMD_MAX,
+
+ /* NAN related */
+ NAN_SUBCMD_ENABLE = ANDROID_NL80211_SUBCMD_NAN_RANGE_START,
+ NAN_SUBCMD_DISABLE, /* 0x1701 */
+ NAN_SUBCMD_PUBLISH, /* 0x1702 */
+ NAN_SUBCMD_SUBSCRIBE, /* 0x1703 */
+ NAN_SUBCMD_PUBLISH_CANCEL, /* 0x1704 */
+ NAN_SUBCMD_SUBSCRIBE_CANCEL, /* 0x1705 */
+ NAN_SUBCMD_TRANSMIT_FOLLOWUP, /* 0x1706 */
+ NAN_SUBCMD_CONFIG, /* 0x1707 */
+ NAN_SUBCMD_TCA, /* 0x1708 */
+ NAN_SUBCMD_STATS, /* 0x1709 */
+ NAN_SUBCMD_GET_CAPABILITIES, /* 0x170A */
+ NAN_SUBCMD_DATA_PATH_IFACE_CREATE, /* 0x170B */
+ NAN_SUBCMD_DATA_PATH_IFACE_DELETE, /* 0x170C */
+ NAN_SUBCMD_DATA_PATH_REQUEST, /* 0x170D */
+ NAN_SUBCMD_DATA_PATH_RESPONSE, /* 0x170E */
+ NAN_SUBCMD_DATA_PATH_END, /* 0x170F */
+ NAN_SUBCMD_DATA_PATH_SEC_INFO, /* 0x1710 */
+ NAN_SUBCMD_VERSION_INFO, /* 0x1711 */
+ NAN_SUBCMD_ENABLE_MERGE, /* 0x1712 */
+ APF_SUBCMD_GET_CAPABILITIES = ANDROID_NL80211_SUBCMD_PKT_FILTER_RANGE_START,
+ APF_SUBCMD_SET_FILTER,
+ APF_SUBCMD_READ_FILTER,
+ WIFI_SUBCMD_TX_POWER_SCENARIO = ANDROID_NL80211_SUBCMD_TX_POWER_RANGE_START,
+ WIFI_SUBCMD_THERMAL_MITIGATION = ANDROID_NL80211_SUBCMD_MITIGATION_RANGE_START,
+ DSCP_SUBCMD_SET_TABLE = ANDROID_NL80211_SUBCMD_DSCP_RANGE_START,
+ DSCP_SUBCMD_RESET_TABLE, /* 0x2001 */
+ CHAVOID_SUBCMD_SET_CONFIG = ANDROID_NL80211_SUBCMD_CHAVOID_RANGE_START,
+
+ TWT_SUBCMD_GETCAPABILITY = ANDROID_NL80211_SUBCMD_TWT_START,
+ TWT_SUBCMD_SETUP_REQUEST,
+ TWT_SUBCMD_TEAR_DOWN_REQUEST,
+ TWT_SUBCMD_INFO_FRAME_REQUEST,
+ TWT_SUBCMD_GETSTATS,
+ TWT_SUBCMD_CLR_STATS,
+
+ WIFI_SUBCMD_CONFIG_VOIP_MODE = ANDROID_NL80211_SUBCMD_VIOP_MODE_START,
+
+ WIFI_SUBCMD_GET_OTA_CURRUNT_INFO = ANDROID_NL80211_SUBCMD_OTA_DOWNLOAD_START,
+ WIFI_SUBCMD_OTA_UPDATE,
+ WIFI_SUBCMD_USABLE_CHANNEL = ANDROID_NL80211_SUBCMD_USABLE_CHANNEL_START,
+ WIFI_SUBCMD_TRIGGER_SSR = ANDROID_NL80211_SUBCMD_INIT_DEINIT_RANGE_START,
+ WIFI_SUBCMD_GET_RADIO_COMBO_MATRIX,
+} WIFI_SUB_COMMAND;
+
+typedef enum {
+ BRCM_RESERVED1 = 0,
+ BRCM_RESERVED2 = 1,
+ GSCAN_EVENT_SIGNIFICANT_CHANGE_RESULTS = 2,
+ GSCAN_EVENT_HOTLIST_RESULTS_FOUND = 3,
+ GSCAN_EVENT_SCAN_RESULTS_AVAILABLE = 4,
+ GSCAN_EVENT_FULL_SCAN_RESULTS = 5,
+ RTT_EVENT_COMPLETE = 6,
+ GSCAN_EVENT_COMPLETE_SCAN = 7,
+ GSCAN_EVENT_HOTLIST_RESULTS_LOST = 8,
+ GSCAN_EVENT_EPNO_EVENT = 9,
+ GOOGLE_DEBUG_RING_EVENT = 10,
+ GOOGLE_DEBUG_MEM_DUMP_EVENT = 11,
+ GSCAN_EVENT_ANQPO_HOTSPOT_MATCH = 12,
+ GOOGLE_RSSI_MONITOR_EVENT = 13,
+ GOOGLE_MKEEP_ALIVE = 14,
+
+ /*
+ * BRCM specific events should be placed after the Generic events
+ * in order to match between the DHD and HAL
+ */
+ NAN_EVENT_ENABLED = 15,
+ NAN_EVENT_DISABLED = 16,
+ NAN_EVENT_SUBSCRIBE_MATCH = 17,
+ NAN_EVENT_PUBLISH_REPLIED_IND = 18,
+ NAN_EVENT_PUBLISH_TERMINATED = 19,
+ NAN_EVENT_SUBSCRIBE_TERMINATED = 20,
+ NAN_EVENT_DE_EVENT = 21,
+ NAN_EVENT_FOLLOWUP = 22,
+ NAN_EVENT_TRANSMIT_FOLLOWUP_IND = 23,
+ NAN_EVENT_DATA_REQUEST = 24,
+ NAN_EVENT_DATA_CONFIRMATION = 25,
+ NAN_EVENT_DATA_END = 26,
+ NAN_EVENT_BEACON = 27,
+ NAN_EVENT_SDF = 28,
+ NAN_EVENT_TCA = 29,
+ NAN_EVENT_SUBSCRIBE_UNMATCH = 30,
+ NAN_EVENT_UNKNOWN = 31,
+ BRCM_VENDOR_EVENT_HANGED = 33,
+ ROAM_EVENT_START,
+ GOOGLE_FILE_DUMP_EVENT = 37,
+ NAN_ASYNC_RESPONSE_DISABLED = 40,
+ BRCM_VENDOR_EVENT_TWT = 43,
+ BRCM_TPUT_DUMP_EVENT = 44,
+ NAN_EVENT_MATCH_EXPIRY = 45
+} WIFI_EVENT;
+
+typedef void (*wifi_internal_event_handler) (wifi_handle handle, int events);
+
+class WifiCommand;
+
+typedef struct {
+ int nl_cmd;
+ uint32_t vendor_id;
+ int vendor_subcmd;
+ nl_recvmsg_msg_cb_t cb_func;
+ void *cb_arg;
+} cb_info;
+
+typedef struct {
+ wifi_request_id id;
+ WifiCommand *cmd;
+} cmd_info;
+
+typedef struct {
+ wifi_handle handle; // handle to wifi data
+ char name[IFNAMSIZ+1]; // interface name + trailing null
+ int id; // id to use when talking to driver
+ bool is_virtual; // mark each iface as virtual or static
+} interface_info;
+
+typedef struct {
+
+ struct nl_sock *cmd_sock; // command socket object
+ struct nl_sock *event_sock; // event socket object
+ int nl80211_family_id; // family id for 80211 driver
+ int cleanup_socks[2]; // sockets used to implement wifi_cleanup
+
+ bool in_event_loop; // Indicates that event loop is active
+ bool clean_up; // Indication to exit since cleanup has started
+
+ wifi_internal_event_handler event_handler; // default event handler
+ wifi_cleaned_up_handler cleaned_up_handler; // socket cleaned up handler
+
+ cb_info *event_cb; // event callbacks
+ int num_event_cb; // number of event callbacks
+ int alloc_event_cb; // number of allocated callback objects
+ pthread_mutex_t cb_lock; // mutex for the event_cb access
+
+ cmd_info *cmd; // Outstanding commands
+ int num_cmd; // number of commands
+ int alloc_cmd; // number of commands allocated
+
+ interface_info **interfaces; // array of interfaces
+ int num_interfaces; // number of interfaces
+ int max_num_interfaces; // max number of interfaces
+ wifi_subsystem_restart_handler restart_handler; // trigger sub system handler
+
+
+ // add other details
+} hal_info;
+
+#define PNO_SSID_FOUND 0x1
+#define PNO_SSID_LOST 0x2
+
+typedef struct wifi_pno_result {
+ unsigned char ssid[DOT11_MAX_SSID_LEN];
+ unsigned char ssid_len;
+ signed char rssi;
+ u16 channel;
+ u16 flags;
+ mac_addr bssid;
+} wifi_pno_result_t;
+
+typedef struct wifi_gscan_result {
+ u64 ts; // Time of discovery
+ u8 ssid[DOT11_MAX_SSID_LEN+1]; // null terminated
+ mac_addr bssid; // BSSID
+ u32 channel; // channel frequency in MHz
+ s32 rssi; // in db
+ u64 rtt; // in nanoseconds
+ u64 rtt_sd; // standard deviation in rtt
+ u16 beacon_period; // units are Kusec
+ u16 capability; // Capability information
+ u32 pad;
+} wifi_gscan_result_t;
+
+typedef struct wifi_gscan_full_result {
+ wifi_gscan_result_t fixed;
+ u32 scan_ch_bucket; // scan chbucket bitmask
+ u32 ie_length; // byte length of Information Elements
+ u8 ie_data[1]; // IE data to follow
+} wifi_gscan_full_result_t;
+
+void twt_deinit_handler();
+
+typedef enum {
+ TWT_EVENT_INVALID = 0,
+ TWT_SETUP_RESPONSE = 1,
+ TWT_TEARDOWN_COMPLETION = 2,
+ TWT_INFORM_FRAME = 3,
+ TWT_NOTIFY = 4,
+ TWT_EVENT_LAST
+} TwtEventType;
+
+typedef enum {
+ TWT_INVALID = 0,
+ TWT_SETUP_REQUEST = 1,
+ TWT_INFO_FRAME_REQUEST = 2,
+ TWT_TEAR_DOWN_REQUEST = 3,
+ TWT_LAST
+} TwtRequestType;
+
+typedef enum {
+ TWT_ATTRIBUTE_INVALID = 0,
+ TWT_ATTRIBUTE_CONFIG_ID = 1,
+ TWT_ATTRIBUTE_NEG_TYPE = 2,
+ TWT_ATTRIBUTE_TRIGGER_TYPE = 3,
+ TWT_ATTRIBUTE_WAKE_DUR_US = 4,
+ TWT_ATTRIBUTE_WAKE_INT_US = 5,
+ TWT_ATTRIBUTE_WAKE_INT_MIN_US = 6,
+ TWT_ATTRIBUTE_WAKE_INT_MAX_US = 7,
+ TWT_ATTRIBUTE_WAKE_DUR_MIN_US = 8,
+ TWT_ATTRIBUTE_WAKE_DUR_MAX_US = 9,
+ TWT_ATTRIBUTE_AVG_PKT_SIZE = 10,
+ TWT_ATTRIBUTE_AVG_PKT_NUM = 11,
+ TWT_ATTRIBUTE_WAKE_TIME_OFF_US = 12,
+ TWT_ATTRIBUTE_ALL_TWT = 13,
+ TWT_ATTRIBUTE_RESUME_TIME_US = 14,
+ TWT_ATTRIBUTE_AVG_EOSP_DUR = 15,
+ TWT_ATTRIBUTE_EOSP_COUNT = 16,
+ TWT_ATTRIBUTE_NUM_SP = 17,
+ TWT_ATTRIBUTE_DEVICE_CAP = 18,
+ TWT_ATTRIBUTE_PEER_CAP = 19,
+ TWT_ATTRIBUTE_STATUS = 20,
+ TWT_ATTRIBUTE_REASON_CODE = 21,
+ TWT_ATTRIBUTE_RESUMED = 22,
+ TWT_ATTRIBUTE_NOTIFICATION = 23,
+ TWT_ATTRIBUTE_SUB_EVENT = 24,
+ TWT_ATTRIBUTE_NUM_PEER_STATS = 25,
+ TWT_ATTRIBUTE_AVG_PKT_NUM_TX = 26,
+ TWT_ATTRIBUTE_AVG_PKT_SIZE_TX = 27,
+ TWT_ATTRIBUTE_AVG_PKT_NUM_RX = 28,
+ TWT_ATTRIBUTE_AVG_PKT_SIZE_RX = 29,
+ TWT_ATTRIBUTE_MAX
+} TWT_ATTRIBUTE;
+
+wifi_error wifi_register_handler(wifi_handle handle, int cmd, nl_recvmsg_msg_cb_t func, void *arg);
+wifi_error wifi_register_vendor_handler(wifi_handle handle,
+ uint32_t id, int subcmd, nl_recvmsg_msg_cb_t func, void *arg);
+
+void wifi_unregister_handler(wifi_handle handle, int cmd);
+void wifi_unregister_vendor_handler_without_lock(wifi_handle handle, uint32_t id, int subcmd);
+void wifi_unregister_vendor_handler(wifi_handle handle, uint32_t id, int subcmd);
+
+wifi_error wifi_register_cmd(wifi_handle handle, int id, WifiCommand *cmd);
+WifiCommand *wifi_unregister_cmd(wifi_handle handle, int id);
+WifiCommand *wifi_get_cmd(wifi_handle handle, int id);
+void wifi_unregister_cmd(wifi_handle handle, WifiCommand *cmd);
+
+interface_info *getIfaceInfo(wifi_interface_handle);
+wifi_handle getWifiHandle(wifi_interface_handle handle);
+hal_info *getHalInfo(wifi_handle handle);
+hal_info *getHalInfo(wifi_interface_handle handle);
+wifi_handle getWifiHandle(hal_info *info);
+wifi_interface_handle getIfaceHandle(interface_info *info);
+wifi_error wifi_cancel_cmd(wifi_request_id id, wifi_interface_handle iface);
+wifi_error wifi_get_cancel_cmd(wifi_request_id id, wifi_interface_handle iface);
+wifi_error nan_deinit_handler();
+wifi_error wifi_start_hal(wifi_interface_handle iface);
+wifi_error wifi_stop_hal(wifi_interface_handle iface);
+wifi_interface_handle wifi_get_wlan_interface(wifi_handle info,
+ wifi_interface_handle *ifaceHandles, int numIfaceHandles);
+#ifdef RING_DUMP
+wifi_error wifi_start_ring_dump(wifi_interface_handle iface,
+ wifi_ring_buffer_data_handler ring_handle);
+wifi_error wifi_stop_ring_dump(wifi_interface_handle iface);
+#endif /* RING_DUMP */
+wifi_error wifi_hal_ota_update(wifi_interface_handle iface, uint32_t ota_version);
+wifi_error wifi_hal_preInit(wifi_interface_handle iface);
+/* API to get wake reason statistics */
+wifi_error wifi_get_wake_reason_stats(wifi_interface_handle handle,
+ WLAN_DRIVER_WAKE_REASON_CNT *wifi_wake_reason_cnt);
+wifi_error wifi_virtual_interface_create(wifi_handle handle, const char* ifname,
+ wifi_interface_type iface_type);
+wifi_error wifi_virtual_interface_delete(wifi_handle handle, const char* ifname);
+wifi_error wifi_set_coex_unsafe_channels(wifi_handle handle, u32 num_channels,
+ wifi_coex_unsafe_channel channels[], u32 restrictions);
+wifi_error wifi_set_voip_mode(wifi_interface_handle handle, wifi_voip_mode mode);
+wifi_error wifi_set_dtim_config(wifi_interface_handle handle, u32 multiplier);
+void set_hautil_mode(bool halutil_mode);
+bool get_halutil_mode();
+
+/* API's to support TWT */
+
+/**@brief twt_get_capability
+ * Request TWT capability
+ * @param wifi_interface_handle:
+ * @return Synchronous wifi_error and TwtCapabilitySet
+ */
+wifi_error twt_get_capability(wifi_interface_handle iface, TwtCapabilitySet* twt_cap_set);
+
+/**@brief twt_register_handler
+ * Request to register TWT callback
+ * @param wifi_interface_handle:
+ * @param TwtCallbackHandler:
+ * @return Synchronous wifi_error
+ */
+wifi_error twt_register_handler(wifi_interface_handle iface, TwtCallbackHandler handler);
+
+/**@brief twt_setup_request
+ * Request to send TWT setup frame
+ * @param wifi_interface_handle:
+ * @param TwtSetupRequest:
+ * @return Synchronous wifi_error
+ * @return Asynchronous EventTwtSetupResponse CB return TwtSetupResponse
+ */
+wifi_error twt_setup_request(wifi_interface_handle iface, TwtSetupRequest* msg);
+
+/**@brief twt_teardown_request
+ * Request to send TWT teardown frame
+ * @param wifi_interface_handle:
+ * @param TwtTeardownRequest:
+ * @return Synchronous wifi_error
+ * @return Asynchronous EventTwtTeardownCompletion CB return TwtTeardownCompletion
+ * TwtTeardownCompletion may also be received due to other events
+ * like CSA, BTCX, TWT scheduler, MultiConnection, peer-initiated teardown, etc.
+ */
+wifi_error twt_teardown_request(wifi_interface_handle iface, TwtTeardownRequest* msg);
+
+/**@brief twt_info_frame_request
+ * Request to send TWT info frame
+ * @param wifi_interface_handle:
+ * @param TwtInfoFrameRequest:
+ * @return Synchronous wifi_error
+ * @return Asynchronous EventTwtInfoFrameReceived CB return TwtInfoFrameReceived
+ * Driver may also receive Peer-initiated TwtInfoFrame
+ */
+wifi_error twt_info_frame_request(wifi_interface_handle iface, TwtInfoFrameRequest* msg);
+
+/**@brief twt_get_stats
+ * Request to get TWT stats
+ * @param wifi_interface_handle:
+ * @param config_id:
+ * @return Synchronous wifi_error and TwtStats
+ */
+wifi_error twt_get_stats(wifi_interface_handle iface, u8 config_id, TwtStats* stats);
+
+/**@brief twt_clear_stats
+ * Request to clear TWT stats
+ * @param wifi_interface_handle:
+ * @param config_id:
+ * @return Synchronous wifi_error
+ */
+wifi_error twt_clear_stats(wifi_interface_handle iface, u8 config_id);
+
+wifi_error wifi_trigger_subsystem_restart(wifi_handle handle);
+// some common macros
+
+#define min(x, y) ((x) < (y) ? (x) : (y))
+#define max(x, y) ((x) > (y) ? (x) : (y))
+
+#define NULL_CHECK_RETURN(ptr, str, ret) \
+ do { \
+ if (!(ptr)) { \
+ ALOGE("%s(): null pointer - #ptr (%s)\n", __FUNCTION__, str); \
+ return ret; \
+ } \
+ } while (0)
+
+#endif
+
diff --git a/synadhd/wifi_hal/cpp_bindings.cpp b/synadhd/wifi_hal/cpp_bindings.cpp
new file mode 100755
index 0000000..5311e6e
--- /dev/null
+++ b/synadhd/wifi_hal/cpp_bindings.cpp
@@ -0,0 +1,792 @@
+/*
+ * Copyright (C) 2017 The Android Open Source Project
+ *
+ * Portions copyright (C) 2017 Broadcom Limited
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <stdint.h>
+#include <fcntl.h>
+#include <sys/socket.h>
+#include <netlink/genl/genl.h>
+#include <netlink/genl/family.h>
+#include <netlink/genl/ctrl.h>
+#include <linux/rtnetlink.h>
+#include <netpacket/packet.h>
+#include <linux/filter.h>
+#include <linux/errqueue.h>
+
+#include <linux/pkt_sched.h>
+#include <netlink/object-api.h>
+#include <netlink/netlink.h>
+#include <netlink/socket.h>
+#include <netlink/handlers.h>
+
+#include <ctype.h>
+#include <errno.h>
+
+#include "wifi_hal.h"
+#include "common.h"
+#include "cpp_bindings.h"
+
+pthread_mutex_t ResponseMutex;
+void InitResponseLock() {
+ pthread_mutex_init(&ResponseMutex, NULL);
+}
+
+void DestroyResponseLock()
+{
+ pthread_mutex_destroy(&ResponseMutex);
+}
+
+void appendFmt(char *buf, int &offset, const char *fmt, ...)
+{
+ va_list params;
+ va_start(params, fmt);
+ offset += vsprintf(buf + offset, fmt, params);
+ va_end(params);
+}
+
+#define C2S(x) case x: return #x;
+
+static const char *cmdToString(int cmd)
+{
+ switch (cmd) {
+ C2S(NL80211_CMD_UNSPEC)
+ C2S(NL80211_CMD_GET_WIPHY)
+ C2S(NL80211_CMD_SET_WIPHY)
+ C2S(NL80211_CMD_NEW_WIPHY)
+ C2S(NL80211_CMD_DEL_WIPHY)
+ C2S(NL80211_CMD_GET_INTERFACE)
+ C2S(NL80211_CMD_SET_INTERFACE)
+ C2S(NL80211_CMD_NEW_INTERFACE)
+ C2S(NL80211_CMD_DEL_INTERFACE)
+ C2S(NL80211_CMD_GET_KEY)
+ C2S(NL80211_CMD_SET_KEY)
+ C2S(NL80211_CMD_NEW_KEY)
+ C2S(NL80211_CMD_DEL_KEY)
+ C2S(NL80211_CMD_GET_BEACON)
+ C2S(NL80211_CMD_SET_BEACON)
+ C2S(NL80211_CMD_START_AP)
+ C2S(NL80211_CMD_STOP_AP)
+ C2S(NL80211_CMD_GET_STATION)
+ C2S(NL80211_CMD_SET_STATION)
+ C2S(NL80211_CMD_NEW_STATION)
+ C2S(NL80211_CMD_DEL_STATION)
+ C2S(NL80211_CMD_GET_MPATH)
+ C2S(NL80211_CMD_SET_MPATH)
+ C2S(NL80211_CMD_NEW_MPATH)
+ C2S(NL80211_CMD_DEL_MPATH)
+ C2S(NL80211_CMD_SET_BSS)
+ C2S(NL80211_CMD_SET_REG)
+ C2S(NL80211_CMD_REQ_SET_REG)
+ C2S(NL80211_CMD_GET_MESH_CONFIG)
+ C2S(NL80211_CMD_SET_MESH_CONFIG)
+ C2S(NL80211_CMD_SET_MGMT_EXTRA_IE)
+ C2S(NL80211_CMD_GET_REG)
+ C2S(NL80211_CMD_GET_SCAN)
+ C2S(NL80211_CMD_TRIGGER_SCAN)
+ C2S(NL80211_CMD_NEW_SCAN_RESULTS)
+ C2S(NL80211_CMD_SCAN_ABORTED)
+ C2S(NL80211_CMD_REG_CHANGE)
+ C2S(NL80211_CMD_AUTHENTICATE)
+ C2S(NL80211_CMD_ASSOCIATE)
+ C2S(NL80211_CMD_DEAUTHENTICATE)
+ C2S(NL80211_CMD_DISASSOCIATE)
+ C2S(NL80211_CMD_MICHAEL_MIC_FAILURE)
+ C2S(NL80211_CMD_REG_BEACON_HINT)
+ C2S(NL80211_CMD_JOIN_IBSS)
+ C2S(NL80211_CMD_LEAVE_IBSS)
+ C2S(NL80211_CMD_TESTMODE)
+ C2S(NL80211_CMD_CONNECT)
+ C2S(NL80211_CMD_ROAM)
+ C2S(NL80211_CMD_DISCONNECT)
+ C2S(NL80211_CMD_SET_WIPHY_NETNS)
+ C2S(NL80211_CMD_GET_SURVEY)
+ C2S(NL80211_CMD_NEW_SURVEY_RESULTS)
+ C2S(NL80211_CMD_SET_PMKSA)
+ C2S(NL80211_CMD_DEL_PMKSA)
+ C2S(NL80211_CMD_FLUSH_PMKSA)
+ C2S(NL80211_CMD_REMAIN_ON_CHANNEL)
+ C2S(NL80211_CMD_CANCEL_REMAIN_ON_CHANNEL)
+ C2S(NL80211_CMD_SET_TX_BITRATE_MASK)
+ C2S(NL80211_CMD_REGISTER_FRAME)
+ C2S(NL80211_CMD_FRAME)
+ C2S(NL80211_CMD_FRAME_TX_STATUS)
+ C2S(NL80211_CMD_SET_POWER_SAVE)
+ C2S(NL80211_CMD_GET_POWER_SAVE)
+ C2S(NL80211_CMD_SET_CQM)
+ C2S(NL80211_CMD_NOTIFY_CQM)
+ C2S(NL80211_CMD_SET_CHANNEL)
+ C2S(NL80211_CMD_SET_WDS_PEER)
+ C2S(NL80211_CMD_FRAME_WAIT_CANCEL)
+ C2S(NL80211_CMD_JOIN_MESH)
+ C2S(NL80211_CMD_LEAVE_MESH)
+ C2S(NL80211_CMD_UNPROT_DEAUTHENTICATE)
+ C2S(NL80211_CMD_UNPROT_DISASSOCIATE)
+ C2S(NL80211_CMD_NEW_PEER_CANDIDATE)
+ C2S(NL80211_CMD_GET_WOWLAN)
+ C2S(NL80211_CMD_SET_WOWLAN)
+ C2S(NL80211_CMD_START_SCHED_SCAN)
+ C2S(NL80211_CMD_STOP_SCHED_SCAN)
+ C2S(NL80211_CMD_SCHED_SCAN_RESULTS)
+ C2S(NL80211_CMD_SCHED_SCAN_STOPPED)
+ C2S(NL80211_CMD_SET_REKEY_OFFLOAD)
+ C2S(NL80211_CMD_PMKSA_CANDIDATE)
+ C2S(NL80211_CMD_TDLS_OPER)
+ C2S(NL80211_CMD_TDLS_MGMT)
+ C2S(NL80211_CMD_UNEXPECTED_FRAME)
+ C2S(NL80211_CMD_PROBE_CLIENT)
+ C2S(NL80211_CMD_REGISTER_BEACONS)
+ C2S(NL80211_CMD_UNEXPECTED_4ADDR_FRAME)
+ C2S(NL80211_CMD_SET_NOACK_MAP)
+ C2S(NL80211_CMD_CH_SWITCH_NOTIFY)
+ C2S(NL80211_CMD_START_P2P_DEVICE)
+ C2S(NL80211_CMD_STOP_P2P_DEVICE)
+ C2S(NL80211_CMD_CONN_FAILED)
+ C2S(NL80211_CMD_SET_MCAST_RATE)
+ C2S(NL80211_CMD_SET_MAC_ACL)
+ C2S(NL80211_CMD_RADAR_DETECT)
+ C2S(NL80211_CMD_GET_PROTOCOL_FEATURES)
+ C2S(NL80211_CMD_UPDATE_FT_IES)
+ C2S(NL80211_CMD_FT_EVENT)
+ C2S(NL80211_CMD_CRIT_PROTOCOL_START)
+ C2S(NL80211_CMD_CRIT_PROTOCOL_STOP)
+ C2S(NL80211_CMD_GET_COALESCE)
+ C2S(NL80211_CMD_SET_COALESCE)
+ C2S(NL80211_CMD_CHANNEL_SWITCH)
+ C2S(NL80211_CMD_VENDOR)
+ C2S(NL80211_CMD_SET_QOS_MAP)
+ default:
+ return "NL80211_CMD_UNKNOWN";
+ }
+}
+
+const char *attributeToString(int attribute)
+{
+ switch (attribute) {
+ C2S(NL80211_ATTR_UNSPEC)
+
+ C2S(NL80211_ATTR_WIPHY)
+ C2S(NL80211_ATTR_WIPHY_NAME)
+
+ C2S(NL80211_ATTR_IFINDEX)
+ C2S(NL80211_ATTR_IFNAME)
+ C2S(NL80211_ATTR_IFTYPE)
+
+ C2S(NL80211_ATTR_MAC)
+
+ C2S(NL80211_ATTR_KEY_DATA)
+ C2S(NL80211_ATTR_KEY_IDX)
+ C2S(NL80211_ATTR_KEY_CIPHER)
+ C2S(NL80211_ATTR_KEY_SEQ)
+ C2S(NL80211_ATTR_KEY_DEFAULT)
+
+ C2S(NL80211_ATTR_BEACON_INTERVAL)
+ C2S(NL80211_ATTR_DTIM_PERIOD)
+ C2S(NL80211_ATTR_BEACON_HEAD)
+ C2S(NL80211_ATTR_BEACON_TAIL)
+
+ C2S(NL80211_ATTR_STA_AID)
+ C2S(NL80211_ATTR_STA_FLAGS)
+ C2S(NL80211_ATTR_STA_LISTEN_INTERVAL)
+ C2S(NL80211_ATTR_STA_SUPPORTED_RATES)
+ C2S(NL80211_ATTR_STA_VLAN)
+ C2S(NL80211_ATTR_STA_INFO)
+
+ C2S(NL80211_ATTR_WIPHY_BANDS)
+
+ C2S(NL80211_ATTR_MNTR_FLAGS)
+
+ C2S(NL80211_ATTR_MESH_ID)
+ C2S(NL80211_ATTR_STA_PLINK_ACTION)
+ C2S(NL80211_ATTR_MPATH_NEXT_HOP)
+ C2S(NL80211_ATTR_MPATH_INFO)
+
+ C2S(NL80211_ATTR_BSS_CTS_PROT)
+ C2S(NL80211_ATTR_BSS_SHORT_PREAMBLE)
+ C2S(NL80211_ATTR_BSS_SHORT_SLOT_TIME)
+
+ C2S(NL80211_ATTR_HT_CAPABILITY)
+
+ C2S(NL80211_ATTR_SUPPORTED_IFTYPES)
+
+ C2S(NL80211_ATTR_REG_ALPHA2)
+ C2S(NL80211_ATTR_REG_RULES)
+
+ C2S(NL80211_ATTR_MESH_CONFIG)
+
+ C2S(NL80211_ATTR_BSS_BASIC_RATES)
+
+ C2S(NL80211_ATTR_WIPHY_TXQ_PARAMS)
+ C2S(NL80211_ATTR_WIPHY_FREQ)
+ C2S(NL80211_ATTR_WIPHY_CHANNEL_TYPE)
+
+ C2S(NL80211_ATTR_KEY_DEFAULT_MGMT)
+
+ C2S(NL80211_ATTR_MGMT_SUBTYPE)
+ C2S(NL80211_ATTR_IE)
+
+ C2S(NL80211_ATTR_MAX_NUM_SCAN_SSIDS)
+
+ C2S(NL80211_ATTR_SCAN_FREQUENCIES)
+ C2S(NL80211_ATTR_SCAN_SSIDS)
+ C2S(NL80211_ATTR_GENERATION) /* replaces old SCAN_GENERATION */
+ C2S(NL80211_ATTR_BSS)
+
+ C2S(NL80211_ATTR_REG_INITIATOR)
+ C2S(NL80211_ATTR_REG_TYPE)
+
+ C2S(NL80211_ATTR_SUPPORTED_COMMANDS)
+
+ C2S(NL80211_ATTR_FRAME)
+ C2S(NL80211_ATTR_SSID)
+ C2S(NL80211_ATTR_AUTH_TYPE)
+ C2S(NL80211_ATTR_REASON_CODE)
+
+ C2S(NL80211_ATTR_KEY_TYPE)
+
+ C2S(NL80211_ATTR_MAX_SCAN_IE_LEN)
+ C2S(NL80211_ATTR_CIPHER_SUITES)
+
+ C2S(NL80211_ATTR_FREQ_BEFORE)
+ C2S(NL80211_ATTR_FREQ_AFTER)
+
+ C2S(NL80211_ATTR_FREQ_FIXED)
+
+
+ C2S(NL80211_ATTR_WIPHY_RETRY_SHORT)
+ C2S(NL80211_ATTR_WIPHY_RETRY_LONG)
+ C2S(NL80211_ATTR_WIPHY_FRAG_THRESHOLD)
+ C2S(NL80211_ATTR_WIPHY_RTS_THRESHOLD)
+
+ C2S(NL80211_ATTR_TIMED_OUT)
+
+ C2S(NL80211_ATTR_USE_MFP)
+
+ C2S(NL80211_ATTR_STA_FLAGS2)
+
+ C2S(NL80211_ATTR_CONTROL_PORT)
+
+ C2S(NL80211_ATTR_TESTDATA)
+
+ C2S(NL80211_ATTR_PRIVACY)
+
+ C2S(NL80211_ATTR_DISCONNECTED_BY_AP)
+ C2S(NL80211_ATTR_STATUS_CODE)
+
+ C2S(NL80211_ATTR_CIPHER_SUITES_PAIRWISE)
+ C2S(NL80211_ATTR_CIPHER_SUITE_GROUP)
+ C2S(NL80211_ATTR_WPA_VERSIONS)
+ C2S(NL80211_ATTR_AKM_SUITES)
+
+ C2S(NL80211_ATTR_REQ_IE)
+ C2S(NL80211_ATTR_RESP_IE)
+
+ C2S(NL80211_ATTR_PREV_BSSID)
+
+ C2S(NL80211_ATTR_KEY)
+ C2S(NL80211_ATTR_KEYS)
+
+ C2S(NL80211_ATTR_PID)
+
+ C2S(NL80211_ATTR_4ADDR)
+
+ C2S(NL80211_ATTR_SURVEY_INFO)
+
+ C2S(NL80211_ATTR_PMKID)
+ C2S(NL80211_ATTR_MAX_NUM_PMKIDS)
+
+ C2S(NL80211_ATTR_DURATION)
+
+ C2S(NL80211_ATTR_COOKIE)
+
+ C2S(NL80211_ATTR_WIPHY_COVERAGE_CLASS)
+
+ C2S(NL80211_ATTR_TX_RATES)
+
+ C2S(NL80211_ATTR_FRAME_MATCH)
+
+ C2S(NL80211_ATTR_ACK)
+
+ C2S(NL80211_ATTR_PS_STATE)
+
+ C2S(NL80211_ATTR_CQM)
+
+ C2S(NL80211_ATTR_LOCAL_STATE_CHANGE)
+
+ C2S(NL80211_ATTR_AP_ISOLATE)
+
+ C2S(NL80211_ATTR_WIPHY_TX_POWER_SETTING)
+ C2S(NL80211_ATTR_WIPHY_TX_POWER_LEVEL)
+
+ C2S(NL80211_ATTR_TX_FRAME_TYPES)
+ C2S(NL80211_ATTR_RX_FRAME_TYPES)
+ C2S(NL80211_ATTR_FRAME_TYPE)
+
+ C2S(NL80211_ATTR_CONTROL_PORT_ETHERTYPE)
+ C2S(NL80211_ATTR_CONTROL_PORT_NO_ENCRYPT)
+
+ C2S(NL80211_ATTR_SUPPORT_IBSS_RSN)
+
+ C2S(NL80211_ATTR_WIPHY_ANTENNA_TX)
+ C2S(NL80211_ATTR_WIPHY_ANTENNA_RX)
+
+ C2S(NL80211_ATTR_MCAST_RATE)
+
+ C2S(NL80211_ATTR_OFFCHANNEL_TX_OK)
+
+ C2S(NL80211_ATTR_BSS_HT_OPMODE)
+
+ C2S(NL80211_ATTR_KEY_DEFAULT_TYPES)
+
+ C2S(NL80211_ATTR_MAX_REMAIN_ON_CHANNEL_DURATION)
+
+ C2S(NL80211_ATTR_MESH_SETUP)
+
+ C2S(NL80211_ATTR_WIPHY_ANTENNA_AVAIL_TX)
+ C2S(NL80211_ATTR_WIPHY_ANTENNA_AVAIL_RX)
+
+ C2S(NL80211_ATTR_SUPPORT_MESH_AUTH)
+ C2S(NL80211_ATTR_STA_PLINK_STATE)
+
+ C2S(NL80211_ATTR_WOWLAN_TRIGGERS)
+ C2S(NL80211_ATTR_WOWLAN_TRIGGERS_SUPPORTED)
+
+ C2S(NL80211_ATTR_SCHED_SCAN_INTERVAL)
+
+ C2S(NL80211_ATTR_INTERFACE_COMBINATIONS)
+ C2S(NL80211_ATTR_SOFTWARE_IFTYPES)
+
+ C2S(NL80211_ATTR_REKEY_DATA)
+
+ C2S(NL80211_ATTR_MAX_NUM_SCHED_SCAN_SSIDS)
+ C2S(NL80211_ATTR_MAX_SCHED_SCAN_IE_LEN)
+
+ C2S(NL80211_ATTR_SCAN_SUPP_RATES)
+
+ C2S(NL80211_ATTR_HIDDEN_SSID)
+
+ C2S(NL80211_ATTR_IE_PROBE_RESP)
+ C2S(NL80211_ATTR_IE_ASSOC_RESP)
+
+ C2S(NL80211_ATTR_STA_WME)
+ C2S(NL80211_ATTR_SUPPORT_AP_UAPSD)
+
+ C2S(NL80211_ATTR_ROAM_SUPPORT)
+
+ C2S(NL80211_ATTR_SCHED_SCAN_MATCH)
+ C2S(NL80211_ATTR_MAX_MATCH_SETS)
+
+ C2S(NL80211_ATTR_PMKSA_CANDIDATE)
+
+ C2S(NL80211_ATTR_TX_NO_CCK_RATE)
+
+ C2S(NL80211_ATTR_TDLS_ACTION)
+ C2S(NL80211_ATTR_TDLS_DIALOG_TOKEN)
+ C2S(NL80211_ATTR_TDLS_OPERATION)
+ C2S(NL80211_ATTR_TDLS_SUPPORT)
+ C2S(NL80211_ATTR_TDLS_EXTERNAL_SETUP)
+
+ C2S(NL80211_ATTR_DEVICE_AP_SME)
+
+ C2S(NL80211_ATTR_DONT_WAIT_FOR_ACK)
+
+ C2S(NL80211_ATTR_FEATURE_FLAGS)
+
+ C2S(NL80211_ATTR_PROBE_RESP_OFFLOAD)
+
+ C2S(NL80211_ATTR_PROBE_RESP)
+
+ C2S(NL80211_ATTR_DFS_REGION)
+
+ C2S(NL80211_ATTR_DISABLE_HT)
+ C2S(NL80211_ATTR_HT_CAPABILITY_MASK)
+
+ C2S(NL80211_ATTR_NOACK_MAP)
+
+ C2S(NL80211_ATTR_INACTIVITY_TIMEOUT)
+
+ C2S(NL80211_ATTR_RX_SIGNAL_DBM)
+
+ C2S(NL80211_ATTR_BG_SCAN_PERIOD)
+
+ C2S(NL80211_ATTR_WDEV)
+
+ C2S(NL80211_ATTR_USER_REG_HINT_TYPE)
+
+ C2S(NL80211_ATTR_CONN_FAILED_REASON)
+
+ C2S(NL80211_ATTR_SAE_DATA)
+
+ C2S(NL80211_ATTR_VHT_CAPABILITY)
+
+ C2S(NL80211_ATTR_SCAN_FLAGS)
+
+ C2S(NL80211_ATTR_CHANNEL_WIDTH)
+ C2S(NL80211_ATTR_CENTER_FREQ1)
+ C2S(NL80211_ATTR_CENTER_FREQ2)
+
+ C2S(NL80211_ATTR_P2P_CTWINDOW)
+ C2S(NL80211_ATTR_P2P_OPPPS)
+
+ C2S(NL80211_ATTR_LOCAL_MESH_POWER_MODE)
+
+ C2S(NL80211_ATTR_ACL_POLICY)
+
+ C2S(NL80211_ATTR_MAC_ADDRS)
+
+ C2S(NL80211_ATTR_MAC_ACL_MAX)
+
+ C2S(NL80211_ATTR_RADAR_EVENT)
+
+ C2S(NL80211_ATTR_EXT_CAPA)
+ C2S(NL80211_ATTR_EXT_CAPA_MASK)
+
+ C2S(NL80211_ATTR_STA_CAPABILITY)
+ C2S(NL80211_ATTR_STA_EXT_CAPABILITY)
+
+ C2S(NL80211_ATTR_PROTOCOL_FEATURES)
+ C2S(NL80211_ATTR_SPLIT_WIPHY_DUMP)
+
+ C2S(NL80211_ATTR_DISABLE_VHT)
+ C2S(NL80211_ATTR_VHT_CAPABILITY_MASK)
+
+ C2S(NL80211_ATTR_MDID)
+ C2S(NL80211_ATTR_IE_RIC)
+
+ C2S(NL80211_ATTR_CRIT_PROT_ID)
+ C2S(NL80211_ATTR_MAX_CRIT_PROT_DURATION)
+
+ C2S(NL80211_ATTR_PEER_AID)
+
+ C2S(NL80211_ATTR_COALESCE_RULE)
+
+ C2S(NL80211_ATTR_CH_SWITCH_COUNT)
+ C2S(NL80211_ATTR_CH_SWITCH_BLOCK_TX)
+ C2S(NL80211_ATTR_CSA_IES)
+ C2S(NL80211_ATTR_CSA_C_OFF_BEACON)
+ C2S(NL80211_ATTR_CSA_C_OFF_PRESP)
+
+ C2S(NL80211_ATTR_RXMGMT_FLAGS)
+
+ C2S(NL80211_ATTR_STA_SUPPORTED_CHANNELS)
+
+ C2S(NL80211_ATTR_STA_SUPPORTED_OPER_CLASSES)
+
+ C2S(NL80211_ATTR_HANDLE_DFS)
+
+ C2S(NL80211_ATTR_SUPPORT_5_MHZ)
+ C2S(NL80211_ATTR_SUPPORT_10_MHZ)
+
+ C2S(NL80211_ATTR_OPMODE_NOTIF)
+
+ C2S(NL80211_ATTR_VENDOR_ID)
+ C2S(NL80211_ATTR_VENDOR_SUBCMD)
+ C2S(NL80211_ATTR_VENDOR_DATA)
+ C2S(NL80211_ATTR_VENDOR_EVENTS)
+
+ C2S(NL80211_ATTR_QOS_MAP)
+ default:
+ return "NL80211_ATTR_UNKNOWN";
+ }
+}
+
+void WifiEvent::log() {
+ parse();
+
+ byte *data = (byte *)genlmsg_attrdata(mHeader, 0);
+ int len = genlmsg_attrlen(mHeader, 0);
+ ALOGD("cmd = %s, len = %d", get_cmdString(), len);
+ ALOGD("vendor_id = %04x, vendor_subcmd = %d", get_vendor_id(), get_vendor_subcmd());
+
+ for (int i = 0; i < len; i += 16) {
+ char line[81];
+ int linelen = min(16, len - i);
+ int offset = 0;
+ appendFmt(line, offset, "%02x", data[i]);
+ for (int j = 1; j < linelen; j++) {
+ appendFmt(line, offset, " %02x", data[i+j]);
+ }
+
+ for (int j = linelen; j < 16; j++) {
+ appendFmt(line, offset, " ");
+ }
+
+ line[23] = '-';
+
+ appendFmt(line, offset, " ");
+
+ for (int j = 0; j < linelen; j++) {
+ if (isprint(data[i+j])) {
+ appendFmt(line, offset, "%c", data[i+j]);
+ } else {
+ appendFmt(line, offset, "-");
+ }
+ }
+
+ ALOGD("%s", line);
+ }
+
+ for (unsigned i = 0; i < NL80211_ATTR_MAX_INTERNAL; i++) {
+ if (mAttributes[i] != NULL) {
+ ALOGD("found attribute %s", attributeToString(i));
+ }
+ }
+
+ ALOGD("-- End of message --");
+}
+
+const char *WifiEvent::get_cmdString() {
+ return cmdToString(get_cmd());
+}
+
+
+int WifiEvent::parse() {
+ if (mHeader != NULL) {
+ return WIFI_SUCCESS;
+ }
+ mHeader = (genlmsghdr *)nlmsg_data(nlmsg_hdr(mMsg));
+ int result = nla_parse(mAttributes, NL80211_ATTR_MAX_INTERNAL, genlmsg_attrdata(mHeader, 0),
+ genlmsg_attrlen(mHeader, 0), NULL);
+
+ // ALOGD("event len = %d", nlmsg_hdr(mMsg)->nlmsg_len);
+ return result;
+}
+
+int WifiRequest::create(int family, uint8_t cmd, int flags, int hdrlen) {
+
+ destroy();
+
+ mMsg = nlmsg_alloc();
+ if (mMsg != NULL) {
+ genlmsg_put(mMsg, /* pid = */ 0, /* seq = */ 0, family,
+ hdrlen, flags, cmd, /* version = */ 0);
+ return WIFI_SUCCESS;
+ } else {
+ return WIFI_ERROR_OUT_OF_MEMORY;
+ }
+}
+
+static int mapErrorCodes(int err)
+{
+ int ret;
+ if (!err) {
+ return WIFI_SUCCESS;
+ }
+ switch (err) {
+ case -EOPNOTSUPP:
+ ret = WIFI_ERROR_NOT_SUPPORTED;
+ break;
+ case -ETIMEDOUT:
+ ret = WIFI_ERROR_TIMED_OUT;
+ break;
+ case -EINVAL:
+ ret = WIFI_ERROR_INVALID_ARGS;
+ break;
+ case -ENOMEM:
+ ret = WIFI_ERROR_OUT_OF_MEMORY;
+ break;
+ case -EBUSY:
+ ret = WIFI_ERROR_BUSY;
+ break;
+ default:
+ ret = WIFI_ERROR_UNKNOWN;
+ }
+ ALOGD("error code %d mapped to %d", err, ret);
+ return ret;
+}
+
+int WifiRequest::create(uint32_t id, int subcmd) {
+ int res = create(NL80211_CMD_VENDOR);
+ if (res < 0) {
+ return mapErrorCodes(res);
+ }
+
+ res = put_u32(NL80211_ATTR_VENDOR_ID, id);
+ if (res < 0) {
+ return mapErrorCodes(res);
+ }
+
+ res = put_u32(NL80211_ATTR_VENDOR_SUBCMD, subcmd);
+ if (res < 0) {
+ return mapErrorCodes(res);
+ }
+
+ if (mIface != -1) {
+ res = set_iface_id(mIface);
+ }
+
+ return mapErrorCodes(res);
+}
+
+
+static int no_seq_check(struct nl_msg *msg, void *arg)
+{
+ return NL_OK;
+}
+
+int WifiCommand::requestResponse() {
+ int err = create(); /* create the message */
+ if (err < 0) {
+ return err;
+ }
+
+ return requestResponse(mMsg);
+}
+
+int WifiCommand::requestResponse(WifiRequest& request) {
+ pthread_mutex_lock(&ResponseMutex);
+ int err = 0;
+
+ struct nl_cb *cb = nl_cb_alloc(NL_CB_DEFAULT);
+ if (!cb)
+ goto out;
+
+ err = nl_send_auto_complete(mInfo->cmd_sock, request.getMessage()); /* send message */
+ if (err < 0)
+ goto out;
+
+ err = 1;
+
+ nl_cb_set(cb, NL_CB_SEQ_CHECK, NL_CB_CUSTOM, no_seq_check, NULL);
+ nl_cb_err(cb, NL_CB_CUSTOM, error_handler, &err);
+ nl_cb_set(cb, NL_CB_FINISH, NL_CB_CUSTOM, finish_handler, &err);
+ nl_cb_set(cb, NL_CB_ACK, NL_CB_CUSTOM, ack_handler, &err);
+ nl_cb_set(cb, NL_CB_VALID, NL_CB_CUSTOM, response_handler, this);
+
+ while (err > 0) { /* wait for reply */
+ int res = nl_recvmsgs(mInfo->cmd_sock, cb);
+ if (res) {
+ ALOGE("nl80211: %s->nl_recvmsgs failed: %d", __func__, res);
+ }
+ }
+out:
+ nl_cb_put(cb);
+ pthread_mutex_unlock(&ResponseMutex);
+ return mapErrorCodes(err);
+}
+
+int WifiCommand::requestEvent(int cmd) {
+
+ ALOGD("requesting event %d", cmd);
+
+ int res = wifi_register_handler(wifiHandle(), cmd, event_handler, this);
+ if (res < 0) {
+ return res;
+ }
+
+ res = create(); /* create the message */
+ if (res < 0)
+ goto out;
+
+ ALOGD("waiting for response %d", cmd);
+
+ res = nl_send_auto_complete(mInfo->cmd_sock, mMsg.getMessage()); /* send message */
+ if (res < 0)
+ goto out;
+
+ ALOGD("waiting for event %d", cmd);
+ res = mCondition.wait();
+ if (res < 0)
+ goto out;
+
+out:
+ wifi_unregister_handler(wifiHandle(), cmd);
+ return mapErrorCodes(res);
+}
+
+int WifiCommand::requestVendorEvent(uint32_t id, int subcmd) {
+
+ int res = wifi_register_vendor_handler(wifiHandle(), id, subcmd, event_handler, this);
+ if (res < 0) {
+ return res;
+ }
+
+ res = create(); /* create the message */
+ if (res < 0)
+ goto out;
+
+ res = nl_send_auto_complete(mInfo->cmd_sock, mMsg.getMessage()); /* send message */
+ if (res < 0)
+ goto out;
+
+ res = mCondition.wait();
+ if (res < 0)
+ goto out;
+
+out:
+ wifi_unregister_vendor_handler(wifiHandle(), id, subcmd);
+ return mapErrorCodes(res);
+}
+
+/* Event handlers */
+int WifiCommand::response_handler(struct nl_msg *msg, void *arg) {
+ // ALOGD("response_handler called");
+ WifiCommand *cmd = (WifiCommand *)arg;
+ WifiEvent reply(msg);
+ int res = reply.parse();
+ if (res < 0) {
+ ALOGE("Failed to parse reply message = %d", res);
+ return NL_SKIP;
+ } else {
+ // reply.log();
+ return cmd->handleResponse(reply);
+ }
+}
+
+int WifiCommand::event_handler(struct nl_msg *msg, void *arg) {
+ WifiCommand *cmd = (WifiCommand *)arg;
+ WifiEvent event(msg);
+ int res = event.parse();
+ if (res < 0) {
+ ALOGE("Failed to parse event = %d", res);
+ res = NL_SKIP;
+ } else {
+ res = cmd->handleEvent(event);
+ }
+
+ cmd->mCondition.signal();
+ return res;
+}
+
+/* Other event handlers */
+int WifiCommand::valid_handler(struct nl_msg *msg, void *arg) {
+ // ALOGD("valid_handler called");
+ int *err = (int *)arg;
+ *err = 0;
+ return NL_SKIP;
+}
+
+int WifiCommand::ack_handler(struct nl_msg *msg, void *arg) {
+ // ALOGD("ack_handler called");
+ int *err = (int *)arg;
+ *err = 0;
+ return NL_STOP;
+}
+
+int WifiCommand::finish_handler(struct nl_msg *msg, void *arg) {
+ // ALOGD("finish_handler called");
+ int *ret = (int *)arg;
+ *ret = 0;
+ return NL_SKIP;
+}
+
+int WifiCommand::error_handler(struct sockaddr_nl *nla, struct nlmsgerr *err, void *arg) {
+ int *ret = (int *)arg;
+ *ret = err->error;
+
+ // ALOGD("error_handler received : %d", err->error);
+ return NL_SKIP;
+}
diff --git a/synadhd/wifi_hal/cpp_bindings.h b/synadhd/wifi_hal/cpp_bindings.h
new file mode 100755
index 0000000..8b5600a
--- /dev/null
+++ b/synadhd/wifi_hal/cpp_bindings.h
@@ -0,0 +1,384 @@
+/*
+ * Copyright (C) 2017 The Android Open Source Project
+ *
+ * Portions copyright (C) 2017 Broadcom Limited
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "wifi_hal.h"
+#include "common.h"
+#include "sync.h"
+
+class WifiEvent
+{
+ /* TODO: remove this when nl headers are updated */
+ static const unsigned NL80211_ATTR_MAX_INTERNAL = 256;
+private:
+ struct nl_msg *mMsg;
+ struct genlmsghdr *mHeader;
+ struct nlattr *mAttributes[NL80211_ATTR_MAX_INTERNAL + 1];
+
+public:
+ WifiEvent(nl_msg *msg) {
+ mMsg = msg;
+ mHeader = NULL;
+ memset(mAttributes, 0, sizeof(mAttributes));
+ }
+ ~WifiEvent() {
+ /* don't destroy mMsg; it doesn't belong to us */
+ }
+
+ void log();
+
+ int parse();
+
+ genlmsghdr *header() {
+ return mHeader;
+ }
+
+ int get_cmd() {
+ return mHeader->cmd;
+ }
+
+ int get_vendor_id() {
+ return get_u32(NL80211_ATTR_VENDOR_ID);
+ }
+
+ int get_vendor_subcmd() {
+ return get_u32(NL80211_ATTR_VENDOR_SUBCMD);
+ }
+
+ void *get_vendor_data() {
+ return get_data(NL80211_ATTR_VENDOR_DATA);
+ }
+
+ int get_vendor_data_len() {
+ return get_len(NL80211_ATTR_VENDOR_DATA);
+ }
+
+ const char *get_cmdString();
+
+ nlattr ** attributes() {
+ return mAttributes;
+ }
+
+ nlattr *get_attribute(int attribute) {
+ return mAttributes[attribute];
+ }
+
+ uint8_t get_u8(int attribute) {
+ return mAttributes[attribute] ? nla_get_u8(mAttributes[attribute]) : 0;
+ }
+
+ uint16_t get_u16(int attribute) {
+ return mAttributes[attribute] ? nla_get_u16(mAttributes[attribute]) : 0;
+ }
+
+ uint32_t get_u32(int attribute) {
+ return mAttributes[attribute] ? nla_get_u32(mAttributes[attribute]) : 0;
+ }
+
+ uint64_t get_u64(int attribute) {
+ return mAttributes[attribute] ? nla_get_u64(mAttributes[attribute]) : 0;
+ }
+
+ int get_len(int attribute) {
+ return mAttributes[attribute] ? nla_len(mAttributes[attribute]) : 0;
+ }
+
+ void *get_data(int attribute) {
+ return mAttributes[attribute] ? nla_data(mAttributes[attribute]) : NULL;
+ }
+
+ void *get_string(int attribute) {
+ return mAttributes[attribute] ? nla_get_string(mAttributes[attribute]) : NULL;
+ }
+private:
+ WifiEvent(const WifiEvent&); // hide copy constructor to prevent copies
+};
+
+class nl_iterator {
+ struct nlattr *pos;
+ int rem;
+public:
+ nl_iterator(struct nlattr *attr) {
+ pos = (struct nlattr *)nla_data(attr);
+ rem = nla_len(attr);
+ }
+ bool has_next() {
+ return nla_ok(pos, rem);
+ }
+ void next() {
+ pos = (struct nlattr *)nla_next(pos, &(rem));
+ }
+ struct nlattr *get() {
+ return pos;
+ }
+ uint16_t get_type() {
+ return nla_type(pos);
+ }
+ uint8_t get_u8() {
+ return nla_get_u8(pos);
+ }
+ uint16_t get_u16() {
+ return nla_get_u16(pos);
+ }
+ uint32_t get_u32() {
+ return nla_get_u32(pos);
+ }
+ uint64_t get_u64() {
+ return nla_get_u64(pos);
+ }
+ void* get_data() {
+ return nla_data(pos);
+ }
+ int get_len() {
+ return nla_len(pos);
+ }
+ void* get_string() {
+ return nla_get_string(pos);
+ }
+private:
+ nl_iterator(const nl_iterator&); // hide copy constructor to prevent copies
+};
+
+class WifiRequest
+{
+private:
+ int mFamily;
+ int mIface;
+ struct nl_msg *mMsg;
+
+public:
+ WifiRequest(int family) {
+ mMsg = NULL;
+ mFamily = family;
+ mIface = -1;
+ }
+
+ WifiRequest(int family, int iface) {
+ mMsg = NULL;
+ mFamily = family;
+ mIface = iface;
+ }
+
+ ~WifiRequest() {
+ destroy();
+ }
+
+ void destroy() {
+ if (mMsg) {
+ nlmsg_free(mMsg);
+ mMsg = NULL;
+ }
+ }
+
+ nl_msg *getMessage() {
+ return mMsg;
+ }
+
+ /* Command assembly helpers */
+ int create(int family, uint8_t cmd, int flags, int hdrlen);
+ int create(uint8_t cmd) {
+ return create(mFamily, cmd, 0, 0);
+ }
+
+ int create(uint32_t id, int subcmd);
+
+ int put(int attribute, void *ptr, unsigned len) {
+ return nla_put(mMsg, attribute, len, ptr);
+ }
+ int put_s8(int attribute, int8_t value) {
+ return nla_put(mMsg, attribute, sizeof(value), &value);
+ }
+ int put_u8(int attribute, uint8_t value) {
+ return nla_put(mMsg, attribute, sizeof(value), &value);
+ }
+ int put_u16(int attribute, uint16_t value) {
+ return nla_put(mMsg, attribute, sizeof(value), &value);
+ }
+ int put_u32(int attribute, uint32_t value) {
+ return nla_put(mMsg, attribute, sizeof(value), &value);
+ }
+ int put_u64(int attribute, uint64_t value) {
+ return nla_put(mMsg, attribute, sizeof(value), &value);
+ }
+ int put_string(int attribute, const char *value) {
+ return nla_put(mMsg, attribute, strlen(value) + 1, value);
+ }
+ int put_addr(int attribute, mac_addr value) {
+ return nla_put(mMsg, attribute, sizeof(mac_addr), value);
+ }
+
+ struct nlattr * attr_start(int attribute) {
+ return nla_nest_start(mMsg, attribute);
+ }
+ void attr_end(struct nlattr *attr) {
+ nla_nest_end(mMsg, attr);
+ }
+
+ int set_iface_id(int ifindex) {
+ return put_u32(NL80211_ATTR_IFINDEX, ifindex);
+ }
+private:
+ WifiRequest(const WifiRequest&); // hide copy constructor to prevent copies
+
+};
+
+class WifiCommand
+{
+protected:
+ const char *mType;
+ hal_info *mInfo;
+ WifiRequest mMsg;
+ Condition mCondition;
+ wifi_request_id mId;
+ interface_info *mIfaceInfo;
+ int mRefs;
+public:
+ WifiCommand(const char *type, wifi_handle handle, wifi_request_id id)
+ : mType(type), mMsg(getHalInfo(handle)->nl80211_family_id), mId(id), mRefs(1)
+ {
+ mIfaceInfo = NULL;
+ mInfo = getHalInfo(handle);
+ // ALOGD("WifiCommand %p created, mInfo = %p, mIfaceInfo = %p", this, mInfo, mIfaceInfo);
+ }
+
+ WifiCommand(const char *type, wifi_interface_handle iface, wifi_request_id id)
+ : mType(type), mMsg(getHalInfo(iface)->nl80211_family_id, getIfaceInfo(iface)->id),
+ mId(id), mRefs(1)
+ {
+ mIfaceInfo = getIfaceInfo(iface);
+ mInfo = getHalInfo(iface);
+ // ALOGD("WifiCommand %p created, mInfo = %p, mIfaceInfo = %p", this, mInfo, mIfaceInfo);
+ }
+
+ virtual ~WifiCommand() {
+ // ALOGD("WifiCommand %p destroyed", this);
+ }
+
+ wifi_request_id id() {
+ return mId;
+ }
+
+ const char *getType() {
+ return mType;
+ }
+
+ virtual void addRef() {
+ int refs = __sync_add_and_fetch(&mRefs, 1);
+ ALOGV("addRef: WifiCommand %p has %d references", this, refs);
+ }
+
+ virtual void releaseRef() {
+ int refs = __sync_sub_and_fetch(&mRefs, 1);
+ if (refs == 0) {
+ delete this;
+ } else {
+ // ALOGD("releaseRef: WifiCommand %p has %d references", this, refs);
+ }
+ }
+
+ virtual int create() {
+ /* by default there is no way to cancel */
+ ALOGD("WifiCommand %p can't be created", this);
+ return WIFI_ERROR_NOT_SUPPORTED;
+ }
+
+ virtual int cancel() {
+ /* by default there is no way to cancel */
+ return WIFI_ERROR_NOT_SUPPORTED;
+ }
+
+ int requestResponse();
+ int requestEvent(int cmd);
+ int requestVendorEvent(uint32_t id, int subcmd);
+ int requestResponse(WifiRequest& request);
+
+protected:
+ wifi_handle wifiHandle() {
+ return getWifiHandle(mInfo);
+ }
+
+ wifi_interface_handle ifaceHandle() {
+ return getIfaceHandle(mIfaceInfo);
+ }
+
+ int familyId() {
+ return mInfo->nl80211_family_id;
+ }
+
+ int ifaceId() {
+ return mIfaceInfo->id;
+ }
+
+ /* Override this method to parse reply and dig out data; save it in the object */
+ virtual int handleResponse(WifiEvent& reply) {
+ ALOGI("skipping a response");
+ return NL_SKIP;
+ }
+
+ /* Override this method to parse event and dig out data; save it in the object */
+ virtual int handleEvent(WifiEvent& event) {
+ ALOGI("skipping an event");
+ return NL_SKIP;
+ }
+
+ int registerHandler(int cmd) {
+ return wifi_register_handler(wifiHandle(), cmd, &event_handler, this);
+ }
+
+ void unregisterHandler(int cmd) {
+ wifi_unregister_handler(wifiHandle(), cmd);
+ }
+
+ int registerVendorHandler(uint32_t id, int subcmd) {
+ return wifi_register_vendor_handler(wifiHandle(), id, subcmd, &event_handler, this);
+ }
+
+ void unregisterVendorHandlerWithoutLock(uint32_t id, int subcmd) {
+ wifi_unregister_vendor_handler_without_lock(wifiHandle(), id, subcmd);
+ }
+
+ void unregisterVendorHandler(uint32_t id, int subcmd) {
+ wifi_unregister_vendor_handler(wifiHandle(), id, subcmd);
+ }
+
+private:
+ WifiCommand(const WifiCommand& ); // hide copy constructor to prevent copies
+
+ /* Event handling */
+ static int response_handler(struct nl_msg *msg, void *arg);
+
+ static int event_handler(struct nl_msg *msg, void *arg);
+
+ /* Other event handlers */
+ static int valid_handler(struct nl_msg *msg, void *arg);
+
+ static int ack_handler(struct nl_msg *msg, void *arg);
+
+ static int finish_handler(struct nl_msg *msg, void *arg);
+
+ static int error_handler(struct sockaddr_nl *nla, struct nlmsgerr *err, void *arg);
+};
+
+/* nl message processing macros (required to pass C++ type checks) */
+
+#define for_each_attr(pos, nla, rem) \
+ for (pos = (nlattr *)nla_data(nla), rem = nla_len(nla); \
+ nla_ok(pos, rem); \
+ pos = (nlattr *)nla_next(pos, &(rem)))
+
+extern void InitResponseLock();
+extern void DestroyResponseLock();
diff --git a/synadhd/wifi_hal/gscan.cpp b/synadhd/wifi_hal/gscan.cpp
new file mode 100755
index 0000000..16772ff
--- /dev/null
+++ b/synadhd/wifi_hal/gscan.cpp
@@ -0,0 +1,2010 @@
+/*
+ * Copyright (C) 2017 The Android Open Source Project
+ *
+ * Portions copyright (C) 2017 Broadcom Limited
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <stdint.h>
+#include <fcntl.h>
+#include <sys/socket.h>
+#include <netlink/genl/genl.h>
+#include <netlink/genl/family.h>
+#include <netlink/genl/ctrl.h>
+#include <linux/rtnetlink.h>
+#include <netpacket/packet.h>
+#include <linux/filter.h>
+#include <linux/errqueue.h>
+
+#include <linux/pkt_sched.h>
+#include <netlink/object-api.h>
+#include <netlink/netlink.h>
+#include <netlink/socket.h>
+#include <netlink/handlers.h>
+
+#include "sync.h"
+
+#define LOG_TAG "WifiHAL"
+//#define LOG_NDEBUG 0 //uncomment to enable verbose logging
+
+#include <log/log.h>
+
+#include "wifi_hal.h"
+#include "common.h"
+#include "cpp_bindings.h"
+
+typedef enum {
+
+ GSCAN_ATTRIBUTE_NUM_BUCKETS = 10,
+ GSCAN_ATTRIBUTE_BASE_PERIOD,
+ GSCAN_ATTRIBUTE_BUCKETS_BAND,
+ GSCAN_ATTRIBUTE_BUCKET_ID,
+ GSCAN_ATTRIBUTE_BUCKET_PERIOD,
+ GSCAN_ATTRIBUTE_BUCKET_NUM_CHANNELS,
+ GSCAN_ATTRIBUTE_BUCKET_CHANNELS,
+ GSCAN_ATTRIBUTE_NUM_AP_PER_SCAN,
+ GSCAN_ATTRIBUTE_REPORT_THRESHOLD,
+ GSCAN_ATTRIBUTE_NUM_SCANS_TO_CACHE,
+ GSCAN_ATTRIBUTE_BAND = GSCAN_ATTRIBUTE_BUCKETS_BAND,
+
+ GSCAN_ATTRIBUTE_ENABLE_FEATURE = 20,
+ GSCAN_ATTRIBUTE_SCAN_RESULTS_COMPLETE, /* indicates no more results */
+ GSCAN_ATTRIBUTE_FLUSH_FEATURE, /* Flush all the configs */
+ GSCAN_ENABLE_FULL_SCAN_RESULTS,
+ GSCAN_ATTRIBUTE_REPORT_EVENTS,
+
+ /* remaining reserved for additional attributes */
+ GSCAN_ATTRIBUTE_NUM_OF_RESULTS = 30,
+ GSCAN_ATTRIBUTE_FLUSH_RESULTS,
+ GSCAN_ATTRIBUTE_SCAN_RESULTS, /* flat array of wifi_scan_result */
+ GSCAN_ATTRIBUTE_SCAN_ID, /* indicates scan number */
+ GSCAN_ATTRIBUTE_SCAN_FLAGS, /* indicates if scan was aborted */
+ GSCAN_ATTRIBUTE_AP_FLAGS, /* flags on significant change event */
+ GSCAN_ATTRIBUTE_NUM_CHANNELS,
+ GSCAN_ATTRIBUTE_CHANNEL_LIST,
+ GSCAN_ATTRIBUTE_CH_BUCKET_BITMASK,
+ /* remaining reserved for additional attributes */
+
+ GSCAN_ATTRIBUTE_SSID = 40,
+ GSCAN_ATTRIBUTE_BSSID,
+ GSCAN_ATTRIBUTE_CHANNEL,
+ GSCAN_ATTRIBUTE_RSSI,
+ GSCAN_ATTRIBUTE_TIMESTAMP,
+ GSCAN_ATTRIBUTE_RTT,
+ GSCAN_ATTRIBUTE_RTTSD,
+
+ /* remaining reserved for additional attributes */
+
+ GSCAN_ATTRIBUTE_HOTLIST_BSSIDS = 50,
+ GSCAN_ATTRIBUTE_RSSI_LOW,
+ GSCAN_ATTRIBUTE_RSSI_HIGH,
+ GSCAN_ATTRIBUTE_HOTLIST_ELEM,
+ GSCAN_ATTRIBUTE_HOTLIST_FLUSH,
+ GSCAN_ATTRIBUTE_HOTLIST_BSSID_COUNT,
+
+ /* remaining reserved for additional attributes */
+ GSCAN_ATTRIBUTE_RSSI_SAMPLE_SIZE = 60,
+ GSCAN_ATTRIBUTE_LOST_AP_SAMPLE_SIZE,
+ GSCAN_ATTRIBUTE_MIN_BREACHING,
+ GSCAN_ATTRIBUTE_SIGNIFICANT_CHANGE_BSSIDS,
+ GSCAN_ATTRIBUTE_SIGNIFICANT_CHANGE_FLUSH,
+
+ /* EPNO */
+ GSCAN_ATTRIBUTE_EPNO_SSID_LIST = 70,
+ GSCAN_ATTRIBUTE_EPNO_SSID,
+ GSCAN_ATTRIBUTE_EPNO_SSID_LEN,
+ GSCAN_ATTRIBUTE_EPNO_RSSI,
+ GSCAN_ATTRIBUTE_EPNO_FLAGS,
+ GSCAN_ATTRIBUTE_EPNO_AUTH,
+ GSCAN_ATTRIBUTE_EPNO_SSID_NUM,
+ GSCAN_ATTRIBUTE_EPNO_FLUSH,
+
+ /* remaining reserved for additional attributes */
+
+ GSCAN_ATTRIBUTE_WHITELIST_SSID = 80,
+ GSCAN_ATTRIBUTE_NUM_WL_SSID,
+ GSCAN_ATTRIBUTE_WL_SSID_LEN,
+ GSCAN_ATTRIBUTE_WL_SSID_FLUSH,
+ GSCAN_ATTRIBUTE_WHITELIST_SSID_ELEM,
+ GSCAN_ATTRIBUTE_NUM_BSSID,
+ GSCAN_ATTRIBUTE_BSSID_PREF_LIST,
+ GSCAN_ATTRIBUTE_BSSID_PREF_FLUSH,
+ GSCAN_ATTRIBUTE_BSSID_PREF,
+ GSCAN_ATTRIBUTE_RSSI_MODIFIER,
+
+ /* remaining reserved for additional attributes */
+
+ GSCAN_ATTRIBUTE_A_BAND_BOOST_THRESHOLD = 90,
+ GSCAN_ATTRIBUTE_A_BAND_PENALTY_THRESHOLD,
+ GSCAN_ATTRIBUTE_A_BAND_BOOST_FACTOR,
+ GSCAN_ATTRIBUTE_A_BAND_PENALTY_FACTOR,
+ GSCAN_ATTRIBUTE_A_BAND_MAX_BOOST,
+ GSCAN_ATTRIBUTE_LAZY_ROAM_HYSTERESIS,
+ GSCAN_ATTRIBUTE_ALERT_ROAM_RSSI_TRIGGER,
+ GSCAN_ATTRIBUTE_LAZY_ROAM_ENABLE,
+
+ /* BSSID blacklist */
+ GSCAN_ATTRIBUTE_BSSID_BLACKLIST_FLUSH = 100,
+ GSCAN_ATTRIBUTE_BLACKLIST_BSSID,
+
+ /* ANQPO */
+ GSCAN_ATTRIBUTE_ANQPO_HS_LIST = 110,
+ GSCAN_ATTRIBUTE_ANQPO_HS_LIST_SIZE,
+ GSCAN_ATTRIBUTE_ANQPO_HS_NETWORK_ID,
+ GSCAN_ATTRIBUTE_ANQPO_HS_NAI_REALM,
+ GSCAN_ATTRIBUTE_ANQPO_HS_ROAM_CONSORTIUM_ID,
+ GSCAN_ATTRIBUTE_ANQPO_HS_PLMN,
+
+ /* Adaptive scan attributes */
+ GSCAN_ATTRIBUTE_BUCKET_STEP_COUNT = 120,
+ GSCAN_ATTRIBUTE_BUCKET_MAX_PERIOD,
+
+ /* ePNO cfg */
+ GSCAN_ATTRIBUTE_EPNO_5G_RSSI_THR = 130,
+ GSCAN_ATTRIBUTE_EPNO_2G_RSSI_THR,
+ GSCAN_ATTRIBUTE_EPNO_INIT_SCORE_MAX,
+ GSCAN_ATTRIBUTE_EPNO_CUR_CONN_BONUS,
+ GSCAN_ATTRIBUTE_EPNO_SAME_NETWORK_BONUS,
+ GSCAN_ATTRIBUTE_EPNO_SECURE_BONUS,
+ GSCAN_ATTRIBUTE_EPNO_5G_BONUS,
+
+ /* Roaming features */
+ GSCAN_ATTRIBUTE_ROAM_STATE_SET = 140,
+ GSCAN_ATTRIBUTE_MAX
+
+} GSCAN_ATTRIBUTE;
+
+typedef struct {
+ int num_bssid; // number of blacklisted BSSIDs
+ mac_addr bssids[MAX_BLACKLIST_BSSID]; // blacklisted BSSIDs
+} wifi_bssid_params;
+
+// helper methods
+wifi_error wifi_enable_full_scan_results(wifi_request_id id, wifi_interface_handle iface,
+ wifi_scan_result_handler handler);
+wifi_error wifi_disable_full_scan_results(wifi_request_id id, wifi_interface_handle iface);
+int wifi_handle_full_scan_event(wifi_request_id id, WifiEvent& event,
+ wifi_scan_result_handler handler);
+void convert_to_hal_result(wifi_scan_result *to, wifi_gscan_result_t *from);
+
+
+void convert_to_hal_result(wifi_scan_result *to, wifi_gscan_result_t *from)
+{
+ to->ts = from->ts;
+ to->channel = from->channel;
+ to->rssi = from->rssi;
+ to->rtt = from->rtt;
+ to->rtt_sd = from->rtt_sd;
+ to->beacon_period = from->beacon_period;
+ to->capability = from->capability;
+ memcpy(to->ssid, from->ssid, (DOT11_MAX_SSID_LEN+1));
+ memcpy(&to->bssid, &from->bssid, sizeof(mac_addr));
+}
+
+/////////////////////////////////////////////////////////////////////////////
+
+class GetCapabilitiesCommand : public WifiCommand
+{
+ void *mCapabilities;
+ uint16_t mRequesttype;
+ int mRequestsize;
+ public:
+ GetCapabilitiesCommand(wifi_interface_handle iface, void *capabitlites, uint16_t request_type,
+ int request_size)
+ : WifiCommand("GetGscanCapabilitiesCommand", iface, 0), mCapabilities(capabitlites), mRequesttype(request_type),
+ mRequestsize(request_size)
+ {
+ memset(mCapabilities, 0, mRequestsize);
+ }
+
+ virtual int create() {
+ ALOGV("Creating message to get scan capabilities; iface = %d", mIfaceInfo->id);
+
+ int ret = mMsg.create(GOOGLE_OUI, mRequesttype);
+ if (ret < 0) {
+ return ret;
+ }
+
+ return ret;
+ }
+
+ protected:
+ virtual int handleResponse(WifiEvent& reply) {
+
+ ALOGV("In GetCapabilities::handleResponse");
+
+ if (reply.get_cmd() != NL80211_CMD_VENDOR) {
+ ALOGD("Ignoring reply with cmd = %d", reply.get_cmd());
+ return NL_SKIP;
+ }
+
+ int id = reply.get_vendor_id();
+ int subcmd = reply.get_vendor_subcmd();
+
+ void *data = reply.get_vendor_data();
+ int len = reply.get_vendor_data_len();
+
+ ALOGV("Id = %0x, subcmd = 0x%x, len = %d, expected len = %d", id, subcmd, len,
+ mRequestsize);
+
+ memcpy(mCapabilities, data, min(len, mRequestsize));
+
+ return NL_OK;
+ }
+};
+
+wifi_error wifi_get_gscan_capabilities(wifi_interface_handle handle,
+ wifi_gscan_capabilities *capabilities)
+{
+ GetCapabilitiesCommand command(handle, capabilities, GSCAN_SUBCMD_GET_CAPABILITIES,
+ (int)sizeof(wifi_gscan_capabilities));
+ return (wifi_error) command.requestResponse();
+}
+
+/* Function to get chipset supported roaming capabilities */
+wifi_error wifi_get_roaming_capabilities(wifi_interface_handle handle,
+ wifi_roaming_capabilities *capabilities)
+{
+ GetCapabilitiesCommand command(handle, capabilities, WIFI_SUBCMD_ROAM_CAPABILITY,
+ (int)sizeof(wifi_roaming_capabilities));
+ return (wifi_error) command.requestResponse();
+}
+
+class GetChannelListCommand : public WifiCommand
+{
+ wifi_channel *channels;
+ int max_channels;
+ int *num_channels;
+ int band;
+public:
+ GetChannelListCommand(wifi_interface_handle iface, wifi_channel *channel_buf, int *ch_num,
+ int num_max_ch, int band)
+ : WifiCommand("GetChannelListCommand", iface, 0), channels(channel_buf),
+ max_channels(num_max_ch), num_channels(ch_num), band(band)
+ {
+ memset(channels, 0, sizeof(wifi_channel) * max_channels);
+ }
+ virtual int create() {
+ ALOGV("Creating message to get channel list; iface = %d", mIfaceInfo->id);
+
+ int ret = mMsg.create(GOOGLE_OUI, GSCAN_SUBCMD_GET_CHANNEL_LIST);
+ if (ret < 0) {
+ return ret;
+ }
+
+ nlattr *data = mMsg.attr_start(NL80211_ATTR_VENDOR_DATA);
+ ret = mMsg.put_u32(GSCAN_ATTRIBUTE_BAND, band);
+ if (ret < 0) {
+ return ret;
+ }
+
+ mMsg.attr_end(data);
+
+ return ret;
+ }
+
+protected:
+ virtual int handleResponse(WifiEvent& reply) {
+
+ ALOGV("In GetChannelList::handleResponse");
+
+ if (reply.get_cmd() != NL80211_CMD_VENDOR) {
+ ALOGD("Ignoring reply with cmd = %d", reply.get_cmd());
+ return NL_SKIP;
+ }
+
+ int id = reply.get_vendor_id();
+ int subcmd = reply.get_vendor_subcmd();
+ int num_channels_to_copy = 0;
+
+ nlattr *vendor_data = reply.get_attribute(NL80211_ATTR_VENDOR_DATA);
+ int len = reply.get_vendor_data_len();
+
+ ALOGV("Id = %0x, subcmd = %d, len = %d", id, subcmd, len);
+ if (vendor_data == NULL || len == 0) {
+ ALOGE("no vendor data in GetChannelList response; ignoring it");
+ return NL_SKIP;
+ }
+
+ for (nl_iterator it(vendor_data); it.has_next(); it.next()) {
+ if (it.get_type() == GSCAN_ATTRIBUTE_NUM_CHANNELS) {
+ num_channels_to_copy = it.get_u32();
+ ALOGI("Got channel list with %d channels", num_channels_to_copy);
+ if(num_channels_to_copy > max_channels)
+ num_channels_to_copy = max_channels;
+ *num_channels = num_channels_to_copy;
+ } else if (it.get_type() == GSCAN_ATTRIBUTE_CHANNEL_LIST && num_channels_to_copy) {
+ memcpy(channels, it.get_data(), sizeof(int) * num_channels_to_copy);
+ } else {
+ ALOGW("Ignoring invalid attribute type = %d, size = %d",
+ it.get_type(), it.get_len());
+ }
+ }
+
+ return NL_OK;
+ }
+};
+
+wifi_error wifi_get_valid_channels(wifi_interface_handle handle,
+ int band, int max_channels, wifi_channel *channels, int *num_channels)
+{
+ GetChannelListCommand command(handle, channels, num_channels,
+ max_channels, band);
+ return (wifi_error) command.requestResponse();
+}
+/////////////////////////////////////////////////////////////////////////////
+
+/* helper functions */
+int createFeatureRequest(WifiRequest& request, int subcmd, int enable) {
+
+ int result = request.create(GOOGLE_OUI, subcmd);
+ if (result < 0) {
+ return result;
+ }
+
+ nlattr *data = request.attr_start(NL80211_ATTR_VENDOR_DATA);
+ result = request.put_u32(GSCAN_ATTRIBUTE_ENABLE_FEATURE, enable);
+ if (result < 0) {
+ return result;
+ }
+
+ request.attr_end(data);
+ return WIFI_SUCCESS;
+}
+
+/////////////////////////////////////////////////////////////////////////////
+class FullScanResultsCommand : public WifiCommand
+{
+ int *mParams;
+ wifi_scan_result_handler mHandler;
+public:
+ FullScanResultsCommand(wifi_interface_handle iface, int id, int *params,
+ wifi_scan_result_handler handler)
+ : WifiCommand("FullScanResultsCommand", iface, id), mParams(params), mHandler(handler)
+ {*mParams = 0;}
+
+ int createRequest(WifiRequest& request, int subcmd, int enable) {
+ int result = request.create(GOOGLE_OUI, subcmd);
+ if (result < 0) {
+ return result;
+ }
+
+ nlattr *data = request.attr_start(NL80211_ATTR_VENDOR_DATA);
+ result = request.put_u32(GSCAN_ENABLE_FULL_SCAN_RESULTS, enable);
+ if (result < 0) {
+ return result;
+ }
+
+ request.attr_end(data);
+ return WIFI_SUCCESS;
+
+ }
+
+ int start() {
+ ALOGV("Enabling Full scan results");
+ WifiRequest request(familyId(), ifaceId());
+ int result = createRequest(request, GSCAN_SUBCMD_ENABLE_FULL_SCAN_RESULTS, 1);
+ if (result != WIFI_SUCCESS) {
+ ALOGE("failed to create request; result = %d", result);
+ return result;
+ }
+
+ registerVendorHandler(GOOGLE_OUI, GSCAN_EVENT_FULL_SCAN_RESULTS);
+
+ result = requestResponse(request);
+ if (result != WIFI_SUCCESS) {
+ unregisterVendorHandler(GOOGLE_OUI, GSCAN_EVENT_FULL_SCAN_RESULTS);
+ ALOGE("failed to enable full scan results; result = %d", result);
+ return result;
+ }
+
+ return result;
+ }
+
+ virtual int cancel() {
+ ALOGV("Disabling Full scan results");
+
+ WifiRequest request(familyId(), ifaceId());
+ int result = createRequest(request, GSCAN_SUBCMD_ENABLE_FULL_SCAN_RESULTS, 0);
+ if (result != WIFI_SUCCESS) {
+ ALOGE("failed to create request; result = %d", result);
+ } else {
+ result = requestResponse(request);
+ if (result != WIFI_SUCCESS) {
+ ALOGE("failed to disable full scan results;result = %d", result);
+ }
+ }
+
+ unregisterVendorHandler(GOOGLE_OUI, GSCAN_EVENT_FULL_SCAN_RESULTS);
+ return WIFI_SUCCESS;
+ }
+
+ virtual int handleResponse(WifiEvent& reply) {
+ ALOGD("Request complete!");
+ /* Nothing to do on response! */
+ return NL_SKIP;
+ }
+
+ virtual int handleEvent(WifiEvent& event) {
+ ALOGV("Full scan results: Got an event");
+ return wifi_handle_full_scan_event(id(), event, mHandler);
+ }
+
+};
+/////////////////////////////////////////////////////////////////////////////
+
+class ScanCommand : public WifiCommand
+{
+ wifi_scan_cmd_params *mParams;
+ wifi_scan_result_handler mHandler;
+public:
+ ScanCommand(wifi_interface_handle iface, int id, wifi_scan_cmd_params *params,
+ wifi_scan_result_handler handler)
+ : WifiCommand("ScanCommand", iface, id), mParams(params), mHandler(handler)
+ { }
+
+ int createSetupRequest(WifiRequest& request) {
+ int result = request.create(GOOGLE_OUI, GSCAN_SUBCMD_SET_CONFIG);
+ if (result < 0) {
+ return result;
+ }
+
+ nlattr *data = request.attr_start(NL80211_ATTR_VENDOR_DATA);
+ result = request.put_u32(GSCAN_ATTRIBUTE_BASE_PERIOD, mParams->base_period);
+ if (result < 0) {
+ return result;
+ }
+
+ result = request.put_u32(GSCAN_ATTRIBUTE_NUM_BUCKETS, mParams->num_buckets);
+ if (result < 0) {
+ return result;
+ }
+
+ for (int i = 0; i < mParams->num_buckets; i++) {
+ nlattr * bucket = request.attr_start(i); // next bucket
+ result = request.put_u32(GSCAN_ATTRIBUTE_BUCKET_ID, mParams->buckets[i].bucket);
+ if (result < 0) {
+ return result;
+ }
+ result = request.put_u32(GSCAN_ATTRIBUTE_BUCKET_PERIOD, mParams->buckets[i].period);
+ if (result < 0) {
+ return result;
+ }
+ result = request.put_u32(GSCAN_ATTRIBUTE_BUCKETS_BAND,
+ mParams->buckets[i].band);
+ if (result < 0) {
+ return result;
+ }
+ result = request.put_u32(GSCAN_ATTRIBUTE_BUCKET_STEP_COUNT,
+ mParams->buckets[i].step_count);
+ if (result < 0) {
+ return result;
+ }
+ result = request.put_u32(GSCAN_ATTRIBUTE_BUCKET_MAX_PERIOD,
+ mParams->buckets[i].max_period);
+ if (result < 0) {
+ return result;
+ }
+ result = request.put_u32(GSCAN_ATTRIBUTE_REPORT_EVENTS,
+ mParams->buckets[i].report_events);
+ if (result < 0) {
+ return result;
+ }
+
+ result = request.put_u32(GSCAN_ATTRIBUTE_BUCKET_NUM_CHANNELS,
+ mParams->buckets[i].num_channels);
+ if (result < 0) {
+ return result;
+ }
+
+ if (mParams->buckets[i].num_channels) {
+ nlattr *channels = request.attr_start(GSCAN_ATTRIBUTE_BUCKET_CHANNELS);
+ ALOGV(" channels: ");
+ for (int j = 0; j < mParams->buckets[i].num_channels; j++) {
+ result = request.put_u32(j, mParams->buckets[i].channels[j].channel);
+ ALOGV(" %u", mParams->buckets[i].channels[j].channel);
+
+ if (result < 0) {
+ return result;
+ }
+ }
+ request.attr_end(channels);
+ }
+
+ request.attr_end(bucket);
+ }
+
+ request.attr_end(data);
+ return WIFI_SUCCESS;
+ }
+
+ int createScanConfigRequest(WifiRequest& request) {
+ int result = request.create(GOOGLE_OUI, GSCAN_SUBCMD_SET_SCAN_CONFIG);
+ if (result < 0) {
+ return result;
+ }
+
+ nlattr *data = request.attr_start(NL80211_ATTR_VENDOR_DATA);
+ result = request.put_u32(GSCAN_ATTRIBUTE_NUM_AP_PER_SCAN, mParams->max_ap_per_scan);
+ if (result < 0) {
+ return result;
+ }
+
+ result = request.put_u32(GSCAN_ATTRIBUTE_REPORT_THRESHOLD,
+ mParams->report_threshold_percent);
+ if (result < 0) {
+ return result;
+ }
+
+ int num_scans = mParams->report_threshold_num_scans;
+
+ result = request.put_u32(GSCAN_ATTRIBUTE_NUM_SCANS_TO_CACHE, num_scans);
+ if (result < 0) {
+ return result;
+ }
+
+ request.attr_end(data);
+ return WIFI_SUCCESS;
+ }
+
+ int createStartRequest(WifiRequest& request) {
+ return createFeatureRequest(request, GSCAN_SUBCMD_ENABLE_GSCAN, 1);
+ }
+
+ int createStopRequest(WifiRequest& request) {
+ return createFeatureRequest(request, GSCAN_SUBCMD_ENABLE_GSCAN, 0);
+ }
+
+ void unregisterVendorHandlerAll() {
+ unregisterVendorHandler(GOOGLE_OUI, GSCAN_EVENT_COMPLETE_SCAN);
+ unregisterVendorHandler(GOOGLE_OUI, GSCAN_EVENT_SCAN_RESULTS_AVAILABLE);
+ unregisterVendorHandler(GOOGLE_OUI, GSCAN_EVENT_FULL_SCAN_RESULTS);
+ }
+
+ int start() {
+ ALOGV("GSCAN start");
+ WifiRequest request(familyId(), ifaceId());
+ int result = createSetupRequest(request);
+ if (result != WIFI_SUCCESS) {
+ ALOGE("failed to create setup request; result = %d", result);
+ return result;
+ }
+
+ registerVendorHandler(GOOGLE_OUI, GSCAN_EVENT_SCAN_RESULTS_AVAILABLE);
+ registerVendorHandler(GOOGLE_OUI, GSCAN_EVENT_COMPLETE_SCAN);
+ registerVendorHandler(GOOGLE_OUI, GSCAN_EVENT_FULL_SCAN_RESULTS);
+
+ result = requestResponse(request);
+ if (result != WIFI_SUCCESS) {
+ unregisterVendorHandlerAll();
+ ALOGE("failed to configure setup; result = %d", result);
+ return result;
+ }
+
+ request.destroy();
+
+ result = createScanConfigRequest(request);
+ if (result != WIFI_SUCCESS) {
+ unregisterVendorHandlerAll();
+ ALOGE("failed to create scan config request; result = %d", result);
+ return result;
+ }
+
+ result = requestResponse(request);
+ if (result != WIFI_SUCCESS) {
+ unregisterVendorHandlerAll();
+ ALOGE("failed to configure scan; result = %d", result);
+ return result;
+ }
+
+ ALOGV(" ....starting scan");
+
+ result = createStartRequest(request);
+ if (result != WIFI_SUCCESS) {
+ unregisterVendorHandlerAll();
+ ALOGE("failed to create start request; result = %d", result);
+ return result;
+ }
+
+ result = requestResponse(request);
+ if (result != WIFI_SUCCESS) {
+ unregisterVendorHandlerAll();
+ ALOGE("failed to start scan; result = %d", result);
+ return result;
+ }
+ return result;
+ }
+
+ virtual int cancel() {
+ ALOGV("Stopping scan");
+
+ WifiRequest request(familyId(), ifaceId());
+ int result = createStopRequest(request);
+ if (result != WIFI_SUCCESS) {
+ ALOGE("failed to create stop request; result = %d", result);
+ } else {
+ result = requestResponse(request);
+ if (result != WIFI_SUCCESS) {
+ ALOGE("failed to stop scan; result = %d", result);
+ }
+ }
+
+ unregisterVendorHandlerAll();
+ return WIFI_SUCCESS;
+ }
+
+ virtual int handleResponse(WifiEvent& reply) {
+ /* Nothing to do on response! */
+ return NL_SKIP;
+ }
+
+ virtual int handleEvent(WifiEvent& event) {
+ ALOGV("Got a scan results event");
+ //event.log();
+
+ nlattr *vendor_data = event.get_attribute(NL80211_ATTR_VENDOR_DATA);
+ int len = event.get_vendor_data_len();
+ int event_id = event.get_vendor_subcmd();
+
+ if ((event_id == GSCAN_EVENT_COMPLETE_SCAN) ||
+ (event_id == GSCAN_EVENT_SCAN_RESULTS_AVAILABLE)) {
+ if (vendor_data == NULL || len != 4) {
+ ALOGI("Bad event data!");
+ return NL_SKIP;
+ }
+ wifi_scan_event evt_type;
+ evt_type = (wifi_scan_event) event.get_u32(NL80211_ATTR_VENDOR_DATA);
+ ALOGV("Received event type %d", evt_type);
+ if(*mHandler.on_scan_event)
+ (*mHandler.on_scan_event)(id(), evt_type);
+ } else if (event_id == GSCAN_EVENT_FULL_SCAN_RESULTS) {
+ wifi_handle_full_scan_event(id(), event, mHandler);
+ }
+ return NL_SKIP;
+ }
+};
+
+wifi_error wifi_start_gscan(
+ wifi_request_id id,
+ wifi_interface_handle iface,
+ wifi_scan_cmd_params params,
+ wifi_scan_result_handler handler)
+{
+ wifi_handle handle = getWifiHandle(iface);
+
+ ALOGV("Starting GScan, halHandle = %p", handle);
+
+ ScanCommand *cmd = new ScanCommand(iface, id, &params, handler);
+ NULL_CHECK_RETURN(cmd, "memory allocation failure", WIFI_ERROR_OUT_OF_MEMORY);
+ wifi_error result = wifi_register_cmd(handle, id, cmd);
+ if (result != WIFI_SUCCESS) {
+ cmd->releaseRef();
+ return result;
+ }
+ result = (wifi_error)cmd->start();
+ if (result != WIFI_SUCCESS) {
+ wifi_unregister_cmd(handle, id);
+ cmd->releaseRef();
+ return result;
+ }
+ return result;
+}
+
+wifi_error wifi_stop_gscan(wifi_request_id id, wifi_interface_handle iface)
+{
+ wifi_handle handle = getWifiHandle(iface);
+ ALOGV("Stopping GScan, wifi_request_id = %d, halHandle = %p", id, handle);
+
+ if (id == -1) {
+ wifi_scan_result_handler handler;
+ wifi_scan_cmd_params dummy_params;
+ memset(&handler, 0, sizeof(handler));
+
+ ScanCommand *cmd = new ScanCommand(iface, id, &dummy_params, handler);
+ NULL_CHECK_RETURN(cmd, "memory allocation failure", WIFI_ERROR_OUT_OF_MEMORY);
+ cmd->cancel();
+ cmd->releaseRef();
+ return WIFI_SUCCESS;
+ }
+
+ return wifi_cancel_cmd(id, iface);
+}
+
+wifi_error wifi_enable_full_scan_results(
+ wifi_request_id id,
+ wifi_interface_handle iface,
+ wifi_scan_result_handler handler)
+{
+ wifi_handle handle = getWifiHandle(iface);
+ int params_dummy;
+
+ ALOGV("Enabling full scan results, halHandle = %p", handle);
+
+ FullScanResultsCommand *cmd = new FullScanResultsCommand(iface, id, &params_dummy, handler);
+ NULL_CHECK_RETURN(cmd, "memory allocation failure", WIFI_ERROR_OUT_OF_MEMORY);
+ wifi_error result = wifi_register_cmd(handle, id, cmd);
+ if (result != WIFI_SUCCESS) {
+ cmd->releaseRef();
+ return result;
+ }
+ result = (wifi_error)cmd->start();
+ if (result != WIFI_SUCCESS) {
+ wifi_unregister_cmd(handle, id);
+ cmd->releaseRef();
+ return result;
+ }
+ return result;
+}
+
+int wifi_handle_full_scan_event(
+ wifi_request_id id,
+ WifiEvent& event,
+ wifi_scan_result_handler handler)
+{
+ nlattr *vendor_data = event.get_attribute(NL80211_ATTR_VENDOR_DATA);
+ unsigned int len = event.get_vendor_data_len();
+
+ if (vendor_data == NULL || len < sizeof(wifi_gscan_full_result_t)) {
+ ALOGI("Full scan results: No scan results found");
+ return NL_SKIP;
+ }
+
+ wifi_gscan_full_result_t *drv_res = (wifi_gscan_full_result_t *)event.get_vendor_data();
+ /* To protect against corrupted data, put a ceiling */
+ int ie_len = min(MAX_PROBE_RESP_IE_LEN, drv_res->ie_length);
+ wifi_scan_result *full_scan_result;
+ wifi_gscan_result_t *fixed = &drv_res->fixed;
+
+ if ((ie_len + offsetof(wifi_gscan_full_result_t, ie_data)) > len) {
+ ALOGE("BAD event data, len %d ie_len %d fixed length %lu!\n", len,
+ ie_len, offsetof(wifi_gscan_full_result_t, ie_data));
+ return NL_SKIP;
+ }
+ full_scan_result = (wifi_scan_result *) malloc((ie_len + offsetof(wifi_scan_result, ie_data)));
+ if (!full_scan_result) {
+ ALOGE("Full scan results: Can't malloc!\n");
+ return NL_SKIP;
+ }
+ convert_to_hal_result(full_scan_result, fixed);
+ full_scan_result->ie_length = ie_len;
+ memcpy(full_scan_result->ie_data, drv_res->ie_data, ie_len);
+ if(handler.on_full_scan_result)
+ handler.on_full_scan_result(id, full_scan_result, drv_res->scan_ch_bucket);
+
+ ALOGV("Full scan result: %-32s %02x:%02x:%02x:%02x:%02x:%02x %d %d %ld %lx %lx %x %d\n",
+ fixed->ssid, fixed->bssid[0], fixed->bssid[1], fixed->bssid[2], fixed->bssid[3],
+ fixed->bssid[4], fixed->bssid[5], fixed->rssi, fixed->channel, fixed->ts,
+ fixed->rtt, fixed->rtt_sd, drv_res->scan_ch_bucket, drv_res->ie_length);
+ free(full_scan_result);
+ return NL_SKIP;
+}
+
+
+wifi_error wifi_disable_full_scan_results(wifi_request_id id, wifi_interface_handle iface)
+{
+ ALOGV("Disabling full scan results");
+
+ if(id == -1) {
+ wifi_scan_result_handler handler;
+ int params_dummy;
+
+ memset(&handler, 0, sizeof(handler));
+ FullScanResultsCommand *cmd = new FullScanResultsCommand(iface, 0, &params_dummy, handler);
+ NULL_CHECK_RETURN(cmd, "memory allocation failure", WIFI_ERROR_OUT_OF_MEMORY);
+ cmd->cancel();
+ cmd->releaseRef();
+ return WIFI_SUCCESS;
+ }
+
+ return wifi_cancel_cmd(id, iface);
+}
+
+
+/////////////////////////////////////////////////////////////////////////////
+
+class GetScanResultsCommand : public WifiCommand {
+ wifi_cached_scan_results *mScans;
+ int mMax;
+ int *mNum;
+ int mRetrieved;
+ byte mFlush;
+ int mCompleted;
+public:
+ GetScanResultsCommand(wifi_interface_handle iface, byte flush,
+ wifi_cached_scan_results *results, int max, int *num)
+ : WifiCommand("GetScanResultsCommand", iface, -1), mScans(results), mMax(max), mNum(num),
+ mRetrieved(0), mFlush(flush), mCompleted(0)
+ { }
+
+ int createRequest(WifiRequest& request, int num, byte flush) {
+ int result = request.create(GOOGLE_OUI, GSCAN_SUBCMD_GET_SCAN_RESULTS);
+ if (result < 0) {
+ return result;
+ }
+
+ nlattr *data = request.attr_start(NL80211_ATTR_VENDOR_DATA);
+ result = request.put_u32(GSCAN_ATTRIBUTE_NUM_OF_RESULTS, num);
+ if (result < 0) {
+ return result;
+ }
+
+ result = request.put_u8(GSCAN_ATTRIBUTE_FLUSH_RESULTS, flush);
+ if (result < 0) {
+ return result;
+ }
+
+ request.attr_end(data);
+ return WIFI_SUCCESS;
+ }
+
+ int execute() {
+ WifiRequest request(familyId(), ifaceId());
+ ALOGV("retrieving %d scan results", mMax);
+
+ for (int i = 0; i < 10 && mRetrieved < mMax; i++) {
+ int num_to_retrieve = mMax - mRetrieved;
+ // ALOGI("retrieving %d scan results in one shot", num_to_retrieve);
+ int result = createRequest(request, num_to_retrieve, mFlush);
+ if (result < 0) {
+ ALOGE("failed to create request");
+ return result;
+ }
+
+ int prev_retrieved = mRetrieved;
+
+ result = requestResponse(request);
+
+ if (result != WIFI_SUCCESS) {
+ ALOGE("failed to retrieve scan results; result = %d", result);
+ return result;
+ }
+
+ if (mRetrieved == prev_retrieved || mCompleted) {
+ /* no more items left to retrieve */
+ break;
+ }
+
+ request.destroy();
+ }
+
+ ALOGV("GetScanResults read %d results", mRetrieved);
+ *mNum = mRetrieved;
+ return WIFI_SUCCESS;
+ }
+
+ virtual int handleResponse(WifiEvent& reply) {
+ ALOGV("In GetScanResultsCommand::handleResponse");
+
+ if (reply.get_cmd() != NL80211_CMD_VENDOR) {
+ ALOGD("Ignoring reply with cmd = %d", reply.get_cmd());
+ return NL_SKIP;
+ }
+
+ int id = reply.get_vendor_id();
+ int subcmd = reply.get_vendor_subcmd();
+
+ ALOGV("Id = %0x, subcmd = %d", id, subcmd);
+
+ /*
+ if (subcmd != GSCAN_SUBCMD_SCAN_RESULTS) {
+ ALOGE("Invalid response to GetScanResultsCommand; ignoring it");
+ return NL_SKIP;
+ }
+ */
+
+ nlattr *vendor_data = reply.get_attribute(NL80211_ATTR_VENDOR_DATA);
+ int len = reply.get_vendor_data_len();
+
+ if (vendor_data == NULL || len == 0) {
+ ALOGE("no vendor data in GetScanResults response; ignoring it");
+ return NL_SKIP;
+ }
+
+ for (nl_iterator it(vendor_data); it.has_next(); it.next()) {
+ if (it.get_type() == GSCAN_ATTRIBUTE_SCAN_RESULTS_COMPLETE) {
+ mCompleted = it.get_u8();
+ ALOGV("retrieved mCompleted flag : %d", mCompleted);
+ } else if (it.get_type() == GSCAN_ATTRIBUTE_SCAN_RESULTS || it.get_type() == 0) {
+ int scan_id = 0, flags = 0, num = 0, scan_ch_bucket_mask = 0;
+ for (nl_iterator it2(it.get()); it2.has_next(); it2.next()) {
+ if (it2.get_type() == GSCAN_ATTRIBUTE_SCAN_ID) {
+ scan_id = it2.get_u32();
+ ALOGV("retrieved scan_id : 0x%0x", scan_id);
+ } else if (it2.get_type() == GSCAN_ATTRIBUTE_SCAN_FLAGS) {
+ flags = it2.get_u8();
+ ALOGV("retrieved scan_flags : 0x%0x", flags);
+ } else if (it2.get_type() == GSCAN_ATTRIBUTE_NUM_OF_RESULTS) {
+ num = it2.get_u32();
+ ALOGV("retrieved num_results: %d", num);
+ } else if (it2.get_type() == GSCAN_ATTRIBUTE_CH_BUCKET_BITMASK) {
+ scan_ch_bucket_mask = it2.get_u32();
+ ALOGD("retrieved scan_ch_bucket_mask: %x", scan_ch_bucket_mask);
+ } else if (it2.get_type() == GSCAN_ATTRIBUTE_SCAN_RESULTS && num) {
+ if (mRetrieved >= mMax) {
+ ALOGW("Stored %d scans, ignoring excess results", mRetrieved);
+ break;
+ }
+ num = min(num, (int)(it2.get_len()/sizeof(wifi_gscan_result)));
+ num = min(num, (int)MAX_AP_CACHE_PER_SCAN);
+ ALOGV("Copying %d scan results", num);
+ wifi_gscan_result_t *results = (wifi_gscan_result_t *)it2.get_data();
+ wifi_scan_result *mScanResults = mScans[mRetrieved].results;
+
+ for (int i = 0; i < num; i++) {
+ wifi_gscan_result_t *result = &results[i];
+ convert_to_hal_result(&mScanResults[i], result);
+ mScanResults[i].ie_length = 0;
+ ALOGV("%02d %-32s %02x:%02x:%02x:%02x:%02x:%02x %04d", i,
+ result->ssid, result->bssid[0], result->bssid[1], result->bssid[2],
+ result->bssid[3], result->bssid[4], result->bssid[5],
+ result->rssi);
+ }
+ mScans[mRetrieved].scan_id = scan_id;
+ mScans[mRetrieved].flags = flags;
+ mScans[mRetrieved].num_results = num;
+ mScans[mRetrieved].buckets_scanned = scan_ch_bucket_mask;
+ ALOGV("Setting result of scan_id : 0x%0x", mScans[mRetrieved].scan_id);
+ mRetrieved++;
+ } else {
+ ALOGW("Ignoring invalid attribute type = %d, size = %d",
+ it.get_type(), it.get_len());
+ }
+ }
+ } else {
+ ALOGW("Ignoring invalid attribute type = %d, size = %d",
+ it.get_type(), it.get_len());
+ }
+ }
+ ALOGV("GetScanResults read %d results", mRetrieved);
+ return NL_OK;
+ }
+};
+
+wifi_error wifi_get_cached_gscan_results(wifi_interface_handle iface, byte flush,
+ int max, wifi_cached_scan_results *results, int *num) {
+ ALOGV("Getting cached scan results, iface handle = %p, num = %d", iface, *num);
+
+ GetScanResultsCommand *cmd = new GetScanResultsCommand(iface, flush, results, max, num);
+ NULL_CHECK_RETURN(cmd, "memory allocation failure", WIFI_ERROR_OUT_OF_MEMORY);
+ wifi_error err = (wifi_error)cmd->execute();
+ cmd->releaseRef();
+ return err;
+}
+
+/////////////////////////////////////////////////////////////////////////////
+
+class BssidHotlistCommand : public WifiCommand
+{
+private:
+ wifi_bssid_hotlist_params mParams;
+ wifi_hotlist_ap_found_handler mHandler;
+ static const int MAX_RESULTS = 64;
+ wifi_scan_result mResults[MAX_RESULTS];
+public:
+ BssidHotlistCommand(wifi_interface_handle handle, int id,
+ wifi_bssid_hotlist_params params, wifi_hotlist_ap_found_handler handler)
+ : WifiCommand("BssidHotlistCommand", handle, id), mParams(params), mHandler(handler)
+ { }
+
+ int createSetupRequest(WifiRequest& request) {
+ int result = request.create(GOOGLE_OUI, GSCAN_SUBCMD_SET_HOTLIST);
+ if (result < 0) {
+ return result;
+ }
+
+ nlattr *data = request.attr_start(NL80211_ATTR_VENDOR_DATA);
+ result = request.put_u8(GSCAN_ATTRIBUTE_HOTLIST_FLUSH, 1);
+ if (result < 0) {
+ return result;
+ }
+
+ result = request.put_u32(GSCAN_ATTRIBUTE_LOST_AP_SAMPLE_SIZE, mParams.lost_ap_sample_size);
+ if (result < 0) {
+ return result;
+ }
+
+ result = request.put_u32(GSCAN_ATTRIBUTE_HOTLIST_BSSID_COUNT, mParams.num_bssid);
+ if (result < 0) {
+ return result;
+ }
+
+ struct nlattr * attr = request.attr_start(GSCAN_ATTRIBUTE_HOTLIST_BSSIDS);
+ for (int i = 0; i < mParams.num_bssid; i++) {
+ nlattr *attr2 = request.attr_start(GSCAN_ATTRIBUTE_HOTLIST_ELEM);
+ if (attr2 == NULL) {
+ return WIFI_ERROR_OUT_OF_MEMORY;
+ }
+ result = request.put_addr(GSCAN_ATTRIBUTE_BSSID, mParams.ap[i].bssid);
+ if (result < 0) {
+ return result;
+ }
+ result = request.put_u8(GSCAN_ATTRIBUTE_RSSI_HIGH, mParams.ap[i].high);
+ if (result < 0) {
+ return result;
+ }
+ result = request.put_u8(GSCAN_ATTRIBUTE_RSSI_LOW, mParams.ap[i].low);
+ if (result < 0) {
+ return result;
+ }
+ request.attr_end(attr2);
+ }
+
+ request.attr_end(attr);
+ request.attr_end(data);
+ return result;
+ }
+
+ int createTeardownRequest(WifiRequest& request) {
+ int result = request.create(GOOGLE_OUI, GSCAN_SUBCMD_SET_HOTLIST);
+ if (result < 0) {
+ return result;
+ }
+
+ nlattr *data = request.attr_start(NL80211_ATTR_VENDOR_DATA);
+ result = request.put_u8(GSCAN_ATTRIBUTE_HOTLIST_FLUSH, 1);
+ if (result < 0) {
+ return result;
+ }
+
+ struct nlattr * attr = request.attr_start(GSCAN_ATTRIBUTE_HOTLIST_BSSIDS);
+ request.attr_end(attr);
+ request.attr_end(data);
+ return result;
+ }
+
+ void unregisterVendorHandlerAll() {
+ unregisterVendorHandler(GOOGLE_OUI, GSCAN_EVENT_HOTLIST_RESULTS_FOUND);
+ unregisterVendorHandler(GOOGLE_OUI, GSCAN_EVENT_HOTLIST_RESULTS_LOST);
+ }
+
+ int start() {
+ ALOGI("Executing hotlist setup request, num = %d", mParams.num_bssid);
+ WifiRequest request(familyId(), ifaceId());
+ int result = createSetupRequest(request);
+ if (result < 0) {
+ return result;
+ }
+
+ registerVendorHandler(GOOGLE_OUI, GSCAN_EVENT_HOTLIST_RESULTS_FOUND);
+ registerVendorHandler(GOOGLE_OUI, GSCAN_EVENT_HOTLIST_RESULTS_LOST);
+
+ result = requestResponse(request);
+ if (result < 0) {
+ unregisterVendorHandlerAll();
+ ALOGI("Failed to execute hotlist setup request, result = %d", result);
+ return result;
+ }
+
+ ALOGI("Successfully set %d APs in the hotlist ", mParams.num_bssid);
+ result = createFeatureRequest(request, GSCAN_SUBCMD_ENABLE_GSCAN, 1);
+ if (result < 0) {
+ unregisterVendorHandlerAll();
+ return result;
+ }
+
+ result = requestResponse(request);
+ if (result < 0) {
+ unregisterVendorHandlerAll();
+ return result;
+ }
+
+ ALOGI("successfully restarted the scan");
+ return result;
+ }
+
+ virtual int cancel() {
+ /* unregister event handler */
+ unregisterVendorHandlerAll();
+ /* create set hotlist message with empty hotlist */
+ WifiRequest request(familyId(), ifaceId());
+ int result = createTeardownRequest(request);
+ if (result < 0) {
+ return result;
+ }
+
+ result = requestResponse(request);
+ if (result < 0) {
+ return result;
+ }
+
+ ALOGI("Successfully reset APs in current hotlist");
+ return result;
+ }
+
+ virtual int handleResponse(WifiEvent& reply) {
+ /* Nothing to do on response! */
+ return NL_SKIP;
+ }
+
+ virtual int handleEvent(WifiEvent& event) {
+ ALOGI("Hotlist AP event");
+ int event_id = event.get_vendor_subcmd();
+ // event.log();
+
+ nlattr *vendor_data = event.get_attribute(NL80211_ATTR_VENDOR_DATA);
+ int len = event.get_vendor_data_len();
+
+ if (vendor_data == NULL || len == 0) {
+ ALOGI("No scan results found");
+ return NL_SKIP;
+ }
+
+ memset(mResults, 0, sizeof(wifi_scan_result) * MAX_RESULTS);
+
+ int num = len / sizeof(wifi_gscan_result_t);
+ wifi_gscan_result_t *inp = (wifi_gscan_result_t *)event.get_vendor_data();
+ num = min(MAX_RESULTS, num);
+ for (int i = 0; i < num; i++, inp++) {
+ convert_to_hal_result(&(mResults[i]), inp);
+ }
+
+ if (event_id == GSCAN_EVENT_HOTLIST_RESULTS_FOUND) {
+ ALOGI("FOUND %d hotlist APs", num);
+ if (*mHandler.on_hotlist_ap_found)
+ (*mHandler.on_hotlist_ap_found)(id(), num, mResults);
+ } else if (event_id == GSCAN_EVENT_HOTLIST_RESULTS_LOST) {
+ ALOGI("LOST %d hotlist APs", num);
+ if (*mHandler.on_hotlist_ap_lost)
+ (*mHandler.on_hotlist_ap_lost)(id(), num, mResults);
+ }
+ return NL_SKIP;
+ }
+};
+
+class ePNOCommand : public WifiCommand
+{
+private:
+ wifi_epno_params epno_params;
+ wifi_epno_handler mHandler;
+ wifi_scan_result mResults[MAX_EPNO_NETWORKS];
+public:
+ ePNOCommand(wifi_interface_handle handle, int id,
+ const wifi_epno_params *params, wifi_epno_handler handler)
+ : WifiCommand("ePNOCommand", handle, id), mHandler(handler)
+ {
+ if (params != NULL) {
+ memcpy(&epno_params, params, sizeof(wifi_epno_params));
+ } else {
+ memset(&epno_params, 0, sizeof(wifi_epno_params));
+ }
+ }
+ int createSetupRequest(WifiRequest& request) {
+ char tmp_buf[DOT11_MAX_SSID_LEN + 1];
+ if (epno_params.num_networks > MAX_EPNO_NETWORKS) {
+ ALOGE("wrong epno num_networks:%d", epno_params.num_networks);
+ return WIFI_ERROR_INVALID_ARGS;
+ }
+ int result = request.create(GOOGLE_OUI, GSCAN_SUBCMD_SET_EPNO_SSID);
+ if (result < 0) {
+ return result;
+ }
+ nlattr *data = request.attr_start(NL80211_ATTR_VENDOR_DATA);
+ result = request.put_u8(GSCAN_ATTRIBUTE_EPNO_FLUSH, 1);
+ if (result < 0) {
+ return result;
+ }
+
+ result = request.put_u8(GSCAN_ATTRIBUTE_EPNO_5G_RSSI_THR,
+ (u8)epno_params.min5GHz_rssi);
+ if (result < 0) {
+ return result;
+ }
+ result = request.put_u8(GSCAN_ATTRIBUTE_EPNO_2G_RSSI_THR,
+ (u8)epno_params.min24GHz_rssi);
+ if (result < 0) {
+ return result;
+ }
+ result = request.put_u16(GSCAN_ATTRIBUTE_EPNO_INIT_SCORE_MAX,
+ epno_params.initial_score_max);
+ if (result < 0) {
+ return result;
+ }
+ result = request.put_u16(GSCAN_ATTRIBUTE_EPNO_CUR_CONN_BONUS,
+ epno_params.current_connection_bonus);
+ if (result < 0) {
+ return result;
+ }
+ result = request.put_u16(GSCAN_ATTRIBUTE_EPNO_SAME_NETWORK_BONUS,
+ epno_params.same_network_bonus);
+ if (result < 0) {
+ return result;
+ }
+ result = request.put_u16(GSCAN_ATTRIBUTE_EPNO_SECURE_BONUS,
+ epno_params.secure_bonus);
+ if (result < 0) {
+ return result;
+ }
+ result = request.put_u16(GSCAN_ATTRIBUTE_EPNO_5G_BONUS,
+ epno_params.band5GHz_bonus);
+ if (result < 0) {
+ return result;
+ }
+ result = request.put_u8(GSCAN_ATTRIBUTE_EPNO_SSID_NUM,
+ epno_params.num_networks);
+ if (result < 0) {
+ return result;
+ }
+ struct nlattr * attr = request.attr_start(GSCAN_ATTRIBUTE_EPNO_SSID_LIST);
+ wifi_epno_network *ssid_list = epno_params.networks;
+ for (int i = 0; i < epno_params.num_networks; i++) {
+ nlattr *attr2 = request.attr_start(i);
+ if (attr2 == NULL) {
+ return WIFI_ERROR_OUT_OF_MEMORY;
+ }
+ strlcpy(tmp_buf, ssid_list[i].ssid, sizeof(tmp_buf));
+ result = request.put(GSCAN_ATTRIBUTE_EPNO_SSID, tmp_buf,
+ strlen(tmp_buf));
+ ALOGI("PNO network: SSID %s flags %x auth %x", tmp_buf,
+ ssid_list[i].flags,
+ ssid_list[i].auth_bit_field);
+ if (result < 0) {
+ return result;
+ }
+ result = request.put_u32(GSCAN_ATTRIBUTE_EPNO_SSID_LEN,
+ strlen(tmp_buf));
+ if (result < 0) {
+ return result;
+ }
+ result = request.put_u32(GSCAN_ATTRIBUTE_EPNO_FLAGS, ssid_list[i].flags);
+ if (result < 0) {
+ return result;
+ }
+ result = request.put_u32(GSCAN_ATTRIBUTE_EPNO_AUTH, ssid_list[i].auth_bit_field);
+ if (result < 0) {
+ return result;
+ }
+ request.attr_end(attr2);
+ }
+ request.attr_end(attr);
+ request.attr_end(data);
+ return result;
+ }
+
+ int createTeardownRequest(WifiRequest& request) {
+ int result = request.create(GOOGLE_OUI, GSCAN_SUBCMD_SET_EPNO_SSID);
+ if (result < 0) {
+ return result;
+ }
+
+ nlattr *data = request.attr_start(NL80211_ATTR_VENDOR_DATA);
+ result = request.put_u8(GSCAN_ATTRIBUTE_EPNO_FLUSH, 1);
+ if (result < 0) {
+ return result;
+ }
+ request.attr_end(data);
+ return result;
+ }
+
+ int start() {
+ ALOGI("Executing ePNO setup request, num = %d", epno_params.num_networks);
+ WifiRequest request(familyId(), ifaceId());
+ int result = createSetupRequest(request);
+ if (result < 0) {
+ return result;
+ }
+
+ registerVendorHandler(GOOGLE_OUI, GSCAN_EVENT_EPNO_EVENT);
+ result = requestResponse(request);
+ if (result < 0) {
+ unregisterVendorHandler(GOOGLE_OUI, GSCAN_EVENT_EPNO_EVENT);
+ ALOGI("Failed to execute ePNO setup request, result = %d", result);
+ return result;
+ }
+
+ ALOGI("Successfully set %d SSIDs for ePNO", epno_params.num_networks);
+ ALOGI("successfully restarted the scan");
+ return result;
+ }
+
+ virtual int cancel() {
+ /* unregister event handler */
+ unregisterVendorHandler(GOOGLE_OUI, GSCAN_EVENT_EPNO_EVENT);
+ /* create set hotlist message with empty hotlist */
+ WifiRequest request(familyId(), ifaceId());
+ int result = createTeardownRequest(request);
+ if (result < 0) {
+ return result;
+ }
+
+ result = requestResponse(request);
+ if (result < 0) {
+ return result;
+ }
+
+ ALOGI("Successfully reset APs in current hotlist");
+ return result;
+ }
+
+ virtual int handleResponse(WifiEvent& reply) {
+ /* Nothing to do on response! */
+ return NL_SKIP;
+ }
+
+ virtual int handleEvent(WifiEvent& event) {
+ ALOGI("ePNO event");
+ // event.log();
+
+ nlattr *vendor_data = event.get_attribute(NL80211_ATTR_VENDOR_DATA);
+ int len = event.get_vendor_data_len();
+
+ if (vendor_data == NULL || len == 0) {
+ ALOGI("No scan results found");
+ return NL_SKIP;
+ }
+
+ memset(mResults, 0, sizeof(wifi_scan_result) * MAX_EPNO_NETWORKS);
+
+ unsigned int num = len / sizeof(wifi_pno_result_t);
+ unsigned int i;
+ num = min(MAX_EPNO_NETWORKS, num);
+ wifi_pno_result_t *res = (wifi_pno_result_t *) event.get_vendor_data();
+ for (i = 0; i < num; i++) {
+ if (res[i].flags == PNO_SSID_FOUND) {
+ memcpy(mResults[i].ssid, res[i].ssid, res[i].ssid_len);
+ memcpy(mResults[i].bssid, res[i].bssid, sizeof(mac_addr));
+
+ mResults[i].ssid[res[i].ssid_len] = '\0';
+ mResults[i].channel = res[i].channel;
+ mResults[i].rssi = res[i].rssi;
+ }
+ }
+ if (*mHandler.on_network_found)
+ (*mHandler.on_network_found)(id(), num, mResults);
+ return NL_SKIP;
+ }
+};
+
+wifi_error wifi_set_bssid_hotlist(wifi_request_id id, wifi_interface_handle iface,
+ wifi_bssid_hotlist_params params, wifi_hotlist_ap_found_handler handler)
+{
+ wifi_handle handle = getWifiHandle(iface);
+
+ BssidHotlistCommand *cmd = new BssidHotlistCommand(iface, id, params, handler);
+ NULL_CHECK_RETURN(cmd, "memory allocation failure", WIFI_ERROR_OUT_OF_MEMORY);
+ wifi_error result = wifi_register_cmd(handle, id, cmd);
+ if (result != WIFI_SUCCESS) {
+ cmd->releaseRef();
+ return result;
+ }
+ result = (wifi_error)cmd->start();
+ if (result != WIFI_SUCCESS) {
+ wifi_unregister_cmd(handle, id);
+ cmd->releaseRef();
+ return result;
+ }
+ return result;
+}
+
+wifi_error wifi_reset_bssid_hotlist(wifi_request_id id, wifi_interface_handle iface)
+{
+ return wifi_cancel_cmd(id, iface);
+}
+
+
+/////////////////////////////////////////////////////////////////////////////
+
+class SignificantWifiChangeCommand : public WifiCommand
+{
+ typedef struct {
+ mac_addr bssid; // BSSID
+ wifi_channel channel; // channel frequency in MHz
+ int num_rssi; // number of rssi samples
+ wifi_rssi rssi[8]; // RSSI history in db
+ } wifi_significant_change_result_internal;
+
+private:
+ wifi_significant_change_params mParams;
+ wifi_significant_change_handler mHandler;
+ static const int MAX_RESULTS = 64;
+ wifi_significant_change_result_internal mResultsBuffer[MAX_RESULTS];
+ wifi_significant_change_result *mResults[MAX_RESULTS];
+public:
+ SignificantWifiChangeCommand(wifi_interface_handle handle, int id,
+ wifi_significant_change_params params, wifi_significant_change_handler handler)
+ : WifiCommand("SignificantWifiChangeCommand", handle, id), mParams(params),
+ mHandler(handler)
+ { }
+
+ int createSetupRequest(WifiRequest& request) {
+ int result = request.create(GOOGLE_OUI, GSCAN_SUBCMD_SET_SIGNIFICANT_CHANGE_CONFIG);
+ if (result < 0) {
+ return result;
+ }
+
+ nlattr *data = request.attr_start(NL80211_ATTR_VENDOR_DATA);
+ result = request.put_u8(GSCAN_ATTRIBUTE_SIGNIFICANT_CHANGE_FLUSH, 1);
+ if (result < 0) {
+ return result;
+ }
+ result = request.put_u16(GSCAN_ATTRIBUTE_RSSI_SAMPLE_SIZE, mParams.rssi_sample_size);
+ if (result < 0) {
+ return result;
+ }
+ result = request.put_u16(GSCAN_ATTRIBUTE_LOST_AP_SAMPLE_SIZE, mParams.lost_ap_sample_size);
+ if (result < 0) {
+ return result;
+ }
+ result = request.put_u16(GSCAN_ATTRIBUTE_MIN_BREACHING, mParams.min_breaching);
+ if (result < 0) {
+ return result;
+ }
+ result = request.put_u16(GSCAN_ATTRIBUTE_NUM_BSSID, mParams.num_bssid);
+ if (result < 0) {
+ return result;
+ }
+ if (mParams.num_bssid != 0) {
+ nlattr* attr = request.attr_start(GSCAN_ATTRIBUTE_SIGNIFICANT_CHANGE_BSSIDS);
+ if (attr == NULL) {
+ return WIFI_ERROR_OUT_OF_MEMORY;
+ }
+
+ for (int i = 0; i < mParams.num_bssid; i++) {
+ nlattr* attr2 = request.attr_start(i);
+ if (attr2 == NULL) {
+ return WIFI_ERROR_OUT_OF_MEMORY;
+ }
+ result = request.put_addr(GSCAN_ATTRIBUTE_BSSID, mParams.ap[i].bssid);
+ if (result < 0) {
+ return result;
+ }
+ result = request.put_u8(GSCAN_ATTRIBUTE_RSSI_HIGH, mParams.ap[i].high);
+ if (result < 0) {
+ return result;
+ }
+ result = request.put_u8(GSCAN_ATTRIBUTE_RSSI_LOW, mParams.ap[i].low);
+ if (result < 0) {
+ return result;
+ }
+ request.attr_end(attr2);
+ }
+
+ request.attr_end(attr);
+ }
+ request.attr_end(data);
+
+ return result;
+ }
+
+ int createTeardownRequest(WifiRequest& request) {
+ int result = request.create(GOOGLE_OUI, GSCAN_SUBCMD_SET_SIGNIFICANT_CHANGE_CONFIG);
+ if (result < 0) {
+ return result;
+ }
+
+ nlattr *data = request.attr_start(NL80211_ATTR_VENDOR_DATA);
+ result = request.put_u16(GSCAN_ATTRIBUTE_SIGNIFICANT_CHANGE_FLUSH, 1);
+ if (result < 0) {
+ return result;
+ }
+
+ request.attr_end(data);
+ return result;
+ }
+
+ int start() {
+ ALOGI("Set significant wifi change config");
+ WifiRequest request(familyId(), ifaceId());
+
+ int result = createSetupRequest(request);
+ if (result < 0) {
+ return result;
+ }
+
+ registerVendorHandler(GOOGLE_OUI, GSCAN_EVENT_SIGNIFICANT_CHANGE_RESULTS);
+
+ result = requestResponse(request);
+ if (result < 0) {
+ unregisterVendorHandler(GOOGLE_OUI, GSCAN_EVENT_SIGNIFICANT_CHANGE_RESULTS);
+ ALOGI("failed to set significant wifi change config %d", result);
+ return result;
+ }
+
+ ALOGI("successfully set significant wifi change config");
+
+ result = createFeatureRequest(request, GSCAN_SUBCMD_ENABLE_GSCAN, 1);
+ if (result < 0) {
+ unregisterVendorHandler(GOOGLE_OUI, GSCAN_EVENT_SIGNIFICANT_CHANGE_RESULTS);
+ return result;
+ }
+
+ result = requestResponse(request);
+ if (result < 0) {
+ unregisterVendorHandler(GOOGLE_OUI, GSCAN_EVENT_SIGNIFICANT_CHANGE_RESULTS);
+ return result;
+ }
+
+ ALOGI("successfully restarted the scan");
+ return result;
+ }
+
+ virtual int cancel() {
+ /* unregister event handler */
+ unregisterVendorHandler(GOOGLE_OUI, GSCAN_EVENT_SIGNIFICANT_CHANGE_RESULTS);
+
+ /* create set significant change monitor message with empty hotlist */
+ WifiRequest request(familyId(), ifaceId());
+
+ int result = createTeardownRequest(request);
+ if (result < 0) {
+ return result;
+ }
+
+ result = requestResponse(request);
+ if (result < 0) {
+ return result;
+ }
+
+ ALOGI("successfully reset significant wifi change config");
+ return result;
+ }
+
+ virtual int handleResponse(WifiEvent& reply) {
+ /* Nothing to do on response! */
+ return NL_SKIP;
+ }
+
+ virtual int handleEvent(WifiEvent& event) {
+ ALOGV("Got a significant wifi change event");
+
+ nlattr *vendor_data = event.get_attribute(NL80211_ATTR_VENDOR_DATA);
+ int len = event.get_vendor_data_len();
+
+ if (vendor_data == NULL || len == 0) {
+ ALOGI("No scan results found");
+ return NL_SKIP;
+ }
+
+ typedef struct {
+ uint16_t flags;
+ uint16_t channel;
+ mac_addr bssid;
+ s8 rssi_history[8];
+ } ChangeInfo;
+
+ int num = min(len / sizeof(ChangeInfo), MAX_RESULTS);
+ ChangeInfo *ci = (ChangeInfo *)event.get_vendor_data();
+
+ for (int i = 0; i < num; i++) {
+ memcpy(mResultsBuffer[i].bssid, ci[i].bssid, sizeof(mac_addr));
+ mResultsBuffer[i].channel = ci[i].channel;
+ mResultsBuffer[i].num_rssi = 8;
+ for (int j = 0; j < mResultsBuffer[i].num_rssi; j++)
+ mResultsBuffer[i].rssi[j] = (int) ci[i].rssi_history[j];
+ mResults[i] = reinterpret_cast<wifi_significant_change_result *>(&(mResultsBuffer[i]));
+ }
+
+ ALOGV("Retrieved %d scan results", num);
+
+ if (num != 0) {
+ (*mHandler.on_significant_change)(id(), num, mResults);
+ } else {
+ ALOGW("No significant change reported");
+ }
+
+ return NL_SKIP;
+ }
+};
+
+wifi_error wifi_set_significant_change_handler(wifi_request_id id, wifi_interface_handle iface,
+ wifi_significant_change_params params, wifi_significant_change_handler handler)
+{
+ wifi_handle handle = getWifiHandle(iface);
+
+ SignificantWifiChangeCommand *cmd = new SignificantWifiChangeCommand(
+ iface, id, params, handler);
+ NULL_CHECK_RETURN(cmd, "memory allocation failure", WIFI_ERROR_OUT_OF_MEMORY);
+ wifi_error result = wifi_register_cmd(handle, id, cmd);
+ if (result != WIFI_SUCCESS) {
+ cmd->releaseRef();
+ return result;
+ }
+ result = (wifi_error)cmd->start();
+ if (result != WIFI_SUCCESS) {
+ wifi_unregister_cmd(handle, id);
+ cmd->releaseRef();
+ return result;
+ }
+ return result;
+}
+
+wifi_error wifi_reset_significant_change_handler(wifi_request_id id, wifi_interface_handle iface)
+{
+ return wifi_cancel_cmd(id, iface);
+}
+
+wifi_error wifi_reset_epno_list(wifi_request_id id, wifi_interface_handle iface)
+{
+ if (id == -1) {
+ wifi_epno_handler handler;
+
+ memset(&handler, 0, sizeof(handler));
+ ePNOCommand *cmd = new ePNOCommand(iface, id, NULL, handler);
+ NULL_CHECK_RETURN(cmd, "memory allocation failure", WIFI_ERROR_OUT_OF_MEMORY);
+ cmd->cancel();
+ cmd->releaseRef();
+ return WIFI_SUCCESS;
+ }
+ return wifi_cancel_cmd(id, iface);
+}
+
+wifi_error wifi_set_epno_list(wifi_request_id id, wifi_interface_handle iface,
+ const wifi_epno_params *params, wifi_epno_handler handler)
+{
+ wifi_handle handle = getWifiHandle(iface);
+ if (handler.on_network_found == NULL) {
+ return WIFI_ERROR_INVALID_ARGS;
+ }
+
+ ePNOCommand *cmd = new ePNOCommand(iface, id, params, handler);
+ NULL_CHECK_RETURN(cmd, "memory allocation failure", WIFI_ERROR_OUT_OF_MEMORY);
+ wifi_error result = wifi_register_cmd(handle, id, cmd);
+ if (result != WIFI_SUCCESS) {
+ cmd->releaseRef();
+ return result;
+ }
+ result = (wifi_error)cmd->start();
+ if (result != WIFI_SUCCESS) {
+ wifi_unregister_cmd(handle, id);
+ cmd->releaseRef();
+ return result;
+ }
+ return result;
+}
+
+class BssidBlacklistCommand : public WifiCommand
+{
+ private:
+ wifi_bssid_params *mParams;
+ public:
+ BssidBlacklistCommand(wifi_interface_handle handle, int id,
+ wifi_bssid_params *params)
+ : WifiCommand("BssidBlacklistCommand", handle, id), mParams(params)
+ { }
+ int createRequest(WifiRequest& request) {
+ if ((mParams->num_bssid < 0) || (mParams->num_bssid > MAX_BLACKLIST_BSSID)) {
+ return WIFI_ERROR_INVALID_ARGS;
+ }
+ int result = request.create(GOOGLE_OUI, WIFI_SUBCMD_SET_BSSID_BLACKLIST);
+ if (result < 0) {
+ return result;
+ }
+
+ nlattr *data = request.attr_start(NL80211_ATTR_VENDOR_DATA);
+ if (!mParams->num_bssid) {
+ result = request.put_u32(GSCAN_ATTRIBUTE_BSSID_BLACKLIST_FLUSH, 1);
+ if (result < 0) {
+ return result;
+ }
+ } else {
+ result = request.put_u32(GSCAN_ATTRIBUTE_NUM_BSSID, mParams->num_bssid);
+ if (result < 0) {
+ return result;
+ }
+ for (int i = 0; i < mParams->num_bssid; i++) {
+ result = request.put_addr(GSCAN_ATTRIBUTE_BLACKLIST_BSSID, mParams->bssids[i]);
+ if (result < 0) {
+ return result;
+ }
+ }
+ }
+ request.attr_end(data);
+ return result;
+ }
+
+ int start() {
+ ALOGV("Executing bssid blacklist request, num = %d", mParams->num_bssid);
+ WifiRequest request(familyId(), ifaceId());
+ int result = createRequest(request);
+ if (result < 0) {
+ return result;
+ }
+
+ result = requestResponse(request);
+ if (result < 0) {
+ ALOGE("Failed to execute bssid blacklist request, result = %d", result);
+ return result;
+ }
+
+ ALOGI("Successfully added %d blacklist bssids", mParams->num_bssid);
+ return result;
+ }
+
+ virtual int handleResponse(WifiEvent& reply) {
+ /* Nothing to do on response! */
+ return NL_SKIP;
+ }
+};
+
+wifi_error wifi_set_bssid_blacklist(wifi_request_id id, wifi_interface_handle iface,
+ wifi_bssid_params params)
+{
+ BssidBlacklistCommand *cmd = new BssidBlacklistCommand(iface, id, &params);
+ NULL_CHECK_RETURN(cmd, "memory allocation failure", WIFI_ERROR_OUT_OF_MEMORY);
+ wifi_error result = (wifi_error)cmd->start();
+ //release the reference of command as well
+ cmd->releaseRef();
+ return result;
+}
+
+wifi_error wifi_configure_roaming(wifi_interface_handle iface,
+ wifi_roaming_config *roam_config)
+{
+ wifi_error ret;
+ wifi_bssid_params bssid_params;
+ unsigned int i;
+ wifi_request_id id = 0;
+
+ /* Set bssid blacklist */
+ if (roam_config->num_blacklist_bssid == 0) {
+ /* Flush request */
+ ALOGI("%s: num_blacklist_bssid == 0 (flush)", __FUNCTION__);
+ }
+
+ bssid_params.num_bssid = roam_config->num_blacklist_bssid;
+
+ for (i = 0; i < roam_config->num_blacklist_bssid; i++) {
+ mac_addr &addr1 = roam_config->blacklist_bssid[i];
+ memcpy(&bssid_params.bssids[i], &roam_config->blacklist_bssid[i],
+ sizeof(mac_addr));
+ ALOGI("%02x:%02x:%02x:%02x:%02x:%02x\n", addr1[0],
+ addr1[1], addr1[2], addr1[3], addr1[4], addr1[5]);
+ }
+ ret = wifi_set_bssid_blacklist(id, iface, bssid_params);
+ if (ret != WIFI_SUCCESS) {
+ ALOGE("%s: Failed to configure blacklist bssids", __FUNCTION__);
+ return ret;
+ }
+
+ return ret;
+}
+
+class FirmwareRoamingStateCommand : public WifiCommand
+{
+ private:
+ fw_roaming_state_t roam_state;
+ public:
+ FirmwareRoamingStateCommand(wifi_interface_handle handle,
+ fw_roaming_state_t state)
+ : WifiCommand("FirmwareRoamingStateCommand", handle, -1), roam_state(state)
+ { }
+ int createRequest(WifiRequest& request) {
+ int result = request.create(GOOGLE_OUI, WIFI_SUBCMD_FW_ROAM_POLICY);
+ if (result < 0) {
+ return result;
+ }
+
+ nlattr *data = request.attr_start(NL80211_ATTR_VENDOR_DATA);
+ result = request.put_u32(GSCAN_ATTRIBUTE_ROAM_STATE_SET, roam_state);
+ if (result < 0) {
+ return result;
+ }
+ request.attr_end(data);
+ return result;
+ }
+
+ int start() {
+ ALOGV("Executing firmware roam state set, state = %d", roam_state);
+ WifiRequest request(familyId(), ifaceId());
+ int result = createRequest(request);
+ if (result < 0) {
+ return result;
+ }
+
+ result = requestResponse(request);
+ if (result < 0) {
+ ALOGE("Failed to execute firmware roam state set, result = %d", result);
+ return result;
+ }
+
+ ALOGI("Successfully set firmware roam state - %d", roam_state);
+ return result;
+ }
+
+ virtual int handleResponse(WifiEvent& reply) {
+ /* Nothing to do on response! */
+ return NL_SKIP;
+ }
+};
+
+wifi_error wifi_enable_firmware_roaming(wifi_interface_handle iface,
+ fw_roaming_state_t state)
+{
+ /* Set firmware roaming state */
+ FirmwareRoamingStateCommand *cmd = new FirmwareRoamingStateCommand(iface, state);
+ NULL_CHECK_RETURN(cmd, "memory allocation failure", WIFI_ERROR_OUT_OF_MEMORY);
+ wifi_error result = (wifi_error)cmd->start();
+ //release the reference of command as well
+ cmd->releaseRef();
+ return result;
+}
+
+////////////////////////////////////////////////////////////////////////////////
+
+class AnqpoConfigureCommand : public WifiCommand
+{
+ int num_hs;
+ wifi_passpoint_network *mNetworks;
+ wifi_passpoint_event_handler mHandler;
+ wifi_scan_result *mResult;
+public:
+ AnqpoConfigureCommand(wifi_request_id id, wifi_interface_handle iface,
+ int num, wifi_passpoint_network *hs_list, wifi_passpoint_event_handler handler)
+ : WifiCommand("AnqpoConfigureCommand", iface, id), num_hs(num), mNetworks(hs_list),
+ mHandler(handler)
+ {
+ mResult = NULL;
+ }
+
+ int createRequest(WifiRequest& request, int val) {
+
+ int result = request.create(GOOGLE_OUI, GSCAN_SUBCMD_ANQPO_CONFIG);
+ result = request.put_u32(GSCAN_ATTRIBUTE_ANQPO_HS_LIST_SIZE, num_hs);
+ if (result < 0) {
+ return result;
+ }
+
+ nlattr *data = request.attr_start(NL80211_ATTR_VENDOR_DATA);
+
+ struct nlattr * attr = request.attr_start(GSCAN_ATTRIBUTE_ANQPO_HS_LIST);
+ for (int i = 0; i < num_hs; i++) {
+ nlattr *attr2 = request.attr_start(i);
+ if (attr2 == NULL) {
+ return WIFI_ERROR_OUT_OF_MEMORY;
+ }
+ result = request.put_u32(GSCAN_ATTRIBUTE_ANQPO_HS_NETWORK_ID, mNetworks[i].id);
+ if (result < 0) {
+ return result;
+ }
+ result = request.put(GSCAN_ATTRIBUTE_ANQPO_HS_NAI_REALM, mNetworks[i].realm, 256);
+ if (result < 0) {
+ return result;
+ }
+ result = request.put(GSCAN_ATTRIBUTE_ANQPO_HS_ROAM_CONSORTIUM_ID,
+ mNetworks[i].roamingConsortiumIds, 128);
+ if (result < 0) {
+ return result;
+ }
+ result = request.put(GSCAN_ATTRIBUTE_ANQPO_HS_PLMN, mNetworks[i].plmn, 3);
+ if (result < 0) {
+ return result;
+ }
+
+ request.attr_end(attr2);
+ }
+
+ request.attr_end(attr);
+ request.attr_end(data);
+
+ return WIFI_SUCCESS;
+ }
+
+ int start() {
+
+ WifiRequest request(familyId(), ifaceId());
+ int result = createRequest(request, num_hs);
+ if (result != WIFI_SUCCESS) {
+ ALOGE("failed to create request; result = %d", result);
+ return result;
+ }
+
+ registerVendorHandler(GOOGLE_OUI, GSCAN_EVENT_ANQPO_HOTSPOT_MATCH);
+
+ result = requestResponse(request);
+ if (result != WIFI_SUCCESS) {
+ unregisterVendorHandler(GOOGLE_OUI, GSCAN_EVENT_ANQPO_HOTSPOT_MATCH);
+ ALOGE("failed to set ANQPO networks; result = %d", result);
+ return result;
+ }
+
+ return result;
+ }
+
+ virtual int cancel() {
+
+ WifiRequest request(familyId(), ifaceId());
+ int result = createRequest(request, 0);
+ if (result != WIFI_SUCCESS) {
+ ALOGE("failed to create request; result = %d", result);
+ } else {
+ result = requestResponse(request);
+ if (result != WIFI_SUCCESS) {
+ ALOGE("failed to reset ANQPO networks;result = %d", result);
+ }
+ }
+
+ unregisterVendorHandler(GOOGLE_OUI, GSCAN_EVENT_ANQPO_HOTSPOT_MATCH);
+ return WIFI_SUCCESS;
+ }
+
+ virtual int handleResponse(WifiEvent& reply) {
+ ALOGD("Request complete!");
+ /* Nothing to do on response! */
+ return NL_SKIP;
+ }
+
+ virtual int handleEvent(WifiEvent& event) {
+ typedef struct {
+ u16 channel; /* channel of GAS protocol */
+ u8 dialog_token; /* GAS dialog token */
+ u8 fragment_id; /* fragment id */
+ u16 status_code; /* status code on GAS completion */
+ u16 data_len; /* length of data to follow */
+ u8 data[1]; /* variable length specified by data_len */
+ } wifi_anqp_gas_resp;
+
+ ALOGI("ANQPO hotspot matched event!");
+
+ nlattr *vendor_data = event.get_attribute(NL80211_ATTR_VENDOR_DATA);
+ unsigned int len = event.get_vendor_data_len();
+
+ if (vendor_data == NULL || len < sizeof(wifi_scan_result)) {
+ ALOGI("No scan results found");
+ return NL_SKIP;
+ }
+ mResult = (wifi_scan_result *)malloc(sizeof(wifi_scan_result));
+ if (!mResult) {
+ return NL_SKIP;
+ }
+ wifi_gscan_full_result_t *drv_res = (wifi_gscan_full_result_t *)event.get_vendor_data();
+ wifi_gscan_result_t *fixed = &drv_res->fixed;
+ convert_to_hal_result(mResult, fixed);
+
+ byte *anqp = (byte *)drv_res + offsetof(wifi_gscan_full_result_t, ie_data) + drv_res->ie_length;
+ wifi_anqp_gas_resp *gas = (wifi_anqp_gas_resp *)anqp;
+ int anqp_len = offsetof(wifi_anqp_gas_resp, data) + gas->data_len;
+ int networkId = *(int *)((byte *)anqp + anqp_len);
+
+ ALOGI("%-32s\t", mResult->ssid);
+
+ ALOGI("%02x:%02x:%02x:%02x:%02x:%02x ", mResult->bssid[0], mResult->bssid[1],
+ mResult->bssid[2], mResult->bssid[3], mResult->bssid[4], mResult->bssid[5]);
+
+ ALOGI("rssi:%d\t", mResult->rssi);
+ ALOGI("channel:%d\t", mResult->channel);
+ ALOGI("ts:0x%jx\t", mResult->ts);
+ ALOGI("rtt:0x%jx\t", mResult->rtt);
+ ALOGI("rtt_sd:0x%jx\n", mResult->rtt_sd);
+
+ if(*mHandler.on_passpoint_network_found)
+ (*mHandler.on_passpoint_network_found)(id(), networkId, mResult, anqp_len, anqp);
+ free(mResult);
+ return NL_SKIP;
+ }
+};
+
+wifi_error wifi_set_passpoint_list(wifi_request_id id, wifi_interface_handle iface, int num,
+ wifi_passpoint_network *networks, wifi_passpoint_event_handler handler)
+{
+ wifi_handle handle = getWifiHandle(iface);
+
+ AnqpoConfigureCommand *cmd = new AnqpoConfigureCommand(id, iface, num, networks, handler);
+ NULL_CHECK_RETURN(cmd, "memory allocation failure", WIFI_ERROR_OUT_OF_MEMORY);
+ wifi_error result = wifi_register_cmd(handle, id, cmd);
+ if (result != WIFI_SUCCESS) {
+ cmd->releaseRef();
+ return result;
+ }
+ result = (wifi_error)cmd->start();
+ if (result != WIFI_SUCCESS) {
+ wifi_unregister_cmd(handle, id);
+ cmd->releaseRef();
+ return result;
+ }
+ return result;
+}
+
+wifi_error wifi_reset_passpoint_list(wifi_request_id id, wifi_interface_handle iface)
+{
+ return wifi_cancel_cmd(id, iface);
+}
diff --git a/synadhd/wifi_hal/link_layer_stats.cpp b/synadhd/wifi_hal/link_layer_stats.cpp
new file mode 100644
index 0000000..8de7acd
--- /dev/null
+++ b/synadhd/wifi_hal/link_layer_stats.cpp
@@ -0,0 +1,303 @@
+/*
+ * Copyright (C) 2017 The Android Open Source Project
+ *
+ * Portions copyright (C) 2017 Broadcom Limited
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <stdint.h>
+#include <fcntl.h>
+#include <sys/socket.h>
+#include <netlink/genl/genl.h>
+#include <netlink/genl/family.h>
+#include <netlink/genl/ctrl.h>
+#include <linux/rtnetlink.h>
+#include <netpacket/packet.h>
+#include <linux/filter.h>
+#include <linux/errqueue.h>
+
+#include <linux/pkt_sched.h>
+#include <netlink/object-api.h>
+#include <netlink/netlink.h>
+#include <netlink/socket.h>
+#include <netlink/handlers.h>
+
+#include "sync.h"
+
+#define LOG_TAG "WifiHAL"
+
+#include <utils/Log.h>
+
+#include "wifi_hal.h"
+#include "common.h"
+#include "cpp_bindings.h"
+
+typedef enum {
+ ANDR_WIFI_ATTRIBUTE_INVALID = 0,
+ ANDR_WIFI_ATTRIBUTE_NUM_RADIO = 1,
+ ANDR_WIFI_ATTRIBUTE_STATS_INFO = 2,
+ ANDR_WIFI_ATTRIBUTE_STATS_MAX = 3
+} LINK_STAT_ATTRIBUTE;
+
+/* Internal radio statistics structure in the driver */
+typedef struct {
+ wifi_radio radio;
+ uint32_t on_time;
+ uint32_t tx_time;
+ uint32_t rx_time;
+ uint32_t on_time_scan;
+ uint32_t on_time_nbd;
+ uint32_t on_time_gscan;
+ uint32_t on_time_roam_scan;
+ uint32_t on_time_pno_scan;
+ uint32_t on_time_hs20;
+ uint32_t num_channels;
+ wifi_channel_stat channels[];
+} wifi_radio_stat_internal;
+
+enum {
+ LSTATS_SUBCMD_GET_INFO = ANDROID_NL80211_SUBCMD_LSTATS_RANGE_START,
+};
+
+class GetLinkStatsCommand : public WifiCommand
+{
+ wifi_stats_result_handler mHandler;
+public:
+ GetLinkStatsCommand(wifi_interface_handle iface, wifi_stats_result_handler handler)
+ : WifiCommand("GetLinkStatsCommand", iface, 0), mHandler(handler)
+ { }
+
+ virtual int create() {
+ // ALOGI("Creating message to get link statistics; iface = %d", mIfaceInfo->id);
+
+ int ret = mMsg.create(GOOGLE_OUI, LSTATS_SUBCMD_GET_INFO);
+ if (ret < 0) {
+ ALOGE("Failed to create %x - %d", LSTATS_SUBCMD_GET_INFO, ret);
+ return ret;
+ }
+
+ return ret;
+ }
+
+protected:
+ virtual int handleResponse(WifiEvent& reply) {
+ void *data = NULL;
+ wifi_radio_stat *radio_stat_ptr = NULL;
+ u8 *iface_stat = NULL;
+ u8 *radioStatsBuf = NULL, *output = NULL, *data_ptr = NULL;
+ uint32_t total_size = 0, per_radio_size = 0, data_len = 0, rem_len = 0;
+ int num_radios = 0, id = 0, subcmd = 0, len = 0;
+
+ // ALOGI("In GetLinkStatsCommand::handleResponse");
+
+ if (reply.get_cmd() != NL80211_CMD_VENDOR) {
+ ALOGD("Ignoring reply with cmd = %d", reply.get_cmd());
+ return NL_SKIP;
+ }
+
+ id = reply.get_vendor_id();
+ subcmd = reply.get_vendor_subcmd();
+ nlattr *vendor_data = reply.get_attribute(NL80211_ATTR_VENDOR_DATA);
+ len = reply.get_vendor_data_len();
+
+ ALOGV("Id = %0x, subcmd = %d, len = %d\n", id, subcmd, len);
+ if (vendor_data == NULL || len == 0) {
+ ALOGE("no vendor data in GetLinkStatCommand response; ignoring it");
+ return NL_SKIP;
+ }
+
+ for (nl_iterator it(vendor_data); it.has_next(); it.next()) {
+ if (it.get_type() == ANDR_WIFI_ATTRIBUTE_NUM_RADIO) {
+ num_radios = it.get_u32();
+ } else if (it.get_type() == ANDR_WIFI_ATTRIBUTE_STATS_INFO) {
+ data = it.get_data();
+ data_len = it.get_len();
+ } else {
+ ALOGW("Ignoring invalid attribute type = %d, size = %d\n",
+ it.get_type(), it.get_len());
+ }
+ }
+
+ if (num_radios) {
+ rem_len = MAX_CMD_RESP_BUF_LEN;
+ radioStatsBuf = (u8 *)malloc(MAX_CMD_RESP_BUF_LEN);
+ if (!radioStatsBuf) {
+ ALOGE("No memory\n");
+ return NL_SKIP;
+ }
+ memset(radioStatsBuf, 0, MAX_CMD_RESP_BUF_LEN);
+ output = radioStatsBuf;
+
+ if (!data || !data_len) {
+ ALOGE("%s: null data\n", __func__);
+ return NL_SKIP;
+ }
+
+ data_ptr = (u8*)data;
+ for (int i = 0; i < num_radios; i++) {
+ rem_len -= per_radio_size;
+ if (rem_len < per_radio_size) {
+ ALOGE("No data left for radio %d\n", i);
+ goto exit;
+ }
+ data_ptr = (u8*)data + total_size;
+ if (!data_ptr) {
+ ALOGE("Invalid data for radio index = %d\n", i);
+ goto exit;
+ }
+ radio_stat_ptr =
+ convertToExternalRadioStatStructure((wifi_radio_stat*)data_ptr,
+ &per_radio_size);
+ if (!radio_stat_ptr || !per_radio_size) {
+ ALOGE("No data for radio %d\n", i);
+ continue;
+ }
+ memcpy(output, radio_stat_ptr, per_radio_size);
+ output += per_radio_size;
+ total_size += per_radio_size;
+ }
+
+ iface_stat = ((u8*)data + total_size);
+ if (!iface_stat || data_len < total_size) {
+ ALOGE("No data for iface stats!!, data_len = %d, total_size = %d\n",
+ data_len, total_size);
+ goto exit;
+ }
+ (*mHandler.on_link_stats_results)(id, (wifi_iface_stat *)iface_stat,
+ num_radios, (wifi_radio_stat *)radioStatsBuf);
+ } else {
+ /* To be deprecated, adding it to keep it backward compatible */
+ // ALOGD("GetLinkStatCommand: zero radio case\n");
+ data = reply.get_vendor_data();
+ if (!data) {
+ ALOGE("Invalid vendor data received\n");
+ return NL_SKIP;
+ }
+
+ num_radios = 1;
+ data = reply.get_vendor_data();
+ len = reply.get_vendor_data_len();
+ if (!data || !len) {
+ ALOGE("Invalid vendor data received\n");
+ return NL_SKIP;
+ }
+ radio_stat_ptr =
+ convertToExternalRadioStatStructureLegacy((wifi_radio_stat_internal *)data);
+ if (!radio_stat_ptr) {
+ ALOGE("Invalid stats pointer received\n");
+ return NL_SKIP;
+ }
+ wifi_iface_stat *iface_stat =
+ (wifi_iface_stat *)((char *)&((wifi_radio_stat_internal *)data)->channels
+ + radio_stat_ptr->num_channels * sizeof(wifi_channel_stat));
+ (*mHandler.on_link_stats_results)(id, iface_stat, num_radios, radio_stat_ptr);
+ }
+exit:
+ if (radio_stat_ptr) {
+ free(radio_stat_ptr);
+ radio_stat_ptr = NULL;
+ }
+ if (radioStatsBuf) {
+ free(radioStatsBuf);
+ radioStatsBuf = NULL;
+ }
+ return NL_OK;
+ }
+
+private:
+ wifi_radio_stat *convertToExternalRadioStatStructure(wifi_radio_stat *internal_stat_ptr,
+ uint32_t *per_radio_size) {
+ wifi_radio_stat *external_stat_ptr = NULL;
+ if (!internal_stat_ptr) {
+ ALOGE("Incoming data is null\n");
+ } else {
+ uint32_t channel_size = internal_stat_ptr->num_channels * sizeof(wifi_channel_stat);
+ *per_radio_size = offsetof(wifi_radio_stat, channels) + channel_size;
+ external_stat_ptr = (wifi_radio_stat *)malloc(*per_radio_size);
+ if (external_stat_ptr) {
+ external_stat_ptr->radio = internal_stat_ptr->radio;
+ external_stat_ptr->on_time = internal_stat_ptr->on_time;
+ external_stat_ptr->tx_time = internal_stat_ptr->tx_time;
+ external_stat_ptr->num_tx_levels = internal_stat_ptr->num_tx_levels;
+ external_stat_ptr->tx_time_per_levels = NULL;
+ external_stat_ptr->rx_time = internal_stat_ptr->rx_time;
+ external_stat_ptr->on_time_scan = internal_stat_ptr->on_time_scan;
+ external_stat_ptr->on_time_nbd = internal_stat_ptr->on_time_nbd;
+ external_stat_ptr->on_time_gscan = internal_stat_ptr->on_time_gscan;
+ external_stat_ptr->on_time_roam_scan = internal_stat_ptr->on_time_roam_scan;
+ external_stat_ptr->on_time_pno_scan = internal_stat_ptr->on_time_pno_scan;
+ external_stat_ptr->on_time_hs20 = internal_stat_ptr->on_time_hs20;
+ external_stat_ptr->num_channels = internal_stat_ptr->num_channels;
+ if (internal_stat_ptr->num_channels) {
+ memcpy(&(external_stat_ptr->channels), &(internal_stat_ptr->channels),
+ channel_size);
+ }
+ }
+ }
+ return external_stat_ptr;
+ }
+
+ wifi_radio_stat *convertToExternalRadioStatStructureLegacy(wifi_radio_stat_internal *internal_stat_ptr) {
+ wifi_radio_stat *external_stat_ptr = NULL;
+ if (!internal_stat_ptr) {
+ ALOGE("Sta_ptr is null\n");
+ } else {
+ uint32_t channel_size = internal_stat_ptr->num_channels * sizeof(wifi_channel_stat);
+ uint32_t total_size = sizeof(wifi_radio_stat) + channel_size;
+ external_stat_ptr = (wifi_radio_stat *)malloc(total_size);
+ if (external_stat_ptr) {
+ external_stat_ptr->radio = internal_stat_ptr->radio;
+ external_stat_ptr->on_time = internal_stat_ptr->on_time;
+ external_stat_ptr->tx_time = internal_stat_ptr->tx_time;
+ external_stat_ptr->rx_time = internal_stat_ptr->rx_time;
+ external_stat_ptr->tx_time_per_levels = NULL;
+ external_stat_ptr->num_tx_levels = 0;
+ external_stat_ptr->on_time_scan = internal_stat_ptr->on_time_scan;
+ external_stat_ptr->on_time_nbd = internal_stat_ptr->on_time_nbd;
+ external_stat_ptr->on_time_gscan = internal_stat_ptr->on_time_gscan;
+ external_stat_ptr->on_time_roam_scan = internal_stat_ptr->on_time_roam_scan;
+ external_stat_ptr->on_time_pno_scan = internal_stat_ptr->on_time_pno_scan;
+ external_stat_ptr->on_time_hs20 = internal_stat_ptr->on_time_hs20;
+ external_stat_ptr->num_channels = internal_stat_ptr->num_channels;
+ if (internal_stat_ptr->num_channels) {
+ memcpy(&(external_stat_ptr->channels), &(internal_stat_ptr->channels),
+ channel_size);
+ }
+ }
+ }
+ return external_stat_ptr;
+ }
+};
+
+wifi_error wifi_get_link_stats(wifi_request_id id,
+ wifi_interface_handle iface, wifi_stats_result_handler handler)
+{
+ GetLinkStatsCommand command(iface, handler);
+ return (wifi_error) command.requestResponse();
+}
+
+wifi_error wifi_set_link_stats(
+ wifi_interface_handle /* iface */, wifi_link_layer_params /* params */)
+{
+ /* Return success here since bcom HAL does not need set link stats. */
+ return WIFI_SUCCESS;
+}
+
+wifi_error wifi_clear_link_stats(
+ wifi_interface_handle /* iface */, u32 /* stats_clear_req_mask */,
+ u32 * /* stats_clear_rsp_mask */, u8 /* stop_req */, u8 * /* stop_rsp */)
+{
+ /* Return success here since bcom HAL does not support clear link stats. */
+ return WIFI_SUCCESS;
+}
diff --git a/synadhd/wifi_hal/nan.cpp b/synadhd/wifi_hal/nan.cpp
new file mode 100755
index 0000000..8536564
--- /dev/null
+++ b/synadhd/wifi_hal/nan.cpp
@@ -0,0 +1,5443 @@
+/*
+ * Copyright (C) 2017 The Android Open Source Project
+ *
+ * Portions copyright (C) 2017 Broadcom Limited
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <stdint.h>
+#include <fcntl.h>
+#include <sys/socket.h>
+#include <netlink/genl/genl.h>
+#include <netlink/genl/family.h>
+#include <netlink/genl/ctrl.h>
+#include <linux/rtnetlink.h>
+#include <netpacket/packet.h>
+#include <linux/filter.h>
+#include <linux/errqueue.h>
+#include <ctype.h>
+#include <linux/pkt_sched.h>
+#include <netlink/object-api.h>
+#include <netlink/netlink.h>
+#include <netlink/socket.h>
+
+#include "nl80211_copy.h"
+
+#include "sync.h"
+
+#define LOG_TAG "WifiHAL"
+
+#include <utils/Log.h>
+#include <log/log.h>
+#include "wifi_hal.h"
+#include "common.h"
+#include "cpp_bindings.h"
+#include "netinet/in.h"
+#include "arpa/inet.h"
+#include <openssl/sha.h>
+#include <openssl/evp.h>
+#include <sys/ioctl.h>
+
+/* Changes between incompatible Version of NAN */
+#define NAN_MAJOR_REL_VERSION 1
+/* Changes between Source and Binary compatible Version of NAN */
+#define NAN_MINOR_REL_VERSION 2
+/* Changes between perfectly compatible Version of NAN */
+#define NAN_PATCH_REL_VERSION 3
+
+#define SVC_NAME_TO_HASH 1
+#define NAN_SVC_HASH_SIZE 6
+#define C2S(x) case x: return #x;
+#define NAN_PUB_RECV_FLAG_MAX 15
+#define NAN_SUB_RECV_FLAG_MAX 7
+#define NAN_DISC_IND_MAX 7
+#define NAN_MAX 255
+#define NAN_MIN 0
+#define INVALID 0xFF
+#define NAN_MAX_PERIOD 16
+#define ISGREATER(i, x) (i > x) ? 1 : 0
+#define NAN_MAX_RSSI 90
+#define NAN_SECURITY_SALT_SIZE 14
+#define NAN_MAC_INVALID_TRANSID 0xFFFF
+
+#define SVCHASH_ISNULL(svc_hash) ((((u8 *)(svc_hash))[0] | \
+ ((u8 *)(svc_hash))[1] | \
+ ((u8 *)(svc_hash))[2] | \
+ ((u8 *)(svc_hash))[3] | \
+ ((u8 *)(svc_hash))[4] | \
+ ((u8 *)(svc_hash))[5]) == 0)
+#define ETHER_ISNULLADDR(ea) ((((u8 *)(ea))[0] | \
+ ((u8 *)(ea))[1] | \
+ ((u8 *)(ea))[2] | \
+ ((u8 *)(ea))[3] | \
+ ((u8 *)(ea))[4] | \
+ ((u8 *)(ea))[5]) == 0)
+
+/* NAN structs versioning b/w DHD and HAL
+ * TODO:add versions for each struct*/
+#define NAN_HAL_VERSION_1 0x2
+struct nan_dbg_cntrs {
+ u32 dp_req; /* cmd */
+ u32 dp_resp; /* cmd */
+ u32 dp_req_evt;
+ u32 dp_confirm_evt;
+ u32 transmit_req; /* cmd */
+ u32 transmit_txs; /* event */
+ u32 transmit_recv; /* event */
+};
+nan_dbg_cntrs counters;
+
+u32 current_dhd_hal_ver = 0;
+
+/* TODO: Known bug in Android which was discovered too late and then left in for backward compatibility.
+ * The issue is that the Service Name selected by the framework is invalid - it contains a space.
+ * Therefore, the underlying implementation partially converts it to lower case and uses the results for PMK generation.
+ * I.e. the PMK is generated based on the following service name: "Wi-Fi Aware Data Path"
+ */
+/* SVC Hash generated for svc name string "Wi-Fi Aware Data Path" */
+u8 NAN_OOB_INTEROP_SVC_HASH[NAN_SVC_HASH_SIZE] = {0x05, 0x9e, 0xd4, 0xcf, 0x89, 0x1a};
+#define NAN_OOB_INTEROP_SVC_NAME "Wi-Fi Aware Data Path"
+
+static const char *NanStatusToString(NanStatusType status)
+{
+ switch (status) {
+ C2S(NAN_STATUS_SUCCESS)
+ C2S(NAN_STATUS_INTERNAL_FAILURE)
+ C2S(NAN_STATUS_PROTOCOL_FAILURE)
+ C2S(NAN_STATUS_INVALID_PUBLISH_SUBSCRIBE_ID)
+ C2S(NAN_STATUS_NO_RESOURCE_AVAILABLE)
+ C2S(NAN_STATUS_INVALID_PARAM)
+ C2S(NAN_STATUS_INVALID_REQUESTOR_INSTANCE_ID)
+ C2S(NAN_STATUS_INVALID_NDP_ID)
+ C2S(NAN_STATUS_NAN_NOT_ALLOWED)
+ C2S(NAN_STATUS_NO_OTA_ACK)
+ C2S(NAN_STATUS_ALREADY_ENABLED)
+ C2S(NAN_STATUS_FOLLOWUP_QUEUE_FULL)
+ C2S(NAN_STATUS_UNSUPPORTED_CONCURRENCY_NAN_DISABLED)
+
+ default:
+ return "NAN_STATUS_INTERNAL_FAILURE";
+ }
+}
+
+/* Nan Data Path Security Information */
+typedef struct {
+ /*
+ Unique Instance Id identifying the Responder's service.
+ This is same as publish_id notified on the subscribe side
+ in a publish/subscribe scenario
+ */
+ u32 requestor_instance_id; /* Value 0 for no publish/subscribe */
+ /*
+ Discovery MAC addr of the publisher/peer
+ */
+ u8 peer_disc_mac_addr[NAN_MAC_ADDR_LEN];
+ /*
+ Unique token Id generated on the initiator/responder
+ side used for a NDP session between two NAN devices
+ */
+ NanDataPathId ndp_instance_id;
+} NanDataPathSecInfoRequest;
+/*
+ * Note: NAN_ATTRIBUTE should match with one that on driver side, wl_cfgnan.h and
+ * NanAttrToString as well for enum to string.
+ */
+typedef enum {
+ NAN_ATTRIBUTE_HEADER = 100,
+ NAN_ATTRIBUTE_HANDLE = 101,
+ NAN_ATTRIBUTE_TRANSAC_ID = 102,
+
+ /* NAN Enable request attributes */
+ NAN_ATTRIBUTE_2G_SUPPORT = 103,
+ NAN_ATTRIBUTE_5G_SUPPORT = 104,
+ NAN_ATTRIBUTE_CLUSTER_LOW = 105,
+ NAN_ATTRIBUTE_CLUSTER_HIGH = 106,
+ NAN_ATTRIBUTE_SID_BEACON = 107,
+ NAN_ATTRIBUTE_SYNC_DISC_2G_BEACON = 108,
+ NAN_ATTRIBUTE_SYNC_DISC_5G_BEACON = 109,
+ NAN_ATTRIBUTE_SDF_2G_SUPPORT = 110,
+ NAN_ATTRIBUTE_SDF_5G_SUPPORT = 111,
+ NAN_ATTRIBUTE_RSSI_CLOSE = 112,
+ NAN_ATTRIBUTE_RSSI_MIDDLE = 113,
+ NAN_ATTRIBUTE_RSSI_PROXIMITY = 114,
+ NAN_ATTRIBUTE_HOP_COUNT_LIMIT = 115,
+ NAN_ATTRIBUTE_RANDOM_FACTOR = 116,
+ NAN_ATTRIBUTE_MASTER_PREF = 117,
+ NAN_ATTRIBUTE_PERIODIC_SCAN_INTERVAL = 118,
+
+ /* Nan Publish/Subscribe request attributes */
+ NAN_ATTRIBUTE_PUBLISH_ID = 119,
+ NAN_ATTRIBUTE_TTL = 120,
+ NAN_ATTRIBUTE_PERIOD = 121,
+ NAN_ATTRIBUTE_REPLIED_EVENT_FLAG = 122,
+ NAN_ATTRIBUTE_PUBLISH_TYPE = 123,
+ NAN_ATTRIBUTE_TX_TYPE = 124,
+ NAN_ATTRIBUTE_PUBLISH_COUNT = 125,
+ NAN_ATTRIBUTE_SERVICE_NAME_LEN = 126,
+ NAN_ATTRIBUTE_SERVICE_NAME = 127,
+ NAN_ATTRIBUTE_SERVICE_SPECIFIC_INFO_LEN = 128,
+ NAN_ATTRIBUTE_SERVICE_SPECIFIC_INFO = 129,
+ NAN_ATTRIBUTE_RX_MATCH_FILTER_LEN = 130,
+ NAN_ATTRIBUTE_RX_MATCH_FILTER = 131,
+ NAN_ATTRIBUTE_TX_MATCH_FILTER_LEN = 132,
+ NAN_ATTRIBUTE_TX_MATCH_FILTER = 133,
+ NAN_ATTRIBUTE_SUBSCRIBE_ID = 134,
+ NAN_ATTRIBUTE_SUBSCRIBE_TYPE = 135,
+ NAN_ATTRIBUTE_SERVICERESPONSEFILTER = 136,
+ NAN_ATTRIBUTE_SERVICERESPONSEINCLUDE = 137,
+ NAN_ATTRIBUTE_USESERVICERESPONSEFILTER = 138,
+ NAN_ATTRIBUTE_SSIREQUIREDFORMATCHINDICATION = 139,
+ NAN_ATTRIBUTE_SUBSCRIBE_MATCH = 140,
+ NAN_ATTRIBUTE_SUBSCRIBE_COUNT = 141,
+ NAN_ATTRIBUTE_MAC_ADDR = 142,
+ NAN_ATTRIBUTE_MAC_ADDR_LIST = 143,
+ NAN_ATTRIBUTE_MAC_ADDR_LIST_NUM_ENTRIES = 144,
+ NAN_ATTRIBUTE_PUBLISH_MATCH = 145,
+
+ /* Nan Event attributes */
+ NAN_ATTRIBUTE_ENABLE_STATUS = 146,
+ NAN_ATTRIBUTE_JOIN_STATUS = 147,
+ NAN_ATTRIBUTE_ROLE = 148,
+ NAN_ATTRIBUTE_MASTER_RANK = 149,
+ NAN_ATTRIBUTE_ANCHOR_MASTER_RANK = 150,
+ NAN_ATTRIBUTE_CNT_PEND_TXFRM = 151,
+ NAN_ATTRIBUTE_CNT_BCN_TX = 152,
+ NAN_ATTRIBUTE_CNT_BCN_RX = 153,
+ NAN_ATTRIBUTE_CNT_SVC_DISC_TX = 154,
+ NAN_ATTRIBUTE_CNT_SVC_DISC_RX = 155,
+ NAN_ATTRIBUTE_AMBTT = 156,
+ NAN_ATTRIBUTE_CLUSTER_ID = 157,
+ NAN_ATTRIBUTE_INST_ID = 158,
+ NAN_ATTRIBUTE_OUI = 159,
+ NAN_ATTRIBUTE_STATUS = 160,
+ NAN_ATTRIBUTE_DE_EVENT_TYPE = 161,
+ NAN_ATTRIBUTE_MERGE = 162,
+ NAN_ATTRIBUTE_IFACE = 163,
+ NAN_ATTRIBUTE_CHANNEL = 164,
+ NAN_ATTRIBUTE_PEER_ID = 165,
+ NAN_ATTRIBUTE_NDP_ID = 167,
+ NAN_ATTRIBUTE_SECURITY = 168,
+ NAN_ATTRIBUTE_QOS = 169,
+ NAN_ATTRIBUTE_RSP_CODE = 170,
+ NAN_ATTRIBUTE_INST_COUNT = 171,
+ NAN_ATTRIBUTE_PEER_DISC_MAC_ADDR = 172,
+ NAN_ATTRIBUTE_PEER_NDI_MAC_ADDR = 173,
+ NAN_ATTRIBUTE_IF_ADDR = 174,
+ NAN_ATTRIBUTE_WARMUP_TIME = 175,
+ NAN_ATTRIBUTE_RECV_IND_CFG = 176,
+ NAN_ATTRIBUTE_RSSI_CLOSE_5G = 177,
+ NAN_ATTRIBUTE_RSSI_MIDDLE_5G = 178,
+ NAN_ATTRIBUTE_RSSI_PROXIMITY_5G = 179,
+ NAN_ATTRIBUTE_CONNMAP = 180,
+ NAN_ATTRIBUTE_24G_CHANNEL = 181,
+ NAN_ATTRIBUTE_5G_CHANNEL = 182,
+ NAN_ATTRIBUTE_DWELL_TIME = 183,
+ NAN_ATTRIBUTE_SCAN_PERIOD = 184,
+ NAN_ATTRIBUTE_RSSI_WINDOW_SIZE = 185,
+ NAN_ATTRIBUTE_CONF_CLUSTER_VAL = 186,
+ NAN_ATTRIBUTE_AVAIL_BIT_MAP = 187,
+ NAN_ATTRIBUTE_ENTRY_CONTROL = 188,
+ NAN_ATTRIBUTE_CIPHER_SUITE_TYPE = 189,
+ NAN_ATTRIBUTE_KEY_TYPE = 190,
+ NAN_ATTRIBUTE_KEY_LEN = 191,
+ NAN_ATTRIBUTE_SCID = 192,
+ NAN_ATTRIBUTE_SCID_LEN = 193,
+ NAN_ATTRIBUTE_SDE_CONTROL_CONFIG_DP = 194,
+ NAN_ATTRIBUTE_SDE_CONTROL_SECURITY = 195,
+ NAN_ATTRIBUTE_SDE_CONTROL_DP_TYPE = 196,
+ NAN_ATTRIBUTE_SDE_CONTROL_RANGE_SUPPORT = 197,
+ NAN_ATTRIBUTE_NO_CONFIG_AVAIL = 198,
+ NAN_ATTRIBUTE_2G_AWAKE_DW = 199,
+ NAN_ATTRIBUTE_5G_AWAKE_DW = 200,
+ NAN_ATTRIBUTE_RANGING_INTERVAL = 201,
+ NAN_ATTRIBUTE_RANGING_INDICATION = 202,
+ NAN_ATTRIBUTE_RANGING_INGRESS_LIMIT = 203,
+ NAN_ATTRIBUTE_RANGING_EGRESS_LIMIT = 204,
+ NAN_ATTRIBUTE_RANGING_AUTO_ACCEPT = 205,
+ NAN_ATTRIBUTE_RANGING_RESULT = 206,
+ NAN_ATTRIBUTE_DISC_IND_CFG = 207,
+ NAN_ATTRIBUTE_RSSI_THRESHOLD_FLAG = 208,
+ NAN_ATTRIBUTE_KEY_DATA = 209,
+ NAN_ATTRIBUTE_SDEA_SERVICE_SPECIFIC_INFO_LEN = 210,
+ NAN_ATTRIBUTE_SDEA_SERVICE_SPECIFIC_INFO = 211,
+ NAN_ATTRIBUTE_REASON = 212,
+ NAN_ATTRIBUTE_MATCH_OCCURRED_FLAG = 213,
+ NAN_ATTRIBUTE_OUT_OF_RESOURCE_FLAG = 214,
+ NAN_ATTRIBUTE_DWELL_TIME_5G = 215,
+ NAN_ATTRIBUTE_SCAN_PERIOD_5G = 216,
+ NAN_ATTRIBUTE_SVC_RESPONDER_POLICY = 217,
+ NAN_ATTRIBUTE_EVENT_MASK = 218,
+ NAN_ATTRIBUTE_SUB_SID_BEACON = 219,
+ NAN_ATTRIBUTE_RANDOMIZATION_INTERVAL = 220,
+ NAN_ATTRIBUTE_CMD_RESP_DATA = 221,
+ NAN_ATTRIBUTE_CMD_USE_NDPE = 222,
+ NAN_ATTRIBUTE_ENABLE_MERGE = 223,
+ NAN_ATTRIBUTE_DISCOVERY_BEACON_INTERVAL = 224,
+ NAN_ATTRIBUTE_NSS = 225,
+ NAN_ATTRIBUTE_ENABLE_RANGING = 226,
+ NAN_ATTRIBUTE_DW_EARLY_TERM = 227,
+ NAN_ATTRIBUTE_CHANNEL_INFO = 228,
+ NAN_ATTRIBUTE_NUM_CHANNELS = 229,
+ NAN_ATTRIBUTE_INSTANT_MODE_ENABLE = 230,
+ NAN_ATTRIBUTE_INSTANT_COMM_CHAN = 231
+} NAN_ATTRIBUTE;
+
+typedef enum {
+ NAN_REQUEST_ENABLE = 0,
+ NAN_REQUEST_DISABLE = 1,
+ NAN_REQUEST_PUBLISH = 2,
+ NAN_REQUEST_PUBLISH_CANCEL = 3,
+ NAN_REQUEST_TRANSMIT_FOLLOWUP = 4,
+ NAN_REQUEST_SUBSCRIBE = 5,
+ NAN_REQUEST_SUBSCRIBE_CANCEL = 6,
+ NAN_REQUEST_STATS = 7,
+ NAN_REQUEST_CONFIG = 8,
+ NAN_REQUEST_TCA = 9,
+ NAN_REQUEST_EVENT_CHECK = 10,
+ NAN_REQUEST_GET_CAPABILITIES = 11,
+ NAN_DATA_PATH_IFACE_CREATE = 12,
+ NAN_DATA_PATH_IFACE_DELETE = 13,
+ NAN_DATA_PATH_INIT_REQUEST = 14,
+ NAN_DATA_PATH_IND_RESPONSE = 15,
+ NAN_DATA_PATH_END = 16,
+ NAN_DATA_PATH_IFACE_UP = 17,
+ NAN_DATA_PATH_SEC_INFO = 18,
+ NAN_VERSION_INFO = 19,
+ NAN_REQUEST_LAST = 0xFFFF
+} NanRequestType;
+
+/*
+ * The enum is based on the BCME Response defs
+ * used in the firmware and defined at
+ * path: src/include/bcmeutils.h
+ */
+enum nan_response_status {
+ BCME_OK = 0,
+ BCME_ERROR = -1,
+ BCME_BADARG = -2,
+ BCME_BADRATESET = -12,
+ BCME_BADBAND = -13,
+ BCME_BUSY = -16,
+ BCME_BADCHAN = -20,
+ BCME_UNSUPPORTED = -23,
+ BCME_BADLEN = -24,
+ BCME_NOTREADY = -25,
+ BCME_NOMEM = -27,
+ BCME_NOTFOUND = -30,
+ BCME_TXFAIL = -38,
+ BCME_RXFAIL = -39,
+ BCME_SCANREJECT = -43,
+ BCME_USAGE_ERROR = -44,
+ BCME_IOCTL_ERROR = -45
+};
+
+enum nan_de_event_type {
+ NAN_EVENT_IFACE = 0,
+ NAN_EVENT_START = 1,
+ NAN_EVENT_JOIN = 2,
+ NAN_EVENT_ROLE_CHANGE = 3,
+ NAN_EVENT_MERGE = 4
+};
+
+typedef struct _nan_hal_resp {
+ u16 instance_id;
+ u16 subcmd;
+ int32_t status;
+ int32_t value;
+ /* Identifier for the instance of the NDP */
+ u16 ndp_instance_id;
+ /* Publisher NMI */
+ u8 pub_nmi[NAN_MAC_ADDR_LEN];
+ /* SVC_HASH */
+ u8 svc_hash[NAN_SVC_HASH_SIZE];
+ char nan_reason[NAN_ERROR_STR_LEN]; /* Describe the NAN reason type */
+ char pad[3];
+ NanCapabilities capabilities;
+} nan_hal_resp_t;
+
+typedef int (*match_fn)(void *p1, void *data);
+
+typedef struct _nan_hal_info {
+ void *nan_handle;
+ void *nan_mac_control;
+ void *nan_disc_control;
+ void *nan_dp_control;
+} nan_hal_info_t;
+
+u8 mNmi[NAN_MAC_ADDR_LEN];
+/* Static functions */
+static int is_de_event(int cmd);
+static int is_dp_event(int cmd);
+static int is_cmd_response(int cmd);
+
+static int get_svc_hash(unsigned char *svc_name, u16 svc_name_len,
+ u8 *svc_hash, u16 svc_hash_len);
+NanResponseType get_response_type(WIFI_SUB_COMMAND nan_subcmd);
+static NanStatusType nan_map_response_status(int vendor_status);
+
+/* Function to separate the common events to NAN1.0 events */
+static int is_de_event(int cmd) {
+ bool is_de_evt = false;
+
+ switch(cmd) {
+ case NAN_EVENT_SUBSCRIBE_UNMATCH:
+ case NAN_EVENT_SUBSCRIBE_TERMINATED:
+ case NAN_EVENT_PUBLISH_TERMINATED:
+ case NAN_EVENT_SUBSCRIBE_MATCH:
+ case NAN_EVENT_FOLLOWUP:
+ case NAN_EVENT_TRANSMIT_FOLLOWUP_IND:
+ case NAN_EVENT_PUBLISH_REPLIED_IND:
+ case NAN_EVENT_MATCH_EXPIRY:
+ is_de_evt = true;
+ break;
+ default:
+ /* Not used */
+ break;
+ }
+ return is_de_evt;
+}
+
+/* Function to separate NAN2.0 events */
+static int is_dp_event(int cmd) {
+ bool is_dp_evt = false;
+
+ switch(cmd) {
+ case NAN_EVENT_DATA_REQUEST:
+ case NAN_EVENT_DATA_CONFIRMATION:
+ case NAN_EVENT_DATA_END:
+ is_dp_evt = true;
+ break;
+ default:
+ /* Not used */
+ break;
+ }
+ return is_dp_evt;
+}
+
+static int is_cmd_response(int cmd) {
+ bool is_cmd_resp = false;
+
+ switch(cmd) {
+ case NAN_ASYNC_RESPONSE_DISABLED:
+ is_cmd_resp = true;
+ break;
+ default:
+ break;
+ }
+ return is_cmd_resp;
+}
+
+static NanStatusType nan_map_response_status (int vendor_status) {
+ NanStatusType hal_status;
+
+ switch(vendor_status) {
+ case BCME_OK:
+ hal_status = NAN_STATUS_SUCCESS;
+ break;
+ case BCME_BUSY:
+ hal_status = NAN_STATUS_NO_RESOURCE_AVAILABLE;
+ break;
+ case BCME_NOTREADY:
+ hal_status = NAN_STATUS_NAN_NOT_ALLOWED;
+ break;
+ case BCME_BADLEN:
+ case BCME_BADBAND:
+ hal_status = NAN_STATUS_INVALID_PARAM;
+ break;
+ case BCME_NOMEM:
+ hal_status = NAN_STATUS_NO_RESOURCE_AVAILABLE;
+ break;
+ case NAN_STATUS_INTERNAL_FAILURE:
+ case NAN_STATUS_PROTOCOL_FAILURE:
+ case NAN_STATUS_INVALID_PUBLISH_SUBSCRIBE_ID:
+ case NAN_STATUS_NO_RESOURCE_AVAILABLE:
+ case NAN_STATUS_INVALID_PARAM:
+ case NAN_STATUS_INVALID_REQUESTOR_INSTANCE_ID:
+ case NAN_STATUS_INVALID_NDP_ID:
+ case NAN_STATUS_NAN_NOT_ALLOWED:
+ case NAN_STATUS_NO_OTA_ACK:
+ case NAN_STATUS_ALREADY_ENABLED:
+ case NAN_STATUS_FOLLOWUP_QUEUE_FULL:
+ case NAN_STATUS_UNSUPPORTED_CONCURRENCY_NAN_DISABLED:
+ hal_status = (NanStatusType)vendor_status;
+ break;
+ default:
+ ALOGE("%s Unknown vendor status, status = %d\n",
+ __func__, vendor_status);
+ /* Generic error */
+ hal_status = NAN_STATUS_INTERNAL_FAILURE;
+ }
+ return hal_status;
+}
+
+static void prhex(const char *msg, u8 *buf, u32 nbytes);
+static const char *NanAttrToString(u16 cmd);
+static const char *NanCmdToString(int cmd);
+static const char *NanRspToString(int cmd);
+
+#define NAN_DBG_ENTER() {ALOGI("Enter: %s\n", __func__);}
+#define NAN_DBG_EXIT() {ALOGI("Exit: %s\n", __func__);}
+
+static int passphrase_to_pmk(u8 *peer_mac, u32 cipher_type,
+ u8 *svc_hash, NanSecurityKeyInfo *key_info, u8 *pmk_hex) {
+ int result = NAN_STATUS_SUCCESS;
+ u8 salt[NAN_SECURITY_SALT_SIZE];
+
+ NAN_DBG_ENTER();
+ salt[0] = 0; /* salt_version */
+ salt[1] = cipher_type;
+ if (svc_hash && peer_mac) {
+ memcpy(&salt[2], svc_hash, NAN_SVC_HASH_SIZE);
+ memcpy(&salt[2 + NAN_SVC_HASH_SIZE], peer_mac,
+ ETHER_ADDR_LEN);
+ prhex("Salt", salt, NAN_SECURITY_SALT_SIZE);
+ } else {
+ ALOGE("Mandory parameters are not present\n");
+ return WIFI_ERROR_INVALID_ARGS;
+ }
+ if (key_info->body.passphrase_info.passphrase_len < NAN_SECURITY_MIN_PASSPHRASE_LEN ||
+ key_info->body.passphrase_info.passphrase_len > NAN_SECURITY_MAX_PASSPHRASE_LEN) {
+ ALOGE("passphrase must be between %d and %d characters long\n",
+ NAN_SECURITY_MIN_PASSPHRASE_LEN,
+ NAN_SECURITY_MAX_PASSPHRASE_LEN);
+ return WIFI_ERROR_INVALID_ARGS;
+ }
+
+ result = PKCS5_PBKDF2_HMAC((const char *) key_info->body.passphrase_info.passphrase,
+ key_info->body.passphrase_info.passphrase_len, salt, sizeof(salt),
+ 4096, ((cipher_type == NAN_CIPHER_SUITE_SHARED_KEY_128_MASK) ?
+ (const EVP_MD *)EVP_sha256():(const EVP_MD *)EVP_sha384()), NAN_PMK_INFO_LEN, pmk_hex);
+ prhex("PMK_HEX", pmk_hex, 32);
+ NAN_DBG_EXIT();
+ return result;
+}
+
+typedef void *NanRequest;
+nan_hal_info_t info;
+
+#define SVC_LIST(info) ((info).svc_list)
+#define SVC_LIST_SIZE(info) ((info).svc_list.total_items)
+#define DP_SVC_LIST(info) ((info).dp_svc_list)
+#define DP_SVC_LIST_SIZE(info) ((info).dp_svc_list.total_items)
+#define NAN_HANDLE(info) ((info).nan_handle)
+#define GET_NAN_HANDLE(info) ((NanHandle *)info.nan_handle)
+#define NAN_MAC_CONTROL(info) ((info).nan_mac_control)
+
+///////////////////////////////////////////////////////////////////////////////
+class NanHandle
+{
+ public:
+ NanCallbackHandler mHandlers;
+ NanHandle(wifi_handle handle, NanCallbackHandler handlers):mHandlers(handlers)
+ {}
+
+};
+
+void HandleExpiryEvent(nan_hal_info_t info, nlattr *vendor_data) {
+ ALOGI("Received NAN_EVENT_MATCH_EXPIRY\n");
+ u16 attr_type;
+ NanMatchExpiredInd expired_event;
+ memset(&expired_event, 0, sizeof(NanMatchExpiredInd));
+
+ for (nl_iterator it(vendor_data); it.has_next(); it.next()) {
+ attr_type = it.get_type();
+ if (attr_type == NAN_ATTRIBUTE_SUBSCRIBE_ID) {
+ expired_event.publish_subscribe_id = it.get_u16();
+ ALOGI("pub_sub id = %u\n",
+ expired_event.publish_subscribe_id);
+ } else if (attr_type == NAN_ATTRIBUTE_PUBLISH_ID) {
+ expired_event.requestor_instance_id = it.get_u32();
+ ALOGI("req_inst id = %u\n", expired_event.requestor_instance_id);
+ }
+ }
+
+ if (expired_event.requestor_instance_id && expired_event.publish_subscribe_id) {
+ GET_NAN_HANDLE(info)->mHandlers.EventMatchExpired(&expired_event);
+ } else {
+ ALOGE("Invalid values for notifying the expired event, dropping the event\n");
+ }
+}
+
+///////////////////////////////////////////////////////////////////////////////
+class NanDiscEnginePrimitive : public WifiCommand
+{
+ NanRequest mParams;
+ NanRequestType mType;
+ u16 mInstId;
+ u32 mPeerId;
+ u16 mTxId;
+
+ public:
+ NanDiscEnginePrimitive(wifi_interface_handle iface, int id,
+ NanRequest params, NanRequestType cmdType)
+ : WifiCommand("NanCommand", iface, id), mParams(params), mType(cmdType)
+ {
+ mInstId = 0;
+ mPeerId = 0;
+ setTransactionId(id);
+ }
+
+ ~NanDiscEnginePrimitive() {
+ ALOGE("NanDiscEnginePrimitive destroyed\n");
+ }
+
+ void setType(NanRequestType type) {
+ mType = type;
+ }
+
+ void setInstId(u16 inst_id) {
+ mInstId = inst_id;
+ }
+
+ int getInstanceId() {
+ return mInstId;
+ }
+
+ void setTransactionId(u16 tx_id) {
+ mTxId = tx_id;
+ }
+
+ int getTransactionId() {
+ return mTxId;
+ }
+
+ void setParams(NanRequest params) {
+ mParams = params;
+ }
+
+ int createRequest(WifiRequest& request)
+ {
+ ALOGI("NAN CMD: %s\n", NanCmdToString(mType));
+ if (mType == NAN_REQUEST_SUBSCRIBE) {
+ return createSubscribeRequest(request,
+ (NanSubscribeRequest *)mParams);
+ } else if (mType == NAN_REQUEST_SUBSCRIBE_CANCEL) {
+ return createSubscribeCancelRequest(request,
+ (NanSubscribeCancelRequest *)mParams);
+ } else if (mType == NAN_REQUEST_PUBLISH) {
+ return createPublishRequest(request,
+ (NanPublishRequest *)mParams);
+ } else if (mType == NAN_REQUEST_PUBLISH_CANCEL) {
+ return createPublishCancelRequest(request,
+ (NanPublishCancelRequest *)mParams);
+ } else if (mType == NAN_REQUEST_TRANSMIT_FOLLOWUP) {
+ return createTransmitFollowupRequest(request,
+ (NanTransmitFollowupRequest *)mParams);
+ } else if (mType == NAN_REQUEST_GET_CAPABILITIES) {
+ return getCapabilitiesRequest(request);
+ } else {
+ ALOGE("%s Unknown Nan request\n", __func__);
+ }
+ return WIFI_SUCCESS;
+ }
+
+ int createPublishRequest(WifiRequest& request, NanPublishRequest *mParams)
+ {
+ NAN_DBG_ENTER();
+ u8 pmk_hex[NAN_PMK_INFO_LEN];
+ int result = request.create(GOOGLE_OUI, NAN_SUBCMD_PUBLISH);
+ if (result < 0) {
+ ALOGE("%s Failed to create request, result = %d\n", __func__, result);
+ return result;
+ }
+
+ /* If handle is 0xFFFF, then update instance_id in response of this request
+ * otherwise, update not needed
+ */
+ mInstId = mParams->publish_id;
+ nlattr *data = request.attr_start(NL80211_ATTR_VENDOR_DATA);
+
+ result = request.put_u32(NAN_ATTRIBUTE_PUBLISH_ID, mInstId);
+ if (result < 0) {
+ ALOGE("%s: Failed to fill pub id, result = %d\n", __func__, result);
+ return result;
+ }
+
+ result = request.put_u16(NAN_ATTRIBUTE_TTL, mParams->ttl);
+ if (result < 0) {
+ ALOGE("%s: Failed to fill ttl, result = %d\n", __func__, result);
+ return result;
+ }
+
+ if (ISGREATER(mParams->period, NAN_MAX_PERIOD)) {
+ ALOGE("%s:Invalid period value.\n", __FUNCTION__);
+ return WIFI_ERROR_NOT_SUPPORTED;
+ }
+ result = request.put_u16(NAN_ATTRIBUTE_PERIOD, mParams->period);
+ if (result < 0) {
+ ALOGE("%s: Failed to fill period, result = %d\n", __func__, result);
+ return result;
+ }
+
+ result = request.put_u8(NAN_ATTRIBUTE_PUBLISH_TYPE, mParams->publish_type);
+ if (result < 0) {
+ ALOGE("%s: Failed to fill pub type, result = %d\n", __func__, result);
+ return result;
+ }
+
+ result = request.put_u8(NAN_ATTRIBUTE_TX_TYPE, mParams->tx_type);
+ if (result < 0) {
+ ALOGE("%s: Failed to fill tx type, result = %d\n", __func__, result);
+ return result;
+ }
+
+ result = request.put_u8(NAN_ATTRIBUTE_PUBLISH_COUNT, mParams->publish_count);
+ if (result < 0) {
+ ALOGE("%s: Failed to fill pub cnt, result = %d\n", __func__, result);
+ return result;
+ }
+
+ if (mParams->service_name_len) {
+ u8 svc_hash[NAN_SVC_HASH_SIZE];
+
+ result = get_svc_hash(mParams->service_name, mParams->service_name_len,
+ svc_hash, NAN_SVC_HASH_SIZE);
+ if (result < 0) {
+ ALOGE("%s: Failed to get hashed svc name\n", __func__);
+ return result;
+ }
+
+ mParams->service_name_len = NAN_SVC_HASH_SIZE;
+ memcpy(mParams->service_name, svc_hash, mParams->service_name_len);
+
+ result = request.put_u16(NAN_ATTRIBUTE_SERVICE_NAME_LEN, mParams->service_name_len);
+ if (result < 0) {
+ ALOGE("%s: Failed to fill svc name len, result = %d\n", __func__, result);
+ return result;
+ }
+
+ result = request.put(NAN_ATTRIBUTE_SERVICE_NAME, (void *)mParams->service_name,
+ mParams->service_name_len);
+ if (result < 0) {
+ ALOGE("%s: Failed to fill svc name, result = %d\n", __func__, result);
+ return result;
+ }
+ }
+
+ if (mParams->service_specific_info_len) {
+ result = request.put_u16(NAN_ATTRIBUTE_SERVICE_SPECIFIC_INFO_LEN,
+ mParams->service_specific_info_len);
+ if (result < 0) {
+ ALOGE("%s: Failed to fill svc info len, result = %d\n", __func__, result);
+ return result;
+ }
+
+ result = request.put(NAN_ATTRIBUTE_SERVICE_SPECIFIC_INFO,
+ (void *)mParams->service_specific_info, mParams->service_specific_info_len);
+ if (result < 0) {
+ ALOGE("%s: Failed to fill svc info, result = %d\n", __func__, result);
+ return result;
+ }
+ }
+
+ if (mParams->rx_match_filter_len) {
+ result = request.put_u16(NAN_ATTRIBUTE_RX_MATCH_FILTER_LEN,
+ mParams->rx_match_filter_len);
+ if (result < 0) {
+ ALOGE("%s: Failed to fill rx match filter len, result = %d\n",
+ __func__, result);
+ return result;
+ }
+
+ prhex(NULL, mParams->rx_match_filter, mParams->rx_match_filter_len);
+ result = request.put(NAN_ATTRIBUTE_RX_MATCH_FILTER,
+ (void *)mParams->rx_match_filter, mParams->rx_match_filter_len);
+ if (result < 0) {
+ ALOGE("%s: Failed to fill rx match filter, result = %d\n", __func__, result);
+ return result;
+ }
+ }
+
+ if (mParams->tx_match_filter_len) {
+ result = request.put_u16(NAN_ATTRIBUTE_TX_MATCH_FILTER_LEN,
+ mParams->tx_match_filter_len);
+ if (result < 0) {
+ ALOGE("%s: Failed to fill tx match filter, result = %d\n", __func__, result);
+ return result;
+ }
+
+ prhex(NULL, mParams->tx_match_filter, mParams->tx_match_filter_len);
+ result = request.put(NAN_ATTRIBUTE_TX_MATCH_FILTER,
+ (void *)mParams->tx_match_filter, mParams->tx_match_filter_len);
+ if (result < 0) {
+ ALOGE("%s: Failed to fill tx match filter, result = %d\n",
+ __func__, result);
+ return result;
+ }
+ }
+
+ result = request.put_u8(NAN_ATTRIBUTE_PUBLISH_MATCH, mParams->publish_match_indicator);
+ if (result < 0) {
+ ALOGE("%s: Failed to fill NAN_ATTRIBUTE_PUBLISH_MATCH, result = %d\n",
+ __func__, result);
+ return result;
+ }
+
+ if (ISGREATER(mParams->recv_indication_cfg, NAN_PUB_RECV_FLAG_MAX)) {
+ ALOGE("%s:Invalid recv_flag value.\n", __FUNCTION__);
+ return WIFI_ERROR_NOT_SUPPORTED;
+ }
+ result = request.put_u8(NAN_ATTRIBUTE_RECV_IND_CFG,
+ mParams->recv_indication_cfg);
+ if (result < 0) {
+ ALOGE("%s: Failed to fill NAN_ATTRIBUTE_RECV_IND_CFG, result = %d\n",
+ __func__, result);
+ return result;
+ }
+
+ result = request.put_u8(NAN_ATTRIBUTE_CIPHER_SUITE_TYPE,
+ mParams->cipher_type);
+ if (result < 0) {
+ ALOGE("%s: Failed to fill NAN_ATTRIBUTE_CIPHER_SUITE_TYPE, result = %d\n",
+ __func__, result);
+ return result;
+ }
+
+ result = request.put_u8(NAN_ATTRIBUTE_KEY_TYPE,
+ mParams->key_info.key_type);
+ if (result < 0) {
+ ALOGE("%s: Failed to fill NAN_ATTRIBUTE_KEY_TYPE, result = %d\n",
+ __func__, result);
+ return result;
+ }
+
+ if (mParams->key_info.key_type == NAN_SECURITY_KEY_INPUT_PMK) {
+ if (mParams->key_info.body.pmk_info.pmk_len) {
+ result = request.put_u32(NAN_ATTRIBUTE_KEY_LEN,
+ mParams->key_info.body.pmk_info.pmk_len);
+ if (result < 0) {
+ ALOGE("%s: Failed to fill pmk len, result = %d\n", __func__, result);
+ return result;
+ }
+ result = request.put(NAN_ATTRIBUTE_KEY_DATA,
+ (void *)mParams->key_info.body.pmk_info.pmk,
+ mParams->key_info.body.pmk_info.pmk_len);
+ if (result < 0) {
+ ALOGE("%s: Failed to fill pmk, result = %d\n", __func__, result);
+ return result;
+ }
+ }
+ }
+
+ if (mParams->key_info.key_type == NAN_SECURITY_KEY_INPUT_PASSPHRASE) {
+ if (mParams->key_info.body.passphrase_info.passphrase_len < NAN_SECURITY_MIN_PASSPHRASE_LEN ||
+ mParams->key_info.body.passphrase_info.passphrase_len > NAN_SECURITY_MAX_PASSPHRASE_LEN) {
+ ALOGE("passphrase must be between %d and %d characters long\n",
+ NAN_SECURITY_MIN_PASSPHRASE_LEN,
+ NAN_SECURITY_MAX_PASSPHRASE_LEN);
+ return NAN_STATUS_INVALID_PARAM;
+ } else {
+ memset(pmk_hex, 0, NAN_PMK_INFO_LEN);
+ result = passphrase_to_pmk(mNmi, mParams->cipher_type,
+ mParams->service_name, &mParams->key_info, pmk_hex);
+ if (result < 0) {
+ ALOGE("%s: Failed to convert passphrase to key data, result = %d\n", __func__, result);
+ return result;
+ }
+ result = request.put_u32(NAN_ATTRIBUTE_KEY_LEN, NAN_PMK_INFO_LEN);
+ if (result < 0) {
+ ALOGE("%s: Failed to fill passphrase len, result = %d\n", __func__, result);
+ return result;
+ }
+ result = request.put(NAN_ATTRIBUTE_KEY_DATA, pmk_hex, NAN_PMK_INFO_LEN);
+ if (result < 0) {
+ ALOGE("%s: Failed to fill passphrase, result = %d\n", __func__, result);
+ return result;
+ }
+ }
+ }
+
+ if (mParams->scid_len) {
+ if ((mParams->scid_len > NAN_MAX_SCID_BUF_LEN) ||
+ (mParams->scid_len % NAN_SCID_INFO_LEN)) {
+ ALOGE("%s: Invalid scid len, = %d\n", __func__, mParams->scid_len);
+ return NAN_STATUS_INVALID_PARAM;
+ }
+ result = request.put_u32(NAN_ATTRIBUTE_SCID_LEN,
+ mParams->scid_len);
+ if (result < 0) {
+ ALOGE("%s: Failed to fill scid len, result = %d\n", __func__, result);
+ return result;
+ }
+
+ prhex(NULL, mParams->scid, mParams->scid_len);
+ result = request.put(NAN_ATTRIBUTE_SCID,
+ (void *)mParams->scid, mParams->scid_len);
+ if (result < 0) {
+ ALOGE("%s: Failed to fill scid, result = %d\n", __func__, result);
+ return result;
+ }
+ }
+
+ result = request.put_u8(NAN_ATTRIBUTE_SDE_CONTROL_CONFIG_DP,
+ mParams->sdea_params.config_nan_data_path);
+
+ if (result < 0) {
+ ALOGE("%s: Failed to fill NAN_ATTRIBUTE_SDE_CONTROL_CONFIG_DP, result = %d\n", __func__, result);
+ return result;
+ }
+
+ result = request.put_u8(NAN_ATTRIBUTE_SDE_CONTROL_SECURITY,
+ mParams->sdea_params.security_cfg);
+ if (result < 0) {
+ ALOGE("%s: Failed to fill NAN_ATTRIBUTE_SDE_CONTROL_SECURITY, result = %d\n", __func__, result);
+ return result;
+ }
+
+ result = request.put_u8(NAN_ATTRIBUTE_SDE_CONTROL_DP_TYPE,
+ mParams->sdea_params.ndp_type);
+ if (result < 0) {
+ ALOGE("%s: Failed to fill NAN_ATTRIBUTE_SDE_CONTROL_DP_TYPE, result = %d\n", __func__, result);
+ return result;
+ }
+
+ result = request.put_u8(NAN_ATTRIBUTE_SDE_CONTROL_RANGE_SUPPORT,
+ mParams->sdea_params.ranging_state);
+ if (result < 0) {
+ ALOGE("%s: Failed to fill NAN_ATTRIBUTE_SDE_CONTROL_RANGE_SUPPORT, result = %d\n", __func__, result);
+ return result;
+ }
+
+ result = request.put_u8(NAN_ATTRIBUTE_RSSI_THRESHOLD_FLAG,
+ mParams->rssi_threshold_flag);
+ if (result < 0) {
+ ALOGE("%s: Failed to fill NAN_ATTRIBUTE_RSSI_THRESHOLD_FLAG, result = %d\n",
+ __func__, result);
+ return result;
+ }
+
+ if (mParams->sdea_service_specific_info_len) {
+ result = request.put_u16(NAN_ATTRIBUTE_SDEA_SERVICE_SPECIFIC_INFO_LEN,
+ mParams->sdea_service_specific_info_len);
+ if (result < 0) {
+ ALOGE("%s: Failed to fill sdea svc info len, result = %d\n", __func__, result);
+ return result;
+ }
+
+ prhex(NULL, mParams->sdea_service_specific_info, mParams->sdea_service_specific_info_len);
+ result = request.put(NAN_ATTRIBUTE_SDEA_SERVICE_SPECIFIC_INFO,
+ (void *)mParams->sdea_service_specific_info, mParams->sdea_service_specific_info_len);
+ if (result < 0) {
+ ALOGE("%s: Failed to fill sdea svc info, result = %d\n", __func__, result);
+ return result;
+ }
+ }
+
+ result = request.put_u8(NAN_ATTRIBUTE_SVC_RESPONDER_POLICY,
+ mParams->service_responder_policy);
+ if (result < 0) {
+ ALOGE("%s: Failed to fill NAN_ATTRIBUTE_SVC_RESPONDER_POLICY, result = %d\n",
+ __func__, result);
+ return result;
+ }
+
+ request.attr_end(data);
+
+ ALOGI("Returning successfully\n");
+ NAN_DBG_EXIT();
+ return result;
+ }
+
+ int createPublishCancelRequest(WifiRequest& request, NanPublishCancelRequest *mParams)
+ {
+ int result = request.create(GOOGLE_OUI, NAN_SUBCMD_PUBLISH_CANCEL);
+ if (result < 0) {
+ ALOGE("%s: Failed to create request, result = %d\n", __func__, result);
+ return result;
+ }
+
+ NAN_DBG_ENTER();
+ nlattr *data = request.attr_start(NL80211_ATTR_VENDOR_DATA);
+
+ if (ISGREATER(mInstId, NAN_MAX)) {
+ ALOGE("%s:Invalid publish count value.\n", __FUNCTION__);
+ return WIFI_ERROR_NOT_SUPPORTED;
+ }
+ ALOGI("%s: pub id = %d, inst_id = %d\n", __func__, mParams->publish_id, mInstId);
+
+ result = request.put_u32(NAN_ATTRIBUTE_PUBLISH_ID, mInstId);
+ if (result < 0) {
+ ALOGE("%s: Failed to fill NAN_ATTRIBUTE_PUBLISH_ID, result = %d\n",
+ __func__, result);
+ return result;
+ }
+ request.attr_end(data);
+ NAN_DBG_EXIT();
+ return WIFI_SUCCESS;
+ }
+
+ int createSubscribeRequest(WifiRequest& request, NanSubscribeRequest *mParams)
+ {
+ int result = request.create(GOOGLE_OUI, NAN_SUBCMD_SUBSCRIBE);
+ if (result < 0) {
+ ALOGE("%s Failed to create request\n", __func__);
+ return result;
+ }
+
+ NAN_DBG_ENTER();
+
+ /* If handle is 0xFFFF, then update instance_id in response of this request
+ * otherwise, update not needed
+ */
+ mInstId = mParams->subscribe_id;
+ nlattr *data = request.attr_start(NL80211_ATTR_VENDOR_DATA);
+
+ result = request.put_u16(NAN_ATTRIBUTE_SUBSCRIBE_ID, mInstId);
+ if (result < 0) {
+ ALOGE("%s: Failed to fill sub id, result = %d\n", __func__, result);
+ return result;
+ }
+
+ result = request.put_u16(NAN_ATTRIBUTE_TTL, mParams->ttl);
+ if (result < 0) {
+ ALOGE("%s: Failed to fill ttl, result = %d\n", __func__, result);
+ return result;
+ }
+
+ if (ISGREATER(mParams->period, NAN_MAX_PERIOD)) {
+ ALOGE("%s:Invalid period value.\n", __FUNCTION__);
+ return WIFI_ERROR_NOT_SUPPORTED;
+ }
+ result = request.put_u16(NAN_ATTRIBUTE_PERIOD, mParams->period);
+ if (result < 0) {
+ ALOGE("%s: Failed to fill period, result = %d\n", __func__, result);
+ return result;
+ }
+
+ result = request.put_u8(NAN_ATTRIBUTE_SUBSCRIBE_TYPE, mParams->subscribe_type);
+ if (result < 0) {
+ ALOGE("%s: Failed to fill sub type, result = %d\n", __func__, result);
+ return result;
+ }
+
+ result = request.put_u8(NAN_ATTRIBUTE_SERVICERESPONSEFILTER,
+ mParams->serviceResponseFilter);
+ if (result < 0) {
+ ALOGE("%s: Failed to fill svc resp filter, result = %d\n", __func__, result);
+ return result;
+ }
+
+ result = request.put_u8(NAN_ATTRIBUTE_SERVICERESPONSEINCLUDE,
+ mParams->serviceResponseInclude);
+ if (result < 0) {
+ ALOGE("%s: Failed to fill svc resp include, result = %d\n", __func__, result);
+ return result;
+ }
+
+ result = request.put_u8(NAN_ATTRIBUTE_USESERVICERESPONSEFILTER,
+ mParams->useServiceResponseFilter);
+ if (result < 0) {
+ ALOGE("%s: Failed to fill use svc resp filter, result = %d\n", __func__, result);
+ return result;
+ }
+
+ result = request.put_u8(NAN_ATTRIBUTE_SSIREQUIREDFORMATCHINDICATION,
+ mParams->ssiRequiredForMatchIndication);
+ if (result < 0) {
+ ALOGE("%s: Failed to fill ssi req match ind, result = %d\n", __func__, result);
+ return result;
+ }
+
+ result = request.put_u8(NAN_ATTRIBUTE_SUBSCRIBE_MATCH,
+ mParams->subscribe_match_indicator);
+ if (result < 0) {
+ ALOGE("%s: Failed to fill sub match, result = %d\n", __func__, result);
+ return result;
+ }
+
+ result = request.put_u8(NAN_ATTRIBUTE_SUBSCRIBE_COUNT, mParams->subscribe_count);
+ if (result < 0) {
+ ALOGE("%s: Failed to fill sub cnt, result = %d\n", __func__, result);
+ return result;
+ }
+
+ if (mParams->service_name_len) {
+ u8 svc_hash[NAN_SVC_HASH_SIZE];
+
+ result = get_svc_hash(mParams->service_name, mParams->service_name_len,
+ svc_hash, NAN_SVC_HASH_SIZE);
+ if (result < 0) {
+ ALOGE("%s: Failed to get hashed svc name\n", __func__);
+ return result;
+ }
+
+ mParams->service_name_len = NAN_SVC_HASH_SIZE;
+ memcpy(mParams->service_name, svc_hash, mParams->service_name_len);
+
+ result = request.put_u16(NAN_ATTRIBUTE_SERVICE_NAME_LEN, mParams->service_name_len);
+ if (result < 0) {
+ ALOGE("%s: Failed to fill svc hash len, result = %d\n",
+ __func__, result);
+ return result;
+ }
+
+ result = request.put(NAN_ATTRIBUTE_SERVICE_NAME, (void *)mParams->service_name,
+ mParams->service_name_len);
+ if (result < 0) {
+ ALOGE("%s: Failed to fill hashed svc name, result = %d\n", __func__, result);
+ return result;
+ }
+ }
+
+ if (mParams->service_specific_info_len) {
+ result = request.put_u16(NAN_ATTRIBUTE_SERVICE_SPECIFIC_INFO_LEN,
+ mParams->service_specific_info_len);
+ if (result < 0) {
+ ALOGE("%s: Failed to fill svc info len, result = %d\n", __func__, result);
+ return result;
+ }
+
+ result = request.put(NAN_ATTRIBUTE_SERVICE_SPECIFIC_INFO,
+ (void *)mParams->service_specific_info, mParams->service_specific_info_len);
+ if (result < 0) {
+ ALOGE("%s: Failed to fill svc info, result = %d\n", __func__, result);
+ return result;
+ }
+ }
+
+ if (mParams->rx_match_filter_len) {
+ result = request.put_u16(NAN_ATTRIBUTE_RX_MATCH_FILTER_LEN,
+ mParams->rx_match_filter_len);
+ if (result < 0) {
+ ALOGE("%s: Failed to fill rx match filter len, result = %d\n", __func__, result);
+ return result;
+ }
+
+ prhex(NULL, mParams->rx_match_filter, mParams->rx_match_filter_len);
+ result = request.put(NAN_ATTRIBUTE_RX_MATCH_FILTER,
+ (void *)mParams->rx_match_filter, mParams->rx_match_filter_len);
+ if (result < 0) {
+ ALOGE("%s: Failed to fill rx match filter, result = %d\n", __func__, result);
+ return result;
+ }
+ }
+
+ if (mParams->tx_match_filter_len) {
+ result = request.put_u16(NAN_ATTRIBUTE_TX_MATCH_FILTER_LEN,
+ mParams->tx_match_filter_len);
+ if (result < 0) {
+ ALOGE("%s: Failed to fill tx match filter len, result = %d\n", __func__, result);
+ return result;
+ }
+
+ prhex(NULL, mParams->tx_match_filter, mParams->tx_match_filter_len);
+ result = request.put(NAN_ATTRIBUTE_TX_MATCH_FILTER,
+ (void *)mParams->tx_match_filter, mParams->tx_match_filter_len);
+ if (result < 0) {
+ ALOGE("%s: Failed to fill tx match filter, result = %d\n", __func__, result);
+ return result;
+ }
+ }
+
+ if (mParams->num_intf_addr_present > NAN_MAX_SUBSCRIBE_MAX_ADDRESS) {
+ ALOGE("%s: Number of mac addrs: %d have crossed the threshold, fail to subscribe\n",
+ __func__, mParams->num_intf_addr_present);
+ return WIFI_ERROR_NOT_SUPPORTED;
+ } else if (mParams->num_intf_addr_present) {
+ result = request.put_u16(NAN_ATTRIBUTE_MAC_ADDR_LIST_NUM_ENTRIES,
+ mParams->num_intf_addr_present);
+ if (result < 0) {
+ ALOGE("%s: Failed to fill mac addr list no, result = %d\n",
+ __func__, result);
+ return result;
+ }
+
+ prhex(NULL, (u8 *)mParams->intf_addr,
+ (mParams->num_intf_addr_present * NAN_MAC_ADDR_LEN));
+ result = request.put(NAN_ATTRIBUTE_MAC_ADDR_LIST, (void *)mParams->intf_addr,
+ (mParams->num_intf_addr_present * NAN_MAC_ADDR_LEN));
+ if (result < 0) {
+ ALOGE("%s: Failed to fill mac addr list, result = %d\n", __func__, result);
+ return result;
+ }
+ }
+
+ if (ISGREATER(mParams->recv_indication_cfg, NAN_SUB_RECV_FLAG_MAX)) {
+ ALOGE("%s:Invalid recv_flag value.\n", __FUNCTION__);
+ return WIFI_ERROR_NOT_SUPPORTED;
+ }
+ result = request.put_u8(NAN_ATTRIBUTE_RECV_IND_CFG,
+ mParams->recv_indication_cfg);
+ if (result < 0) {
+ ALOGE("%s: Failed to fill recv_indication_cfg, result = %d\n",
+ __func__, result);
+ return result;
+ }
+
+ result = request.put_u8(NAN_ATTRIBUTE_CIPHER_SUITE_TYPE,
+ mParams->cipher_type);
+ if (result < 0) {
+ ALOGE("%s: Failed to fill NAN_ATTRIBUTE_CIPHER_SUITE_TYPE, result = %d\n",
+ __func__, result);
+ return result;
+ }
+
+ result = request.put_u8(NAN_ATTRIBUTE_KEY_TYPE,
+ mParams->key_info.key_type);
+ if (result < 0) {
+ ALOGE("%s: Failed to fill NAN_ATTRIBUTE_KEY_TYPE, result = %d\n",
+ __func__, result);
+ return result;
+ }
+
+ if (mParams->key_info.key_type == NAN_SECURITY_KEY_INPUT_PMK) {
+ if (mParams->key_info.body.pmk_info.pmk_len) {
+ result = request.put_u32(NAN_ATTRIBUTE_KEY_LEN,
+ mParams->key_info.body.pmk_info.pmk_len);
+ if (result < 0) {
+ ALOGE("%s: Failed to fill pmk len, result = %d\n", __func__, result);
+ return result;
+ }
+ result = request.put(NAN_ATTRIBUTE_KEY_DATA,
+ (void *)mParams->key_info.body.pmk_info.pmk,
+ mParams->key_info.body.pmk_info.pmk_len);
+ if (result < 0) {
+ ALOGE("%s: Failed to fill pmk, result = %d\n", __func__, result);
+ return result;
+ }
+ }
+ }
+
+ if (mParams->scid_len) {
+ if (mParams->scid_len != NAN_SCID_INFO_LEN) {
+ ALOGE("%s: Invalid scid len, = %d\n", __func__, mParams->scid_len);
+ return NAN_STATUS_INVALID_PARAM;
+ }
+ result = request.put_u32(NAN_ATTRIBUTE_SCID_LEN,
+ mParams->scid_len);
+ if (result < 0) {
+ ALOGE("%s: Failed to fill scid len, result = %d\n", __func__, result);
+ return result;
+ }
+
+ result = request.put(NAN_ATTRIBUTE_SCID,
+ (void *)mParams->scid, mParams->scid_len);
+ if (result < 0) {
+ ALOGE("%s: Failed to fill scid, result = %d\n", __func__, result);
+ return result;
+ }
+ }
+
+ result = request.put_u8(NAN_ATTRIBUTE_SDE_CONTROL_CONFIG_DP,
+ mParams->sdea_params.config_nan_data_path);
+ if (result < 0) {
+ ALOGE("%s: Failed to fill config_nan_data_path, result = %d\n", __func__, result);
+ return result;
+ }
+
+ result = request.put_u8(NAN_ATTRIBUTE_SDE_CONTROL_SECURITY,
+ mParams->sdea_params.security_cfg);
+ if (result < 0) {
+ ALOGE("%s: Failed to fill security_cfg, result = %d\n", __func__, result);
+ return result;
+ }
+
+ result = request.put_u8(NAN_ATTRIBUTE_SDE_CONTROL_DP_TYPE,
+ mParams->sdea_params.ndp_type);
+ if (result < 0) {
+ ALOGE("%s: Failed to fill ndp_type, result = %d\n", __func__, result);
+ return result;
+ }
+
+ result = request.put_u8(NAN_ATTRIBUTE_SDE_CONTROL_RANGE_SUPPORT,
+ mParams->sdea_params.ranging_state);
+ if (result < 0) {
+ ALOGE("%s: Failed to fill ranging state, result = %d\n", __func__, result);
+ return result;
+ }
+
+ if (mParams->sdea_params.ranging_state == NAN_RANGING_ENABLE) {
+ result = request.put_u32(NAN_ATTRIBUTE_RANGING_INTERVAL,
+ mParams->ranging_cfg.ranging_interval_msec);
+ if (result < 0) {
+ ALOGE("%s: Failed to fill ranging_interval_msec, result = %d\n", __func__, result);
+ return result;
+ }
+
+ result = request.put_u32(NAN_ATTRIBUTE_RANGING_EGRESS_LIMIT,
+ mParams->ranging_cfg.distance_egress_mm);
+ if (result < 0) {
+ ALOGE("%s: Failed to fill distance_egress_mm, result = %d\n", __func__, result);
+ return result;
+ }
+
+ result = request.put_u32(NAN_ATTRIBUTE_RANGING_INDICATION,
+ mParams->ranging_cfg.config_ranging_indications);
+ if (result < 0) {
+ ALOGE("%s: Failed to fill config_ranging_indications, result = %d\n", __func__, result);
+ return result;
+ }
+
+ result = request.put_u32(NAN_ATTRIBUTE_RANGING_INGRESS_LIMIT,
+ mParams->ranging_cfg.distance_ingress_mm);
+ if (result < 0) {
+ ALOGE("%s: Failed to fill distance_ingress_mm, result = %d\n", __func__, result);
+ return result;
+ }
+ }
+
+ ALOGI("%s:RSSI threshold flag %d", __func__, mParams->rssi_threshold_flag);
+ result = request.put_u8(NAN_ATTRIBUTE_RSSI_THRESHOLD_FLAG,
+ mParams->rssi_threshold_flag);
+ if (result < 0) {
+ ALOGE("%s: Failed to fill rssi_threshold_flag, result = %d\n",
+ __func__, result);
+ return result;
+ }
+
+ if (mParams->sdea_service_specific_info_len) {
+ result = request.put_u16(NAN_ATTRIBUTE_SDEA_SERVICE_SPECIFIC_INFO_LEN,
+ mParams->sdea_service_specific_info_len);
+ if (result < 0) {
+ ALOGE("%s: Failed to fill sdea svc info len, result = %d\n", __func__, result);
+ return result;
+ }
+
+ prhex(NULL, mParams->sdea_service_specific_info, mParams->sdea_service_specific_info_len);
+ result = request.put(NAN_ATTRIBUTE_SDEA_SERVICE_SPECIFIC_INFO,
+ (void *)mParams->sdea_service_specific_info, mParams->sdea_service_specific_info_len);
+ if (result < 0) {
+ ALOGE("%s: Failed to fill sdea svc info, result = %d\n", __func__, result);
+ return result;
+ }
+ }
+
+ request.attr_end(data);
+ NAN_DBG_EXIT();
+ return WIFI_SUCCESS;
+ }
+
+ int createSubscribeCancelRequest(WifiRequest& request,
+ NanSubscribeCancelRequest *mParams) {
+ int result = request.create(GOOGLE_OUI, NAN_SUBCMD_SUBSCRIBE_CANCEL);
+ if (result < 0) {
+ ALOGE("%s Failed to create request \n", __func__);
+ return result;
+ }
+
+ NAN_DBG_ENTER();
+ nlattr *data = request.attr_start(NL80211_ATTR_VENDOR_DATA);
+
+ if (ISGREATER(mInstId, NAN_MAX)) {
+ ALOGE("%s:Invalid subscribe id value.\n", __FUNCTION__);
+ return WIFI_ERROR_NOT_SUPPORTED;
+ }
+ ALOGI("%s: sub id = %u\n", __func__, mInstId);
+
+ result = request.put_u16(NAN_ATTRIBUTE_SUBSCRIBE_ID, mInstId);
+ if (result < 0) {
+ ALOGE("%s: Failed to fill sub id, result = %d\n", __func__, result);
+ return result;
+ }
+
+ request.attr_end(data);
+ NAN_DBG_EXIT();
+ return WIFI_SUCCESS;
+ }
+
+ int createTransmitFollowupRequest(WifiRequest& request,
+ NanTransmitFollowupRequest *mParams)
+ {
+ int result = request.create(GOOGLE_OUI, NAN_SUBCMD_TRANSMIT_FOLLOWUP);
+ if (result < 0) {
+ ALOGE("%s Failed to create request \n", __func__);
+ return result;
+ }
+
+ NAN_DBG_ENTER();
+
+ /* If handle is 0xFFFF, then update instance_id in response of this request
+ * otherwise, update not needed
+ */
+ mInstId = mParams->publish_subscribe_id;
+ mPeerId = mParams->requestor_instance_id;
+ mTxId = getTransactionId();
+ nlattr *data = request.attr_start(NL80211_ATTR_VENDOR_DATA);
+
+ result = request.put_u32(NAN_ATTRIBUTE_PEER_ID, mPeerId);
+ if (result < 0) {
+ ALOGE("%s: Failed to fill peer id, result = %d\n", __func__, result);
+ return result;
+ }
+
+ result = request.put_u16(NAN_ATTRIBUTE_INST_ID, mInstId);
+ if (result < 0) {
+ ALOGE("%s Failed to fill inst id = %d \n", __func__, mInstId);
+ return result;
+ }
+
+ result = request.put_addr(NAN_ATTRIBUTE_MAC_ADDR, mParams->addr);
+ if (result < 0) {
+ ALOGE("%s: Failed to fill mac addr\n", __func__);
+ return result;
+ }
+
+ if (mParams->service_specific_info_len > 0) {
+ result = request.put_u16(NAN_ATTRIBUTE_SERVICE_SPECIFIC_INFO_LEN,
+ mParams->service_specific_info_len);
+ if (result < 0) {
+ ALOGE("%s: Failed to fill svc info len \n", __func__);
+ return result;
+ }
+
+ prhex(NULL, mParams->service_specific_info, mParams->service_specific_info_len);
+ result = request.put(NAN_ATTRIBUTE_SERVICE_SPECIFIC_INFO,
+ (void *)mParams->service_specific_info, mParams->service_specific_info_len);
+ if (result < 0) {
+ ALOGE("%s: Failed to put svc info, result = %d", __func__, result);
+ return result;
+ }
+ mParams->service_specific_info[mParams->service_specific_info_len] = '\0';
+ ALOGI("Transmit service info string is %s\n", mParams->service_specific_info);
+ }
+
+ if (ISGREATER(mParams->recv_indication_cfg, NAN_PUB_RECV_FLAG_MAX)) {
+ ALOGE("%s:Invalid recv_flag value.\n", __FUNCTION__);
+ return WIFI_ERROR_NOT_SUPPORTED;
+ }
+
+ result = request.put_u8(NAN_ATTRIBUTE_RECV_IND_CFG,
+ mParams->recv_indication_cfg);
+ if (result < 0) {
+ ALOGE("%s: Failed to fill NAN_ATTRIBUTE_RECV_IND_CFG, result = %d\n",
+ __func__, result);
+ return result;
+ }
+ result = request.put_u16(NAN_ATTRIBUTE_TRANSAC_ID, mTxId);
+ if (result < 0) {
+ ALOGE("%s: Failed to fill NAN_ATTRIBUTE_TRANSAC_ID, result = %d\n",
+ __func__, result);
+ return result;
+ }
+
+ if (mParams->sdea_service_specific_info_len) {
+ result = request.put_u16(NAN_ATTRIBUTE_SDEA_SERVICE_SPECIFIC_INFO_LEN,
+ mParams->sdea_service_specific_info_len);
+ if (result < 0) {
+ ALOGE("%s: Failed to fill sdea svc info len, result = %d\n", __func__, result);
+ return result;
+ }
+
+ prhex(NULL, mParams->sdea_service_specific_info, mParams->sdea_service_specific_info_len);
+ result = request.put(NAN_ATTRIBUTE_SDEA_SERVICE_SPECIFIC_INFO,
+ (void *)mParams->sdea_service_specific_info, mParams->sdea_service_specific_info_len);
+ if (result < 0) {
+ ALOGE("%s: Failed to fill sdea svc info, result = %d\n", __func__, result);
+ return result;
+ }
+ }
+
+ request.attr_end(data);
+ NAN_DBG_EXIT();
+ return WIFI_SUCCESS;
+ }
+
+ int getCapabilitiesRequest(WifiRequest& request) {
+ int result = 0;
+ NAN_DBG_ENTER();
+
+ result = request.create(GOOGLE_OUI, NAN_SUBCMD_GET_CAPABILITIES);
+ if (result < 0) {
+ ALOGE("%s Failed to create request \n", __func__);
+ return result;
+ }
+ nlattr *data = request.attr_start(NL80211_ATTR_VENDOR_DATA);
+
+ request.attr_end(data);
+
+ NAN_DBG_EXIT();
+ return WIFI_SUCCESS;
+ }
+
+ int start()
+ {
+ int result = 0;
+ WifiRequest request(familyId(), ifaceId());
+ result = createRequest(request);
+ if (result != WIFI_SUCCESS) {
+ ALOGE("%s: Failed to create setup request; result = %d\n", __func__, result);
+ return result;
+ }
+
+ result = requestResponse(request);
+ if (result != WIFI_SUCCESS) {
+ ALOGE("%s: Failed to configure setup; result = %d\n", __func__, result);
+ return result;
+ }
+
+ request.destroy();
+ return WIFI_SUCCESS;
+ }
+
+ virtual bool valid_disc_response_type(int response_type) {
+ bool valid = false;
+ switch(response_type) {
+ case NAN_RESPONSE_PUBLISH:
+ case NAN_RESPONSE_SUBSCRIBE:
+ case NAN_GET_CAPABILITIES:
+ case NAN_RESPONSE_PUBLISH_CANCEL:
+ case NAN_RESPONSE_SUBSCRIBE_CANCEL:
+ case NAN_RESPONSE_TRANSMIT_FOLLOWUP:
+ valid = true;
+ break;
+ default:
+ ALOGE("NanDiscEnginePrmitive:Unknown cmd Response: %d\n", response_type);
+ break;
+ }
+ return valid;
+ }
+
+ int handleResponse(WifiEvent& reply)
+ {
+ nan_hal_resp_t *rsp_vndr_data = NULL;
+ NanResponseMsg rsp_data;
+ u32 len;
+ if (reply.get_cmd() != NL80211_CMD_VENDOR || reply.get_vendor_data() == NULL) {
+ ALOGD("Ignoring reply with cmd = %d", reply.get_cmd());
+ return NL_SKIP;
+ }
+ rsp_vndr_data = (nan_hal_resp_t *)reply.get_vendor_data();
+ len = reply.get_vendor_data_len();
+ ALOGI("NanDiscEnginePrmitive::handle response\n");
+ memset(&rsp_data, 0, sizeof(NanResponseMsg));
+ rsp_data.response_type = get_response_type((WIFI_SUB_COMMAND)rsp_vndr_data->subcmd);
+ if (!valid_disc_response_type(rsp_data.response_type))
+ return NL_SKIP;
+
+ rsp_data.status = nan_map_response_status(rsp_vndr_data->status);
+ ALOGE("Mapped hal status = %d\n", rsp_data.status);
+ if (rsp_vndr_data->nan_reason[0] == '\0') {
+ memcpy(rsp_data.nan_error, NanStatusToString(rsp_data.status),
+ strlen(NanStatusToString(rsp_data.status)));
+ rsp_data.nan_error[strlen(NanStatusToString(rsp_data.status))] = '\0';
+ }
+ rsp_data.nan_error[NAN_ERROR_STR_LEN - 1] = '\0';
+ ALOGI("\n Received nan_error string %s\n", (u8*)rsp_data.nan_error);
+
+ if (mInstId == 0 &&
+ (rsp_data.response_type == NAN_RESPONSE_PUBLISH ||
+ rsp_data.response_type == NAN_RESPONSE_SUBSCRIBE)) {
+ ALOGI("Received service instance_id %d\n", rsp_vndr_data->instance_id);
+ mInstId = rsp_vndr_data->instance_id;
+ }
+
+ if (rsp_data.response_type == NAN_RESPONSE_PUBLISH) {
+ rsp_data.body.publish_response.publish_id = mInstId;
+ } else if (rsp_data.response_type == NAN_RESPONSE_SUBSCRIBE) {
+ rsp_data.body.subscribe_response.subscribe_id = mInstId;
+ } else if (rsp_data.response_type == NAN_GET_CAPABILITIES) {
+ memcpy((void *)&rsp_data.body.nan_capabilities, (void *)&rsp_vndr_data->capabilities,
+ min(len, sizeof(rsp_data.body.nan_capabilities)));
+ }
+
+ GET_NAN_HANDLE(info)->mHandlers.NotifyResponse(id(), &rsp_data);
+ ALOGI("NanDiscEnginePrmitive:Received response for cmd [%s], ret %d\n",
+ NanRspToString(rsp_data.response_type), rsp_data.status);
+
+ return NL_SKIP;
+ }
+
+ int handleEvent(WifiEvent& event) {
+ int cmd = event.get_vendor_subcmd();
+ u16 attr_type;
+
+ ALOGI("Received NanDiscEnginePrimitive event: %d\n", event.get_cmd());
+ nlattr *vendor_data = event.get_attribute(NL80211_ATTR_VENDOR_DATA);
+
+ switch(cmd) {
+ case NAN_EVENT_PUBLISH_TERMINATED:
+ NanPublishTerminatedInd pub_term_event;
+
+ memset(&pub_term_event, 0, sizeof(NanPublishTerminatedInd));
+
+ for (nl_iterator it(vendor_data); it.has_next(); it.next()) {
+ attr_type = it.get_type();
+
+ if (attr_type == NAN_ATTRIBUTE_PUBLISH_ID) {
+ pub_term_event.publish_id = it.get_u32();
+ ALOGI("pub id = %u", pub_term_event.publish_id);
+ } else if (attr_type == NAN_ATTRIBUTE_STATUS) {
+ pub_term_event.reason = (NanStatusType)it.get_u8();
+ ALOGI("pub termination status %u", pub_term_event.reason);
+ } else if (attr_type == NAN_ATTRIBUTE_REASON) {
+ u8 len = min(it.get_len(), sizeof(pub_term_event.nan_reason));
+ memcpy(pub_term_event.nan_reason, it.get_data(), len);
+ ALOGI("pub termination reason: %s, len = %d\n",
+ pub_term_event.nan_reason, len);
+ } else {
+ ALOGE("Unknown attr: %u\n", attr_type);
+ }
+ }
+
+ GET_NAN_HANDLE(info)->mHandlers.EventPublishTerminated(&pub_term_event);
+ break;
+
+ case NAN_EVENT_SUBSCRIBE_MATCH:
+ NanMatchInd subscribe_event;
+
+ memset(&subscribe_event, 0, sizeof(NanMatchInd));
+
+ /* By default FW is unable to cache this match */
+ subscribe_event.out_of_resource_flag = true;
+
+ for (nl_iterator it(vendor_data); it.has_next(); it.next()) {
+ attr_type = it.get_type();
+
+ if (attr_type == NAN_ATTRIBUTE_SUBSCRIBE_ID) {
+ ALOGI("sub id: %u", it.get_u16());
+ subscribe_event.publish_subscribe_id = it.get_u8();
+ } else if (attr_type == NAN_ATTRIBUTE_PUBLISH_ID) {
+ ALOGI("pub id: %u", it.get_u32());
+ subscribe_event.requestor_instance_id = it.get_u8();
+ } else if (attr_type == NAN_ATTRIBUTE_MAC_ADDR) {
+ memcpy(subscribe_event.addr, it.get_data(), NAN_MAC_ADDR_LEN);
+ ALOGI("Publisher mac: " MACSTR, MAC2STR(subscribe_event.addr));
+ } else if (attr_type == NAN_ATTRIBUTE_SERVICE_SPECIFIC_INFO_LEN) {
+ ALOGI("svc length %d", it.get_u16());
+ subscribe_event.service_specific_info_len = it.get_u16();
+ } else if (attr_type == NAN_ATTRIBUTE_SERVICE_SPECIFIC_INFO) {
+ memcpy(subscribe_event.service_specific_info, it.get_data(),
+ subscribe_event.service_specific_info_len);
+ subscribe_event.service_specific_info
+ [subscribe_event.service_specific_info_len] = '\0';
+ ALOGI("service info: %s", subscribe_event.service_specific_info);
+ } else if (attr_type == NAN_ATTRIBUTE_TX_MATCH_FILTER_LEN) {
+ ALOGI("sdf match filter length: %d", subscribe_event.sdf_match_filter_len);
+ subscribe_event.sdf_match_filter_len = it.get_u16();
+ } else if (attr_type == NAN_ATTRIBUTE_TX_MATCH_FILTER) {
+ memcpy(subscribe_event.sdf_match_filter, it.get_data(),
+ subscribe_event.sdf_match_filter_len);
+ subscribe_event.sdf_match_filter
+ [subscribe_event.sdf_match_filter_len] = '\0';
+ ALOGI("sdf match filter: %s", subscribe_event.sdf_match_filter);
+ } else if (attr_type == NAN_ATTRIBUTE_CIPHER_SUITE_TYPE) {
+ ALOGI("Peer Cipher suite type: %u", it.get_u8());
+ subscribe_event.peer_cipher_type = it.get_u8();
+ } else if (attr_type == NAN_ATTRIBUTE_SCID_LEN) {
+ ALOGI("scid length %d", it.get_u32());
+ subscribe_event.scid_len= it.get_u32();
+ } else if (attr_type == NAN_ATTRIBUTE_SCID) {
+ memcpy(subscribe_event.scid, it.get_data(),
+ subscribe_event.scid_len);
+ subscribe_event.scid
+ [subscribe_event.scid_len] = '\0';
+ ALOGI("scid: %s", subscribe_event.scid);
+ } else if (attr_type == NAN_ATTRIBUTE_RANGING_INDICATION) {
+ subscribe_event.range_info.ranging_event_type = it.get_u32();
+ ALOGI("ranging indication %d", it.get_u32());
+ } else if (attr_type == NAN_ATTRIBUTE_RANGING_RESULT) {
+ subscribe_event.range_info.range_measurement_mm = it.get_u32();
+ ALOGI("ranging result %d", it.get_u32());
+ } else if (attr_type == NAN_ATTRIBUTE_RSSI_PROXIMITY) {
+ subscribe_event.rssi_value = it.get_u8();
+ ALOGI("rssi value : %u", it.get_u8());
+ } else if (attr_type == NAN_ATTRIBUTE_SDEA_SERVICE_SPECIFIC_INFO_LEN) {
+ ALOGI("sdea svc length %d", it.get_u16());
+ subscribe_event.sdea_service_specific_info_len = it.get_u16();
+ } else if (attr_type == NAN_ATTRIBUTE_SDEA_SERVICE_SPECIFIC_INFO) {
+ memcpy(subscribe_event.sdea_service_specific_info, it.get_data(),
+ subscribe_event.sdea_service_specific_info_len);
+ subscribe_event.sdea_service_specific_info
+ [subscribe_event.sdea_service_specific_info_len] = '\0';
+ ALOGI("sdea service info: %s", subscribe_event.sdea_service_specific_info);
+ } else if (attr_type == NAN_ATTRIBUTE_MATCH_OCCURRED_FLAG) {
+ ALOGI("match occurred flag: %u", it.get_u8());
+ subscribe_event.match_occured_flag = it.get_u8();
+ } else if (attr_type == NAN_ATTRIBUTE_OUT_OF_RESOURCE_FLAG) {
+ ALOGI("Out of resource flag: %u", it.get_u8());
+ subscribe_event.out_of_resource_flag = it.get_u8();
+ } else if (attr_type == NAN_ATTRIBUTE_SDE_CONTROL_CONFIG_DP) {
+ ALOGI("Peer config for data path needed: %u", it.get_u8());
+ subscribe_event.peer_sdea_params.config_nan_data_path = it.get_u8();
+ } else if (attr_type == NAN_ATTRIBUTE_SDE_CONTROL_DP_TYPE) {
+ ALOGI("Data Path type: %u", it.get_u8());
+ subscribe_event.peer_sdea_params.ndp_type = (NdpType)it.get_u8();
+ } else if (attr_type == NAN_ATTRIBUTE_SDE_CONTROL_SECURITY) {
+ ALOGI("Security configuration: %u", it.get_u8());
+ subscribe_event.peer_sdea_params.security_cfg =
+ (NanDataPathSecurityCfgStatus)it.get_u8();
+ } else if (attr_type == NAN_ATTRIBUTE_SDE_CONTROL_RANGE_SUPPORT) {
+ ALOGI("Ranging report state: %u", it.get_u8());
+ subscribe_event.peer_sdea_params.range_report = (NanRangeReport)it.get_u8();
+ }
+ }
+
+ GET_NAN_HANDLE(info)->mHandlers.EventMatch(&subscribe_event);
+ break;
+
+ case NAN_EVENT_SUBSCRIBE_UNMATCH:
+ ALOGE("%s: Not applicable yet\n", __func__);
+ break;
+
+ case NAN_EVENT_SUBSCRIBE_TERMINATED:
+ NanSubscribeTerminatedInd sub_term_event;
+ memset(&sub_term_event, 0, sizeof(NanSubscribeTerminatedInd));
+
+ for (nl_iterator it(vendor_data); it.has_next(); it.next()) {
+ attr_type = it.get_type();
+
+ if (attr_type == NAN_ATTRIBUTE_SUBSCRIBE_ID) {
+ sub_term_event.subscribe_id = it.get_u16();
+ ALOGI("sub id = %u", sub_term_event.subscribe_id);
+ } else if (attr_type == NAN_ATTRIBUTE_STATUS) {
+ sub_term_event.reason = (NanStatusType)it.get_u16();
+ ALOGI("sub termination status %u", sub_term_event.reason);
+ } else if (attr_type == NAN_ATTRIBUTE_REASON) {
+ u8 len = min(it.get_len(), sizeof(sub_term_event.nan_reason));
+ memcpy(sub_term_event.nan_reason, it.get_data(), len);
+ ALOGI("sub termination nan reason: %s, len = %d\n",
+ sub_term_event.nan_reason, len);
+ } else {
+ ALOGI("Unknown attr: %d\n", attr_type);
+ }
+ }
+
+ GET_NAN_HANDLE(info)->mHandlers.EventSubscribeTerminated(&sub_term_event);
+ break;
+ case NAN_EVENT_MATCH_EXPIRY:
+ HandleExpiryEvent(info, vendor_data);
+ break;
+ case NAN_EVENT_FOLLOWUP:
+ NanFollowupInd followup_event;
+ memset(&followup_event, 0, sizeof(NanFollowupInd));
+
+ for (nl_iterator it(vendor_data); it.has_next(); it.next()) {
+ attr_type = it.get_type();
+
+ if (attr_type == NAN_ATTRIBUTE_MAC_ADDR) {
+ memcpy(followup_event.addr, it.get_data(), NAN_MAC_ADDR_LEN);
+ } else if (attr_type == NAN_ATTRIBUTE_PEER_ID) {
+ followup_event.publish_subscribe_id = it.get_u16();
+ } else if (attr_type == NAN_ATTRIBUTE_INST_ID) {
+ followup_event.requestor_instance_id = it.get_u32();
+ } else if (attr_type == NAN_ATTRIBUTE_SERVICE_SPECIFIC_INFO_LEN) {
+ followup_event.service_specific_info_len = it.get_u16();
+ } else if (attr_type == NAN_ATTRIBUTE_SERVICE_SPECIFIC_INFO) {
+ memcpy(followup_event.service_specific_info, it.get_data(),
+ followup_event.service_specific_info_len);
+ } else if (attr_type == NAN_ATTRIBUTE_SDEA_SERVICE_SPECIFIC_INFO) {
+ memcpy(followup_event.sdea_service_specific_info, it.get_data(),
+ followup_event.sdea_service_specific_info_len);
+ }
+ }
+ counters.transmit_recv++;
+ GET_NAN_HANDLE(info)->mHandlers.EventFollowup(&followup_event);
+ break;
+
+ case NAN_EVENT_TRANSMIT_FOLLOWUP_IND:
+ NanTransmitFollowupInd followup_ind;
+ counters.transmit_txs++;
+ memset(&followup_ind, 0, sizeof(NanTransmitFollowupInd));
+ for (nl_iterator it(vendor_data); it.has_next(); it.next()) {
+ attr_type = it.get_type();
+ if (attr_type == NAN_ATTRIBUTE_TRANSAC_ID) {
+ followup_ind.id = it.get_u16();
+ } else if (attr_type == NAN_ATTRIBUTE_STATUS) {
+ followup_ind.reason = (NanStatusType)it.get_u8();
+ } else if (attr_type == NAN_ATTRIBUTE_REASON) {
+ u8 len = min(it.get_len(), sizeof(followup_ind.nan_reason));
+ memcpy(followup_ind.nan_reason, it.get_data(), len);
+ ALOGI("nan transmit followup ind: reason: %s, len = %d\n",
+ followup_ind.nan_reason, len);
+ }
+ }
+ GET_NAN_HANDLE(info)->mHandlers.EventTransmitFollowup(&followup_ind);
+ break;
+#ifdef NOT_YET
+ case NAN_EVENT_PUBLISH_REPLIED_IND:
+ NanPublishRepliedInd pub_reply_event;
+ memset(&pub_reply_event, 0, sizeof(pub_reply_event));
+
+ for (nl_iterator it(vendor_data); it.has_next(); it.next()) {
+ attr_type = it.get_type();
+
+ if (attr_type == NAN_ATTRIBUTE_SUBSCRIBE_ID) {
+ ALOGI("sub id: %u", it.get_u16());
+ pub_reply_event.requestor_instance_id = it.get_u8();
+ } else if (attr_type == NAN_ATTRIBUTE_MAC_ADDR) {
+ memcpy(pub_reply_event.addr, it.get_data(), NAN_MAC_ADDR_LEN);
+ ALOGI("Subscriber mac: " MACSTR, MAC2STR(pub_reply_event.addr));
+ } else if (attr_type == NAN_ATTRIBUTE_RSSI_PROXIMITY) {
+ pub_reply_event.rssi_value = it.get_u8();
+ ALOGI("Received rssi value : %u", it.get_u8());
+ }
+ }
+ GET_NAN_HANDLE(info)->mHandlers.EventPublishReplied(&pub_reply_event);
+ break;
+#endif /* NOT_YET */
+ } // end-of-switch-case
+ return NL_SKIP;
+ }
+};
+
+
+///////////////////////////////////////////////////////////////////////////////
+class NanDataPathPrimitive : public WifiCommand
+{
+ NanRequest reqContext;
+ u32 mNdpId;
+ NanRequestType mType;
+ u8 count;
+
+ public:
+ NanDataPathPrimitive(wifi_interface_handle iface, int id,
+ NanRequest params, NanRequestType cmdType)
+ : WifiCommand("NanCommand", iface, id), reqContext(params), mType(cmdType)
+ {
+ mNdpId = 0;
+ count = 0;
+ }
+ ~NanDataPathPrimitive() {
+ ALOGE("NanDataPathPrimitive destroyed\n");
+ }
+ u8 mSvcHash[NAN_SVC_HASH_SIZE];
+ u8 mPubNmi[NAN_MAC_ADDR_LEN];
+
+ void setType(NanRequestType type ) {
+ mType = type;
+ }
+
+ int getNdpId() {
+ return mNdpId;
+ }
+
+ int createRequest(WifiRequest& request)
+ {
+ ALOGI("NAN CMD: %s\n", NanCmdToString(mType));
+ if (mType == NAN_DATA_PATH_IFACE_CREATE) {
+ return createDataPathIfaceRequest(request, (char *)reqContext);
+ } else if (mType == NAN_DATA_PATH_IFACE_DELETE) {
+ return deleteDataPathIfaceRequest(request, (char *)reqContext);
+ } else if (mType == NAN_DATA_PATH_INIT_REQUEST) {
+ return createDataPathInitRequest(request,
+ (NanDataPathInitiatorRequest *)reqContext);
+ } else if (mType == NAN_DATA_PATH_IND_RESPONSE) {
+ return createDataPathIndResponse(request,
+ (NanDataPathIndicationResponse *)reqContext);
+ } else if (mType == NAN_DATA_PATH_END) {
+ return createDataPathEndRequest(request,
+ (NanDataPathEndRequest *)reqContext);
+ } else if (mType == NAN_DATA_PATH_SEC_INFO) {
+ return createDataPathSecInfoRequest(request,
+ (NanDataPathSecInfoRequest *)reqContext);
+ } else {
+ ALOGE("%s: Unknown NDP request: %d\n", __func__, mType);
+ }
+
+ return WIFI_SUCCESS;
+ }
+
+ int createDataPathIfaceRequest(WifiRequest& request, char *iface_name)
+ {
+ int result = request.create(GOOGLE_OUI, NAN_SUBCMD_DATA_PATH_IFACE_CREATE);
+ if (result < 0) {
+ ALOGE("%s Failed to create request\n", __func__);
+ return result;
+ }
+
+ nlattr *data = request.attr_start(NL80211_ATTR_VENDOR_DATA);
+ result = request.put_string(NAN_ATTRIBUTE_IFACE, (char *)iface_name);
+ if (result < 0) {
+ ALOGE("%s: Failed to fill iface, result = %d\n", __func__, result);
+ return result;
+ }
+
+ request.attr_end(data);
+ return WIFI_SUCCESS;
+ }
+
+ int deleteDataPathIfaceRequest(WifiRequest& request, char *iface_name)
+ {
+ int result = request.create(GOOGLE_OUI, NAN_SUBCMD_DATA_PATH_IFACE_DELETE);
+ if (result < 0) {
+ ALOGE("%s: Failed to create request, result = %d\n", __func__, result);
+ return result;
+ }
+
+ nlattr *data = request.attr_start(NL80211_ATTR_VENDOR_DATA);
+
+ result = request.put_string(NAN_ATTRIBUTE_IFACE, (char *)iface_name);
+ if (result < 0) {
+ ALOGE("%s: Failed to fill iface, result = %d\n", __func__, result);
+ return result;
+ }
+
+ request.attr_end(data);
+ return WIFI_SUCCESS;
+ }
+
+ int createDataPathSecInfoRequest(WifiRequest& request, NanDataPathSecInfoRequest *mParams)
+ {
+ int result = request.create(GOOGLE_OUI, NAN_SUBCMD_DATA_PATH_SEC_INFO);
+ if (result < 0) {
+ ALOGE("%s Failed to create request\n", __func__);
+ return result;
+ }
+
+ nlattr *data = request.attr_start(NL80211_ATTR_VENDOR_DATA);
+
+ result = request.put_u32(NAN_ATTRIBUTE_PUBLISH_ID, mParams->requestor_instance_id);
+ if (result < 0) {
+ ALOGE("%s: Failed to fill instance id = %d, result = %d\n",
+ __func__, mParams->requestor_instance_id, result);
+ return result;
+ }
+
+ result = request.put_addr(NAN_ATTRIBUTE_MAC_ADDR, mParams->peer_disc_mac_addr);
+ if (result < 0) {
+ ALOGE("%s: Failed to fill mac addr, result = %d\n", __func__, result);
+ return result;
+ }
+
+ result = request.put_u32(NAN_ATTRIBUTE_NDP_ID, mParams->ndp_instance_id);
+ if (result < 0) {
+ ALOGE("%s: Failed to fill ndp_instance_id = %d, result = %d\n",
+ __func__, mParams->ndp_instance_id, result);
+ return result;
+ }
+
+ request.attr_end(data);
+ return WIFI_SUCCESS;
+ }
+
+ int createDataPathInitRequest(WifiRequest& request, NanDataPathInitiatorRequest *mParams)
+ {
+ int result = request.create(GOOGLE_OUI, NAN_SUBCMD_DATA_PATH_REQUEST);
+ u8 pmk_hex[NAN_PMK_INFO_LEN];
+ if (result < 0) {
+ ALOGE("%s: Failed to create request, result = %d\n", __func__, result);
+ return result;
+ }
+
+ mNdpId = mParams->requestor_instance_id;
+ nlattr *data = request.attr_start(NL80211_ATTR_VENDOR_DATA);
+
+ result = request.put_u32(NAN_ATTRIBUTE_PUBLISH_ID, mParams->requestor_instance_id);
+ if (result < 0) {
+ ALOGE("%s: Failed to fill pub id = %d, result = %d\n",
+ __func__, mParams->requestor_instance_id, result);
+ return result;
+ }
+
+ result = request.put_u32(NAN_ATTRIBUTE_CHANNEL, (u32)mParams->channel);
+ if (result < 0) {
+ ALOGE("%s: Failed to fill channel = %d, result = %d\n",
+ __func__, mParams->channel, result);
+ return result;
+ }
+
+ result = request.put_addr(NAN_ATTRIBUTE_MAC_ADDR, mParams->peer_disc_mac_addr);
+ if (result < 0) {
+ ALOGE("%s: Failed to fill mac addr, result = %d\n", __func__, result);
+ return result;
+ }
+
+ result = request.put_string(NAN_ATTRIBUTE_IFACE, mParams->ndp_iface);
+ if (result < 0) {
+ ALOGE("%s: Failed to fill ndp_iface, result = %d\n", __func__, result);
+ return result;
+ }
+
+ result = request.put_u8(NAN_ATTRIBUTE_SECURITY,
+ (NanDataPathSecurityCfgStatus)mParams->ndp_cfg.security_cfg);
+ if (result < 0) {
+ ALOGE("%s: Failed to fill security, result = %d\n", __func__, result);
+ return result;
+ }
+
+ result = request.put_u8(NAN_ATTRIBUTE_QOS,
+ (NanDataPathQosCfg) mParams->ndp_cfg.qos_cfg);
+ if (result < 0) {
+ ALOGE("%s: Failed to fill QoS, result = %d\n", __func__, result);
+ return result;
+ }
+
+ if (mParams->app_info.ndp_app_info_len) {
+ result = request.put_u16(NAN_ATTRIBUTE_SERVICE_SPECIFIC_INFO_LEN,
+ mParams->app_info.ndp_app_info_len);
+ if (result < 0) {
+ ALOGE("%s: Failed to fill svc info len = %d, result = %d\n",
+ __func__, mParams->app_info.ndp_app_info_len, result);
+ return result;
+ }
+
+ result = request.put(NAN_ATTRIBUTE_SERVICE_SPECIFIC_INFO,
+ (void *)mParams->app_info.ndp_app_info, mParams->app_info.ndp_app_info_len);
+ if (result < 0) {
+ ALOGE("%s: Failed to fill svc info, result = %d\n", __func__, result);
+ return result;
+ }
+ }
+
+ result = request.put_u8(NAN_ATTRIBUTE_CIPHER_SUITE_TYPE,
+ mParams->cipher_type);
+ if (result < 0) {
+ ALOGE("%s: Failed to fill NAN_ATTRIBUTE_CIPHER_SUITE_TYPE, result = %d\n",
+ __func__, result);
+ return result;
+ }
+
+ result = request.put_u8(NAN_ATTRIBUTE_KEY_TYPE,
+ mParams->key_info.key_type);
+ if (result < 0) {
+ ALOGE("%s: Failed to fill NAN_ATTRIBUTE_KEY_TYPE, result = %d\n",
+ __func__, result);
+ return result;
+ }
+
+
+ if (mParams->service_name_len) {
+ result = request.put_u16(NAN_ATTRIBUTE_SERVICE_NAME_LEN, mParams->service_name_len);
+ if (result < 0) {
+ ALOGE("%s: Failed to fill svc name len, result = %d\n", __func__, result);
+ return result;
+ }
+
+ prhex(NULL, mParams->service_name, mParams->service_name_len);
+ result = request.put(NAN_ATTRIBUTE_SERVICE_NAME, (void *)mParams->service_name,
+ mParams->service_name_len);
+ if (result < 0) {
+ ALOGE("%s: Failed to fill svc name, result = %d\n", __func__, result);
+ return result;
+ }
+ }
+
+ if (mParams->key_info.key_type == NAN_SECURITY_KEY_INPUT_PMK) {
+ if (mParams->key_info.body.pmk_info.pmk_len) {
+ result = request.put_u32(NAN_ATTRIBUTE_KEY_LEN,
+ mParams->key_info.body.pmk_info.pmk_len);
+ if (result < 0) {
+ ALOGE("%s: Failed to fill pmk len, result = %d\n", __func__, result);
+ return result;
+ }
+ result = request.put(NAN_ATTRIBUTE_KEY_DATA,
+ (void *)mParams->key_info.body.pmk_info.pmk,
+ mParams->key_info.body.pmk_info.pmk_len);
+ if (result < 0) {
+ ALOGE("%s: Failed to fill pmk, result = %d\n", __func__, result);
+ return result;
+ }
+ }
+ }
+
+ if (mParams->key_info.key_type == NAN_SECURITY_KEY_INPUT_PASSPHRASE) {
+ if (mParams->key_info.body.passphrase_info.passphrase_len < NAN_SECURITY_MIN_PASSPHRASE_LEN ||
+ mParams->key_info.body.passphrase_info.passphrase_len > NAN_SECURITY_MAX_PASSPHRASE_LEN) {
+ ALOGE("passphrase must be between %d and %d characters long\n",
+ NAN_SECURITY_MIN_PASSPHRASE_LEN,
+ NAN_SECURITY_MAX_PASSPHRASE_LEN);
+ return NAN_STATUS_INVALID_PARAM;
+ } else {
+ memset(pmk_hex, 0, NAN_PMK_INFO_LEN);
+ result = passphrase_to_pmk(mParams->peer_disc_mac_addr, mParams->cipher_type,
+ mParams->service_name, &mParams->key_info, pmk_hex);
+ if (result < 0) {
+ ALOGE("%s: Failed to convert passphrase to key data, result = %d\n", __func__, result);
+ return result;
+ }
+ result = request.put_u32(NAN_ATTRIBUTE_KEY_LEN, NAN_PMK_INFO_LEN);
+ if (result < 0) {
+ ALOGE("%s: Failed to fill passphrase len, result = %d\n", __func__, result);
+ return result;
+ }
+ result = request.put(NAN_ATTRIBUTE_KEY_DATA, pmk_hex, NAN_PMK_INFO_LEN);
+ if (result < 0) {
+ ALOGE("%s: Failed to fill passphrase, result = %d\n", __func__, result);
+ return result;
+ }
+ prhex("PMK", pmk_hex, NAN_PMK_INFO_LEN);
+ }
+ }
+
+ if (mParams->scid_len) {
+ if (mParams->scid_len != NAN_SCID_INFO_LEN) {
+ ALOGE("%s: Invalid scid len, = %d\n", __func__, mParams->scid_len);
+ return NAN_STATUS_INVALID_PARAM;
+ }
+ result = request.put_u32(NAN_ATTRIBUTE_SCID_LEN,
+ mParams->scid_len);
+ if (result < 0) {
+ ALOGE("%s: Failed to fill scid len, result = %d\n", __func__, result);
+ return result;
+ }
+
+ result = request.put(NAN_ATTRIBUTE_SCID,
+ (void *)mParams->scid, mParams->scid_len);
+ if (result < 0) {
+ ALOGE("%s: Failed to fill scid, result = %d\n", __func__, result);
+ return result;
+ }
+ }
+
+ request.attr_end(data);
+ return WIFI_SUCCESS;
+ }
+
+ int createDataPathIndResponse(WifiRequest& request,
+ NanDataPathIndicationResponse *mParams)
+ {
+ int result = request.create(GOOGLE_OUI, NAN_SUBCMD_DATA_PATH_RESPONSE);
+ u8 pmk_hex[NAN_PMK_INFO_LEN];
+ if (result < 0) {
+ ALOGE("%s: Failed to create request, result = %d\n", __func__, result);
+ return result;
+ }
+
+ nlattr *data = request.attr_start(NL80211_ATTR_VENDOR_DATA);
+
+ result = request.put_u32(NAN_ATTRIBUTE_NDP_ID, mParams->ndp_instance_id);
+ if (result < 0) {
+ ALOGE("%s: Failed to fill ndp_instance_id = %d, result = %d\n",
+ __func__, mParams->ndp_instance_id, result);
+ return result;
+ }
+
+ result = request.put_string(NAN_ATTRIBUTE_IFACE, mParams->ndp_iface);
+ if (result < 0) {
+ ALOGE("%s: Failed to fill ndp_iface, result = %d\n", __func__, result);
+ return result;
+ }
+
+ result = request.put_u8(NAN_ATTRIBUTE_SECURITY,
+ (NanDataPathSecurityCfgStatus)mParams->ndp_cfg.security_cfg);
+ if (result < 0) {
+ ALOGE("%s: Failed to fill security_cfg, result = %d\n", __func__, result);
+ return result;
+ }
+
+ result = request.put_u8(NAN_ATTRIBUTE_QOS,
+ (NanDataPathQosCfg)mParams->ndp_cfg.qos_cfg);
+ if (result < 0) {
+ ALOGE("%s: Failed to fill qos_cfg, result = %d\n", __func__, result);
+ return result;
+ }
+
+ if (mParams->app_info.ndp_app_info_len) {
+ result = request.put_u16(NAN_ATTRIBUTE_SERVICE_SPECIFIC_INFO_LEN,
+ mParams->app_info.ndp_app_info_len);
+ if (result < 0) {
+ ALOGE("%s: Failed to fill svc info len = %d, result = %d\n",
+ __func__, mParams->app_info.ndp_app_info_len, result);
+ return result;
+ }
+
+ result = request.put(NAN_ATTRIBUTE_SERVICE_SPECIFIC_INFO,
+ (void *)mParams->app_info.ndp_app_info, mParams->app_info.ndp_app_info_len);
+ if (result < 0) {
+ ALOGE("%s: Failed to fill svc info, result = %d\n", __func__, result);
+ return result;
+ }
+ }
+
+ result = request.put_u8(NAN_ATTRIBUTE_RSP_CODE, mParams->rsp_code);
+ if (result < 0) {
+ ALOGE("%s: Failed to fill resp code = %d, result = %d\n",
+ __func__, mParams->rsp_code, result);
+ return result;
+ }
+
+ result = request.put_u8(NAN_ATTRIBUTE_CIPHER_SUITE_TYPE,
+ mParams->cipher_type);
+ if (result < 0) {
+ ALOGE("%s: Failed to fill cipher_type, result = %d\n",
+ __func__, result);
+ return result;
+ }
+
+ result = request.put_u8(NAN_ATTRIBUTE_KEY_TYPE,
+ mParams->key_info.key_type);
+ if (result < 0) {
+ ALOGE("%s: Failed to fill key type, result = %d\n",
+ __func__, result);
+ return result;
+ }
+
+ if (mParams->service_name_len) {
+ result = request.put_u16(NAN_ATTRIBUTE_SERVICE_NAME_LEN, mParams->service_name_len);
+ if (result < 0) {
+ ALOGE("%s: Failed to fill svc name len, result = %d\n", __func__, result);
+ return result;
+ }
+
+ prhex(NULL, mParams->service_name, mParams->service_name_len);
+ result = request.put(NAN_ATTRIBUTE_SERVICE_NAME, (void *)mParams->service_name,
+ mParams->service_name_len);
+ if (result < 0) {
+ ALOGE("%s: Failed to fill svc name, result = %d\n", __func__, result);
+ return result;
+ }
+ }
+
+ if (mParams->key_info.key_type == NAN_SECURITY_KEY_INPUT_PMK) {
+ if (mParams->key_info.body.pmk_info.pmk_len) {
+ result = request.put_u32(NAN_ATTRIBUTE_KEY_LEN,
+ mParams->key_info.body.pmk_info.pmk_len);
+ if (result < 0) {
+ ALOGE("%s: Failed to fill pmk len, result = %d\n", __func__, result);
+ return result;
+ }
+ result = request.put(NAN_ATTRIBUTE_KEY_DATA,
+ (void *)mParams->key_info.body.pmk_info.pmk,
+ mParams->key_info.body.pmk_info.pmk_len);
+ if (result < 0) {
+ ALOGE("%s: Failed to fill pmk, result = %d\n", __func__, result);
+ return result;
+ }
+ }
+ }
+
+ if (mParams->key_info.key_type == NAN_SECURITY_KEY_INPUT_PASSPHRASE) {
+ if (mParams->key_info.body.passphrase_info.passphrase_len < NAN_SECURITY_MIN_PASSPHRASE_LEN ||
+ mParams->key_info.body.passphrase_info.passphrase_len > NAN_SECURITY_MAX_PASSPHRASE_LEN) {
+ ALOGE("passphrase must be between %d and %d characters long\n",
+ NAN_SECURITY_MIN_PASSPHRASE_LEN,
+ NAN_SECURITY_MAX_PASSPHRASE_LEN);
+ return NAN_STATUS_INVALID_PARAM;
+ } else {
+ memset(pmk_hex, 0, NAN_PMK_INFO_LEN);
+ result = passphrase_to_pmk(mPubNmi, mParams->cipher_type,
+ mParams->service_name, &mParams->key_info, pmk_hex);
+ if (result < 0) {
+ ALOGE("%s: Failed to convert passphrase to key data, result = %d\n", __func__, result);
+ return result;
+ }
+ result = request.put_u32(NAN_ATTRIBUTE_KEY_LEN, NAN_PMK_INFO_LEN);
+ if (result < 0) {
+ ALOGE("%s: Failed to fill passphrase len, result = %d\n", __func__, result);
+ return result;
+ }
+ result = request.put(NAN_ATTRIBUTE_KEY_DATA, pmk_hex, NAN_PMK_INFO_LEN);
+ if (result < 0) {
+ ALOGE("%s: Failed to fill passphrase, result = %d\n", __func__, result);
+ return result;
+ }
+ }
+ }
+
+ if (mParams->scid_len) {
+ if (mParams->scid_len != NAN_SCID_INFO_LEN) {
+ ALOGE("%s: Invalid scid len, = %d\n", __func__, mParams->scid_len);
+ return NAN_STATUS_INVALID_PARAM;
+ }
+ result = request.put_u32(NAN_ATTRIBUTE_SCID_LEN,
+ mParams->scid_len);
+ if (result < 0) {
+ ALOGE("%s: Failed to fill scid len, result = %d\n", __func__, result);
+ return result;
+ }
+
+ prhex(NULL, mParams->scid, mParams->scid_len);
+ result = request.put(NAN_ATTRIBUTE_SCID,
+ (void *)mParams->scid, mParams->scid_len);
+ if (result < 0) {
+ ALOGE("%s: Failed to fill scid, result = %d\n", __func__, result);
+ return result;
+ }
+ }
+
+ request.attr_end(data);
+ return WIFI_SUCCESS;
+ }
+
+ int createDataPathEndRequest(WifiRequest& request, NanDataPathEndRequest *mParams)
+ {
+ int result = request.create(GOOGLE_OUI, NAN_SUBCMD_DATA_PATH_END);
+ if (result < 0) {
+ ALOGE("%s: Failed to create request, result = %d\n", __func__, result);
+ return result;
+ }
+
+ count = mParams->num_ndp_instances;
+ nlattr *data = request.attr_start(NL80211_ATTR_VENDOR_DATA);
+
+ result = request.put_u8(NAN_ATTRIBUTE_INST_COUNT, mParams->num_ndp_instances);
+ if (result < 0) {
+ ALOGE("%s: Failed to fill num_ndp_instances = %d, result = %d\n",
+ __func__, mParams->num_ndp_instances, result);
+ return result;
+ }
+
+ while (count) {
+ result = request.put_u32(NAN_ATTRIBUTE_NDP_ID, mParams->ndp_instance_id[count-1]);
+ if (result < 0) {
+ ALOGE("%s: Failed to fill ndp id = %d, result = %d\n",
+ __func__, mParams->ndp_instance_id[count-1], result);
+ return result;
+ }
+ ALOGE("%s:NDP ID = %d\n", __func__, mParams->ndp_instance_id[count-1]);
+ count -= 1;
+ }
+
+ request.attr_end(data);
+ return WIFI_SUCCESS;
+ }
+
+ int open()
+ {
+ WifiRequest request(familyId(), ifaceId());
+ int result = createRequest(request);
+ if (result != WIFI_SUCCESS) {
+ ALOGE("%s: failed to create setup request; result = %d", __func__, result);
+ return result;
+ }
+
+ result = requestResponse(request);
+ if (result != WIFI_SUCCESS) {
+ ALOGE("%s: failed to configure setup; result = %d", __func__, result);
+ return result;
+ }
+
+ request.destroy();
+ return WIFI_SUCCESS;
+ }
+
+ virtual bool valid_dp_response_type(int response_type) {
+ bool valid = false;
+ switch(response_type) {
+ case NAN_DP_INTERFACE_CREATE:
+ case NAN_DP_INTERFACE_DELETE:
+ case NAN_DP_INITIATOR_RESPONSE:
+ case NAN_DP_RESPONDER_RESPONSE:
+ case NAN_DP_END:
+ valid = true;
+ break;
+ default:
+ ALOGE("NanDataPathPrmitive::Unknown cmd Response: %d\n", response_type);
+ break;
+ }
+ return valid;
+ }
+
+ int handleResponse(WifiEvent& reply)
+ {
+ nan_hal_resp_t *rsp_vndr_data = NULL;
+
+ if (reply.get_cmd() != NL80211_CMD_VENDOR || reply.get_vendor_data() == NULL) {
+ ALOGD("Ignoring reply with cmd = %d", reply.get_cmd());
+ return NL_SKIP;
+ }
+
+ rsp_vndr_data = (nan_hal_resp_t *)reply.get_vendor_data();
+ ALOGI("NanDataPathPrmitive::handle response\n");
+ int32_t result = rsp_vndr_data->value;
+ NanResponseMsg rsp_data;
+
+ memset(&rsp_data, 0, sizeof(NanResponseMsg));
+ rsp_data.response_type = get_response_type((WIFI_SUB_COMMAND)rsp_vndr_data->subcmd);
+
+ if ((WIFI_SUB_COMMAND)rsp_vndr_data->subcmd == NAN_SUBCMD_DATA_PATH_SEC_INFO) {
+ /* Follow through */
+ } else if (!valid_dp_response_type(rsp_data.response_type)) {
+ return NL_SKIP;
+ }
+ rsp_data.status = nan_map_response_status(rsp_vndr_data->status);
+ ALOGE("Mapped hal status = %d\n", rsp_data.status);
+
+ if (rsp_vndr_data->nan_reason[0] == '\0') {
+ memcpy(rsp_data.nan_error, NanStatusToString(rsp_data.status),
+ strlen(NanStatusToString(rsp_data.status)));
+ rsp_data.nan_error[strlen(NanStatusToString(rsp_data.status))] = '\0';
+ }
+ rsp_data.nan_error[NAN_ERROR_STR_LEN - 1] = '\0';
+ ALOGI("\n Received nan_error string %s\n", (u8*)rsp_data.nan_error);
+
+ if (rsp_data.response_type == NAN_DP_INITIATOR_RESPONSE) {
+ ALOGI("received ndp instance_id %d and ret = %d\n", rsp_vndr_data->ndp_instance_id, result);
+ rsp_data.body.data_request_response.ndp_instance_id = rsp_vndr_data->ndp_instance_id;
+ mNdpId = rsp_vndr_data->ndp_instance_id;
+ } else if ((WIFI_SUB_COMMAND)rsp_vndr_data->subcmd == NAN_SUBCMD_DATA_PATH_SEC_INFO) {
+ memcpy(mPubNmi, rsp_vndr_data->pub_nmi, NAN_MAC_ADDR_LEN);
+ memcpy(mSvcHash, rsp_vndr_data->svc_hash, NAN_SVC_HASH_SIZE);
+ return NL_SKIP;
+ }
+
+ ALOGI("NanDataPathPrmitive:Received response for cmd [%s], ret %d\n",
+ NanRspToString(rsp_data.response_type), rsp_data.status);
+ GET_NAN_HANDLE(info)->mHandlers.NotifyResponse(id(), &rsp_data);
+ return NL_SKIP;
+ }
+
+ int handleEvent(WifiEvent& event)
+ {
+ int cmd = event.get_vendor_subcmd();
+ u16 attr_type;
+
+ nlattr *vendor_data = event.get_attribute(NL80211_ATTR_VENDOR_DATA);
+
+ switch(cmd) {
+ case NAN_EVENT_DATA_REQUEST: {
+ NanDataPathRequestInd ndp_request_event;
+ memset(&ndp_request_event, 0, sizeof(NanDataPathRequestInd));
+ u16 ndp_ind_app_info_len = 0;
+ counters.dp_req_evt++;
+ ALOGI("Received NAN_EVENT_DATA_REQUEST_INDICATION\n");
+
+ for (nl_iterator it(vendor_data); it.has_next(); it.next()) {
+ attr_type = it.get_type();
+
+ if (attr_type == NAN_ATTRIBUTE_PUBLISH_ID) {
+ ALOGI("publish_id: %u\n", it.get_u32());
+ ndp_request_event.service_instance_id = it.get_u32();
+
+ } else if (attr_type == NAN_ATTRIBUTE_MAC_ADDR) {
+ memcpy(ndp_request_event.peer_disc_mac_addr,
+ it.get_data(), NAN_MAC_ADDR_LEN);
+ ALOGI("Discovery MAC addr of the peer/initiator: " MACSTR "\n",
+ MAC2STR(ndp_request_event.peer_disc_mac_addr));
+
+ } else if (attr_type == NAN_ATTRIBUTE_NDP_ID) {
+ ALOGI("ndp id: %u\n", it.get_u32());
+ ndp_request_event.ndp_instance_id = it.get_u32();
+
+ } else if (attr_type == NAN_ATTRIBUTE_SECURITY) {
+ ALOGI("security: %u\n",
+ (NanDataPathSecurityCfgStatus)it.get_u8());
+ ndp_request_event.ndp_cfg.security_cfg =
+ (NanDataPathSecurityCfgStatus)it.get_u8();
+
+ } else if (attr_type == NAN_ATTRIBUTE_QOS) {
+ ALOGI("QoS: %u\n", (NanDataPathQosCfg)it.get_u8());
+ ndp_request_event.ndp_cfg.qos_cfg = (NanDataPathQosCfg)it.get_u8();
+
+ } else if (attr_type == NAN_ATTRIBUTE_SERVICE_SPECIFIC_INFO_LEN) {
+ ndp_request_event.app_info.ndp_app_info_len = it.get_u16();
+ ndp_ind_app_info_len = ndp_request_event.app_info.ndp_app_info_len;
+
+ } else if (attr_type == NAN_ATTRIBUTE_SERVICE_SPECIFIC_INFO) {
+ memcpy(ndp_request_event.app_info.ndp_app_info, it.get_data(),
+ ndp_ind_app_info_len);
+ ndp_request_event.app_info.ndp_app_info
+ [ndp_ind_app_info_len] = '\0';
+ ALOGI("service info: %s\n", ndp_request_event.app_info.ndp_app_info);
+
+ } else if (attr_type == NAN_ATTRIBUTE_SCID_LEN) {
+ ALOGI("scid len: %u\n", it.get_u32());
+ ndp_request_event.scid_len = it.get_u32();
+
+ } else if (attr_type == NAN_ATTRIBUTE_SCID) {
+ memcpy(ndp_request_event.scid, it.get_data(),
+ ndp_request_event.scid_len);
+ ndp_request_event.scid[ndp_request_event.scid_len] = '\0';
+ ALOGI("scid : %s\n", ndp_request_event.scid);
+
+ }
+ }
+
+ GET_NAN_HANDLE(info)->mHandlers.EventDataRequest(&ndp_request_event);
+ break;
+ }
+ case NAN_EVENT_DATA_CONFIRMATION: {
+ NanDataPathConfirmInd ndp_create_confirmation_event;
+ memset(&ndp_create_confirmation_event, 0, sizeof(NanDataPathConfirmInd));
+ u16 ndp_conf_app_info_len = 0;
+ u8 chan_idx = 0;
+ counters.dp_confirm_evt++;
+ ALOGI("Received NAN_EVENT_DATA_CONFIRMATION\n");
+
+ for (nl_iterator it(vendor_data); it.has_next(); it.next()) {
+ attr_type = it.get_type();
+
+ if (attr_type == NAN_ATTRIBUTE_NDP_ID) {
+ ALOGI("ndp id: %u", it.get_u32());
+ ndp_create_confirmation_event.ndp_instance_id = it.get_u32();
+
+ } else if (attr_type == NAN_ATTRIBUTE_PEER_NDI_MAC_ADDR) {
+ memcpy(ndp_create_confirmation_event.peer_ndi_mac_addr, it.get_data(),
+ NAN_MAC_ADDR_LEN);
+ ALOGI("NDI mac address of the peer: " MACSTR "\n",
+ MAC2STR(ndp_create_confirmation_event.peer_ndi_mac_addr));
+
+ } else if (attr_type == NAN_ATTRIBUTE_SERVICE_SPECIFIC_INFO_LEN) {
+ ALOGI("service info len: %d", it.get_u16());
+ ndp_create_confirmation_event.app_info.ndp_app_info_len = it.get_u16();
+ ndp_conf_app_info_len = ndp_create_confirmation_event.app_info.ndp_app_info_len;
+ } else if (attr_type == NAN_ATTRIBUTE_SERVICE_SPECIFIC_INFO) {
+ memcpy(ndp_create_confirmation_event.app_info.ndp_app_info,
+ it.get_data(), ndp_conf_app_info_len);
+ ndp_create_confirmation_event.app_info.ndp_app_info[ndp_conf_app_info_len]
+ = '\0';
+ ALOGI("service info: %s",
+ ndp_create_confirmation_event.app_info.ndp_app_info);
+
+ } else if (attr_type == NAN_ATTRIBUTE_RSP_CODE) {
+ ALOGI("response code: %u", (NanDataPathResponseCode)it.get_u8());
+ ndp_create_confirmation_event.rsp_code =
+ (NanDataPathResponseCode)it.get_u8();
+ } else if (attr_type == NAN_ATTRIBUTE_STATUS) {
+ ALOGI("reason code %u", (NanDataPathResponseCode)it.get_u8());
+ ndp_create_confirmation_event.rsp_code =
+ (NanDataPathResponseCode)it.get_u8();
+ } else if (attr_type == NAN_ATTRIBUTE_NUM_CHANNELS) {
+ ALOGI("num channels %u", it.get_u32());
+ if (it.get_u32() <= NAN_MAX_CHANNEL_INFO_SUPPORTED) {
+ ndp_create_confirmation_event.num_channels = it.get_u32();
+ } else {
+ ndp_create_confirmation_event.num_channels =
+ NAN_MAX_CHANNEL_INFO_SUPPORTED;
+ ALOGE("num channels reset to max allowed %u",
+ ndp_create_confirmation_event.num_channels);
+ }
+ } else if (attr_type == NAN_ATTRIBUTE_CHANNEL_INFO) {
+ ALOGI("Channel info \n");
+ memcpy((u8 *)ndp_create_confirmation_event.channel_info, it.get_data(),
+ ndp_create_confirmation_event.num_channels * sizeof(NanChannelInfo));
+ while (chan_idx < ndp_create_confirmation_event.num_channels) {
+ ALOGI("channel: %u, Bandwidth: %u, nss: %u\n",
+ ndp_create_confirmation_event.channel_info[chan_idx].channel,
+ ndp_create_confirmation_event.channel_info[chan_idx].bandwidth,
+ ndp_create_confirmation_event.channel_info[chan_idx].nss);
+ chan_idx++;
+ }
+ }
+ }
+ GET_NAN_HANDLE(info)->mHandlers.EventDataConfirm(&ndp_create_confirmation_event);
+ break;
+ }
+ case NAN_EVENT_DATA_END: {
+ NanDataPathEndInd ndp_end_event;
+ memset(&ndp_end_event, 0, sizeof(NanDataPathEndInd));
+ u16 attr_type;
+ ALOGI("Received NAN_EVENT_DATA_END\n");
+
+ for (nl_iterator it(vendor_data); it.has_next(); it.next()) {
+ attr_type = it.get_type();
+
+ if (attr_type == NAN_ATTRIBUTE_INST_COUNT) {
+ ALOGI("ndp count: %u\n", it.get_u8());
+ ndp_end_event.num_ndp_instances = it.get_u8();
+ count = it.get_u8();
+ } else if (attr_type == NAN_ATTRIBUTE_NDP_ID) {
+ while (count) {
+ ndp_end_event.ndp_instance_id[count-1] = it.get_u32();
+ ALOGI("NDP Id from the Event = %u\n", ndp_end_event.ndp_instance_id[count-1]);
+ count -= 1;
+ }
+ } else {
+ ALOGI("Unknown attr_type: %s\n", NanAttrToString(attr_type));
+ }
+ }
+
+ GET_NAN_HANDLE(info)->mHandlers.EventDataEnd(&ndp_end_event);
+ break;
+ }
+ } // end-of-switch
+ return NL_SKIP;
+ }
+};
+
+
+///////////////////////////////////////////////////////////////////////////////
+class NanMacControl : public WifiCommand
+{
+ NanRequest mParams;
+ transaction_id mId = NAN_MAC_INVALID_TRANSID;
+ wifi_interface_handle mIface;
+ NanRequestType mType;
+ u32 mVersion;
+
+ public:
+ NanMacControl(wifi_interface_handle iface, int id,
+ NanRequest params, NanRequestType cmdType)
+ : WifiCommand("NanCommand", iface, id), mParams(params), mType(cmdType)
+ {
+ mVersion = 0;
+ setIface(iface);
+ setId(id);
+ }
+ ~NanMacControl() {
+ ALOGE("NanMacControl destroyed\n");
+ }
+
+ void setIface(wifi_interface_handle iface ) {
+ mIface = iface;
+ }
+
+ void setId(transaction_id id) {
+ if (id != NAN_MAC_INVALID_TRANSID) {
+ mId = id;
+ }
+ }
+
+ transaction_id getId() {
+ return mId;
+ }
+
+ void setType(NanRequestType type) {
+ mType = type;
+ }
+ u32 getVersion() {
+ return mVersion;
+ }
+
+ void setMsg(NanRequest params) {
+ mParams = params;
+ }
+
+ int createRequest(WifiRequest& request) {
+ ALOGI("NAN CMD: %s\n", NanCmdToString(mType));
+ if (mType == NAN_REQUEST_ENABLE) {
+ return createEnableRequest(request, (NanEnableRequest *)mParams);
+ } else if (mType == NAN_REQUEST_DISABLE) {
+ return createDisableRequest(request);
+ } else if (mType == NAN_REQUEST_CONFIG) {
+ return createConfigRequest(request, (NanConfigRequest*)mParams);
+ } else if (mType == NAN_REQUEST_STATS) {
+ /* TODO: Not yet implemented */
+ } else if (mType == NAN_REQUEST_TCA) {
+ /* TODO: Not yet implemented */
+ } else if (mType == NAN_VERSION_INFO) {
+ return createVersionRequest(request);
+ } else {
+ ALOGE("Unknown Nan request\n");
+ }
+
+ return WIFI_SUCCESS;
+ }
+
+ int createVersionRequest(WifiRequest& request) {
+ int result = request.create(GOOGLE_OUI, NAN_SUBCMD_VERSION_INFO);
+ if (result < 0) {
+ ALOGE("%s: Fail to create request\n", __func__);
+ return result;
+ }
+ nlattr *data = request.attr_start(NL80211_ATTR_VENDOR_DATA);
+ request.attr_end(data);
+ NAN_DBG_EXIT();
+ return WIFI_SUCCESS;
+ }
+
+ int createEnableRequest(WifiRequest& request, NanEnableRequest *mParams) {
+ int result = request.create(GOOGLE_OUI, NAN_SUBCMD_ENABLE);
+ s8 rssi;
+ if (result < 0) {
+ ALOGE("%s: Fail to create request\n", __func__);
+ return result;
+ }
+
+ NAN_DBG_ENTER();
+
+ nlattr *data = request.attr_start(NL80211_ATTR_VENDOR_DATA);
+
+ if (mParams->config_2dot4g_support) {
+ result = request.put_u8(NAN_ATTRIBUTE_2G_SUPPORT, mParams->support_2dot4g_val);
+ if (result < 0) {
+ ALOGE("%s: Failing in 2g support, result = %d\n", __func__, result);
+ return result;
+ }
+ }
+
+ if (mParams->config_support_5g) {
+ result = request.put_u8(NAN_ATTRIBUTE_5G_SUPPORT, mParams->support_5g_val);
+ if (result < 0) {
+ ALOGE("%s: Failing in 5g support, result = %d\n", __func__, result);
+ return result;
+ }
+ }
+
+ result = request.put_u16(NAN_ATTRIBUTE_CLUSTER_LOW, mParams->cluster_low);
+ if (result < 0) {
+ ALOGE("%s: Failing in cluster low, result = %d\n", __func__, result);
+ return result;
+ }
+
+ result = request.put_u16(NAN_ATTRIBUTE_CLUSTER_HIGH, mParams->cluster_high);
+ if (result < 0) {
+ ALOGE("%s: Failing in cluster high, result = %d\n", __func__, result);
+ return result;
+ }
+
+ if (mParams->config_sid_beacon) {
+ result = request.put_u8(NAN_ATTRIBUTE_SID_BEACON, mParams->sid_beacon_val);
+ if (result < 0) {
+ ALOGE("%s: Failing in sid beacon, result = %d\n", __func__, result);
+ return result;
+ }
+ }
+
+ if (mParams->config_subscribe_sid_beacon) {
+ result = request.put_u8(NAN_ATTRIBUTE_SUB_SID_BEACON, mParams->subscribe_sid_beacon_val);
+ if (result < 0) {
+ ALOGE("%s: Failing in sub sid beacon, result = %d\n", __func__, result);
+ return result;
+ }
+ }
+
+ if (mParams->config_2dot4g_beacons) {
+ result = request.put_u8(NAN_ATTRIBUTE_SYNC_DISC_2G_BEACON, mParams->beacon_2dot4g_val);
+ if (result < 0) {
+ ALOGE("%s: Failing in beacon_2dot4g_val, result = %d\n", __func__, result);
+ return result;
+ }
+ }
+
+ if (mParams->config_5g_beacons) {
+ result = request.put_u8(NAN_ATTRIBUTE_SYNC_DISC_5G_BEACON, mParams->beacon_5g_val);
+ if (result < 0) {
+ ALOGE("%s: Failing in 5g beacon, result = %d\n", __func__, result);
+ return result;
+ }
+ }
+
+ if (mParams->config_2dot4g_sdf) {
+ result = request.put_u8(NAN_ATTRIBUTE_SDF_2G_SUPPORT, mParams->sdf_2dot4g_val);
+ if (result < 0) {
+ ALOGE("%s: Failing in 2dot4g sdf, result = %d\n", __func__, result);
+ return result;
+ }
+ }
+
+ if (mParams->config_5g_sdf) {
+ result = request.put_u8(NAN_ATTRIBUTE_SDF_5G_SUPPORT, mParams->sdf_5g_val);
+ if (result < 0) {
+ ALOGE("%s: Failing in 5g sdf, result = %d\n", __func__, result);
+ return result;
+ }
+ }
+
+ if (mParams->config_2dot4g_rssi_close) {
+ if (ISGREATER(mParams->rssi_close_2dot4g_val, NAN_MAX_RSSI)) {
+ ALOGI("%s: Invalid rssi param \n", __func__);
+ return WIFI_ERROR_INVALID_ARGS;
+ }
+ rssi = -mParams->rssi_close_2dot4g_val;
+ result = request.put_s8(NAN_ATTRIBUTE_RSSI_CLOSE, rssi);
+ if (result < 0) {
+ ALOGE("%s: Failing in 2g rssi close, result = %d\n", __func__, result);
+ return result;
+ }
+ }
+
+ if (mParams->config_2dot4g_rssi_middle) {
+ if (ISGREATER(mParams->rssi_middle_2dot4g_val, NAN_MAX_RSSI)) {
+ ALOGI("%s: Invalid rssi param \n", __func__);
+ return WIFI_ERROR_INVALID_ARGS;
+ }
+ rssi = -mParams->rssi_middle_2dot4g_val;
+ result = request.put_s8(NAN_ATTRIBUTE_RSSI_MIDDLE, rssi);
+ if (result < 0) {
+ ALOGE("%s: Failing in 2g rssi middle, result = %d\n", __func__, result);
+ return result;
+ }
+ }
+
+ if (mParams->config_2dot4g_rssi_proximity) {
+ if (ISGREATER(mParams->rssi_proximity_2dot4g_val, NAN_MAX_RSSI)) {
+ ALOGI("%s: Invalid rssi param \n", __func__);
+ return WIFI_ERROR_INVALID_ARGS;
+ }
+ rssi = -mParams->rssi_proximity_2dot4g_val;
+ result = request.put_s8(NAN_ATTRIBUTE_RSSI_PROXIMITY, rssi);
+ if (result < 0) {
+ ALOGE("%s: Failing in 2g rssi proximity, result = %d\n", __func__, result);
+ return result;
+ }
+ }
+
+ if (mParams->config_5g_rssi_close) {
+ if (ISGREATER(mParams->rssi_close_5g_val, NAN_MAX_RSSI)) {
+ ALOGI("%s: Invalid rssi param \n", __func__);
+ return WIFI_ERROR_INVALID_ARGS;
+ }
+ rssi = -mParams->rssi_close_5g_val;
+ result = request.put_s8(NAN_ATTRIBUTE_RSSI_CLOSE_5G, rssi);
+ if (result < 0) {
+ ALOGE("%s: Failing in 5g rssi close, result = %d\n", __func__, result);
+ return result;
+ }
+ }
+
+ if (mParams->config_5g_rssi_middle) {
+ if (ISGREATER(mParams->rssi_middle_5g_val, NAN_MAX_RSSI)) {
+ ALOGI("%s: Invalid rssi param \n", __func__);
+ return WIFI_ERROR_INVALID_ARGS;
+ }
+ rssi = -mParams->rssi_middle_5g_val;
+ result = request.put_s8(NAN_ATTRIBUTE_RSSI_MIDDLE_5G, rssi);
+ if (result < 0) {
+ ALOGE("%s: Failing in 5g rssi middle, result = %d\n", __func__, result);
+ return result;
+ }
+ }
+
+ if (mParams->config_5g_rssi_close_proximity) {
+ if (ISGREATER(mParams->rssi_close_proximity_5g_val, NAN_MAX_RSSI)) {
+ ALOGI("%s: Invalid rssi param \n", __func__);
+ return WIFI_ERROR_INVALID_ARGS;
+ }
+ rssi = -mParams->rssi_close_proximity_5g_val;
+ result = request.put_s8(NAN_ATTRIBUTE_RSSI_PROXIMITY_5G, rssi);
+ if (result < 0) {
+ ALOGE("%s: Failing in rssi_close_proximity_5g_val, result = %d\n", __func__, result);
+ return result;
+ }
+ }
+
+ if (mParams->config_cluster_attribute_val) {
+ result = request.put_u8(NAN_ATTRIBUTE_CONF_CLUSTER_VAL, mParams->config_cluster_attribute_val);
+ if (result < 0) {
+ ALOGE("%s: Failing in config_cluster_attribute_val, result = %d\n", __func__, result);
+ return result;
+ }
+ }
+
+ if (mParams->config_hop_count_limit) {
+ result = request.put_u8(NAN_ATTRIBUTE_HOP_COUNT_LIMIT,
+ mParams->hop_count_limit_val);
+ if (result < 0) {
+ ALOGE("%s: Failing in hop cnt limit, result = %d\n", __func__, result);
+ return result;
+ }
+ }
+
+ if (mParams->config_oui) {
+ ALOGI("%s: oui = 0x%04x\n", __func__, mParams->oui_val);
+ result = request.put_u32(NAN_ATTRIBUTE_OUI, mParams->oui_val);
+ if (result < 0) {
+ ALOGE("%s: Failing in oui, result = %d\n", __func__, result);
+ return result;
+ }
+ }
+
+ result = request.put_u8(NAN_ATTRIBUTE_MASTER_PREF, mParams->master_pref);
+ if (result < 0) {
+ ALOGE("%s: Failing in master pref, result = %d\n", __func__, result);
+ return result;
+ }
+ if (mParams->config_random_factor_force) {
+ result = request.put_u8(NAN_ATTRIBUTE_RANDOM_FACTOR, mParams->random_factor_force_val);
+ if (result < 0) {
+ ALOGE("%s: Failing in random factor, result = %d\n", __func__, result);
+ return result;
+ }
+ }
+
+ if (mParams->config_24g_channel) {
+ result = request.put_u32(NAN_ATTRIBUTE_24G_CHANNEL, mParams->channel_24g_val);
+ if (result < 0) {
+ ALOGE("%s: Failing in 2.4g channel, result = %d\n", __func__, result);
+ return result;
+ }
+ }
+
+ if (mParams->config_5g_channel) {
+ result = request.put_u32(NAN_ATTRIBUTE_5G_CHANNEL, mParams->channel_5g_val);
+ if (result < 0) {
+ ALOGE("%s: Failing in 5g channel, result = %d\n", __func__, result);
+ return result;
+ }
+ }
+
+ if (mParams->config_intf_addr) {
+ result = request.put_addr(NAN_ATTRIBUTE_IF_ADDR, mParams->intf_addr_val);
+ if (result < 0) {
+ ALOGE("%s: Failing in intf addr val, result = %d\n", __func__, result);
+ return result;
+ }
+ }
+
+ if (mParams->config_dw.config_2dot4g_dw_band) {
+ result = request.put_u32(NAN_ATTRIBUTE_2G_AWAKE_DW, mParams->config_dw.dw_2dot4g_interval_val);
+ if (result < 0) {
+ ALOGE("%s: Failing in 2dot4g awake dw, result = %d\n", __func__, result);
+ return result;
+ }
+ }
+
+ if (mParams->config_dw.config_5g_dw_band) {
+ result = request.put_u32(NAN_ATTRIBUTE_5G_AWAKE_DW, mParams->config_dw.dw_5g_interval_val);
+ if (result < 0) {
+ ALOGE("%s: Failing in 5g awake dw, result = %d\n", __func__, result);
+ return result;
+ }
+ }
+
+ if (ISGREATER(mParams->discovery_indication_cfg, NAN_DISC_IND_MAX)) {
+ ALOGE("%s:Invalid disc_ind_cfg value.\n", __FUNCTION__);
+ return WIFI_ERROR_INVALID_ARGS;
+ }
+
+ result = request.put_u8(NAN_ATTRIBUTE_DISC_IND_CFG,
+ mParams->discovery_indication_cfg);
+ if (result < 0) {
+ ALOGE("%s: Failed to fill NAN_ATTRIBUTE_DISC_IND_CFG, result = %d\n",
+ __func__, result);
+ return result;
+ }
+
+ if (mParams->config_rssi_window_size) {
+ result = request.put_u8(NAN_ATTRIBUTE_RSSI_WINDOW_SIZE,
+ mParams->rssi_window_size_val);
+ if (result < 0) {
+ ALOGE("%s: Failing in rssi_window_size_val, result = %d\n", __func__, result);
+ return result;
+ }
+ }
+
+ if (mParams->config_scan_params) {
+ result = request.put_u8(NAN_ATTRIBUTE_DWELL_TIME,
+ mParams->scan_params_val.dwell_time[0]);
+ if (result < 0) {
+ ALOGE("%s: Failing in dwell time, result = %d\n", __func__, result);
+ return result;
+ }
+ result = request.put_u8(NAN_ATTRIBUTE_DWELL_TIME_5G,
+ mParams->scan_params_val.dwell_time[1]);
+ if (result < 0) {
+ ALOGE("%s: Failing in 5g dwell time, result = %d\n", __func__, result);
+ return result;
+ }
+ result = request.put_u16(NAN_ATTRIBUTE_SCAN_PERIOD,
+ mParams->scan_params_val.scan_period[0]);
+ if (result < 0) {
+ ALOGE("%s: Failing in scan_period, result = %d\n", __func__, result);
+ return result;
+ }
+ result = request.put_u16(NAN_ATTRIBUTE_SCAN_PERIOD_5G,
+ mParams->scan_params_val.scan_period[1]);
+ if (result < 0) {
+ ALOGE("%s: Failing in 5g scan_period, result = %d\n", __func__, result);
+ return result;
+ }
+ }
+
+ if (mParams->config_disc_mac_addr_randomization) {
+ result = request.put_u32(NAN_ATTRIBUTE_RANDOMIZATION_INTERVAL,
+ mParams->disc_mac_addr_rand_interval_sec);
+ if (result < 0) {
+ ALOGE("%s: Failing to fill rand mac address interval, result = %d\n", __func__, result);
+ return result;
+ }
+ }
+
+ if (mParams->config_discovery_beacon_int) {
+ result = request.put_u32(NAN_ATTRIBUTE_DISCOVERY_BEACON_INTERVAL,
+ mParams->discovery_beacon_interval);
+ if (result < 0) {
+ ALOGE("%s: Failing to fill disc beacon interval, result = %d\n", __func__, result);
+ return result;
+ }
+ }
+
+ if (mParams->config_nss) {
+ result = request.put_u32(NAN_ATTRIBUTE_NSS, mParams->nss);
+ if (result < 0) {
+ ALOGE("%s: Failing to fill nss, result = %d\n", __func__, result);
+ return result;
+ }
+ }
+
+ if (mParams->config_enable_ranging) {
+ result = request.put_u32(NAN_ATTRIBUTE_ENABLE_RANGING, mParams->enable_ranging);
+ if (result < 0) {
+ ALOGE("%s: Failing to fill enable ranging value, result = %d\n", __func__, result);
+ return result;
+ }
+ }
+
+ if (mParams->config_dw_early_termination) {
+ result = request.put_u32(NAN_ATTRIBUTE_DW_EARLY_TERM, mParams->enable_dw_termination);
+ if (result < 0) {
+ ALOGE("%s: Failing to fill enable dw termination value, result = %d\n",
+ __func__, result);
+ return result;
+ }
+ }
+
+ if (mParams->config_ndpe_attr) {
+ result = request.put_u32(NAN_ATTRIBUTE_CMD_USE_NDPE,
+ mParams->use_ndpe_attr);
+ if (result < 0) {
+ ALOGE("%s: Failing to fill use_ndpe, result = %d\n", __func__, result);
+ return result;
+ }
+ }
+
+ if (mParams->config_enable_instant_mode) {
+ result = request.put_u32(NAN_ATTRIBUTE_INSTANT_MODE_ENABLE,
+ mParams->enable_instant_mode);
+ if (result < 0) {
+ ALOGE("%s: Failing to fill enable instant mode, result = %d\n", __func__, result);
+ return result;
+ }
+ }
+
+ if (mParams->enable_instant_mode && mParams->config_instant_mode_channel
+ && mParams->instant_mode_channel) {
+ result = request.put_u32(NAN_ATTRIBUTE_INSTANT_COMM_CHAN,
+ mParams->instant_mode_channel);
+ if (result < 0) {
+ ALOGE("%s: Failing in config instant channel, result = %d\n", __func__, result);
+ return result;
+ }
+ ALOGI("%s: instant mode channel = %d\n", __func__, mParams->instant_mode_channel);
+ }
+
+ request.attr_end(data);
+ NAN_DBG_EXIT();
+ return WIFI_SUCCESS;
+ }
+
+ int createDisableRequest(WifiRequest& request) {
+ NAN_DBG_ENTER();
+
+ int result = request.create(GOOGLE_OUI, NAN_SUBCMD_DISABLE);
+ if (result < 0) {
+ ALOGE("%s: Fail to create request, result = %d\n", __func__, result);
+ return result;
+ }
+
+ nlattr *data = request.attr_start(NL80211_ATTR_VENDOR_DATA);
+
+ request.attr_end(data);
+
+ NAN_DBG_EXIT();
+ return result;
+ }
+
+ int createConfigRequest(WifiRequest& request, NanConfigRequest *mParams) {
+
+ int result = request.create(GOOGLE_OUI, NAN_SUBCMD_CONFIG);
+ s8 rssi;
+ if (result < 0) {
+ ALOGE("%s: Fail to create config request\n", __func__);
+ return result;
+ }
+
+ NAN_DBG_ENTER();
+
+ nlattr *data = request.attr_start(NL80211_ATTR_VENDOR_DATA);
+
+ if (mParams->config_sid_beacon) {
+ result = request.put_u8(NAN_ATTRIBUTE_SID_BEACON, mParams->sid_beacon);
+ if (result < 0) {
+ ALOGE("%s: Failing in sid beacon, result = %d\n", __func__, result);
+ return result;
+ }
+ }
+
+ if (mParams->config_subscribe_sid_beacon) {
+ result = request.put_u8(NAN_ATTRIBUTE_SUB_SID_BEACON, mParams->subscribe_sid_beacon_val);
+ if (result < 0) {
+ ALOGE("%s: Failing in sub sid beacon, result = %d\n", __func__, result);
+ return result;
+ }
+ }
+
+ if (mParams->config_rssi_proximity) {
+ if (ISGREATER(mParams->rssi_proximity, NAN_MAX_RSSI)) {
+ ALOGI("%s: Invalid rssi param \n", __func__);
+ return WIFI_ERROR_INVALID_ARGS;
+ }
+ rssi = -mParams->rssi_proximity;
+ result = request.put_s8(NAN_ATTRIBUTE_RSSI_PROXIMITY, rssi);
+ if (result < 0) {
+ ALOGE("%s: Failing in rssi_proximity, result = %d\n", __func__, result);
+ return result;
+ }
+ }
+
+ if (mParams->config_master_pref) {
+ ALOGI("%s: master pref = %u\n", __func__, mParams->master_pref);
+ result = request.put_u8(NAN_ATTRIBUTE_MASTER_PREF, mParams->master_pref);
+ if (result < 0) {
+ ALOGE("%s: Failing in master pref, result = %d\n", __func__, result);
+ return result;
+ }
+ }
+
+ if (mParams->config_5g_rssi_close_proximity) {
+ if (ISGREATER(mParams->rssi_close_proximity_5g_val, NAN_MAX_RSSI)) {
+ ALOGI("%s: Invalid rssi param \n", __func__);
+ return WIFI_ERROR_INVALID_ARGS;
+ }
+ rssi = -mParams->rssi_close_proximity_5g_val;
+ result = request.put_s8(NAN_ATTRIBUTE_RSSI_PROXIMITY_5G, rssi);
+ if (result < 0) {
+ ALOGE("%s: Failing in rssi_close_proximity_5g_val, result = %d\n", __func__, result);
+ return result;
+ }
+ }
+
+ if (mParams->config_rssi_window_size) {
+ result = request.put_u8(NAN_ATTRIBUTE_RSSI_WINDOW_SIZE,
+ mParams->rssi_window_size_val);
+ if (result < 0) {
+ ALOGE("%s: Failing in rssi_window_size_val, result = %d\n", __func__, result);
+ return result;
+ }
+ }
+
+ if (mParams->config_scan_params) {
+ result = request.put_u8(NAN_ATTRIBUTE_DWELL_TIME,
+ mParams->scan_params_val.dwell_time[0]);
+ if (result < 0) {
+ ALOGE("%s: Failing in dwell time, result = %d\n", __func__, result);
+ return result;
+ }
+
+ result = request.put_u8(NAN_ATTRIBUTE_DWELL_TIME_5G,
+ mParams->scan_params_val.dwell_time[1]);
+ if (result < 0) {
+ ALOGE("%s: Failing in 5g dwell time, result = %d\n", __func__, result);
+ return result;
+ }
+ result = request.put_u16(NAN_ATTRIBUTE_SCAN_PERIOD,
+ mParams->scan_params_val.scan_period[0]);
+ if (result < 0) {
+ ALOGE("%s: Failing in scan_period, result = %d\n", __func__, result);
+ return result;
+ }
+
+ result = request.put_u16(NAN_ATTRIBUTE_SCAN_PERIOD_5G,
+ mParams->scan_params_val.scan_period[1]);
+ if (result < 0) {
+ ALOGE("%s: Failing in 5g scan_period, result = %d\n", __func__, result);
+ return result;
+ }
+ }
+
+ if (mParams->config_random_factor_force) {
+ result = request.put_u8(NAN_ATTRIBUTE_RANDOM_FACTOR, mParams->random_factor_force_val);
+ if (result < 0) {
+ ALOGE("%s: Failing in random factor, result = %d\n", __func__, result);
+ return result;
+ }
+ }
+
+ if (mParams->config_hop_count_force) {
+ result = request.put_u8(NAN_ATTRIBUTE_HOP_COUNT_LIMIT,
+ mParams->hop_count_force_val);
+ if (result < 0) {
+ ALOGE("%s: Failing in hop cnt limit, result = %d\n", __func__, result);
+ return result;
+ }
+ }
+
+ if (mParams->config_cluster_attribute_val) {
+ result = request.put_u8(NAN_ATTRIBUTE_CONF_CLUSTER_VAL, mParams->config_cluster_attribute_val);
+ if (result < 0) {
+ ALOGE("%s: Failing in config_cluster_attribute_val, result = %d\n", __func__, result);
+ return result;
+ }
+ }
+
+ if (mParams->config_fam) {
+ while (mParams->fam_val.numchans) {
+ result = request.put_u8(NAN_ATTRIBUTE_ENTRY_CONTROL,
+ mParams->fam_val.famchan[mParams->fam_val.numchans].entry_control);
+ if (result < 0) {
+ ALOGE("%s: Failing in entry control, result = %d\n", __func__, result);
+ return result;
+ }
+
+ result = request.put_u32(NAN_ATTRIBUTE_CHANNEL,
+ (u32)mParams->fam_val.famchan[mParams->fam_val.numchans].channel);
+ if (result < 0) {
+ ALOGE("%s: Failed to fill channel = %d, result = %d\n", __func__,
+ mParams->fam_val.famchan[mParams->fam_val.numchans].channel, result);
+ return result;
+ }
+
+ result = request.put_u32(NAN_ATTRIBUTE_AVAIL_BIT_MAP,
+ (u32)mParams->fam_val.famchan[mParams->fam_val.numchans].avail_interval_bitmap);
+ if (result < 0) {
+ ALOGE("%s: Failed to fill avail interval bitmap = %d, result = %d\n", __func__,
+ mParams->fam_val.famchan[mParams->fam_val.numchans].avail_interval_bitmap, result);
+ return result;
+ }
+ mParams->fam_val.numchans -= 1;
+ }
+
+ }
+
+ if (mParams->config_dw.config_2dot4g_dw_band) {
+ result = request.put_u32(NAN_ATTRIBUTE_2G_AWAKE_DW, mParams->config_dw.dw_2dot4g_interval_val);
+ if (result < 0) {
+ ALOGE("%s: Failing in 2dot4g awake dw, result = %d\n", __func__, result);
+ return result;
+ }
+ }
+
+ if (mParams->config_dw.config_5g_dw_band) {
+ result = request.put_u32(NAN_ATTRIBUTE_5G_AWAKE_DW, mParams->config_dw.dw_5g_interval_val);
+ if (result < 0) {
+ ALOGE("%s: Failing in 5g awake dw, result = %d\n", __func__, result);
+ return result;
+ }
+ }
+ if (ISGREATER(mParams->discovery_indication_cfg, NAN_DISC_IND_MAX)) {
+ ALOGE("%s:Invalid disc_ind_cfg value.\n", __FUNCTION__);
+ return WIFI_ERROR_INVALID_ARGS;
+ }
+ result = request.put_u8(NAN_ATTRIBUTE_DISC_IND_CFG,
+ mParams->discovery_indication_cfg);
+ if (result < 0) {
+ ALOGE("%s: Failed to fill NAN_ATTRIBUTE_DISC_IND_CFG, result = %d\n",
+ __func__, result);
+ return result;
+ }
+ if (mParams->config_disc_mac_addr_randomization) {
+ result = request.put_u32(NAN_ATTRIBUTE_RANDOMIZATION_INTERVAL,
+ mParams->disc_mac_addr_rand_interval_sec);
+ if (result < 0) {
+ ALOGE("%s: Failing in 5g scan_period, result = %d\n", __func__, result);
+ return result;
+ }
+ }
+ if (mParams->config_ndpe_attr) {
+ result = request.put_u32(NAN_ATTRIBUTE_CMD_USE_NDPE,
+ mParams->use_ndpe_attr);
+ if (result < 0) {
+ ALOGE("%s: Failing to fill use_ndpe, result = %d\n", __func__, result);
+ return result;
+ }
+ }
+
+ if (mParams->config_disc_mac_addr_randomization) {
+ result = request.put_u32(NAN_ATTRIBUTE_RANDOMIZATION_INTERVAL,
+ mParams->disc_mac_addr_rand_interval_sec);
+ if (result < 0) {
+ ALOGE("%s: Failing to fill rand mac interval, result = %d\n", __func__, result);
+ return result;
+ }
+ }
+
+ if (mParams->config_discovery_beacon_int) {
+ result = request.put_u32(NAN_ATTRIBUTE_DISCOVERY_BEACON_INTERVAL,
+ mParams->discovery_beacon_interval);
+ if (result < 0) {
+ ALOGE("%s: Failing to fill disc beacon interval, result = %d\n", __func__, result);
+ return result;
+ }
+ }
+
+ if (mParams->config_nss) {
+ result = request.put_u32(NAN_ATTRIBUTE_NSS, mParams->nss);
+ if (result < 0) {
+ ALOGE("%s: Failing to fill nss, result = %d\n", __func__, result);
+ return result;
+ }
+ }
+
+ if (mParams->config_enable_ranging) {
+ result = request.put_u32(NAN_ATTRIBUTE_ENABLE_RANGING, mParams->enable_ranging);
+ if (result < 0) {
+ ALOGE("%s: Failing to fill enable ranging value, result = %d\n", __func__, result);
+ return result;
+ }
+ }
+
+ if (mParams->config_dw_early_termination) {
+ result = request.put_u32(NAN_ATTRIBUTE_DW_EARLY_TERM, mParams->enable_dw_termination);
+ if (result < 0) {
+ ALOGE("%s: Failing to fill enable dw termination value, result = %d\n",
+ __func__, result);
+ return result;
+ }
+ }
+
+ if (mParams->config_enable_instant_mode) {
+ result = request.put_u32(NAN_ATTRIBUTE_INSTANT_MODE_ENABLE,
+ mParams->enable_instant_mode);
+ if (result < 0) {
+ ALOGE("%s: Failing to fill enable instant mode, result = %d\n", __func__, result);
+ return result;
+ }
+ }
+
+ if (mParams->enable_instant_mode && mParams->config_instant_mode_channel
+ && mParams->instant_mode_channel) {
+ result = request.put_u32(NAN_ATTRIBUTE_INSTANT_COMM_CHAN,
+ mParams->instant_mode_channel);
+ if (result < 0) {
+ ALOGE("%s: Failing in config instant channel, result = %d\n", __func__, result);
+ return result;
+ }
+ ALOGI("%s: instant mode channel = %d\n", __func__, mParams->instant_mode_channel);
+ }
+
+ request.attr_end(data);
+ NAN_DBG_EXIT();
+ return WIFI_SUCCESS;
+ }
+
+ int start()
+ {
+ NAN_DBG_ENTER();
+
+ WifiRequest request(familyId(), ifaceId());
+ int result = createRequest(request);
+ if (result != WIFI_SUCCESS) {
+ ALOGE("%s: Failed to create setup request; result = %d", __func__, result);
+ return result;
+ }
+
+ result = requestResponse(request);
+ if (result != WIFI_SUCCESS) {
+ ALOGE("%s: Failed to configure setup; result = %d", __func__, result);
+ return result;
+ }
+
+ request.destroy();
+ NAN_DBG_EXIT();
+ return WIFI_SUCCESS;
+ }
+
+ int cancel()
+ {
+ NAN_DBG_ENTER();
+
+ WifiRequest request(familyId(), ifaceId());
+ int result = createRequest(request);
+ if (result != WIFI_SUCCESS) {
+ ALOGE("%s: Failed to create setup request; result = %d", __func__, result);
+ return result;
+ }
+
+ result = requestResponse(request);
+ if (result != WIFI_SUCCESS) {
+ ALOGE("%s: Failed to configure setup; result = %d", __func__, result);
+ return result;
+ }
+
+ request.destroy();
+ NAN_DBG_EXIT();
+ return WIFI_SUCCESS;
+ }
+
+ int handleResponse(WifiEvent& reply) {
+ nan_hal_resp_t *rsp_vndr_data = NULL;
+
+ if (reply.get_cmd() != NL80211_CMD_VENDOR || reply.get_vendor_data() == NULL) {
+ ALOGD("Ignoring reply with cmd = %d", reply.get_cmd());
+ return NL_SKIP;
+ }
+
+ rsp_vndr_data = (nan_hal_resp_t *)reply.get_vendor_data();
+ ALOGI("NanMacControl::handleResponse\n");
+ if (mType == NAN_VERSION_INFO) {
+ mVersion = *((u32*)reply.get_vendor_data());
+ ALOGI("Response not required for version cmd %d\n", mVersion);
+ return NL_SKIP;
+ }
+ if (rsp_vndr_data->subcmd == NAN_SUBCMD_CONFIG) {
+ NanResponseMsg rsp_data;
+ memset(&rsp_data, 0, sizeof(NanResponseMsg));
+ rsp_data.response_type = get_response_type((WIFI_SUB_COMMAND)rsp_vndr_data->subcmd);
+ rsp_data.status = nan_map_response_status(rsp_vndr_data->status);
+
+ ALOGI("NanMacControl:Received response for cmd [%s], TxID %d ret %d\n",
+ NanRspToString(rsp_data.response_type), id(), rsp_data.status);
+
+ GET_NAN_HANDLE(info)->mHandlers.NotifyResponse(id(), &rsp_data);
+ }
+ if (rsp_vndr_data->subcmd == NAN_SUBCMD_ENABLE) {
+ NanResponseMsg rsp_data;
+ memset(&rsp_data, 0, sizeof(NanResponseMsg));
+ rsp_data.response_type = get_response_type((WIFI_SUB_COMMAND)rsp_vndr_data->subcmd);
+ rsp_data.status = nan_map_response_status(rsp_vndr_data->status);
+
+ ALOGI("NanMacControl:Received response for cmd [%s], TxID %d ret %d\n",
+ NanRspToString(rsp_data.response_type), mId, rsp_data.status);
+
+ if( rsp_data.status != NAN_STATUS_SUCCESS) {
+ GET_NAN_HANDLE(info)->mHandlers.NotifyResponse(mId, &rsp_data);
+ }
+ }
+ return NL_SKIP;
+ }
+
+ int handleAsyncResponse(nan_hal_resp_t *rsp_vndr_data) {
+ NanResponseMsg rsp_data;
+ ALOGI("NanMacControl::handleAsyncResponse\n");
+ /* Enable response will be provided to framework in event path */
+ if (rsp_vndr_data->subcmd == NAN_SUBCMD_ENABLE) {
+ return NL_SKIP;
+ }
+ memset(&rsp_data, 0, sizeof(NanResponseMsg));
+ rsp_data.response_type = get_response_type((WIFI_SUB_COMMAND)rsp_vndr_data->subcmd);
+ rsp_data.status = nan_map_response_status(rsp_vndr_data->status);
+ ALOGE("Mapped hal status = %d\n", rsp_data.status);
+
+ /* populate error string if not coming from DHD */
+ if (rsp_vndr_data->nan_reason[0] == '\0') {
+ memcpy(rsp_data.nan_error, NanStatusToString(rsp_data.status),
+ strlen(NanStatusToString(rsp_data.status)));
+ rsp_data.nan_error[strlen(NanStatusToString(rsp_data.status))] = '\0';
+ }
+ rsp_data.nan_error[NAN_ERROR_STR_LEN - 1] = '\0';
+ ALOGI("\n Received nan_error string %s\n", (u8*)rsp_data.nan_error);
+ ALOGI("Retrieved ID = %d\n", mId);
+
+ if ((rsp_vndr_data->subcmd == NAN_SUBCMD_DISABLE) &&
+ (mId != NAN_MAC_INVALID_TRANSID)) {
+ GET_NAN_HANDLE(info)->mHandlers.NotifyResponse(mId, &rsp_data);
+ mId = NAN_MAC_INVALID_TRANSID;
+ }
+ return NL_SKIP;
+ }
+
+ int handleEvent(WifiEvent& event) {
+ u32 ndp_instance_id = 0;
+ int event_id = event.get_vendor_subcmd();
+ nlattr *vendor_data = event.get_attribute(NL80211_ATTR_VENDOR_DATA);
+ int len = event.get_vendor_data_len();
+ u16 attr_type;
+ nan_hal_resp_t *rsp_vndr_data = NULL;
+
+ ALOGI("%s: Received NanMacControl event = %d (len=%d)\n",
+ __func__, event.get_cmd(), len);
+ if (!vendor_data || len == 0) {
+ ALOGE("No event data found");
+ return NL_SKIP;
+ }
+
+ for (nl_iterator it(vendor_data); it.has_next(); it.next()) {
+ attr_type = it.get_type();
+
+ if (it.get_type() == NAN_ATTRIBUTE_HANDLE) {
+ } else if (it.get_type() == NAN_ATTRIBUTE_NDP_ID) {
+ ndp_instance_id = it.get_u32();
+ ALOGI("handleEvent: ndp_instance_id = [%d]\n", ndp_instance_id);
+ } else if (attr_type == NAN_ATTRIBUTE_CMD_RESP_DATA) {
+ ALOGI("sizeof cmd response data: %ld, it.get_len() = %d\n",
+ sizeof(nan_hal_resp_t), it.get_len());
+ if (it.get_len() == sizeof(nan_hal_resp_t)) {
+ rsp_vndr_data = (nan_hal_resp_t*)it.get_data();
+ } else {
+ ALOGE("Wrong cmd response data received\n");
+ return NL_SKIP;
+ }
+ }
+ }
+
+ ALOGI("Received vendor sub cmd %d\n", event_id);
+ if (is_de_event(event_id)) {
+
+ NanDiscEnginePrimitive *de_prim =
+ (NanDiscEnginePrimitive *)(info.nan_disc_control);
+ if (de_prim != NULL) {
+ de_prim->handleEvent(event);
+ } else {
+ ALOGE("%s: de_primitive is no more available\n", __func__);
+ }
+ return NL_SKIP;
+
+ } else if (is_dp_event(event_id)) {
+
+ NanDataPathPrimitive *dp_prim =
+ (NanDataPathPrimitive *)(info.nan_dp_control);
+ ALOGI("ndp_instance_id = [%d]\n", ndp_instance_id);
+ if (dp_prim != NULL) {
+ dp_prim->handleEvent(event);
+ } else {
+ ALOGE("%s: dp_primitive is no more available\n", __func__);
+ }
+ return NL_SKIP;
+ } else {
+ if (is_cmd_response(event_id)) {
+ ALOGE("Handling cmd response asynchronously\n");
+ if (rsp_vndr_data != NULL) {
+ handleAsyncResponse(rsp_vndr_data);
+ } else {
+ ALOGE("Wrong response data, rsp_vndr_data is NULL\n");
+ return NL_SKIP;
+ }
+ }
+ }
+
+ switch(event_id) {
+ case NAN_EVENT_DE_EVENT:
+ NanDiscEngEventInd de_event;
+ memset(&de_event, 0, sizeof(de_event));
+
+ for (nl_iterator it(vendor_data); it.has_next(); it.next()) {
+ attr_type = it.get_type();
+
+ if (attr_type == NAN_ATTRIBUTE_CLUSTER_ID) {
+ memcpy(&de_event.data.cluster.addr, it.get_data(), NAN_MAC_ADDR_LEN);
+ ALOGI("cluster id = " MACSTR "\n", MAC2STR(de_event.data.cluster.addr));
+ } else if (attr_type == NAN_ATTRIBUTE_ENABLE_STATUS) {
+ ALOGI("nan enable status = %u\n", it.get_u16());
+ } else if (attr_type == NAN_ATTRIBUTE_JOIN_STATUS) {
+ ALOGI("nan joined status = %u\n", it.get_u16());
+ } else if (attr_type == NAN_ATTRIBUTE_DE_EVENT_TYPE) {
+ u8 de_type = it.get_u8();
+ ALOGI("nan de event type = %u\n", de_type);
+ if (de_type == NAN_EVENT_IFACE) {
+ de_event.event_type = NAN_EVENT_ID_DISC_MAC_ADDR;
+ ALOGI("received NAN_EVENT_ID_DISC_MAC_ADDR event\n");
+ } else if (de_type == NAN_EVENT_START) {
+ de_event.event_type = NAN_EVENT_ID_STARTED_CLUSTER;
+ ALOGI("received NAN cluster started event\n");
+ } else if (de_type == NAN_EVENT_JOIN) {
+ /* To be deprecated */
+ de_event.event_type = NAN_EVENT_ID_JOINED_CLUSTER;
+ ALOGI("received join event\n");
+ } else if (de_type == NAN_EVENT_ROLE_CHANGE) {
+ ALOGI("received device role change event\n");
+ } else if (de_type == NAN_EVENT_MERGE) {
+ ALOGI("received merge event\n");
+ } else {
+ ALOGI("received unknown DE event, [%d]\n", de_type);
+ }
+ } else if (attr_type == NAN_ATTRIBUTE_MAC_ADDR) {
+ memcpy(&de_event.data.mac_addr.addr, it.get_data(), NAN_MAC_ADDR_LEN);
+ memcpy(mNmi, it.get_data(), NAN_MAC_ADDR_LEN);
+ ALOGI("Primary discovery mac address = " MACSTR "\n",
+ MAC2STR(mNmi));
+ }
+ }
+ GET_NAN_HANDLE(info)->mHandlers.EventDiscEngEvent(&de_event);
+ /* XXX: WAR for sending intf addr to generate Identity
+ * change callback in framework
+ * Also WAR for enable response
+ */
+ if (de_event.event_type == NAN_EVENT_ID_STARTED_CLUSTER) {
+ NanResponseMsg rsp_data;
+ memcpy(&de_event.data.mac_addr.addr, mNmi, NAN_MAC_ADDR_LEN);
+ de_event.event_type = NAN_EVENT_ID_DISC_MAC_ADDR;
+ GET_NAN_HANDLE(info)->mHandlers.EventDiscEngEvent(&de_event);
+ rsp_data.response_type = NAN_RESPONSE_ENABLED;
+ rsp_data.status = NAN_STATUS_SUCCESS;
+ memcpy(rsp_data.nan_error, NanStatusToString(rsp_data.status),
+ strlen(NanStatusToString(rsp_data.status)));
+ GET_NAN_HANDLE(info)->mHandlers.NotifyResponse(mId, &rsp_data);
+ /* clean up mId to distinguish duplciated disable command */
+ mId = NAN_MAC_INVALID_TRANSID;
+ }
+ break;
+
+ case NAN_EVENT_DISABLED:
+ ALOGI("Received NAN_EVENT_DISABLED\n");
+ NanDisabledInd disabled_ind;
+ memset(&disabled_ind, 0, sizeof(NanDisabledInd));
+ for (nl_iterator it(vendor_data); it.has_next(); it.next()) {
+ attr_type = it.get_type();
+ if (attr_type == NAN_ATTRIBUTE_STATUS) {
+ disabled_ind.reason = (NanStatusType)it.get_u8();
+ ALOGI("Nan Disable:status %u", disabled_ind.reason);
+ } else if (attr_type == NAN_ATTRIBUTE_REASON) {
+ u8 len = min(it.get_len(), sizeof(disabled_ind.nan_reason));
+ memcpy(disabled_ind.nan_reason, it.get_data(), len);
+ ALOGI("Disabled nan reason: %s, len = %d\n",
+ disabled_ind.nan_reason, len);
+ }
+ }
+
+ GET_NAN_HANDLE(info)->mHandlers.EventDisabled(&disabled_ind);
+ /* unregister Nan vendor events */
+ unRegisterNanVendorEvents();
+ break;
+
+ case NAN_EVENT_SDF:
+ ALOGI("Received NAN_EVENT_SDF:\n");
+ NanBeaconSdfPayloadInd sdfInd;
+ memset(&sdfInd, 0, sizeof(sdfInd));
+
+ for (nl_iterator it(vendor_data); it.has_next(); it.next()) {
+ attr_type = it.get_type();
+
+ if (attr_type == NAN_ATTRIBUTE_SERVICE_SPECIFIC_INFO_LEN) {
+ sdfInd.data.frame_len = it.get_u16();
+ if (sdfInd.data.frame_len > NAN_MAX_FRAME_DATA_LEN) {
+ sdfInd.data.frame_len = NAN_MAX_FRAME_DATA_LEN;
+ }
+ ALOGI("Received NAN_ATTRIBUTE_SERVICE_SPECIFIC_INFO_LEN: 0x%x(%d)\n",
+ sdfInd.data.frame_len, sdfInd.data.frame_len);
+
+ } else if (attr_type == NAN_ATTRIBUTE_SERVICE_SPECIFIC_INFO) {
+ ALOGI("Received NAN_ATTRIBUTE_SERVICE_SPECIFIC_INFO\n");
+ memcpy(&sdfInd.data.frame_data, it.get_data(), sdfInd.data.frame_len);
+ prhex("sdfInd.data.frame_data: ", (u8*)sdfInd.data.frame_data,
+ sdfInd.data.frame_len);
+ }
+ }
+ GET_NAN_HANDLE(info)->mHandlers.EventBeaconSdfPayload(&sdfInd);
+ break;
+
+ case NAN_EVENT_TCA:
+ ALOGI("Received NAN_EVENT_TCA\n");
+ break;
+
+ case NAN_EVENT_UNKNOWN:
+ ALOGI("Received NAN_EVENT_UNKNOWN\n");
+ break;
+ } // end-of-switch
+
+ return NL_SKIP;
+ }
+ void unRegisterNanVendorEvents()
+ {
+ int i = 0;
+ for (i = NAN_EVENT_ENABLED; i <= NAN_EVENT_DATA_END; i++) {
+ unregisterVendorHandler(GOOGLE_OUI, i);
+ }
+ unregisterVendorHandler(GOOGLE_OUI, NAN_ASYNC_RESPONSE_DISABLED);
+ unregisterVendorHandler(GOOGLE_OUI, NAN_EVENT_MATCH_EXPIRY);
+ }
+ void registerNanVendorEvents()
+ {
+ int i = 0;
+ for (i = NAN_EVENT_ENABLED; i <= NAN_EVENT_DATA_END; i++) {
+ registerVendorHandler(GOOGLE_OUI, i);
+ }
+ registerVendorHandler(GOOGLE_OUI, NAN_ASYNC_RESPONSE_DISABLED);
+ registerVendorHandler(GOOGLE_OUI, NAN_EVENT_MATCH_EXPIRY);
+ }
+};
+
+/* pretty hex print a contiguous buffer */
+static void prhex(const char *msg, u8 *buf, u32 nbytes)
+{
+ char line[128];
+ char *p;
+ int len = sizeof(line);
+ int nchar;
+ u32 i;
+
+ if (msg && (msg[0] != '\0')) {
+ printf("%s:\n", msg);
+ }
+
+ p = line;
+ for (i = 0; i < nbytes; i++) {
+ if (i % 16 == 0) {
+ nchar = snprintf(p, len, " %04d: ", i); /* line prefix */
+ p += nchar;
+ len -= nchar;
+ }
+
+ if (len > 0) {
+ nchar = snprintf(p, len, "%02x ", buf[i]);
+ p += nchar;
+ len -= nchar;
+ }
+
+ if (i % 16 == 15) {
+ ALOGE("%s\n", line); /* flush line */
+ p = line;
+ len = sizeof(line);
+ }
+ }
+
+ /* flush last partial line */
+ if (p != line) {
+ ALOGE("%s\n", line);
+ }
+}
+
+
+static const char *NanRspToString(int cmd_resp)
+{
+ switch (cmd_resp) {
+ C2S(NAN_RESPONSE_ENABLED)
+ C2S(NAN_RESPONSE_DISABLED)
+ C2S(NAN_RESPONSE_PUBLISH)
+ C2S(NAN_RESPONSE_SUBSCRIBE)
+ C2S(NAN_RESPONSE_PUBLISH_CANCEL)
+ C2S(NAN_RESPONSE_SUBSCRIBE_CANCEL)
+ C2S(NAN_RESPONSE_TRANSMIT_FOLLOWUP)
+ C2S(NAN_RESPONSE_CONFIG)
+ C2S(NAN_RESPONSE_TCA)
+ C2S(NAN_RESPONSE_STATS)
+ C2S(NAN_DP_INTERFACE_CREATE)
+ C2S(NAN_DP_INTERFACE_DELETE)
+ C2S(NAN_DP_INITIATOR_RESPONSE)
+ C2S(NAN_DP_RESPONDER_RESPONSE)
+ C2S(NAN_DP_END)
+ C2S(NAN_GET_CAPABILITIES)
+
+ default:
+ return "UNKNOWN_NAN_CMD_RESPONSE";
+ }
+}
+
+static const char *NanCmdToString(int cmd)
+{
+ switch (cmd) {
+ C2S(NAN_REQUEST_ENABLE)
+ C2S(NAN_REQUEST_DISABLE)
+ C2S(NAN_REQUEST_PUBLISH)
+ C2S(NAN_REQUEST_PUBLISH_CANCEL)
+ C2S(NAN_REQUEST_TRANSMIT_FOLLOWUP)
+ C2S(NAN_REQUEST_SUBSCRIBE)
+ C2S(NAN_REQUEST_SUBSCRIBE_CANCEL)
+ C2S(NAN_REQUEST_STATS)
+ C2S(NAN_REQUEST_CONFIG)
+ C2S(NAN_REQUEST_TCA)
+ C2S(NAN_REQUEST_EVENT_CHECK)
+ C2S(NAN_REQUEST_GET_CAPABILITIES)
+ C2S(NAN_DATA_PATH_IFACE_CREATE)
+ C2S(NAN_DATA_PATH_IFACE_DELETE)
+ C2S(NAN_DATA_PATH_INIT_REQUEST)
+ C2S(NAN_DATA_PATH_IND_RESPONSE)
+ C2S(NAN_DATA_PATH_END)
+ C2S(NAN_DATA_PATH_IFACE_UP)
+ C2S(NAN_DATA_PATH_SEC_INFO)
+ C2S(NAN_VERSION_INFO)
+ default:
+ return "UNKNOWN_NAN_CMD";
+ }
+}
+
+static const char *NanAttrToString(u16 cmd)
+{
+ switch (cmd) {
+ C2S(NAN_ATTRIBUTE_HEADER)
+ C2S(NAN_ATTRIBUTE_HANDLE)
+ C2S(NAN_ATTRIBUTE_TRANSAC_ID)
+ C2S(NAN_ATTRIBUTE_5G_SUPPORT)
+ C2S(NAN_ATTRIBUTE_CLUSTER_LOW)
+ C2S(NAN_ATTRIBUTE_CLUSTER_HIGH)
+ C2S(NAN_ATTRIBUTE_SID_BEACON)
+ C2S(NAN_ATTRIBUTE_SYNC_DISC_5G_BEACON)
+ C2S(NAN_ATTRIBUTE_RSSI_CLOSE)
+ C2S(NAN_ATTRIBUTE_RSSI_MIDDLE)
+ C2S(NAN_ATTRIBUTE_RSSI_PROXIMITY)
+ C2S(NAN_ATTRIBUTE_HOP_COUNT_LIMIT)
+ C2S(NAN_ATTRIBUTE_RANDOM_FACTOR)
+ C2S(NAN_ATTRIBUTE_MASTER_PREF)
+ C2S(NAN_ATTRIBUTE_PERIODIC_SCAN_INTERVAL)
+ C2S(NAN_ATTRIBUTE_PUBLISH_ID)
+ C2S(NAN_ATTRIBUTE_TTL)
+ C2S(NAN_ATTRIBUTE_PERIOD)
+ C2S(NAN_ATTRIBUTE_REPLIED_EVENT_FLAG)
+ C2S(NAN_ATTRIBUTE_PUBLISH_TYPE)
+ C2S(NAN_ATTRIBUTE_TX_TYPE)
+ C2S(NAN_ATTRIBUTE_PUBLISH_COUNT)
+ C2S(NAN_ATTRIBUTE_SERVICE_NAME_LEN)
+ C2S(NAN_ATTRIBUTE_SERVICE_NAME)
+ C2S(NAN_ATTRIBUTE_SERVICE_SPECIFIC_INFO_LEN)
+ C2S(NAN_ATTRIBUTE_SERVICE_SPECIFIC_INFO)
+ C2S(NAN_ATTRIBUTE_RX_MATCH_FILTER_LEN)
+ C2S(NAN_ATTRIBUTE_RX_MATCH_FILTER)
+ C2S(NAN_ATTRIBUTE_TX_MATCH_FILTER_LEN)
+ C2S(NAN_ATTRIBUTE_TX_MATCH_FILTER)
+ C2S(NAN_ATTRIBUTE_SUBSCRIBE_ID)
+ C2S(NAN_ATTRIBUTE_SUBSCRIBE_TYPE)
+ C2S(NAN_ATTRIBUTE_SERVICERESPONSEFILTER)
+ C2S(NAN_ATTRIBUTE_SERVICERESPONSEINCLUDE)
+ C2S(NAN_ATTRIBUTE_USESERVICERESPONSEFILTER)
+ C2S(NAN_ATTRIBUTE_SSIREQUIREDFORMATCHINDICATION)
+ C2S(NAN_ATTRIBUTE_SUBSCRIBE_MATCH)
+ C2S(NAN_ATTRIBUTE_SUBSCRIBE_COUNT)
+ C2S(NAN_ATTRIBUTE_MAC_ADDR)
+ C2S(NAN_ATTRIBUTE_MAC_ADDR_LIST)
+ C2S(NAN_ATTRIBUTE_MAC_ADDR_LIST_NUM_ENTRIES)
+ C2S(NAN_ATTRIBUTE_PUBLISH_MATCH)
+ C2S(NAN_ATTRIBUTE_ENABLE_STATUS)
+ C2S(NAN_ATTRIBUTE_JOIN_STATUS)
+ C2S(NAN_ATTRIBUTE_ROLE)
+ C2S(NAN_ATTRIBUTE_MASTER_RANK)
+ C2S(NAN_ATTRIBUTE_ANCHOR_MASTER_RANK)
+ C2S(NAN_ATTRIBUTE_CNT_PEND_TXFRM)
+ C2S(NAN_ATTRIBUTE_CNT_BCN_TX)
+ C2S(NAN_ATTRIBUTE_CNT_BCN_RX)
+ C2S(NAN_ATTRIBUTE_CNT_SVC_DISC_TX)
+ C2S(NAN_ATTRIBUTE_CNT_SVC_DISC_RX)
+ C2S(NAN_ATTRIBUTE_AMBTT)
+ C2S(NAN_ATTRIBUTE_CLUSTER_ID)
+ C2S(NAN_ATTRIBUTE_INST_ID)
+ C2S(NAN_ATTRIBUTE_OUI)
+ C2S(NAN_ATTRIBUTE_STATUS)
+ C2S(NAN_ATTRIBUTE_DE_EVENT_TYPE)
+ C2S(NAN_ATTRIBUTE_MERGE)
+ C2S(NAN_ATTRIBUTE_IFACE)
+ C2S(NAN_ATTRIBUTE_CHANNEL)
+ C2S(NAN_ATTRIBUTE_PEER_ID)
+ C2S(NAN_ATTRIBUTE_NDP_ID)
+ C2S(NAN_ATTRIBUTE_SECURITY)
+ C2S(NAN_ATTRIBUTE_QOS)
+ C2S(NAN_ATTRIBUTE_RSP_CODE)
+ C2S(NAN_ATTRIBUTE_INST_COUNT)
+ C2S(NAN_ATTRIBUTE_PEER_DISC_MAC_ADDR)
+ C2S(NAN_ATTRIBUTE_PEER_NDI_MAC_ADDR)
+ C2S(NAN_ATTRIBUTE_IF_ADDR)
+ C2S(NAN_ATTRIBUTE_WARMUP_TIME)
+ C2S(NAN_ATTRIBUTE_RANGING_RESULT)
+ C2S(NAN_ATTRIBUTE_RANGING_INDICATION)
+ C2S(NAN_ATTRIBUTE_SDEA_SERVICE_SPECIFIC_INFO_LEN)
+ C2S(NAN_ATTRIBUTE_SDEA_SERVICE_SPECIFIC_INFO)
+ C2S(NAN_ATTRIBUTE_RANDOMIZATION_INTERVAL)
+ C2S(NAN_ATTRIBUTE_ENABLE_MERGE)
+
+ default:
+ return "NAN_ATTRIBUTE_UNKNOWN";
+ }
+}
+
+NanResponseType get_response_type(WIFI_SUB_COMMAND nan_subcmd)
+{
+ NanResponseType response_type;
+
+ switch(nan_subcmd) {
+ case NAN_SUBCMD_ENABLE:
+ response_type = NAN_RESPONSE_ENABLED;
+ break;
+ case NAN_SUBCMD_DISABLE:
+ response_type = NAN_RESPONSE_DISABLED;
+ break;
+ case NAN_SUBCMD_PUBLISH:
+ response_type = NAN_RESPONSE_PUBLISH;
+ break;
+ case NAN_SUBCMD_SUBSCRIBE:
+ response_type = NAN_RESPONSE_SUBSCRIBE;
+ break;
+ case NAN_SUBCMD_PUBLISH_CANCEL:
+ response_type = NAN_RESPONSE_PUBLISH_CANCEL;
+ break;
+ case NAN_SUBCMD_SUBSCRIBE_CANCEL:
+ response_type = NAN_RESPONSE_SUBSCRIBE_CANCEL;
+ break;
+ case NAN_SUBCMD_TRANSMIT_FOLLOWUP:
+ response_type = NAN_RESPONSE_TRANSMIT_FOLLOWUP;
+ break;
+ case NAN_SUBCMD_CONFIG:
+ response_type = NAN_RESPONSE_CONFIG;
+ break;
+ case NAN_SUBCMD_TCA:
+ response_type = NAN_RESPONSE_TCA;
+ break;
+ case NAN_SUBCMD_STATS:
+ response_type = NAN_RESPONSE_STATS;
+ break;
+ case NAN_SUBCMD_DATA_PATH_IFACE_CREATE:
+ response_type = NAN_DP_INTERFACE_CREATE;
+ break;
+ case NAN_SUBCMD_DATA_PATH_IFACE_DELETE:
+ response_type = NAN_DP_INTERFACE_DELETE;
+ break;
+ case NAN_SUBCMD_DATA_PATH_REQUEST:
+ response_type = NAN_DP_INITIATOR_RESPONSE;
+ break;
+ case NAN_SUBCMD_DATA_PATH_RESPONSE:
+ response_type = NAN_DP_RESPONDER_RESPONSE;
+ break;
+ case NAN_SUBCMD_DATA_PATH_END:
+ response_type = NAN_DP_END;
+ break;
+ case NAN_SUBCMD_GET_CAPABILITIES:
+ response_type = NAN_GET_CAPABILITIES;
+ break;
+ default:
+ /* unknown response for a command */
+ response_type = NAN_RESPONSE_ERROR;
+ break;
+ }
+
+ return response_type;
+}
+
+static int get_svc_hash(unsigned char *svc_name,
+ u16 svc_name_len, u8 *svc_hash, u16 svc_hash_len)
+{
+ SHA256_CTX sha_ctx;
+ u8 sha_hash[SHA256_DIGEST_LENGTH];
+ unsigned char *p;
+ int len = svc_name_len;
+
+ if (!svc_name || !svc_hash) {
+ ALOGE("Bad arguments!!\n");
+ return WIFI_ERROR_UNKNOWN;
+ }
+
+ if (svc_hash_len < NAN_SVC_HASH_SIZE) {
+ ALOGE("Bad len!!\n");
+ return WIFI_ERROR_UNKNOWN;
+ }
+ for (p = svc_name; *p; p++)
+ {
+ *p = tolower((int)*p);
+ }
+ SHA256_Init(&sha_ctx);
+ SHA256_Update(&sha_ctx, svc_name, len);
+ SHA256_Final(sha_hash, &sha_ctx);
+
+ memcpy(svc_hash, sha_hash, NAN_SVC_HASH_SIZE);
+ ALOGI("svc_name: %s\n", svc_name);
+ prhex("svc_hash:", svc_hash, NAN_SVC_HASH_SIZE);
+
+ return WIFI_SUCCESS;
+}
+
+static int dump_NanEnableRequest(NanEnableRequest* msg)
+{
+ ALOGI("%s: Dump NanEnableRequest msg:\n", __func__);
+
+ if (msg == NULL) {
+ ALOGE("Invalid msg\n");
+ return WIFI_ERROR_UNKNOWN;
+ }
+
+ ALOGI("master_pref=%u\n", msg->master_pref);
+ ALOGI("cluster_low=%u\n", msg->cluster_low);
+ ALOGI("cluster_high=%u\n", msg->cluster_high);
+ ALOGI("config_support_5g=%u\n", msg->config_support_5g);
+ ALOGI("support_5g_val=%u\n", msg->support_5g_val);
+ ALOGI("config_sid_beacon=%u\n", msg->config_sid_beacon);
+ ALOGI("sid beacon=%u\n", msg->sid_beacon_val);
+ ALOGI("config_sub_sid_beacon=%u\n", msg->config_subscribe_sid_beacon);
+ ALOGI("sub sid beacon=%u\n", msg->subscribe_sid_beacon_val);
+ ALOGI("config_2dot4g_rssi_close=%u\n", msg->config_2dot4g_rssi_close);
+ ALOGI("rssi_close_2dot4g_val=%u\n", msg->rssi_close_2dot4g_val);
+ ALOGI("config_2dot4g_rssi_middle=%u\n", msg->config_2dot4g_rssi_middle);
+ ALOGI("rssi_middle_2dot4g_val=%u\n", msg->rssi_middle_2dot4g_val);
+ ALOGI("config_2dot4g_rssi_proximity=%u\n", msg->config_2dot4g_rssi_proximity);
+ ALOGI("rssi_proximity_2dot4g_val=%u\n", msg->rssi_proximity_2dot4g_val);
+ ALOGI("config_hop_count_limit=%u\n", msg->config_hop_count_limit);
+ ALOGI("hop_count_limit_val=%u\n", msg->hop_count_limit_val);
+ ALOGI("config_2dot4g_support=%u\n", msg->config_2dot4g_support);
+ ALOGI("support_2dot4g_val=%u\n", msg->support_2dot4g_val);
+ ALOGI("config_2dot4g_beacons=%u\n", msg->config_2dot4g_beacons);
+ ALOGI("beacon_2dot4g_val=%u\n", msg->beacon_2dot4g_val);
+ ALOGI("config_2dot4g_sdf=%u\n", msg->config_2dot4g_sdf);
+ ALOGI("sdf_2dot4g_val=%u\n", msg->sdf_2dot4g_val);
+ ALOGI("config_5g_beacons=%u\n", msg->config_5g_beacons);
+ ALOGI("beacon_5g_val=%u\n", msg->beacon_5g_val);
+ ALOGI("config_5g_sdf=%u\n", msg->config_5g_sdf);
+ ALOGI("config_5g_rssi_close=%u\n", msg->config_5g_rssi_close);
+ ALOGI("rssi_close_5g_val=%u\n", msg->rssi_close_5g_val);
+ ALOGI("config_5g_rssi_middle=%u\n", msg->config_5g_rssi_middle);
+ ALOGI("rssi_middle_5g_val=%u\n", msg->rssi_middle_5g_val);
+ ALOGI("config_5g_rssi_close_proximity=%u\n", msg->config_5g_rssi_close_proximity);
+ ALOGI("rssi_close_proximity_5g_val=%u\n", msg->rssi_close_proximity_5g_val);
+ ALOGI("config_rssi_window_size=%u\n", msg->config_rssi_window_size);
+ ALOGI("rssi_window_size_val=%u\n", msg->rssi_window_size_val);
+ ALOGI("config_oui=%u\n", msg->config_oui);
+ ALOGI("oui_val=%u\n", msg->oui_val);
+ ALOGI("config_intf_addr=%u\n", msg->config_intf_addr);
+ ALOGI("intf_addr_val=" MACSTR "\n", MAC2STR(msg->intf_addr_val));
+ ALOGI("config_cluster_attribute_val=%u\n", msg->config_cluster_attribute_val);
+ ALOGI("config_scan_params=%u\n", msg->config_scan_params);
+ if (msg->config_scan_params) {
+ ALOGI("dwell_time=%u\n", msg->scan_params_val.dwell_time[0]);
+ ALOGI("scan_period=%u\n", msg->scan_params_val.scan_period[0]);
+ }
+ ALOGI("config_random_factor_force=%u\n", msg->config_random_factor_force);
+ ALOGI("random_factor_force_val=%u\n", msg->random_factor_force_val);
+ ALOGI("config_hop_count_force=%u\n", msg->config_hop_count_force);
+ ALOGI("config_24g_channel=%u\n", msg->config_24g_channel);
+ ALOGI("channel_24g_val=%u\n", msg->channel_24g_val);
+ ALOGI("config_5g_channel=%u\n", msg->config_5g_channel);
+ ALOGI("channel_5g_val=%u\n", msg->channel_5g_val);
+ ALOGI("config_dw.config_2dot4g_dw_band=%u\n", msg->config_dw.config_2dot4g_dw_band);
+ if (msg->config_dw.config_2dot4g_dw_band) {
+ ALOGI("dw_2dot4g_interval_val=%u\n", msg->config_dw.dw_2dot4g_interval_val);
+ }
+ ALOGI("config_dw.config_5g_dw_band=%u\n", msg->config_dw.config_5g_dw_band);
+ if (msg->config_dw.config_5g_dw_band) {
+ ALOGI("dw_5g_interval_val=%u\n", msg->config_dw.dw_5g_interval_val);
+ }
+ ALOGI("discovery_indication_cfg=%u\n", msg->discovery_indication_cfg);
+ ALOGI("config_ndpe_attr=%u\n", msg->config_ndpe_attr);
+ if (msg->config_ndpe_attr) {
+ ALOGI("use_ndpe_attr=%u\n", msg->use_ndpe_attr);
+ }
+ ALOGI("config_discovery_beacon_int=%u\n", msg->config_discovery_beacon_int);
+ if (msg->config_discovery_beacon_int) {
+ ALOGI("discovery beacon interval =%u\n", msg->discovery_beacon_interval);
+ }
+ ALOGI("config_nss=%u\n", msg->config_nss);
+ if (msg->config_nss) {
+ ALOGI("nss =%u\n", msg->nss);
+ }
+ ALOGI("config_enable_ranging =%u\n", msg->config_enable_ranging);
+ if (msg->config_enable_ranging) {
+ ALOGI("enable_ranging =%u\n", msg->enable_ranging);
+ }
+ ALOGI("config_dw_early_termination =%u\n", msg->config_dw_early_termination);
+ if (msg->config_dw_early_termination) {
+ ALOGI("enable_dw_termination =%u\n", msg->enable_dw_termination);
+ }
+ ALOGI("config_disc_mac_addr_randomization=%u\n", msg->config_disc_mac_addr_randomization);
+ if (msg->config_disc_mac_addr_randomization) {
+ ALOGI("disc_mac_addr_rand_interval_sec =%u\n", msg->disc_mac_addr_rand_interval_sec);
+ }
+ ALOGI("config_enable_instant_mode =%u\n", msg->config_enable_instant_mode);
+ if (msg->config_enable_instant_mode) {
+ ALOGI("enable_instant_mode =%u\n", msg->enable_instant_mode);
+ }
+ ALOGI("config_instant_mode_channel=%u\n", msg->config_instant_mode_channel);
+ if (msg->config_instant_mode_channel) {
+ ALOGI("instant_mode_channel=%u\n", msg->instant_mode_channel);
+ }
+
+ return WIFI_SUCCESS;
+}
+
+#ifdef CONFIG_BRCM
+static int dump_NanConfigRequestRequest(NanConfigRequest* msg)
+{
+ ALOGI("%s: Dump NanConfigRequest msg:\n", __func__);
+
+ if (msg == NULL) {
+ ALOGE("Invalid msg\n");
+ return WIFI_ERROR_UNKNOWN;
+ }
+
+ ALOGI("master_pref=%u\n", msg->master_pref);
+ ALOGI("sid beacon=%u\n", msg->sid_beacon);
+ ALOGI("config_sub_sid_beacon=%u\n", msg->config_subscribe_sid_beacon);
+ ALOGI("sub sid beacon=%u\n", msg->subscribe_sid_beacon_val);
+ ALOGI("rssi_proximity=%u\n", msg->rssi_proximity);
+ ALOGI("rssi_close_proximity_5g_val=%u\n", msg->rssi_close_proximity_5g_val);
+ ALOGI("rssi_window_size_val=%u\n", msg->rssi_window_size_val);
+ ALOGI("scan_params_val.dwell_time[0]=%u\n", msg->scan_params_val.dwell_time[0]);
+ ALOGI("scan_params_val.scan_period[0]=%u\n", msg->scan_params_val.scan_period[0]);
+ ALOGI("config_scan_params=%u\n", msg->config_scan_params);
+ ALOGI("random_factor_force_val=%u\n", msg->random_factor_force_val);
+ ALOGI("hop_count_force_val=%u\n", msg->hop_count_force_val);
+ ALOGI("fam_val.numchans=%u\n", msg->fam_val.numchans);
+ ALOGI("fam_val.famchan[0].entry_control=%u\n", msg->fam_val.famchan[0].entry_control);
+ ALOGI("fam_val.famchan[0].class_val=%u\n", msg->fam_val.famchan[0].class_val);
+ ALOGI("fam_val.famchan[0].channel=%u\n", msg->fam_val.famchan[0].channel);
+ ALOGI("fam_val.famchan[0].mapid=%u\n", msg->fam_val.famchan[0].mapid);
+ ALOGI("fam_val.famchan[0].avail_interval_bitmap=%u\n", msg->fam_val.famchan[0].avail_interval_bitmap);
+ ALOGI("config_dw.config_2dot4g_dw_band=%u\n", msg->config_dw.config_2dot4g_dw_band);
+ if (msg->config_dw.config_2dot4g_dw_band) {
+ ALOGI("dw_2dot4g_interval_val=%u\n", msg->config_dw.dw_2dot4g_interval_val);
+ }
+ ALOGI("config_dw.config_5g_dw_band=%u\n", msg->config_dw.config_5g_dw_band);
+ if (msg->config_dw.config_5g_dw_band) {
+ ALOGI("dw_5g_interval_val=%u\n", msg->config_dw.dw_5g_interval_val);
+ }
+ ALOGI("discovery_indication_cfg=%u\n", msg->discovery_indication_cfg);
+ ALOGI("config_ndpe_attr=%u\n", msg->config_ndpe_attr);
+ if (msg->config_ndpe_attr) {
+ ALOGI("use_ndpe_attr=%u\n", msg->use_ndpe_attr);
+ }
+ ALOGI("config_discovery_beacon_int=%u\n", msg->config_discovery_beacon_int);
+ if (msg->config_discovery_beacon_int) {
+ ALOGI("discovery beacon interval =%u\n", msg->discovery_beacon_interval);
+ }
+ ALOGI("config_nss=%u\n", msg->config_nss);
+ if (msg->config_nss) {
+ ALOGI("nss =%u\n", msg->nss);
+ }
+ ALOGI("config_enable_ranging =%u\n", msg->config_enable_ranging);
+ if (msg->config_enable_ranging) {
+ ALOGI("enable_ranging =%u\n", msg->enable_ranging);
+ }
+ ALOGI("config_dw_early_termination =%u\n", msg->config_dw_early_termination);
+ if (msg->config_dw_early_termination) {
+ ALOGI("enable_dw_termination =%u\n", msg->enable_dw_termination);
+ }
+
+ ALOGI("config_disc_mac_addr_randomization=%u\n", msg->config_disc_mac_addr_randomization);
+ if (msg->config_disc_mac_addr_randomization) {
+ ALOGI("disc_mac_addr_rand_interval_sec =%u\n", msg->disc_mac_addr_rand_interval_sec);
+ }
+ ALOGI("config_enable_instant_mode =%u\n", msg->config_enable_instant_mode);
+ if (msg->config_enable_instant_mode) {
+ ALOGI("enable_instant_mode =%u\n", msg->enable_instant_mode);
+ }
+ ALOGI("config_instant_mode_channel=%u\n", msg->config_instant_mode_channel);
+ if (msg->config_instant_mode_channel) {
+ ALOGI("instant_mode_channel=%u\n", msg->instant_mode_channel);
+ }
+
+ return WIFI_SUCCESS;
+}
+
+static int dump_NanPublishRequest(NanPublishRequest* msg)
+{
+ ALOGI("%s: Dump NanPublishRequest msg:\n", __func__);
+ if (msg == NULL) {
+ ALOGE("Invalid msg\n");
+ return WIFI_ERROR_UNKNOWN;
+ }
+ ALOGI("publish_id=%u\n", msg->publish_id);
+ ALOGI("ttl=%u\n", msg->ttl);
+ ALOGI("period=%u\n", msg->period);
+ ALOGI("publish_type=%u\n", msg->publish_type);
+ ALOGI("tx_type=%u\n", msg->tx_type);
+ ALOGI("publish_count=%u\n", msg->publish_count);
+ ALOGI("publish_match_indicator=%u\n", msg->publish_match_indicator);
+ ALOGI("service_responder_policy=%u\n", msg->service_responder_policy);
+ ALOGI("service_name_len=%u\n", msg->service_name_len);
+ if (msg->service_name_len) {
+ ALOGI("service_name=%s\n", msg->service_name);
+ }
+ ALOGI("service_specific_info_len=%u\n", msg->service_specific_info_len);
+ if (msg->service_specific_info_len) {
+ ALOGI("service_specific_info=%s\n", msg->service_specific_info);
+ }
+ ALOGI("rx_match_filter_len=%u\n", msg->rx_match_filter_len);
+ if (msg->rx_match_filter_len) {
+ prhex("rx_match_filter", msg->rx_match_filter, msg->rx_match_filter_len);
+ }
+ ALOGI("tx_match_filter_len=%u\n", msg->tx_match_filter_len);
+ if (msg->tx_match_filter_len) {
+ prhex("tx_match_filter", msg->tx_match_filter, msg->tx_match_filter_len);
+ }
+ ALOGI("rssi_threshold_flag=%u\n", msg->rssi_threshold_flag);
+ ALOGI("connmap=%u\n", msg->connmap);
+ ALOGI("recv_indication_cfg=%u\n", msg->recv_indication_cfg);
+ ALOGI("cipher_type=%u\n", msg->cipher_type);
+ ALOGI("key_info: key_type =%u\n", msg->key_info.key_type);
+ ALOGI("key_info: pmk info=%s\n", msg->key_info.body.pmk_info.pmk);
+ ALOGI("key_info: passphrase_info=%s\n", msg->key_info.body.passphrase_info.passphrase);
+ ALOGI("scid_len=%u\n", msg->scid_len);
+ if (msg->scid_len) {
+ ALOGI("scid=%s\n", msg->scid);
+ }
+ ALOGI("NanSdeaCtrlParams NdpType=%u\n", msg->sdea_params.ndp_type);
+ ALOGI("NanSdeaCtrlParams security_cfg=%u\n", msg->sdea_params.security_cfg);
+ ALOGI("NanSdeaCtrlParams ranging_state=%u\n", msg->sdea_params.ranging_state);
+ ALOGI("NanSdeaCtrlParams range_report=%u\n", msg->sdea_params.range_report);
+ ALOGI("NanRangingCfg ranging_interval_msec=%u\n", msg->ranging_cfg.ranging_interval_msec);
+ ALOGI("NanRangingCfg config_ranging_indications=%u\n", msg->ranging_cfg.config_ranging_indications);
+ ALOGI("NanRangingCfg distance_ingress_mm=%u\n", msg->ranging_cfg.distance_ingress_mm);
+ ALOGI("NanRangingCfg distance_egress_mm=%u\n", msg->ranging_cfg.distance_egress_mm);
+ ALOGI("NanRangingAutoResponse = %u\n", msg->ranging_auto_response);
+ ALOGI("range_response_cfg=%u\n", msg->range_response_cfg.ranging_response);
+
+ ALOGI("sdea_service_specific_info_len=%u\n", msg->sdea_service_specific_info_len);
+ if (msg->sdea_service_specific_info_len) {
+ ALOGI("sdea_service_specific_info=%s\n", msg->sdea_service_specific_info);
+ }
+
+ return WIFI_SUCCESS;
+}
+
+static int dump_NanSubscribeRequest(NanSubscribeRequest* msg)
+{
+ ALOGI("%s: Dump NanSubscribeRequest msg:\n", __func__);
+ u8 i = 0;
+ if (msg == NULL) {
+ ALOGE("Invalid msg\n");
+ return WIFI_ERROR_UNKNOWN;
+ }
+ ALOGI("subscribe_id=%u\n", msg->subscribe_id);
+ ALOGI("ttl=%u\n", msg->ttl);
+ ALOGI("period=%u\n", msg->period);
+ ALOGI("subscribe_type=%u\n", msg->subscribe_type);
+ ALOGI("serviceResponseFilter=%u\n", msg->serviceResponseFilter);
+ ALOGI("serviceResponseInclude=%u\n", msg->serviceResponseInclude);
+ ALOGI("useServiceResponseFilter=%u\n", msg->useServiceResponseFilter);
+ ALOGI("ssiRequiredForMatchIndication=%u\n", msg->ssiRequiredForMatchIndication);
+ ALOGI("subscribe_count=%u\n", msg->subscribe_count);
+ ALOGI("subscribe_match_indicator=%u\n", msg->subscribe_match_indicator);
+ ALOGI("service_name_len=%u\n", msg->service_name_len);
+ if (msg->service_name_len)
+ ALOGI("service_name=%s\n", msg->service_name);
+ ALOGI("service_specific_info_len=%u\n", msg->service_specific_info_len);
+ if (msg->service_specific_info_len)
+ ALOGI("service_specific_info=%s\n", msg->service_specific_info);
+ ALOGI("rx_match_filter_len=%u\n", msg->rx_match_filter_len);
+ if (msg->rx_match_filter_len)
+ prhex("rx_match_filter", msg->rx_match_filter, msg->rx_match_filter_len);
+ ALOGI("tx_match_filter_len=%u\n", msg->tx_match_filter_len);
+ if (msg->tx_match_filter_len)
+ prhex("tx_match_filter", msg->tx_match_filter, msg->tx_match_filter_len);
+ ALOGI("rssi_threshold_flag=%u\n", msg->rssi_threshold_flag);
+ ALOGI("connmap=%u\n", msg->connmap);
+ ALOGI("num_intf_addr_present=%u\n", msg->num_intf_addr_present);
+ if (msg->num_intf_addr_present) {
+ for (i = 0; i < NAN_MAX_SUBSCRIBE_MAX_ADDRESS; i++) {
+ ALOGI("peer_disc_mac_addr=" MACSTR "\n", MAC2STR(msg->intf_addr[i]));
+ }
+ }
+ ALOGI("recv_indication_cfg=%u\n", msg->recv_indication_cfg);
+ ALOGI("cipher_type=%u\n", msg->cipher_type);
+ ALOGI("key_info: key_type =%u\n", msg->key_info.key_type);
+ ALOGI("key_info: pmk info=%s\n", msg->key_info.body.pmk_info.pmk);
+ ALOGI("key_info: passphrase_info=%s\n", msg->key_info.body.passphrase_info.passphrase);
+ ALOGI("scid_len=%u\n", msg->scid_len);
+ if (msg->scid_len) {
+ ALOGI("scid=%s\n", msg->scid);
+ }
+ ALOGI("NanSdeaCtrlParams NdpType=%u\n", msg->sdea_params.ndp_type);
+ ALOGI("NanSdeaCtrlParams security_cfg=%u\n", msg->sdea_params.security_cfg);
+ ALOGI("NanSdeaCtrlParams ranging_state=%u\n", msg->sdea_params.ranging_state);
+ ALOGI("NanSdeaCtrlParams range_report=%u\n", msg->sdea_params.range_report);
+ ALOGI("NanRangingCfg ranging_interval_msec=%u\n", msg->ranging_cfg.ranging_interval_msec);
+ ALOGI("NanRangingCfg config_ranging_indications=%u\n", msg->ranging_cfg.config_ranging_indications);
+ ALOGI("NanRangingCfg distance_ingress_mm=%u\n", msg->ranging_cfg.distance_ingress_mm);
+ ALOGI("NanRangingCfg distance_egress_mm=%u\n", msg->ranging_cfg.distance_egress_mm);
+ ALOGI("NanRangingAutoResponse = %u\n", msg->ranging_auto_response);
+ ALOGI("range_response = %u\n", msg->range_response_cfg.ranging_response);
+
+ ALOGI("sdea_service_specific_info_len=%u\n", msg->sdea_service_specific_info_len);
+ if (msg->sdea_service_specific_info_len)
+ ALOGI("sdea_service_specific_info=%s\n", msg->sdea_service_specific_info);
+
+ return WIFI_SUCCESS;
+}
+
+static int dump_NanTransmitFollowupRequest(NanTransmitFollowupRequest* msg)
+{
+ ALOGI("%s: Dump NanTransmitFollowupRequest msg:\n", __func__);
+ if (msg == NULL) {
+ ALOGE("Invalid msg\n");
+ return WIFI_ERROR_UNKNOWN;
+ }
+ ALOGI("publish_subscribe_id=%u\n", msg->publish_subscribe_id);
+ ALOGI("requestor_instance_id=%u\n", msg->requestor_instance_id);
+ ALOGI("addr=" MACSTR "\n", MAC2STR(msg->addr));
+ ALOGI("priority=%u\n", msg->priority);
+ ALOGI("dw_or_faw=%u\n", msg->dw_or_faw);
+ ALOGI("service_specific_info_len=%u\n", msg->service_specific_info_len);
+ if (msg->service_specific_info_len)
+ ALOGI("service_specific_info=%s\n", msg->service_specific_info);
+ ALOGI("recv_indication_cfg=%u\n", msg->recv_indication_cfg);
+ ALOGI("sdea_service_specific_info_len=%u\n", msg->sdea_service_specific_info_len);
+ if (msg->sdea_service_specific_info_len)
+ ALOGI("sdea_service_specific_info=%s\n", msg->sdea_service_specific_info);
+
+ return WIFI_SUCCESS;
+}
+
+static int dump_NanDataPathInitiatorRequest(NanDataPathInitiatorRequest* msg)
+{
+ ALOGI("%s: Dump NanDataPathInitiatorRequest msg:\n", __func__);
+
+ if (msg == NULL) {
+ ALOGE("Invalid msg\n");
+ return WIFI_ERROR_UNKNOWN;
+ }
+
+ ALOGI("requestor_instance_id=%d\n", msg->requestor_instance_id);
+ ALOGI("channel_request_type=%d\n", msg->channel_request_type);
+ ALOGI("channel=%u\n", msg->channel);
+ ALOGI("peer_disc_mac_addr=" MACSTR "\n", MAC2STR(msg->peer_disc_mac_addr));
+ ALOGI("ndp_iface=%s\n", msg->ndp_iface);
+ ALOGI("ndp_cfg: security_cfg =%u\n", msg->ndp_cfg.security_cfg);
+ ALOGI("ndp_cfg: qos_cfg=%u\n", msg->ndp_cfg.qos_cfg);
+ ALOGI("dp app info len=%u\n", msg->app_info.ndp_app_info_len);
+ if (msg->app_info.ndp_app_info_len) {
+ prhex("dp app info=: ", (u8*)msg->app_info.ndp_app_info,
+ msg->app_info.ndp_app_info_len);
+ }
+ ALOGI("cipher_type=%u\n", msg->cipher_type);
+ ALOGI("key_info: key_type =%u\n", msg->key_info.key_type);
+ ALOGI("key_info: pmk info=%s\n", msg->key_info.body.pmk_info.pmk);
+ ALOGI("key_info: passphrase_info=%s\n", msg->key_info.body.passphrase_info.passphrase);
+ ALOGI("scid_len=%u\n", msg->scid_len);
+ if (msg->scid_len) {
+ ALOGI("scid=%s\n", msg->scid);
+ }
+ if (msg->service_name_len) {
+ ALOGI("service_name=%s\n", msg->service_name);
+ }
+ return WIFI_SUCCESS;
+}
+
+static int dump_NanDataPathIndicationResponse(NanDataPathIndicationResponse* msg)
+{
+ ALOGI("%s: Dump NanDataPathIndicationResponse msg:\n", __func__);
+
+ if (msg == NULL) {
+ ALOGE("Invalid msg\n");
+ return WIFI_ERROR_UNKNOWN;
+ }
+
+ ALOGI("ndp_instance_id=%d\n", msg->ndp_instance_id);
+ ALOGI("ndp_iface=%s\n", msg->ndp_iface);
+ ALOGI("ndp_cfg: security_cfg =%u\n", msg->ndp_cfg.security_cfg);
+ ALOGI("response code =%u\n", msg->rsp_code);
+ ALOGI("ndp_cfg: qos_cfg=%u\n", msg->ndp_cfg.qos_cfg);
+ ALOGI("dp app info len=%u\n", msg->app_info.ndp_app_info_len);
+ if (msg->app_info.ndp_app_info_len) {
+ prhex("dp app info=: ", (u8*)msg->app_info.ndp_app_info,
+ msg->app_info.ndp_app_info_len);
+ }
+ ALOGI("cipher_type=%u\n", msg->cipher_type);
+ ALOGI("key_info: key_type =%u\n", msg->key_info.key_type);
+ ALOGI("key_info: pmk info=%s\n", msg->key_info.body.pmk_info.pmk);
+ ALOGI("key_info: passphrase_info=%s\n", msg->key_info.body.passphrase_info.passphrase);
+ ALOGI("service_name_len=%u\n", msg->service_name_len);
+ ALOGI("scid_len=%u\n", msg->scid_len);
+ if (msg->scid_len) {
+ ALOGI("scid=%s\n", msg->scid);
+ }
+ if (msg->service_name_len) {
+ ALOGI("service_name=%s\n", msg->service_name);
+ }
+ return WIFI_SUCCESS;
+}
+#endif /* CONFIG_BRCM */
+
+void nan_reset_dbg_counters()
+{
+ memset(&counters, 0, sizeof(counters));
+}
+
+///////////////////////////////////////////////////////////////////////////////
+wifi_error nan_enable_request(transaction_id id,
+ wifi_interface_handle iface, NanEnableRequest* msg)
+{
+ wifi_error ret = WIFI_SUCCESS;
+ wifi_handle handle = getWifiHandle(iface);
+ NanRequestType cmdType = NAN_REQUEST_ENABLE;
+
+ ALOGI("Enabling Nan, Handle = %p\n", handle);
+
+#ifdef CONFIG_BRCM
+ // check up nan enable params from Nan manager level
+ dump_NanEnableRequest(msg);
+#endif /* CONFIG_BRCM */
+ nan_reset_dbg_counters();
+ /* XXX: WAR posting async enable response */
+ //NanMacControl *cmd = new NanMacControl(iface, id, (void *)msg, cmdType);
+ NanMacControl *cmd = (NanMacControl*)(info.nan_mac_control);
+ NULL_CHECK_RETURN(cmd, "memory allocation failure", WIFI_ERROR_OUT_OF_MEMORY);
+ cmd->setType(cmdType);
+ cmd->setId(id);
+ cmd->setMsg((void *)msg);
+ ret = (wifi_error)cmd->start();
+ if (ret != WIFI_SUCCESS) {
+ ALOGE("%s : failed in start, error = %d\n", __func__, ret);
+ }
+ //cmd->releaseRef();
+ return ret;
+}
+
+void nan_dump_dbg_counters()
+{
+ ALOGI("Num Data Path Requests %d\n", counters.dp_req);
+ ALOGI("Num Data Path Responses %d\n", counters.dp_resp);
+ ALOGI("Num Data Path Confirms %d\n", counters.dp_confirm_evt);
+ ALOGI("Num Data Path Request Events %d\n", counters.dp_req_evt);
+ ALOGI("Num Transmit Requests %d\n", counters.transmit_req);
+ ALOGI("Num Followup Transmits Recvd %d\n", counters.transmit_recv);
+ ALOGI("Num Transmit Success %d\n", counters.transmit_txs);
+}
+
+wifi_error nan_disable_request(transaction_id id,
+ wifi_interface_handle iface)
+{
+ wifi_handle handle = getWifiHandle(iface);
+ NanRequestType cmdType = NAN_REQUEST_DISABLE;
+ wifi_error ret = WIFI_SUCCESS;
+
+ ALOGI("Disabling Nan, Handle = %p\n", handle);
+ NanMacControl *cmd = new NanMacControl(iface, id, NULL, cmdType);
+ NanMacControl *mac_prim = (NanMacControl*)(info.nan_mac_control);
+
+ if (id != NAN_MAC_INVALID_TRANSID) {
+ ALOGE("Disable NAN MAC transId= %d\n", id);
+ mac_prim->setId(id);
+ } else {
+ ALOGE("Invalid transId= %d cur= %d\n", id, mac_prim->getId());
+ }
+
+ NULL_CHECK_RETURN(cmd, "memory allocation failure", WIFI_ERROR_OUT_OF_MEMORY);
+
+ nan_dump_dbg_counters();
+
+ ret = (wifi_error)cmd->cancel();
+ if (ret != WIFI_SUCCESS) {
+ ALOGE("cancel failed, error = %d\n", ret);
+ } else {
+ ALOGE("Deinitializing Nan Mac Control = %p\n", cmd);
+ }
+ cmd->releaseRef();
+ return ret;
+}
+
+wifi_error nan_publish_request(transaction_id id,
+ wifi_interface_handle iface, NanPublishRequest* msg)
+{
+ wifi_error ret = WIFI_SUCCESS;
+ wifi_handle handle = getWifiHandle(iface);
+
+ ALOGI("Publish Nan, halHandle = %p\n", handle);
+#ifdef CONFIG_BRCM
+ dump_NanPublishRequest(msg);
+#endif /* CONFIG_BRCM */
+
+ NanRequestType cmdType = NAN_REQUEST_PUBLISH;
+ NanDiscEnginePrimitive *cmd = new NanDiscEnginePrimitive(iface, id, (void *)msg, cmdType);
+ NULL_CHECK_RETURN(cmd, "memory allocation failure", WIFI_ERROR_OUT_OF_MEMORY);
+ ret = (wifi_error)cmd->start();
+ if (ret != WIFI_SUCCESS) {
+ ALOGE("%s : failed in start, error = %d\n", __func__, ret);
+ }
+ cmd->releaseRef();
+ return ret;
+}
+
+/* Function to send NAN request to the wifi driver */
+wifi_error nan_publish_cancel_request(transaction_id id,
+ wifi_interface_handle iface, NanPublishCancelRequest* msg)
+{
+ wifi_error ret = WIFI_SUCCESS;
+ NanDiscEnginePrimitive *cmd;
+ NanRequestType cmdType = NAN_REQUEST_PUBLISH_CANCEL;
+
+ ALOGE("Cancellling publish request %d\n", msg->publish_id);
+ cmd = new NanDiscEnginePrimitive(iface, id, (void *)msg, cmdType);
+ cmd->setInstId(msg->publish_id);
+ cmd->setType(cmdType);
+ NULL_CHECK_RETURN(cmd, "memory allocation failure", WIFI_ERROR_OUT_OF_MEMORY);
+
+ ret = (wifi_error)cmd->start();
+ if (ret != WIFI_SUCCESS) {
+ ALOGE("%s : failed in start, error = %d\n", __func__, ret);
+ }
+ cmd->releaseRef();
+ return ret;
+}
+
+/* Function to send NAN request to the wifi driver */
+wifi_error nan_subscribe_request(transaction_id id,
+ wifi_interface_handle iface, NanSubscribeRequest* msg)
+{
+ wifi_error ret = WIFI_SUCCESS;
+ wifi_handle handle = getWifiHandle(iface);
+ ALOGI("Subscribe Nan, halHandle = %p handle[%d]\n", handle, msg->subscribe_id);
+ NanDiscEnginePrimitive *cmd;
+#ifdef CONFIG_BRCM
+ dump_NanSubscribeRequest(msg);
+#endif /* CONFIG_BRCM */
+
+ NanRequestType cmdType = NAN_REQUEST_SUBSCRIBE;
+ cmd = new NanDiscEnginePrimitive(iface, id, (void *)msg, cmdType);
+ NULL_CHECK_RETURN(cmd, "memory allocation failure", WIFI_ERROR_OUT_OF_MEMORY);
+ ret = (wifi_error)cmd->start();
+ if (ret != WIFI_SUCCESS) {
+ ALOGE("%s : failed in start, error = %d\n", __func__, ret);
+ }
+ cmd->releaseRef();
+ return ret;
+
+}
+
+/* Function to send NAN request to the wifi driver.*/
+wifi_error nan_subscribe_cancel_request(transaction_id id,
+ wifi_interface_handle iface, NanSubscribeCancelRequest* msg)
+{
+ wifi_error ret = WIFI_SUCCESS;
+ NanDiscEnginePrimitive *cmd;
+ NanRequestType cmdType = NAN_REQUEST_SUBSCRIBE_CANCEL;
+
+ ALOGE("creating new instance + %d\n", msg->subscribe_id);
+ cmd = new NanDiscEnginePrimitive(iface, id, (void *)msg, cmdType);
+ cmd->setInstId(msg->subscribe_id);
+ cmd->setType(cmdType);
+ ret = (wifi_error)cmd->start();
+ if (ret != WIFI_SUCCESS) {
+ ALOGE("%s : failed in start, error = %d\n", __func__, ret);
+ }
+ cmd->releaseRef();
+
+ return ret;
+}
+
+/* Function to send nan transmit followup Request to the wifi driver.*/
+wifi_error nan_transmit_followup_request(transaction_id id,
+ wifi_interface_handle iface, NanTransmitFollowupRequest* msg)
+{
+ NanDiscEnginePrimitive *cmd = NULL;
+ NanRequestType cmdType = NAN_REQUEST_TRANSMIT_FOLLOWUP;
+ wifi_error ret = WIFI_SUCCESS;
+
+#ifdef CONFIG_BRCM
+ dump_NanTransmitFollowupRequest(msg);
+#endif /* CONFIG_BRCM */
+ counters.transmit_req++;
+ cmd = new NanDiscEnginePrimitive(iface, id, (void *)msg, cmdType);
+ NULL_CHECK_RETURN(cmd, "memory allocation failure", WIFI_ERROR_OUT_OF_MEMORY);
+ cmd->setTransactionId(id);
+
+ ret = (wifi_error)cmd->start();
+ if (ret != WIFI_SUCCESS) {
+ ALOGE("%s : failed in start, error = %d\n", __func__, ret);
+ }
+ cmd->releaseRef();
+ return ret;
+}
+
+/* Function to send NAN statistics request to the wifi driver */
+wifi_error nan_stats_request(transaction_id id,
+ wifi_interface_handle iface, NanStatsRequest* msg)
+{
+ wifi_handle handle = getWifiHandle(iface);
+
+ ALOGI("Nan Stats, halHandle = %p", handle);
+
+#ifdef NOT_SUPPORTED
+ NanRequestType cmdType = NAN_REQUEST_STATS;
+ wifi_error ret = WIFI_SUCCESS;
+ NanCommand *cmd = new NanCommand(iface, id, (void *)msg, cmdType);
+ NULL_CHECK_RETURN(cmd, "memory allocation failure", WIFI_ERROR_OUT_OF_MEMORY);
+ ret = (wifi_error)cmd->start();
+ if (ret != WIFI_SUCCESS) {
+ ALOGE("%s : failed in start, error = %d\n", __func__, ret);
+ }
+ cmd->releaseRef();
+ return ret;
+#else
+ return WIFI_ERROR_NOT_SUPPORTED;
+#endif
+}
+
+/* Function to send NAN configuration request to the wifi driver */
+wifi_error nan_config_request(transaction_id id,
+ wifi_interface_handle iface, NanConfigRequest* msg)
+{
+ wifi_error ret = WIFI_SUCCESS;
+ wifi_handle handle = getWifiHandle(iface);
+ NanRequestType cmdType = NAN_REQUEST_CONFIG;
+
+ ALOGI("Configuring Nan, halHandle = %p\n", handle);
+
+#ifdef CONFIG_BRCM
+ /* check up nan config params from Nan manager level */
+ dump_NanConfigRequestRequest(msg);
+#endif /* CONFIG_BRCM */
+
+ NanMacControl *cmd = new NanMacControl(iface, id, (void *)msg, cmdType);
+ NULL_CHECK_RETURN(cmd, "memory allocation failure", WIFI_ERROR_OUT_OF_MEMORY);
+
+ cmd->setType(cmdType);
+ ret = (wifi_error)cmd->start();
+ if (ret != WIFI_SUCCESS) {
+ ALOGE("start failed, error = %d\n", ret);
+ } else {
+ ALOGE("Initializing Nan Mac Control = %p\n", cmd);
+ }
+ cmd->releaseRef();
+ return ret;
+}
+
+/* Function to send NAN request to the wifi driver */
+wifi_error nan_tca_request(transaction_id id,
+ wifi_interface_handle iface, NanTCARequest* msg)
+{
+ wifi_handle handle = getWifiHandle(iface);
+
+ ALOGI("Nan TCA, halHandle = %p", handle);
+
+#ifdef NOT_SUPPORTED
+ NanRequestType cmdType = NAN_REQUEST_TCA;
+ wifi_error ret = WIFI_SUCCESS;
+ NanCommand *cmd = new NanCommand(iface, id, (void *)msg, cmdType);
+ NULL_CHECK_RETURN(cmd, "memory allocation failure", WIFI_ERROR_OUT_OF_MEMORY);
+
+ ret = (wifi_error)cmd->start();
+ if (ret != WIFI_SUCCESS) {
+ ALOGE("%s : failed in start, error = %d\n", __func__, ret);
+ }
+ cmd->releaseRef();
+ return ret;
+#else
+ return WIFI_ERROR_NOT_SUPPORTED;
+#endif
+}
+
+wifi_error nan_beacon_sdf_payload_request(transaction_id id,
+ wifi_interface_handle iface, NanBeaconSdfPayloadRequest* msg)
+{
+ ALOGI("Nan Beacon Sdf Payload Request");
+ return WIFI_ERROR_NOT_SUPPORTED;
+}
+
+wifi_error nan_get_capabilities(transaction_id id, wifi_interface_handle iface)
+{
+ wifi_error ret = WIFI_SUCCESS;
+ wifi_handle handle = getWifiHandle(iface);
+ ALOGI("Get Nan Capabilities, id=%d, halHandle=%p\n", id, handle);
+
+ NanRequestType cmdType = NAN_REQUEST_GET_CAPABILITIES;
+ NanDiscEnginePrimitive *cmd = new NanDiscEnginePrimitive(iface, id, NULL, cmdType);
+ NULL_CHECK_RETURN(cmd, "memory allocation failure", WIFI_ERROR_OUT_OF_MEMORY);
+
+ ret = (wifi_error)cmd->start();
+ if (ret != WIFI_SUCCESS) {
+ ALOGE("%s : failed in start, error = %d\n", __func__, ret);
+ }
+ cmd->releaseRef();
+ return ret;
+}
+wifi_error nan_check_dhd_hal_version(wifi_interface_handle iface,
+ wifi_handle handle)
+{
+ NanRequestType cmdType = NAN_VERSION_INFO;
+ NanMacControl *cmd = new NanMacControl(iface, 0, NULL, cmdType);
+ wifi_error ret = WIFI_SUCCESS;
+ u32 version;
+
+ NULL_CHECK_RETURN(cmd, "memory allocation failure", WIFI_ERROR_OUT_OF_MEMORY);
+
+ cmd->setType(cmdType);
+
+ ret = (wifi_error)cmd->start();
+ if (ret != WIFI_SUCCESS) {
+ ALOGI("\nVersion subcmd failed ret = %x\n", ret);
+ ret = WIFI_ERROR_NOT_SUPPORTED;
+ goto done;
+ }
+ version = cmd->getVersion();
+ /* check if version handled..can support multiple versions */
+ if (version == NAN_HAL_VERSION_1) {
+ ALOGI("\nGot the supported version %d\n", version);
+ current_dhd_hal_ver = version;
+ ret = WIFI_SUCCESS;
+ goto done;
+ } else {
+ ALOGI("\nGot the unsupported version %d\n", version);
+ ret = WIFI_ERROR_NOT_SUPPORTED;
+ goto done;
+ }
+done:
+ cmd->releaseRef();
+ return ret;
+}
+wifi_error nan_deinit_handler()
+{
+ if (info.nan_mac_control) {
+ /* register for Nan vendor events with info mac class*/
+ NanMacControl *cmd_event = (NanMacControl*)(info.nan_mac_control);
+ cmd_event->unRegisterNanVendorEvents();
+ delete (NanMacControl*)info.nan_mac_control;
+ info.nan_mac_control = NULL;
+ }
+ if (info.nan_disc_control) {
+ delete (NanDiscEnginePrimitive*)info.nan_disc_control;
+ info.nan_disc_control = NULL;
+ }
+ if (info.nan_dp_control) {
+ delete (NanDataPathPrimitive*)info.nan_dp_control;
+ info.nan_dp_control = NULL;
+ }
+ if (NAN_HANDLE(info)) {
+ delete GET_NAN_HANDLE(info);
+ NAN_HANDLE(info) = NULL;
+ }
+ ALOGI("wifi nan internal clean up done");
+ return WIFI_SUCCESS;
+}
+wifi_error nan_register_handler(wifi_interface_handle iface,
+ NanCallbackHandler handlers)
+{
+ wifi_handle handle = getWifiHandle(iface);
+ if (NAN_HANDLE(info)) {
+ /* cleanup and re-register */
+ nan_deinit_handler();
+ }
+ ALOGI("\nChecking version compat\n");
+ /* checking version compat b/w DHD and HAL */
+ if (nan_check_dhd_hal_version(iface, handle) != WIFI_SUCCESS) {
+ ALOGE("\n Get version failed..check DHD\n");
+ return WIFI_ERROR_NOT_SUPPORTED;
+ }
+ memset(&info, 0, sizeof(info));
+ NAN_HANDLE(info) = new NanHandle(handle, handlers);
+ info.nan_mac_control =
+ (void*)new NanMacControl(iface, 0, NULL, NAN_REQUEST_LAST);
+ NULL_CHECK_RETURN(info.nan_mac_control, "memory allocation failure", WIFI_ERROR_OUT_OF_MEMORY);
+ info.nan_disc_control =
+ (void*)new NanDiscEnginePrimitive(iface, 0, NULL, NAN_REQUEST_LAST);
+ NULL_CHECK_RETURN(info.nan_disc_control, "memory allocation failure", WIFI_ERROR_OUT_OF_MEMORY);
+ info.nan_dp_control =
+ (void*)new NanDataPathPrimitive(iface, 0, NULL, NAN_REQUEST_LAST);
+ NULL_CHECK_RETURN(info.nan_dp_control, "memory allocation failure", WIFI_ERROR_OUT_OF_MEMORY);
+
+ /* register for Nan vendor events with info mac class*/
+ NanMacControl *cmd_event = (NanMacControl*)(info.nan_mac_control);
+ cmd_event->registerNanVendorEvents();
+ return WIFI_SUCCESS;
+}
+
+wifi_error nan_get_version(wifi_handle handle, NanVersion* version)
+{
+ wifi_error ret = WIFI_SUCCESS;
+ if (version) {
+ *version = (NAN_MAJOR_REL_VERSION << 16 | NAN_MINOR_REL_VERSION << 8 |
+ NAN_PATCH_REL_VERSION);
+ } else {
+ ret = WIFI_ERROR_INVALID_ARGS;
+ }
+
+ return ret;
+}
+
+
+///////////////////////////////////////////////////////////////////////////////
+class NanEventCap : public WifiCommand
+{
+ public:
+ NanEventCap(wifi_interface_handle iface, int id)
+ : WifiCommand("NanCommand", iface, id)
+ {}
+
+ int start()
+ {
+ registerNanVendorEvents();
+ return WIFI_SUCCESS;
+ }
+
+ int handleResponse(WifiEvent& reply) {
+ return NL_SKIP;
+ }
+ void unRegisterNanVendorEvents()
+ {
+ int i = 0;
+ for (i = NAN_EVENT_ENABLED; i <= NAN_EVENT_DATA_END; i++) {
+ unregisterVendorHandler(GOOGLE_OUI, i);
+ }
+ unregisterVendorHandler(GOOGLE_OUI, NAN_ASYNC_RESPONSE_DISABLED);
+ unregisterVendorHandler(GOOGLE_OUI, NAN_EVENT_MATCH_EXPIRY);
+ }
+ void registerNanVendorEvents()
+ {
+ int i = 0;
+ for (i = NAN_EVENT_ENABLED; i <= NAN_EVENT_DATA_END; i++) {
+ registerVendorHandler(GOOGLE_OUI, i);
+ }
+ registerVendorHandler(GOOGLE_OUI, NAN_ASYNC_RESPONSE_DISABLED);
+ registerVendorHandler(GOOGLE_OUI, NAN_EVENT_MATCH_EXPIRY);
+ }
+
+ int handleEvent(WifiEvent& event) {
+ int cmd = event.get_vendor_subcmd();
+ u16 attr_type;
+ nlattr *vendor_data = event.get_attribute(NL80211_ATTR_VENDOR_DATA);
+
+ switch(cmd) {
+ case NAN_EVENT_DE_EVENT: {
+ u16 attr_type;
+ NanDiscEngEventInd de_event;
+ memset(&de_event, 0, sizeof(NanDiscEngEventInd));
+
+ for (nl_iterator it(vendor_data); it.has_next(); it.next()) {
+ attr_type = it.get_type();
+ if (attr_type == NAN_ATTRIBUTE_CLUSTER_ID) {
+ memcpy(&de_event.data.cluster.addr, it.get_data(), NAN_MAC_ADDR_LEN);
+ ALOGI("cluster id = " MACSTR "\n", MAC2STR(de_event.data.cluster.addr));
+ } else if (attr_type == NAN_ATTRIBUTE_ENABLE_STATUS) {
+ ALOGI("nan enable status = %u\n", it.get_u16());
+ } else if (attr_type == NAN_ATTRIBUTE_JOIN_STATUS) {
+ ALOGI("nan joined status = %u\n", it.get_u16());
+ } else if (attr_type == NAN_ATTRIBUTE_DE_EVENT_TYPE) {
+ u8 de_type = it.get_u8();
+ ALOGI("nan de event type = %u\n", de_type);
+ if (de_type == NAN_EVENT_IFACE) {
+ de_event.event_type = NAN_EVENT_ID_DISC_MAC_ADDR;
+ ALOGI("received NAN_EVENT_ID_DISC_MAC_ADDR event\n");
+ } else if (de_type == NAN_EVENT_START) {
+ de_event.event_type = NAN_EVENT_ID_STARTED_CLUSTER;
+ ALOGI("received NAN cluster started event\n");
+ } else if (de_type == NAN_EVENT_JOIN) {
+ /* To be deprecated */
+ de_event.event_type = NAN_EVENT_ID_JOINED_CLUSTER;
+ ALOGI("received join event\n");
+ } else if (de_type == NAN_EVENT_ROLE_CHANGE) {
+ ALOGI("received device role change event\n");
+ } else if (de_type == NAN_EVENT_MERGE) {
+ ALOGI("received Merge Event\n");
+ } else {
+ ALOGI("received unknown DE event, [%d]\n", de_type);
+ }
+ } else if (attr_type == NAN_ATTRIBUTE_MAC_ADDR) {
+ memcpy(&de_event.data.cluster.addr, it.get_data(), NAN_MAC_ADDR_LEN);
+ memcpy(mNmi, it.get_data(), NAN_MAC_ADDR_LEN);
+ ALOGI("Primary discovery mac address = " MACSTR "\n",
+ MAC2STR(mNmi));
+ }
+ }
+
+ GET_NAN_HANDLE(info)->mHandlers.EventDiscEngEvent(&de_event);
+ break;
+ }
+ case NAN_EVENT_DISABLED: {
+ ALOGI("Received NAN_EVENT_DISABLED\n");
+ NanDisabledInd disabled_ind;
+ memset(&disabled_ind, 0, sizeof(NanDisabledInd));
+ for (nl_iterator it(vendor_data); it.has_next(); it.next()) {
+ attr_type = it.get_type();
+ if (attr_type == NAN_ATTRIBUTE_STATUS) {
+ disabled_ind.reason = (NanStatusType)it.get_u8();
+ ALOGI("Nan Disable:status %u", disabled_ind.reason);
+ } else if (attr_type == NAN_ATTRIBUTE_REASON) {
+ u8 len = min(it.get_len(), sizeof(disabled_ind.nan_reason));
+ memcpy(disabled_ind.nan_reason, it.get_data(), len);
+ ALOGI("nan disabled reason: %s, len = %d\n",
+ disabled_ind.nan_reason, len);
+ }
+ }
+
+ GET_NAN_HANDLE(info)->mHandlers.EventDisabled(&disabled_ind);
+ unRegisterNanVendorEvents();
+ break;
+ }
+ case NAN_EVENT_PUBLISH_TERMINATED: {
+ ALOGI("Received NAN_EVENT_PUBLISH_TERMINATED\n");
+ NanPublishTerminatedInd pub_term_event;
+ memset(&pub_term_event, 0, sizeof(NanPublishTerminatedInd));
+
+ for (nl_iterator it(vendor_data); it.has_next(); it.next()) {
+ attr_type = it.get_type();
+
+ if (attr_type == NAN_ATTRIBUTE_PUBLISH_ID) {
+ pub_term_event.publish_id = it.get_u32();
+ ALOGI("pub id %u", pub_term_event.publish_id);
+ } else if (attr_type == NAN_ATTRIBUTE_STATUS) {
+ pub_term_event.reason = (NanStatusType)it.get_u8();
+ ALOGI("pub termination status %u", pub_term_event.reason);
+ } else if (attr_type == NAN_ATTRIBUTE_REASON) {
+ u8 len = min(it.get_len(), sizeof(pub_term_event.nan_reason));
+ memcpy(pub_term_event.nan_reason, it.get_data(), len);
+ ALOGI("Pub termination nan reason: %s, len = %d\n",
+ pub_term_event.nan_reason, len);
+ } else {
+ ALOGE("Unknown attr\n");
+ }
+ }
+
+ GET_NAN_HANDLE(info)->mHandlers.EventPublishTerminated(&pub_term_event);
+ break;
+ }
+ case NAN_EVENT_SUBSCRIBE_MATCH: {
+ NanMatchInd subscribe_event;
+ memset(&subscribe_event, 0, sizeof(NanMatchInd));
+ ALOGI("Received NAN_EVENT_SUBSCRIBE_MATCH\n");
+
+ /* By default FW is unable to cache this match */
+ subscribe_event.out_of_resource_flag = true;
+
+ for (nl_iterator it(vendor_data); it.has_next(); it.next()) {
+ attr_type = it.get_type();
+
+ if (attr_type == NAN_ATTRIBUTE_SUBSCRIBE_ID) {
+ ALOGI("sub id: %u", it.get_u16());
+ subscribe_event.publish_subscribe_id = it.get_u16();
+
+ } else if (attr_type == NAN_ATTRIBUTE_PUBLISH_ID) {
+ ALOGI("pub id %u", it.get_u32());
+ subscribe_event.requestor_instance_id = it.get_u32();
+
+ } else if (attr_type == NAN_ATTRIBUTE_MAC_ADDR) {
+ memcpy(subscribe_event.addr, it.get_data(), NAN_MAC_ADDR_LEN);
+ ALOGI("publisher mac: " MACSTR, MAC2STR(subscribe_event.addr));
+
+ } else if (attr_type == NAN_ATTRIBUTE_SERVICE_SPECIFIC_INFO_LEN) {
+ ALOGI("svc length: %d", it.get_u16());
+ subscribe_event.service_specific_info_len = it.get_u16();
+
+ } else if (attr_type == NAN_ATTRIBUTE_SERVICE_SPECIFIC_INFO) {
+ memcpy(subscribe_event.service_specific_info, it.get_data(),
+ subscribe_event.service_specific_info_len);
+ subscribe_event.service_specific_info
+ [subscribe_event.service_specific_info_len] = '\0';
+ ALOGI("service info: %s", subscribe_event.service_specific_info);
+
+ } else if (attr_type == NAN_ATTRIBUTE_TX_MATCH_FILTER_LEN) {
+ ALOGI("sdf match filter length: %d", subscribe_event.sdf_match_filter_len);
+ subscribe_event.sdf_match_filter_len = it.get_u16();
+
+ } else if (attr_type == NAN_ATTRIBUTE_TX_MATCH_FILTER) {
+ memcpy(subscribe_event.sdf_match_filter, it.get_data(),
+ subscribe_event.sdf_match_filter_len);
+ subscribe_event.sdf_match_filter
+ [subscribe_event.sdf_match_filter_len] = '\0';
+ ALOGI("sdf match filter: %s", subscribe_event.sdf_match_filter);
+ } else if (attr_type == NAN_ATTRIBUTE_CIPHER_SUITE_TYPE) {
+ ALOGI("Peer Cipher suite type: %u", it.get_u8());
+ subscribe_event.peer_cipher_type = it.get_u8();
+ } else if (attr_type == NAN_ATTRIBUTE_SCID_LEN) {
+ ALOGI("scid length %d", it.get_u32());
+ subscribe_event.scid_len= it.get_u32();
+ } else if (attr_type == NAN_ATTRIBUTE_SCID) {
+ memcpy(subscribe_event.scid, it.get_data(),
+ subscribe_event.scid_len);
+ subscribe_event.scid
+ [subscribe_event.scid_len] = '\0';
+ ALOGI("scid: %s", subscribe_event.scid);
+ } else if (attr_type == NAN_ATTRIBUTE_RANGING_INDICATION) {
+ subscribe_event.range_info.ranging_event_type = it.get_u32();
+ ALOGI("ranging indication %d", it.get_u32());
+ } else if (attr_type == NAN_ATTRIBUTE_RANGING_RESULT) {
+ subscribe_event.range_info.range_measurement_mm = it.get_u32();
+ ALOGI("ranging result %d", it.get_u32());
+ } else if (attr_type == NAN_ATTRIBUTE_RSSI_PROXIMITY) {
+ subscribe_event.rssi_value = it.get_u8();
+ ALOGI("rssi value : %u", it.get_u8());
+ } else if (attr_type == NAN_ATTRIBUTE_SDEA_SERVICE_SPECIFIC_INFO_LEN) {
+ ALOGI("sdea svc length %d", it.get_u16());
+ subscribe_event.sdea_service_specific_info_len = it.get_u16();
+ } else if (attr_type == NAN_ATTRIBUTE_SDEA_SERVICE_SPECIFIC_INFO) {
+ memcpy(subscribe_event.sdea_service_specific_info, it.get_data(),
+ subscribe_event.sdea_service_specific_info_len);
+ subscribe_event.sdea_service_specific_info
+ [subscribe_event.sdea_service_specific_info_len] = '\0';
+ ALOGI("sdea service info: %s", subscribe_event.sdea_service_specific_info);
+ } else if (attr_type == NAN_ATTRIBUTE_MATCH_OCCURRED_FLAG) {
+ ALOGI("match occurred flag: %u", it.get_u8());
+ subscribe_event.match_occured_flag = it.get_u8();
+ } else if (attr_type == NAN_ATTRIBUTE_OUT_OF_RESOURCE_FLAG) {
+ ALOGI("Out of resource flag: %u", it.get_u8());
+ subscribe_event.out_of_resource_flag = it.get_u8();
+ } else if (attr_type == NAN_ATTRIBUTE_SDE_CONTROL_CONFIG_DP) {
+ ALOGI("Peer config for data path needed: %u", it.get_u8());
+ subscribe_event.peer_sdea_params.config_nan_data_path = it.get_u8();
+ } else if (attr_type == NAN_ATTRIBUTE_SDE_CONTROL_DP_TYPE) {
+ ALOGI("Data Path type: %u", it.get_u8());
+ subscribe_event.peer_sdea_params.ndp_type = (NdpType)it.get_u8();
+ } else if (attr_type == NAN_ATTRIBUTE_SDE_CONTROL_SECURITY) {
+ ALOGI("Security configuration: %u", it.get_u8());
+ subscribe_event.peer_sdea_params.security_cfg =
+ (NanDataPathSecurityCfgStatus)it.get_u8();
+ } else if (attr_type == NAN_ATTRIBUTE_SDE_CONTROL_RANGE_SUPPORT) {
+ ALOGI("Ranging report state: %u", it.get_u8());
+ subscribe_event.peer_sdea_params.range_report = (NanRangeReport)it.get_u8();
+ }
+ }
+
+ GET_NAN_HANDLE(info)->mHandlers.EventMatch(&subscribe_event);
+ break;
+ }
+ case NAN_EVENT_SUBSCRIBE_UNMATCH: {
+ ALOGI("Received NAN_EVENT_SUBSCRIBE_UNMATCH\n");
+ ALOGE("%s: Not applicable yet\n", __func__);
+ break;
+ }
+ case NAN_EVENT_SUBSCRIBE_TERMINATED: {
+ NanSubscribeTerminatedInd sub_term_event;
+ memset(&sub_term_event, 0, sizeof(NanSubscribeTerminatedInd));
+ ALOGI("Received NAN_EVENT_SUBSCRIBE_TERMINATED\n");
+
+ for (nl_iterator it(vendor_data); it.has_next(); it.next()) {
+ attr_type = it.get_type();
+
+ if (attr_type == NAN_ATTRIBUTE_SUBSCRIBE_ID) {
+ sub_term_event.subscribe_id = it.get_u16();
+ ALOGI("sub id: %u", sub_term_event.subscribe_id);
+ } else if (attr_type == NAN_ATTRIBUTE_STATUS) {
+ sub_term_event.reason = (NanStatusType)it.get_u8();
+ ALOGI("sub termination status %u", sub_term_event.reason);
+ } else if (attr_type == NAN_ATTRIBUTE_REASON) {
+ u8 len = min(it.get_len(), sizeof(sub_term_event.nan_reason));
+ memcpy(sub_term_event.nan_reason, it.get_data(), len);
+ ALOGI("sub termination nan reason: %s, len = %d\n",
+ sub_term_event.nan_reason, len);
+ } else {
+ ALOGE("Unknown attr: %u\n", attr_type);
+ }
+ }
+
+ GET_NAN_HANDLE(info)->mHandlers.EventSubscribeTerminated(&sub_term_event);
+ break;
+ }
+ case NAN_EVENT_MATCH_EXPIRY:
+ HandleExpiryEvent(info, vendor_data);
+ break;
+ case NAN_EVENT_FOLLOWUP: {
+ NanFollowupInd followup_event;
+ memset(&followup_event, 0, sizeof(NanFollowupInd));
+ ALOGI("Received NAN_EVENT_FOLLOWUP\n");
+
+ for (nl_iterator it(vendor_data); it.has_next(); it.next()) {
+ attr_type = it.get_type();
+
+ if (attr_type == NAN_ATTRIBUTE_MAC_ADDR) {
+ memcpy(followup_event.addr, it.get_data(), NAN_MAC_ADDR_LEN);
+
+ } else if (attr_type == NAN_ATTRIBUTE_PEER_ID) {
+ followup_event.publish_subscribe_id = it.get_u16();
+
+ } else if (attr_type == NAN_ATTRIBUTE_INST_ID) {
+ followup_event.requestor_instance_id = it.get_u32();
+
+ } else if (attr_type == NAN_ATTRIBUTE_SERVICE_SPECIFIC_INFO_LEN) {
+ followup_event.service_specific_info_len = it.get_u16();
+
+ } else if (attr_type == NAN_ATTRIBUTE_SERVICE_SPECIFIC_INFO) {
+ memcpy(followup_event.service_specific_info, it.get_data(),
+ followup_event.service_specific_info_len);
+ followup_event.service_specific_info[followup_event.service_specific_info_len] =
+ '\0';
+ } else if (attr_type == NAN_ATTRIBUTE_SDEA_SERVICE_SPECIFIC_INFO_LEN) {
+ ALOGI("sdea svc length %d", it.get_u16());
+ followup_event.sdea_service_specific_info_len = it.get_u16();
+ } else if (attr_type == NAN_ATTRIBUTE_SDEA_SERVICE_SPECIFIC_INFO) {
+ memcpy(followup_event.sdea_service_specific_info, it.get_data(),
+ followup_event.sdea_service_specific_info_len);
+ followup_event.sdea_service_specific_info[followup_event.sdea_service_specific_info_len] = '\0';
+ ALOGI("sdea service info: %s", followup_event.sdea_service_specific_info);
+ }
+ }
+
+ GET_NAN_HANDLE(info)->mHandlers.EventFollowup(&followup_event);
+ break;
+ }
+ case NAN_EVENT_SDF: {
+ ALOGI("Received NAN_EVENT_SDF:\n");
+ NanBeaconSdfPayloadInd sdfInd;
+ memset(&sdfInd, 0, sizeof(sdfInd));
+
+ for (nl_iterator it(vendor_data); it.has_next(); it.next()) {
+ attr_type = it.get_type();
+
+ if (attr_type == NAN_ATTRIBUTE_SERVICE_SPECIFIC_INFO_LEN) {
+ sdfInd.data.frame_len = it.get_u16();
+ if (sdfInd.data.frame_len > NAN_MAX_FRAME_DATA_LEN) {
+ sdfInd.data.frame_len = NAN_MAX_FRAME_DATA_LEN;
+ }
+ ALOGI("Received NAN_ATTRIBUTE_SERVICE_SPECIFIC_INFO_LEN: 0x%x(%d)\n",
+ sdfInd.data.frame_len, sdfInd.data.frame_len);
+
+ } else if (attr_type == NAN_ATTRIBUTE_SERVICE_SPECIFIC_INFO) {
+ ALOGI("Received NAN_ATTRIBUTE_SERVICE_SPECIFIC_INFO\n");
+ memcpy(&sdfInd.data.frame_data, it.get_data(), sdfInd.data.frame_len);
+ prhex("sdfInd.data.frame_data: ", (u8*)sdfInd.data.frame_data,
+ sdfInd.data.frame_len);
+ }
+ }
+ GET_NAN_HANDLE(info)->mHandlers.EventBeaconSdfPayload(&sdfInd);
+ break;
+ }
+#ifdef NOT_YET
+ case NAN_EVENT_PUBLISH_REPLIED_IND: {
+ ALOGI("Received NAN_EVENT_PUBLISH_REPLIED_IND\n");
+ NanPublishRepliedInd pub_reply_event;
+ memset(&pub_reply_event, 0, sizeof(pub_reply_event));
+
+ for (nl_iterator it(vendor_data); it.has_next(); it.next()) {
+ attr_type = it.get_type();
+
+ if (attr_type == NAN_ATTRIBUTE_SUBSCRIBE_ID) {
+ ALOGI("sub id: %u", it.get_u32());
+ pub_reply_event.requestor_instance_id = it.get_u32();
+ } else if (attr_type == NAN_ATTRIBUTE_MAC_ADDR) {
+ memcpy(pub_reply_event.addr, it.get_data(), NAN_MAC_ADDR_LEN);
+ ALOGI("Subscriber mac: " MACSTR, MAC2STR(pub_reply_event.addr));
+ } else if (attr_type == NAN_ATTRIBUTE_RSSI_PROXIMITY) {
+ pub_reply_event.rssi_value = it.get_u8();
+ ALOGI("Received rssi value : %u", it.get_u8());
+ }
+ }
+ GET_NAN_HANDLE(info)->mHandlers.EventPublishReplied(&pub_reply_event);
+ break;
+ }
+#endif /* NOT_YET */
+ case NAN_EVENT_TCA: {
+ ALOGI("Received NAN_EVENT_TCA\n");
+ //GET_NAN_HANDLE(info)->mHandlers.EventTca(&sdfPayload);
+ break;
+ }
+ case NAN_EVENT_DATA_REQUEST: {
+ ALOGI("Received NAN_EVENT_DATA_REQUEST_INDICATION\n");
+ NanDataPathRequestInd ndp_request_event;
+ memset(&ndp_request_event, 0, sizeof(NanDataPathRequestInd));
+ u16 ndp_ind_app_info_len = 0;
+
+ for (nl_iterator it(vendor_data); it.has_next(); it.next()) {
+ attr_type = it.get_type();
+
+ if (attr_type == NAN_ATTRIBUTE_PUBLISH_ID) {
+ ALOGI("publish_id: %u\n", it.get_u32());
+ ndp_request_event.service_instance_id = it.get_u32();
+
+ } else if (attr_type == NAN_ATTRIBUTE_MAC_ADDR) {
+ memcpy(ndp_request_event.peer_disc_mac_addr,
+ it.get_data(), NAN_MAC_ADDR_LEN);
+ ALOGI("Discovery MAC addr of the peer/initiator: " MACSTR "\n",
+ MAC2STR(ndp_request_event.peer_disc_mac_addr));
+
+ } else if (attr_type == NAN_ATTRIBUTE_NDP_ID) {
+ ALOGI("ndp id: %u\n", it.get_u32());
+ ndp_request_event.ndp_instance_id = it.get_u32();
+
+ } else if (attr_type == NAN_ATTRIBUTE_SECURITY) {
+ ALOGI("security: %u\n", (NanDataPathSecurityCfgStatus) it.get_u8());
+ ndp_request_event.ndp_cfg.security_cfg =
+ (NanDataPathSecurityCfgStatus)it.get_u8();
+
+ } else if (attr_type == NAN_ATTRIBUTE_QOS) {
+ ALOGI("QoS: %u", (NanDataPathQosCfg)it.get_u8());
+ ndp_request_event.ndp_cfg.qos_cfg = (NanDataPathQosCfg)it.get_u8();
+
+ } else if (attr_type == NAN_ATTRIBUTE_SERVICE_SPECIFIC_INFO_LEN) {
+ ALOGI("service info len: %d\n", it.get_u16());
+ ndp_ind_app_info_len = it.get_u16();
+ ndp_request_event.app_info.ndp_app_info_len = ndp_ind_app_info_len;
+
+ } else if (attr_type == NAN_ATTRIBUTE_SERVICE_SPECIFIC_INFO) {
+ memcpy(ndp_request_event.app_info.ndp_app_info,
+ it.get_data(), ndp_ind_app_info_len);
+ ndp_request_event.app_info.ndp_app_info[ndp_ind_app_info_len] = '\0';
+ ALOGI("service info: %s\n", ndp_request_event.app_info.ndp_app_info);
+
+ } else if (attr_type == NAN_ATTRIBUTE_SCID_LEN) {
+ ALOGI("scid length %d\n", it.get_u32());
+ ndp_request_event.scid_len= it.get_u32();
+
+ } else if (attr_type == NAN_ATTRIBUTE_SCID) {
+ memcpy(ndp_request_event.scid, it.get_data(),
+ ndp_request_event.scid_len);
+ ndp_request_event.scid[ndp_request_event.scid_len] = '\0';
+ ALOGI("scid: %s\n", ndp_request_event.scid);
+ }
+ }
+
+ GET_NAN_HANDLE(info)->mHandlers.EventDataRequest(&ndp_request_event);
+ break;
+ }
+ case NAN_EVENT_DATA_CONFIRMATION: {
+ ALOGI("Received NAN_EVENT_DATA_CONFIRMATION\n");
+ NanDataPathConfirmInd ndp_create_confirmation_event;
+ memset(&ndp_create_confirmation_event, 0, sizeof(NanDataPathConfirmInd));
+ u16 ndp_conf_app_info_len = 0;
+
+ for (nl_iterator it(vendor_data); it.has_next(); it.next()) {
+ attr_type = it.get_type();
+
+ if (attr_type == NAN_ATTRIBUTE_NDP_ID) {
+ ALOGI("ndp id: %u", it.get_u32());
+ ndp_create_confirmation_event.ndp_instance_id = it.get_u32();
+
+ } else if (attr_type == NAN_ATTRIBUTE_PEER_NDI_MAC_ADDR) {
+ memcpy(ndp_create_confirmation_event.peer_ndi_mac_addr,
+ it.get_data(), NAN_MAC_ADDR_LEN);
+ ALOGI("NDI mac address of the peer: " MACSTR "\n",
+ MAC2STR(ndp_create_confirmation_event.peer_ndi_mac_addr));
+
+ } else if (attr_type == NAN_ATTRIBUTE_SERVICE_SPECIFIC_INFO_LEN) {
+ ALOGI("service info string len: %d\n", it.get_u16());
+ ndp_conf_app_info_len = it.get_u16();
+ ndp_create_confirmation_event.app_info.ndp_app_info_len =
+ ndp_conf_app_info_len;
+
+ } else if (attr_type == NAN_ATTRIBUTE_SERVICE_SPECIFIC_INFO) {
+ memcpy(ndp_create_confirmation_event.app_info.ndp_app_info, it.get_data(),
+ ndp_conf_app_info_len);
+ ndp_create_confirmation_event.app_info.ndp_app_info[ndp_conf_app_info_len] =
+ '\0';
+ ALOGI("service info string: %s\n",
+ ndp_create_confirmation_event.app_info.ndp_app_info);
+
+ } else if (attr_type == NAN_ATTRIBUTE_RSP_CODE) {
+ ALOGI("response code %u\n", (NanDataPathResponseCode) it.get_u8());
+ ndp_create_confirmation_event.rsp_code =
+ (NanDataPathResponseCode)it.get_u8();
+ }
+ }
+
+ GET_NAN_HANDLE(info)->mHandlers.EventDataConfirm(&ndp_create_confirmation_event);
+ break;
+ }
+ case NAN_EVENT_DATA_END: {
+ ALOGI("Received NAN_EVENT_DATA_END\n");
+ NanDataPathEndInd ndp_end_event;
+ memset(&ndp_end_event, 0, sizeof(NanDataPathEndInd));
+ u8 count = 0;
+
+ for (nl_iterator it(vendor_data); it.has_next(); it.next()) {
+ attr_type = it.get_type();
+ if (attr_type == NAN_ATTRIBUTE_INST_COUNT) {
+ ALOGI("ndp count: %u\n", it.get_u8());
+ ndp_end_event.num_ndp_instances = it.get_u8();
+ count = it.get_u8();
+ } else if (attr_type == NAN_ATTRIBUTE_NDP_ID) {
+ ALOGI("count: %u\n", count);
+ while (count) {
+ ndp_end_event.ndp_instance_id[count-1] = it.get_u32();
+ ALOGI("ndp id: %u\n", ndp_end_event.ndp_instance_id[count-1]);
+ count -= 1;
+ }
+ } else {
+ ALOGI("Unknown attr_type: %s\n", NanAttrToString(attr_type));
+ }
+ }
+
+ GET_NAN_HANDLE(info)->mHandlers.EventDataEnd(&ndp_end_event);
+ break;
+ }
+ case NAN_EVENT_TRANSMIT_FOLLOWUP_IND: {
+ ALOGI("Received NAN_EVENT_TRANSMIT_FOLLOWUP_IND\n");
+ NanTransmitFollowupInd followup_ind;
+ memset(&followup_ind, 0, sizeof(NanTransmitFollowupInd));
+
+ for (nl_iterator it(vendor_data); it.has_next(); it.next()) {
+ attr_type = it.get_type();
+ if (attr_type == NAN_ATTRIBUTE_TRANSAC_ID) {
+ followup_ind.id = it.get_u16();
+ } else if (attr_type == NAN_ATTRIBUTE_STATUS) {
+ followup_ind.reason = (NanStatusType)it.get_u8();
+ } else if (attr_type == NAN_ATTRIBUTE_REASON) {
+ u8 len = min(it.get_len(), sizeof(followup_ind.nan_reason));
+ memcpy(followup_ind.nan_reason, it.get_data(), len);
+ ALOGI("nan transmit followup ind: reason: %s, len = %d\n",
+ followup_ind.nan_reason, len);
+ }
+ }
+
+ GET_NAN_HANDLE(info)->mHandlers.EventTransmitFollowup(&followup_ind);
+ break;
+ }
+ case NAN_EVENT_UNKNOWN:
+ ALOGI("Received NAN_EVENT_UNKNOWN\n");
+ break;
+ } // end-of-switch
+ return NL_SKIP;
+ }
+};
+
+/* To see event prints in console */
+wifi_error nan_event_check_request(transaction_id id, wifi_interface_handle iface)
+{
+ NanEventCap *cmd = new NanEventCap(iface, id);
+ if (cmd == NULL) {
+ return WIFI_ERROR_NOT_SUPPORTED;
+ }
+ return (wifi_error)cmd->start();
+}
+
+/* Create NAN Data Interface */
+wifi_error nan_data_interface_create(transaction_id id,
+ wifi_interface_handle iface, char* iface_name)
+{
+ wifi_error ret = WIFI_SUCCESS;
+ NAN_DBG_ENTER();
+
+ NanRequestType cmdType = NAN_DATA_PATH_IFACE_CREATE;
+ NanDataPathPrimitive *cmd =
+ new NanDataPathPrimitive(iface, id, (void *)iface_name, cmdType);
+ NULL_CHECK_RETURN(cmd, "memory allocation failure", WIFI_ERROR_OUT_OF_MEMORY);
+
+ ret = (wifi_error)cmd->open();
+ if (ret != WIFI_SUCCESS) {
+ ALOGE("%s : failed in open, error = %d\n", __func__, ret);
+ }
+ cmd->releaseRef();
+
+ NAN_DBG_EXIT();
+ return ret;
+}
+
+/* Delete NAN Data Interface */
+wifi_error nan_data_interface_delete(transaction_id id,
+ wifi_interface_handle iface, char* iface_name)
+{
+ wifi_error ret = WIFI_SUCCESS;
+ NAN_DBG_ENTER();
+
+ NanRequestType cmdType = NAN_DATA_PATH_IFACE_DELETE;
+ NanDataPathPrimitive *cmd =
+ new NanDataPathPrimitive(iface, id, (void *)iface_name, cmdType);
+ NULL_CHECK_RETURN(cmd, "memory allocation failure", WIFI_ERROR_OUT_OF_MEMORY);
+
+ ret = (wifi_error)cmd->open();
+ if (ret != WIFI_SUCCESS) {
+ ALOGE("%s : failed in open, error = %d\n", __func__, ret);
+ }
+ cmd->releaseRef();
+
+ NAN_DBG_EXIT();
+ return ret;
+}
+
+/* Initiate a NDP session: Initiator */
+wifi_error nan_data_request_initiator(transaction_id id,
+ wifi_interface_handle iface, NanDataPathInitiatorRequest* msg)
+{
+ wifi_error ret = WIFI_SUCCESS;
+
+ NAN_DBG_ENTER();
+ NanRequestType cmdType;
+ NanDataPathPrimitive *cmd = NULL;
+
+#ifdef CONFIG_BRCM
+ dump_NanDataPathInitiatorRequest(msg);
+#endif /* CONFIG_BRCM */
+ counters.dp_req++;
+ if (msg->service_name_len) {
+ if (strncmp(NAN_OOB_INTEROP_SVC_NAME,
+ (char*)msg->service_name, msg->service_name_len) == 0) {
+ ALOGI("Use Hardcoded svc_hash\n");
+ msg->service_name_len = NAN_SVC_HASH_SIZE;
+ memcpy(msg->service_name, NAN_OOB_INTEROP_SVC_HASH, NAN_SVC_HASH_SIZE);
+ } else {
+ u8 svc_hash[NAN_SVC_HASH_SIZE];
+
+ ret = (wifi_error)get_svc_hash(msg->service_name, msg->service_name_len,
+ svc_hash, NAN_SVC_HASH_SIZE);
+ if (ret < 0) {
+ ALOGE("%s: Failed to get hashed svc name\n", __func__);
+ goto done;
+ }
+
+ ALOGI("Created svc_hash\n");
+ msg->service_name_len = NAN_SVC_HASH_SIZE;
+ memcpy(msg->service_name, svc_hash, msg->service_name_len);
+ }
+ } else if (msg->key_info.key_type == NAN_SECURITY_KEY_INPUT_PASSPHRASE) {
+ NanDataPathSecInfoRequest msg_sec_info;
+ if (msg->requestor_instance_id == 0) {
+ ALOGE("Invalid Pub ID = %d, Mandatory param is missing\n", msg->requestor_instance_id);
+ ret = WIFI_ERROR_INVALID_ARGS;
+ goto done;
+ } else {
+ ALOGI("Pub ID = %d, Mandatory param is present\n", msg->requestor_instance_id);
+ }
+ if (ETHER_ISNULLADDR(msg->peer_disc_mac_addr)) {
+ ALOGE("Invalid Pub NMI, Mandatory param is missing\n");
+ ret = WIFI_ERROR_INVALID_ARGS;
+ goto done;
+ }
+
+ msg_sec_info.requestor_instance_id = msg->requestor_instance_id;
+ memcpy(msg_sec_info.peer_disc_mac_addr, msg->peer_disc_mac_addr, NAN_MAC_ADDR_LEN);
+ msg_sec_info.ndp_instance_id = 0;
+ cmdType = NAN_DATA_PATH_SEC_INFO;
+ cmd = new NanDataPathPrimitive(iface, id, (void *)&msg_sec_info, cmdType);
+ NULL_CHECK_RETURN(cmd, "memory allocation failure", WIFI_ERROR_OUT_OF_MEMORY);
+ ret = (wifi_error)cmd->open();
+ if (ret != WIFI_SUCCESS) {
+ ALOGE("%s : failed in start, error = %d\n", __func__, ret);
+ goto done;
+ }
+ memcpy(msg->service_name, cmd->mSvcHash, NAN_SVC_HASH_SIZE);
+ }
+ /* free old command */
+ if (cmd) {
+ cmd->releaseRef();
+ }
+ cmdType = NAN_DATA_PATH_INIT_REQUEST;
+ cmd = new NanDataPathPrimitive(iface, id, (void *)msg, cmdType);
+ NULL_CHECK_RETURN(cmd, "memory allocation failure", WIFI_ERROR_OUT_OF_MEMORY);
+ ret = (wifi_error)cmd->open();
+ if (ret != WIFI_SUCCESS) {
+ ALOGE("%s : failed in open, error = %d\n", __func__, ret);
+ goto done;
+ }
+done:
+ if (cmd) {
+ cmd->releaseRef();
+ }
+
+ NAN_DBG_EXIT();
+ return ret;
+}
+
+/* Response to a data indication received corresponding to a NDP session.
+ * An indication is received with a data request and the responder will send a data response
+ */
+wifi_error nan_data_indication_response(transaction_id id,
+ wifi_interface_handle iface, NanDataPathIndicationResponse* msg)
+{
+ wifi_error ret = WIFI_SUCCESS;
+ NAN_DBG_ENTER();
+ NanRequestType cmdType;
+ u8 pub_nmi[NAN_MAC_ADDR_LEN] = {0};
+ NanDataPathPrimitive *cmd = NULL;
+
+#ifdef CONFIG_BRCM
+ dump_NanDataPathIndicationResponse(msg);
+#endif /* CONFIG_BRCM */
+ counters.dp_resp++;
+ if (msg->service_name_len) {
+ if (strncmp(NAN_OOB_INTEROP_SVC_NAME,
+ (char*)msg->service_name, msg->service_name_len) == 0) {
+ ALOGI("Use Hardcoded svc_hash\n");
+ msg->service_name_len = NAN_SVC_HASH_SIZE;
+ memcpy(msg->service_name, NAN_OOB_INTEROP_SVC_HASH, NAN_SVC_HASH_SIZE);
+ } else {
+ u8 svc_hash[NAN_SVC_HASH_SIZE];
+
+ ret = (wifi_error)get_svc_hash(msg->service_name, msg->service_name_len,
+ svc_hash, NAN_SVC_HASH_SIZE);
+ if (ret < 0) {
+ ALOGE("%s: Failed to get hashed svc name\n", __func__);
+ goto done;
+ }
+ ALOGI("Created svc_hash\n");
+ msg->service_name_len = NAN_SVC_HASH_SIZE;
+ memcpy(msg->service_name, svc_hash, msg->service_name_len);
+ }
+ }
+ if (msg->key_info.key_type == NAN_SECURITY_KEY_INPUT_PASSPHRASE) {
+ NanDataPathSecInfoRequest msg_sec_info;
+
+ if (msg->ndp_instance_id == 0) {
+ ALOGE("Invalid NDP ID, Mandatory info is not present\n");
+ ret = WIFI_ERROR_INVALID_ARGS;
+ goto done;
+ } else {
+ ALOGI("NDP ID = %d, Mandatory info is present\n", msg->ndp_instance_id);
+ }
+ msg_sec_info.ndp_instance_id = msg->ndp_instance_id;
+ msg_sec_info.requestor_instance_id = 0;
+ cmdType = NAN_DATA_PATH_SEC_INFO;
+ cmd = new NanDataPathPrimitive(iface, id, (void *)&msg_sec_info, cmdType);
+ NULL_CHECK_RETURN(cmd, "memory allocation failure", WIFI_ERROR_OUT_OF_MEMORY);
+
+ ret = (wifi_error)cmd->open();
+ if (ret != WIFI_SUCCESS) {
+ ALOGE("%s : failed in start, error = %d\n", __func__, ret);
+ goto done;
+ }
+
+ if (ETHER_ISNULLADDR(cmd->mPubNmi)) {
+ ALOGE("Invalid Pub NMI\n");
+ ret = WIFI_ERROR_INVALID_ARGS;
+ goto done;
+ }
+ memcpy(pub_nmi, cmd->mPubNmi, NAN_MAC_ADDR_LEN);
+
+ if (!msg->service_name_len) {
+ if (SVCHASH_ISNULL(cmd->mSvcHash)) {
+ ALOGE("Invalid svc_hash\n");
+ ret = WIFI_ERROR_INVALID_ARGS;
+ goto done;
+ }
+ memcpy(msg->service_name, cmd->mSvcHash, NAN_SVC_HASH_SIZE);
+ }
+ }
+ /* free old command */
+ if (cmd) {
+ cmd->releaseRef();
+ }
+ cmdType = NAN_DATA_PATH_IND_RESPONSE;
+ cmd = new NanDataPathPrimitive(iface, id, (void *)msg, cmdType);
+ NULL_CHECK_RETURN(cmd, "memory allocation failure", WIFI_ERROR_OUT_OF_MEMORY);
+ memcpy(cmd->mPubNmi, pub_nmi, NAN_MAC_ADDR_LEN);
+ ret = (wifi_error)cmd->open();
+ if (ret != WIFI_SUCCESS) {
+ ALOGE("%s : failed in open, error = %d\n", __func__, ret);
+ goto done;
+ }
+
+done:
+ if (cmd) {
+ cmd->releaseRef();
+ }
+ NAN_DBG_EXIT();
+ return ret;
+}
+
+/* NDL termination request: from either Initiator/Responder */
+wifi_error nan_data_end(transaction_id id,
+ wifi_interface_handle iface, NanDataPathEndRequest* msg)
+{
+ wifi_error ret = WIFI_SUCCESS;
+ NanDataPathPrimitive *cmd;
+ NanRequestType cmdType = NAN_DATA_PATH_END;
+ NAN_DBG_ENTER();
+
+ cmd = new NanDataPathPrimitive(iface, id, (void *)msg, cmdType);
+ NULL_CHECK_RETURN(cmd, "memory allocation failure", WIFI_ERROR_OUT_OF_MEMORY);
+
+ ret = (wifi_error)cmd->open();
+ if (ret != WIFI_SUCCESS) {
+ ALOGE("%s : failed in open, error = %d\n", __func__, ret);
+ }
+ cmd->releaseRef();
+ NAN_DBG_EXIT();
+ return ret;
+}
diff --git a/synadhd/wifi_hal/rtt.cpp b/synadhd/wifi_hal/rtt.cpp
new file mode 100644
index 0000000..510714b
--- /dev/null
+++ b/synadhd/wifi_hal/rtt.cpp
@@ -0,0 +1,812 @@
+/*
+ * Copyright (C) 2017 The Android Open Source Project
+ *
+ * Portions copyright (C) 2017 Broadcom Limited
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <stdint.h>
+#include <fcntl.h>
+#include <sys/socket.h>
+#include <netlink/genl/genl.h>
+#include <netlink/genl/family.h>
+#include <netlink/genl/ctrl.h>
+#include <linux/rtnetlink.h>
+#include <netpacket/packet.h>
+#include <linux/filter.h>
+#include <linux/errqueue.h>
+
+#include <linux/pkt_sched.h>
+#include <netlink/object-api.h>
+#include <netlink/netlink.h>
+#include <netlink/socket.h>
+#include <netlink-private/object-api.h>
+#include <netlink-private/types.h>
+
+#include "nl80211_copy.h"
+
+#include "sync.h"
+
+#define LOG_TAG "WifiHAL"
+
+#include <log/log.h>
+#include <utils/String8.h>
+
+#include "wifi_hal.h"
+#include "common.h"
+#include "cpp_bindings.h"
+
+using namespace android;
+#define RTT_RESULT_V2_SIZE (sizeof(wifi_rtt_result_v2));
+typedef enum {
+
+ RTT_SUBCMD_SET_CONFIG = ANDROID_NL80211_SUBCMD_RTT_RANGE_START,
+ RTT_SUBCMD_CANCEL_CONFIG,
+ RTT_SUBCMD_GETCAPABILITY,
+ RTT_SUBCMD_GETAVAILCHANNEL,
+ RTT_SUBCMD_SET_RESPONDER,
+ RTT_SUBCMD_CANCEL_RESPONDER,
+} RTT_SUB_COMMAND;
+
+typedef enum {
+ RTT_ATTRIBUTE_TARGET_INVALID = 0,
+ RTT_ATTRIBUTE_TARGET_CNT = 1,
+ RTT_ATTRIBUTE_TARGET_INFO = 2,
+ RTT_ATTRIBUTE_TARGET_MAC = 3,
+ RTT_ATTRIBUTE_TARGET_TYPE = 4,
+ RTT_ATTRIBUTE_TARGET_PEER = 5,
+ RTT_ATTRIBUTE_TARGET_CHAN = 6,
+ RTT_ATTRIBUTE_TARGET_PERIOD = 7,
+ RTT_ATTRIBUTE_TARGET_NUM_BURST = 8,
+ RTT_ATTRIBUTE_TARGET_NUM_FTM_BURST = 9,
+ RTT_ATTRIBUTE_TARGET_NUM_RETRY_FTM = 10,
+ RTT_ATTRIBUTE_TARGET_NUM_RETRY_FTMR = 11,
+ RTT_ATTRIBUTE_TARGET_LCI = 12,
+ RTT_ATTRIBUTE_TARGET_LCR = 13,
+ RTT_ATTRIBUTE_TARGET_BURST_DURATION = 14,
+ RTT_ATTRIBUTE_TARGET_PREAMBLE = 15,
+ RTT_ATTRIBUTE_TARGET_BW = 16,
+ RTT_ATTRIBUTE_RESULTS_COMPLETE = 30,
+ RTT_ATTRIBUTE_RESULTS_PER_TARGET = 31,
+ RTT_ATTRIBUTE_RESULT_CNT = 32,
+ RTT_ATTRIBUTE_RESULT = 33,
+ RTT_ATTRIBUTE_RESULT_DETAIL = 34,
+ RTT_ATTRIBUTE_RESULT_EXTRA = 35,
+ /* Add any new RTT_ATTRIBUTE prior to RTT_ATTRIBUTE_MAX */
+ RTT_ATTRIBUTE_MAX
+} RTT_ATTRIBUTE;
+typedef struct strmap_entry {
+ int id;
+ String8 text;
+} strmap_entry_t;
+struct dot11_rm_ie {
+ u8 id;
+ u8 len;
+ u8 token;
+ u8 mode;
+ u8 type;
+} __attribute__ ((packed));
+typedef struct dot11_rm_ie dot11_rm_ie_t;
+
+typedef struct rtt_result_extra {
+ wifi_channel frequency;
+ wifi_rtt_bw packet_bw;
+} rtt_result_extra_t;
+
+#define DOT11_HDR_LEN 2
+#define DOT11_RM_IE_LEN 5
+#define DOT11_MNG_MEASURE_REQUEST_ID 38 /* 11H MeasurementRequest */
+#define DOT11_MNG_MEASURE_REPORT_ID 39 /* 11H MeasurementResponse */
+#define DOT11_MEASURE_TYPE_LCI 8 /* d11 measurement LCI type */
+#define DOT11_MEASURE_TYPE_CIVICLOC 11 /* d11 measurement location civic */
+
+static const strmap_entry_t err_info[] = {
+ {RTT_STATUS_SUCCESS, String8("Success")},
+ {RTT_STATUS_FAILURE, String8("Failure")},
+ {RTT_STATUS_FAIL_NO_RSP, String8("No response")},
+ {RTT_STATUS_FAIL_INVALID_TS, String8("Invalid Timestamp")},
+ {RTT_STATUS_FAIL_PROTOCOL, String8("Protocol error")},
+ {RTT_STATUS_FAIL_REJECTED, String8("Rejected")},
+ {RTT_STATUS_FAIL_NOT_SCHEDULED_YET, String8("not scheduled")},
+ {RTT_STATUS_FAIL_SCHEDULE, String8("schedule failed")},
+ {RTT_STATUS_FAIL_TM_TIMEOUT, String8("timeout")},
+ {RTT_STATUS_FAIL_AP_ON_DIFF_CHANNEL, String8("AP is on difference channel")},
+ {RTT_STATUS_FAIL_NO_CAPABILITY, String8("no capability")},
+ {RTT_STATUS_FAIL_BUSY_TRY_LATER, String8("busy and try later")},
+ {RTT_STATUS_ABORTED, String8("aborted")}
+};
+
+ static const char*
+get_err_info(int status)
+{
+ int i;
+ const strmap_entry_t *p_entry;
+ int num_entries = sizeof(err_info)/ sizeof(err_info[0]);
+ /* scan thru the table till end */
+ p_entry = err_info;
+ for (i = 0; i < (int) num_entries; i++)
+ {
+ if (p_entry->id == status)
+ return p_entry->text;
+ p_entry++; /* next entry */
+ }
+ return "unknown error"; /* not found */
+}
+
+class GetRttCapabilitiesCommand : public WifiCommand
+{
+ wifi_rtt_capabilities *mCapabilities;
+public:
+ GetRttCapabilitiesCommand(wifi_interface_handle iface, wifi_rtt_capabilities *capabitlites)
+ : WifiCommand("GetRttCapabilitiesCommand", iface, 0), mCapabilities(capabitlites)
+ {
+ memset(mCapabilities, 0, sizeof(*mCapabilities));
+ }
+
+ virtual int create() {
+ ALOGD("Creating message to get scan capabilities; iface = %d", mIfaceInfo->id);
+
+ int ret = mMsg.create(GOOGLE_OUI, RTT_SUBCMD_GETCAPABILITY);
+ if (ret < 0) {
+ return ret;
+ }
+
+ return ret;
+ }
+
+protected:
+ virtual int handleResponse(WifiEvent& reply) {
+
+ ALOGD("In GetRttCapabilitiesCommand::handleResponse");
+
+ if (reply.get_cmd() != NL80211_CMD_VENDOR) {
+ ALOGD("Ignoring reply with cmd = %d", reply.get_cmd());
+ return NL_SKIP;
+ }
+
+ int id = reply.get_vendor_id();
+ int subcmd = reply.get_vendor_subcmd();
+
+ void *data = reply.get_vendor_data();
+ int len = reply.get_vendor_data_len();
+
+ ALOGD("Id = %0x, subcmd = %d, len = %d, expected len = %d", id, subcmd, len,
+ sizeof(*mCapabilities));
+
+ memcpy(mCapabilities, data, min(len, (int) sizeof(*mCapabilities)));
+
+ return NL_OK;
+ }
+};
+
+
+class GetRttResponderInfoCommand : public WifiCommand
+{
+ wifi_rtt_responder* mResponderInfo;
+public:
+ GetRttResponderInfoCommand(wifi_interface_handle iface, wifi_rtt_responder *responderInfo)
+ : WifiCommand("GetRttResponderInfoCommand", iface, 0), mResponderInfo(responderInfo)
+ {
+ memset(mResponderInfo, 0 , sizeof(*mResponderInfo));
+
+ }
+
+ virtual int create() {
+ ALOGD("Creating message to get responder info ; iface = %d", mIfaceInfo->id);
+
+ int ret = mMsg.create(GOOGLE_OUI, RTT_SUBCMD_GETAVAILCHANNEL);
+ if (ret < 0) {
+ return ret;
+ }
+
+ return ret;
+ }
+
+protected:
+ virtual int handleResponse(WifiEvent& reply) {
+
+ ALOGD("In GetRttResponderInfoCommand::handleResponse");
+
+ if (reply.get_cmd() != NL80211_CMD_VENDOR) {
+ ALOGD("Ignoring reply with cmd = %d", reply.get_cmd());
+ return NL_SKIP;
+ }
+
+ int id = reply.get_vendor_id();
+ int subcmd = reply.get_vendor_subcmd();
+
+ void *data = reply.get_vendor_data();
+ int len = reply.get_vendor_data_len();
+
+ ALOGD("Id = %0x, subcmd = %d, len = %d, expected len = %d", id, subcmd, len,
+ sizeof(*mResponderInfo));
+
+ memcpy(mResponderInfo, data, min(len, (int) sizeof(*mResponderInfo)));
+
+ return NL_OK;
+ }
+};
+
+
+class EnableResponderCommand : public WifiCommand
+{
+ wifi_channel_info mChannelInfo;
+ wifi_rtt_responder* mResponderInfo;
+ unsigned m_max_duration_sec;
+public:
+ EnableResponderCommand(wifi_interface_handle iface, int id, wifi_channel_info channel_hint,
+ unsigned max_duration_seconds, wifi_rtt_responder *responderInfo)
+ : WifiCommand("EnableResponderCommand", iface, 0), mChannelInfo(channel_hint),
+ m_max_duration_sec(max_duration_seconds), mResponderInfo(responderInfo)
+ {
+ memset(mResponderInfo, 0, sizeof(*mResponderInfo));
+ }
+
+ virtual int create() {
+ ALOGD("Creating message to set responder ; iface = %d", mIfaceInfo->id);
+
+ int ret = mMsg.create(GOOGLE_OUI, RTT_SUBCMD_SET_RESPONDER);
+ if (ret < 0) {
+ return ret;
+ }
+
+ return ret;
+ }
+
+protected:
+ virtual int handleResponse(WifiEvent& reply) {
+
+ ALOGD("In EnableResponderCommand::handleResponse");
+
+ if (reply.get_cmd() != NL80211_CMD_VENDOR) {
+ ALOGD("Ignoring reply with cmd = %d", reply.get_cmd());
+ return NL_SKIP;
+ }
+
+ int id = reply.get_vendor_id();
+ int subcmd = reply.get_vendor_subcmd();
+
+ void *data = reply.get_vendor_data();
+ int len = reply.get_vendor_data_len();
+
+ ALOGD("Id = %0x, subcmd = %d, len = %d, expected len = %d", id, subcmd, len,
+ sizeof(*mResponderInfo));
+
+ memcpy(mResponderInfo, data, min(len, (int) sizeof(*mResponderInfo)));
+
+ return NL_OK;
+ }
+};
+
+
+class CancelResponderCommand : public WifiCommand
+{
+
+public:
+ CancelResponderCommand(wifi_interface_handle iface, int id)
+ : WifiCommand("CancelResponderCommand", iface, 0)/*, mChannelInfo(channel)*/
+ {
+
+ }
+
+ virtual int create() {
+ ALOGD("Creating message to cancel responder ; iface = %d", mIfaceInfo->id);
+
+ int ret = mMsg.create(GOOGLE_OUI, RTT_SUBCMD_CANCEL_RESPONDER);
+ if (ret < 0) {
+ return ret;
+ }
+
+ return ret;
+ }
+
+protected:
+ virtual int handleResponse(WifiEvent& reply) {
+ /* Nothing to do on response! */
+ return NL_SKIP;
+ }
+
+};
+
+
+class RttCommand : public WifiCommand
+{
+ unsigned numRttParams;
+ int mCompleted;
+ int currentIdx;
+ int currDtlIdx;
+ int totalCnt;
+ static const int MAX_RESULTS = 1024;
+ wifi_rtt_result_v2 *rttResults_v2[MAX_RESULTS];
+ wifi_rtt_config *rttParams;
+ wifi_rtt_event_handler rttHandler;
+public:
+ RttCommand(wifi_interface_handle iface, int id, unsigned num_rtt_config,
+ wifi_rtt_config rtt_config[], wifi_rtt_event_handler handler)
+ : WifiCommand("RttCommand", iface, id), numRttParams(num_rtt_config), rttParams(rtt_config),
+ rttHandler(handler)
+ {
+ memset(rttResults_v2, 0, sizeof(rttResults_v2));
+ currentIdx = 0;
+ mCompleted = 0;
+ totalCnt = 0;
+ currDtlIdx = 0;
+ }
+
+ RttCommand(wifi_interface_handle iface, int id)
+ : WifiCommand("RttCommand", iface, id)
+ {
+ currentIdx = 0;
+ mCompleted = 0;
+ totalCnt = 0;
+ currDtlIdx = 0;
+ numRttParams = 0;
+ memset(rttResults_v2, 0, sizeof(rttResults_v2));
+ rttParams = NULL;
+ rttHandler.on_rtt_results_v2 = NULL;
+ }
+
+ int createSetupRequest(WifiRequest& request) {
+ int result = request.create(GOOGLE_OUI, RTT_SUBCMD_SET_CONFIG);
+ if (result < 0) {
+ return result;
+ }
+
+ nlattr *data = request.attr_start(NL80211_ATTR_VENDOR_DATA);
+ result = request.put_u8(RTT_ATTRIBUTE_TARGET_CNT, numRttParams);
+ if (result < 0) {
+ return result;
+ }
+ nlattr *rtt_config = request.attr_start(RTT_ATTRIBUTE_TARGET_INFO);
+ for (unsigned i = 0; i < numRttParams; i++) {
+ nlattr *attr2 = request.attr_start(i);
+ if (attr2 == NULL) {
+ return WIFI_ERROR_OUT_OF_MEMORY;
+ }
+
+ result = request.put_addr(RTT_ATTRIBUTE_TARGET_MAC, rttParams[i].addr);
+ if (result < 0) {
+ return result;
+ }
+
+ result = request.put_u8(RTT_ATTRIBUTE_TARGET_TYPE, rttParams[i].type);
+ if (result < 0) {
+ return result;
+ }
+
+ result = request.put_u8(RTT_ATTRIBUTE_TARGET_PEER, rttParams[i].peer);
+ if (result < 0) {
+ return result;
+ }
+
+ result = request.put(RTT_ATTRIBUTE_TARGET_CHAN, &rttParams[i].channel,
+ sizeof(wifi_channel_info));
+ if (result < 0) {
+ return result;
+ }
+
+ result = request.put_u32(RTT_ATTRIBUTE_TARGET_NUM_BURST, rttParams[i].num_burst);
+ if (result < 0) {
+ return result;
+ }
+
+ result = request.put_u32(RTT_ATTRIBUTE_TARGET_NUM_FTM_BURST,
+ rttParams[i].num_frames_per_burst);
+ if (result < 0) {
+ return result;
+ }
+
+ result = request.put_u32(RTT_ATTRIBUTE_TARGET_NUM_RETRY_FTM,
+ rttParams[i].num_retries_per_rtt_frame);
+ if (result < 0) {
+ return result;
+ }
+
+ result = request.put_u32(RTT_ATTRIBUTE_TARGET_NUM_RETRY_FTMR,
+ rttParams[i].num_retries_per_ftmr);
+ if (result < 0) {
+ return result;
+ }
+
+ result = request.put_u32(RTT_ATTRIBUTE_TARGET_PERIOD,
+ rttParams[i].burst_period);
+ if (result < 0) {
+ return result;
+ }
+
+ result = request.put_u32(RTT_ATTRIBUTE_TARGET_BURST_DURATION,
+ rttParams[i].burst_duration);
+ if (result < 0) {
+ return result;
+ }
+
+ result = request.put_u8(RTT_ATTRIBUTE_TARGET_LCI,
+ rttParams[i].LCI_request);
+ if (result < 0) {
+ return result;
+ }
+
+ result = request.put_u8(RTT_ATTRIBUTE_TARGET_LCR,
+ rttParams[i].LCR_request);
+ if (result < 0) {
+ return result;
+ }
+
+ result = request.put_u8(RTT_ATTRIBUTE_TARGET_BW,
+ rttParams[i].bw);
+ if (result < 0) {
+ return result;
+ }
+
+ result = request.put_u8(RTT_ATTRIBUTE_TARGET_PREAMBLE,
+ rttParams[i].preamble);
+ if (result < 0) {
+ return result;
+ }
+ request.attr_end(attr2);
+ }
+
+ request.attr_end(rtt_config);
+ request.attr_end(data);
+ return WIFI_SUCCESS;
+ }
+
+ int createTeardownRequest(WifiRequest& request, unsigned num_devices, mac_addr addr[]) {
+ int result = request.create(GOOGLE_OUI, RTT_SUBCMD_CANCEL_CONFIG);
+ if (result < 0) {
+ return result;
+ }
+
+ nlattr *data = request.attr_start(NL80211_ATTR_VENDOR_DATA);
+ result = request.put_u8(RTT_ATTRIBUTE_TARGET_CNT, num_devices);
+
+ if (result < 0) {
+ return result;
+ }
+ for(unsigned i = 0; i < num_devices; i++) {
+ result = request.put_addr(RTT_ATTRIBUTE_TARGET_MAC, addr[i]);
+ if (result < 0) {
+ return result;
+ }
+ }
+ request.attr_end(data);
+ return result;
+ }
+ int start() {
+ ALOGD("Setting RTT configuration");
+ WifiRequest request(familyId(), ifaceId());
+ int result = createSetupRequest(request);
+ if (result != WIFI_SUCCESS) {
+ ALOGE("failed to create setup request; result = %d", result);
+ return result;
+ }
+
+ registerVendorHandler(GOOGLE_OUI, RTT_EVENT_COMPLETE);
+ result = requestResponse(request);
+ if (result != WIFI_SUCCESS) {
+ unregisterVendorHandler(GOOGLE_OUI, RTT_EVENT_COMPLETE);
+ ALOGE("failed to configure RTT setup; result = %d", result);
+ return result;
+ }
+
+ ALOGI("Successfully started RTT operation");
+ return result;
+ }
+
+ virtual int cancel() {
+ ALOGD("Stopping RTT");
+
+ WifiRequest request(familyId(), ifaceId());
+ int result = createTeardownRequest(request, 0, NULL);
+ if (result != WIFI_SUCCESS) {
+ ALOGE("failed to create stop request; result = %d", result);
+ } else {
+ result = requestResponse(request);
+ if (result != WIFI_SUCCESS) {
+ ALOGE("failed to stop scan; result = %d", result);
+ }
+ }
+
+ unregisterVendorHandler(GOOGLE_OUI, RTT_EVENT_COMPLETE);
+ return WIFI_SUCCESS;
+ }
+
+ int cancel_specific(unsigned num_devices, mac_addr addr[]) {
+ ALOGE("Stopping RTT");
+
+ WifiRequest request(familyId(), ifaceId());
+ int result = createTeardownRequest(request, num_devices, addr);
+ if (result != WIFI_SUCCESS) {
+ ALOGE("failed to create stop request; result = %d", result);
+ } else {
+ result = requestResponse(request);
+ if (result != WIFI_SUCCESS) {
+ ALOGE("failed to stop RTT; result = %d", result);
+ }
+ }
+
+ unregisterVendorHandler(GOOGLE_OUI, RTT_EVENT_COMPLETE);
+ return WIFI_SUCCESS;
+ }
+
+ virtual int handleResponse(WifiEvent& reply) {
+ /* Nothing to do on response! */
+ return NL_SKIP;
+ }
+
+ virtual int handleEvent(WifiEvent& event) {
+ ALOGI("Got an RTT event");
+ nlattr *vendor_data = event.get_attribute(NL80211_ATTR_VENDOR_DATA);
+ int len = event.get_vendor_data_len();
+ int nextidx = 0;
+ if (vendor_data == NULL || len == 0) {
+ ALOGI("No rtt results found");
+ return NL_STOP;
+ }
+ for (nl_iterator it(vendor_data); it.has_next(); it.next()) {
+ if (it.get_type() == RTT_ATTRIBUTE_RESULTS_COMPLETE) {
+ mCompleted = it.get_u32();
+ ALOGI("retrieved completed flag : %d\n", mCompleted);
+ } else if (it.get_type() == RTT_ATTRIBUTE_RESULTS_PER_TARGET) {
+ int result_cnt = 0;
+ mac_addr bssid;
+ for (nl_iterator it2(it.get()); it2.has_next(); it2.next()) {
+ if (it2.get_type() == RTT_ATTRIBUTE_TARGET_MAC) {
+ memcpy(bssid, it2.get_data(), sizeof(mac_addr));
+ ALOGI("retrieved target mac : %02x:%02x:%02x:%02x:%02x:%02x\n",
+ bssid[0],
+ bssid[1],
+ bssid[2],
+ bssid[3],
+ bssid[4],
+ bssid[5]);
+ } else if (it2.get_type() == RTT_ATTRIBUTE_RESULT_CNT) {
+ result_cnt = it2.get_u32();
+ ALOGI("retrieved result_cnt : %d\n", result_cnt);
+ } else if (it2.get_type() == RTT_ATTRIBUTE_RESULT_EXTRA) {
+ if (rttResults_v2[currentIdx] == NULL) {
+ mCompleted = 1;
+ ALOGE("failed to allocate the rttResults_v2\n");
+ break;
+ }
+ rtt_result_extra_t *rtt_result_extra =
+ (rtt_result_extra_t *)malloc(it2.get_len());
+ if (rtt_result_extra == NULL) {
+ mCompleted = 1;
+ ALOGE("failed to allocate the rtt_result_extra\n");
+ break;
+ }
+ /* Update RTT frequency & packet_bw */
+ memcpy(rtt_result_extra, it2.get_data(), it2.get_len());
+ rttResults_v2[currentIdx]->frequency = rtt_result_extra->frequency;
+ rttResults_v2[currentIdx]->packet_bw = rtt_result_extra->packet_bw;
+ free(rtt_result_extra);
+ ALOGI("retrieved currentIdx %d rtt_result_v2 :\n"
+ "\tfrequency : %d, packet_bw : %d\n",
+ currentIdx, rttResults_v2[currentIdx]->frequency,
+ rttResults_v2[currentIdx]->packet_bw);
+ } else if (it2.get_type() == RTT_ATTRIBUTE_RESULT) {
+ currentIdx = nextidx;
+ int result_v2_len = sizeof(wifi_rtt_result_v2) +
+ it2.get_len() - sizeof(wifi_rtt_result);
+ int result_len = it2.get_len();
+ rttResults_v2[currentIdx] = (wifi_rtt_result_v2 *)malloc(result_v2_len);
+ wifi_rtt_result_v2 *rtt_result_v2 = rttResults_v2[currentIdx];
+ if (rtt_result_v2 == NULL) {
+ mCompleted = 1;
+ ALOGE("failed to allocate the wifi_rtt_result_v2\n");
+ break;
+ }
+ wifi_rtt_result *rtt_result = &rtt_result_v2->rtt_result;
+ memcpy(rtt_result, it2.get_data(), it2.get_len());
+ result_len -= sizeof(wifi_rtt_result);
+ if (result_len > 0) {
+ dot11_rm_ie_t *ele_1;
+ dot11_rm_ie_t *ele_2;
+ /* The result has LCI or LCR element */
+ ele_1 = (dot11_rm_ie_t *)(rtt_result + 1);
+ if (ele_1->id == DOT11_MNG_MEASURE_REPORT_ID) {
+ if (ele_1->type == DOT11_MEASURE_TYPE_LCI) {
+ rtt_result->LCI = (wifi_information_element *)ele_1;
+ result_len -= (ele_1->len + DOT11_HDR_LEN);
+ /* get a next rm ie */
+ if (result_len > 0) {
+ ele_2 = (dot11_rm_ie_t *)((char *)ele_1 +
+ (ele_1->len + DOT11_HDR_LEN));
+ if ((ele_2->id == DOT11_MNG_MEASURE_REPORT_ID) &&
+ (ele_2->type == DOT11_MEASURE_TYPE_CIVICLOC)) {
+ rtt_result->LCR = (wifi_information_element *)ele_2;
+ }
+ }
+ } else if (ele_1->type == DOT11_MEASURE_TYPE_CIVICLOC){
+ rtt_result->LCR = (wifi_information_element *)ele_1;
+ result_len -= (ele_1->len + DOT11_HDR_LEN);
+ /* get a next rm ie */
+ if (result_len > 0) {
+ ele_2 = (dot11_rm_ie_t *)((char *)ele_1 +
+ (ele_1->len + DOT11_HDR_LEN));
+ if ((ele_2->id == DOT11_MNG_MEASURE_REPORT_ID) &&
+ (ele_2->type == DOT11_MEASURE_TYPE_LCI)) {
+ rtt_result->LCI = (wifi_information_element *)ele_2;
+ }
+ }
+ }
+ }
+ }
+ totalCnt++;
+
+ /* Fill out rtt_result_v2 */
+ rtt_result_v2->frequency = UNSPECIFIED;
+ rtt_result_v2->packet_bw = WIFI_RTT_BW_UNSPECIFIED;
+
+ ALOGI("retrieved currentIdx %d rtt_result : \n\tburst_num :%d,"
+ " measurement_number : %d, success_number : %d\n"
+ "\tnumber_per_burst_peer : %d, status : %s, "
+ "retry_after_duration : %d s\n \trssi : %d dbm,"
+ " rx_rate : %d Kbps, rtt : %lu ns, rtt_sd : %lu\n"
+ "\tdistance : %d cm, burst_duration : %d ms,"
+ " negotiated_burst_num : %d\n",
+ currentIdx, rtt_result_v2->rtt_result.burst_num,
+ rtt_result_v2->rtt_result.measurement_number,
+ rtt_result_v2->rtt_result.success_number,
+ rtt_result_v2->rtt_result.number_per_burst_peer,
+ get_err_info(rtt_result_v2->rtt_result.status),
+ rtt_result_v2->rtt_result.retry_after_duration,
+ rtt_result_v2->rtt_result.rssi,
+ rtt_result_v2->rtt_result.rx_rate.bitrate * 100,
+ (unsigned long)rtt_result_v2->rtt_result.rtt / 1000,
+ (unsigned long)rtt_result_v2->rtt_result.rtt_sd,
+ rtt_result_v2->rtt_result.distance_mm / 10,
+ rtt_result_v2->rtt_result.burst_duration,
+ rtt_result_v2->rtt_result.negotiated_burst_num);
+ nextidx = currentIdx;
+ nextidx++;
+ }
+ }
+ }
+ }
+ if (mCompleted) {
+ unregisterVendorHandler(GOOGLE_OUI, RTT_EVENT_COMPLETE);
+ if (*rttHandler.on_rtt_results_v2) {
+ (*rttHandler.on_rtt_results_v2)(id(), totalCnt, rttResults_v2);
+ }
+ for (int i = 0; i < currentIdx; i++) {
+ free(rttResults_v2[i]);
+ rttResults_v2[i] = NULL;
+ }
+ totalCnt = currentIdx = 0;
+ WifiCommand *cmd = wifi_unregister_cmd(wifiHandle(), id());
+ if (cmd)
+ cmd->releaseRef();
+ }
+ return NL_SKIP;
+ }
+};
+
+
+/* API to request RTT measurement */
+wifi_error wifi_rtt_range_request(wifi_request_id id, wifi_interface_handle iface,
+ unsigned num_rtt_config, wifi_rtt_config rtt_config[], wifi_rtt_event_handler handler)
+{
+ if (iface == NULL) {
+ ALOGE("wifi_rtt_range_request: NULL iface pointer provided."
+ " Exit.");
+ return WIFI_ERROR_INVALID_ARGS;
+ }
+
+ wifi_handle handle = getWifiHandle(iface);
+ if (handle == NULL) {
+ ALOGE("wifi_rtt_range_request: NULL handle pointer provided."
+ " Exit.");
+ return WIFI_ERROR_INVALID_ARGS;
+ }
+
+ RttCommand *cmd = new RttCommand(iface, id, num_rtt_config, rtt_config, handler);
+ NULL_CHECK_RETURN(cmd, "memory allocation failure", WIFI_ERROR_OUT_OF_MEMORY);
+ wifi_error result = wifi_register_cmd(handle, id, cmd);
+ if (result != WIFI_SUCCESS) {
+ cmd->releaseRef();
+ return result;
+ }
+ result = (wifi_error)cmd->start();
+ if (result != WIFI_SUCCESS) {
+ wifi_unregister_cmd(handle, id);
+ cmd->releaseRef();
+ return result;
+ }
+ return result;
+}
+
+/* API to cancel RTT measurements */
+wifi_error wifi_rtt_range_cancel(wifi_request_id id, wifi_interface_handle iface,
+ unsigned num_devices, mac_addr addr[])
+{
+ if (iface == NULL) {
+ ALOGE("wifi_rtt_range_cancel: NULL iface pointer provided."
+ " Exit.");
+ return WIFI_ERROR_INVALID_ARGS;
+ }
+
+ wifi_handle handle = getWifiHandle(iface);
+ if (handle == NULL) {
+ ALOGE("wifi_rtt_range_cancel: NULL handle pointer provided."
+ " Exit.");
+ return WIFI_ERROR_INVALID_ARGS;
+ }
+
+ RttCommand *cmd = new RttCommand(iface, id);
+ NULL_CHECK_RETURN(cmd, "memory allocation failure", WIFI_ERROR_OUT_OF_MEMORY);
+ cmd->cancel_specific(num_devices, addr);
+ cmd->releaseRef();
+ return WIFI_SUCCESS;
+}
+
+/* API to get RTT capability */
+wifi_error wifi_get_rtt_capabilities(wifi_interface_handle iface,
+ wifi_rtt_capabilities *capabilities)
+{
+ if (iface == NULL) {
+ ALOGE("wifi_get_rtt_capabilities: NULL iface pointer provided."
+ " Exit.");
+ return WIFI_ERROR_INVALID_ARGS;
+ }
+
+ if (capabilities == NULL) {
+ ALOGE("wifi_get_rtt_capabilities: NULL capabilities pointer provided."
+ " Exit.");
+ return WIFI_ERROR_INVALID_ARGS;
+ }
+
+ GetRttCapabilitiesCommand command(iface, capabilities);
+ return (wifi_error) command.requestResponse();
+}
+
+/* API to get the responder information */
+wifi_error wifi_rtt_get_responder_info(wifi_interface_handle iface,
+ wifi_rtt_responder* responderInfo)
+{
+ if (iface == NULL) {
+ ALOGE("wifi_rtt_get_responder_info: NULL iface pointer provided."
+ " Exit.");
+ return WIFI_ERROR_INVALID_ARGS;
+ }
+
+ GetRttResponderInfoCommand command(iface, responderInfo);
+ return (wifi_error) command.requestResponse();
+
+}
+
+/**
+ * Enable RTT responder mode.
+ * channel_hint - hint of the channel information where RTT responder should be enabled on.
+ * max_duration_seconds - timeout of responder mode.
+ * wifi_rtt_responder - information for RTT responder e.g. channel used and preamble supported.
+ */
+wifi_error wifi_enable_responder(wifi_request_id id, wifi_interface_handle iface,
+ wifi_channel_info channel_hint, unsigned max_duration_seconds,
+ wifi_rtt_responder* responderInfo)
+{
+ EnableResponderCommand command(iface, id, channel_hint, max_duration_seconds, responderInfo);
+ return (wifi_error) command.requestResponse();
+}
+
+/**
+ * Disable RTT responder mode.
+ */
+wifi_error wifi_disable_responder(wifi_request_id id, wifi_interface_handle iface)
+{
+ CancelResponderCommand command(iface, id);
+ return (wifi_error) command.requestResponse();
+}
+
diff --git a/synadhd/wifi_hal/syna_version.h b/synadhd/wifi_hal/syna_version.h
new file mode 100755
index 0000000..9323a24
--- /dev/null
+++ b/synadhd/wifi_hal/syna_version.h
@@ -0,0 +1 @@
+#define HAL_VERSION "SYNA vendor HAL"
diff --git a/synadhd/wifi_hal/sync.h b/synadhd/wifi_hal/sync.h
new file mode 100644
index 0000000..1118c71
--- /dev/null
+++ b/synadhd/wifi_hal/sync.h
@@ -0,0 +1,71 @@
+/*
+ * Copyright (C) 2017 The Android Open Source Project
+ *
+ * Portions copyright (C) 2017 Broadcom Limited
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <pthread.h>
+
+#ifndef __WIFI_HAL_SYNC_H__
+#define __WIFI_HAL_SYNC_H__
+
+class Mutex
+{
+private:
+ pthread_mutex_t mMutex;
+public:
+ Mutex() {
+ pthread_mutex_init(&mMutex, NULL);
+ }
+ ~Mutex() {
+ pthread_mutex_destroy(&mMutex);
+ }
+ int tryLock() {
+ return pthread_mutex_trylock(&mMutex);
+ }
+ int lock() {
+ return pthread_mutex_lock(&mMutex);
+ }
+ void unlock() {
+ pthread_mutex_unlock(&mMutex);
+ }
+};
+
+class Condition
+{
+private:
+ pthread_cond_t mCondition;
+ pthread_mutex_t mMutex;
+
+public:
+ Condition() {
+ pthread_mutex_init(&mMutex, NULL);
+ pthread_cond_init(&mCondition, NULL);
+ }
+ ~Condition() {
+ pthread_cond_destroy(&mCondition);
+ pthread_mutex_destroy(&mMutex);
+ }
+
+ int wait() {
+ return pthread_cond_wait(&mCondition, &mMutex);
+ }
+
+ void signal() {
+ pthread_cond_signal(&mCondition);
+ }
+};
+
+#endif
diff --git a/synadhd/wifi_hal/twt.cpp b/synadhd/wifi_hal/twt.cpp
new file mode 100755
index 0000000..15bb738
--- /dev/null
+++ b/synadhd/wifi_hal/twt.cpp
@@ -0,0 +1,947 @@
+/*
+ * Copyright (C) 2017 The Android Open Source Project
+ *
+ * Portions copyright (C) 2020 Broadcom Limited
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <stdint.h>
+#include <fcntl.h>
+#include <sys/socket.h>
+#include <netlink/genl/genl.h>
+#include <netlink/genl/family.h>
+#include <netlink/genl/ctrl.h>
+#include <linux/rtnetlink.h>
+#include <netpacket/packet.h>
+#include <linux/filter.h>
+#include <linux/errqueue.h>
+
+#include <linux/pkt_sched.h>
+#include <netlink/object-api.h>
+#include <netlink/netlink.h>
+#include <netlink/socket.h>
+#include <netlink/handlers.h>
+
+#include "sync.h"
+
+#define LOG_TAG "WifiHAL"
+
+#include <utils/Log.h>
+
+#include "wifi_hal.h"
+#include "common.h"
+#include "cpp_bindings.h"
+
+static const char *TwtCmdToString(int cmd);
+static void EventGetAttributeData(u8 sub_event_type, nlattr *vendor_data);
+typedef void *TwtRequest;
+
+#define C2S(x) case x: return #x;
+
+typedef struct _twt_hal_info {
+ void *twt_handle;
+ void *twt_feature_request;
+} twt_hal_info_t;
+
+twt_hal_info_t twt_info;
+
+#define TWT_HANDLE(twt_info) ((twt_info).twt_handle)
+#define GET_TWT_HANDLE(twt_info) ((TwtHandle *)twt_info.twt_handle)
+
+#define WL_TWT_CAP_FLAGS_REQ_SUPPORT (1u << 0u)
+#define WL_TWT_CAP_FLAGS_RESP_SUPPORT (1u << 1u)
+#define WL_TWT_CAP_FLAGS_BTWT_SUPPORT (1u << 2u)
+#define WL_TWT_CAP_FLAGS_FLEX_SUPPORT (1u << 3u)
+
+class TwtHandle
+{
+ public:
+ TwtCallbackHandler mHandlers;
+ TwtHandle(wifi_handle handle, TwtCallbackHandler handlers):mHandlers(handlers)
+ {}
+
+};
+
+
+static const char *TwtCmdToString(int cmd)
+{
+ switch (cmd) {
+ C2S(TWT_SETUP_REQUEST);
+ C2S(TWT_INFO_FRAME_REQUEST);
+ C2S(TWT_TEAR_DOWN_REQUEST);
+ default:
+ return "UNKNOWN_NAN_CMD";
+ }
+}
+
+static bool is_twt_sub_event(int sub_event_type)
+{
+ bool is_twt_event = false;
+ switch (sub_event_type) {
+ case TWT_SETUP_RESPONSE:
+ case TWT_TEARDOWN_COMPLETION:
+ case TWT_INFORM_FRAME:
+ case TWT_NOTIFY:
+ is_twt_event = true;
+ }
+ return is_twt_event;
+}
+
+void EventGetAttributeData(u8 sub_event_type, nlattr *vendor_data)
+{
+ u8 attr_type = 0;
+
+ switch (sub_event_type) {
+ case TWT_SETUP_RESPONSE:
+ TwtSetupResponse setup_response;
+ for (nl_iterator it(vendor_data); it.has_next(); it.next()) {
+ attr_type = it.get_type();
+ switch (attr_type) {
+ case TWT_ATTRIBUTE_CONFIG_ID:
+ ALOGI("config_id = %u\n", it.get_u8());
+ setup_response.config_id = it.get_u8();
+ break;
+ case TWT_ATTRIBUTE_NEG_TYPE:
+ ALOGI("neg type = %u\n", it.get_u8());
+ setup_response.negotiation_type = it.get_u8();
+ break;
+ case TWT_ATTRIBUTE_REASON_CODE:
+ setup_response.reason_code = (TwtSetupReasonCode)it.get_u8();
+ ALOGI("reason code = %u\n", setup_response.reason_code);
+ break;
+ case TWT_ATTRIBUTE_STATUS:
+ setup_response.status = it.get_u8();
+ ALOGI("status = %u\n", setup_response.status);
+ break;
+ case TWT_ATTRIBUTE_TRIGGER_TYPE:
+ setup_response.trigger_type = it.get_u8();
+ ALOGI("trigger type = %u\n", setup_response.trigger_type);
+ break;
+ case TWT_ATTRIBUTE_WAKE_DUR_US:
+ setup_response.wake_dur_us = it.get_u32();
+ ALOGI("wake_dur_us = %d\n", setup_response.wake_dur_us);
+ break;
+ case TWT_ATTRIBUTE_WAKE_INT_US:
+ setup_response.wake_int_us = it.get_u32();
+ ALOGI("wake_int_us = %d\n", setup_response.wake_int_us);
+ break;
+ case TWT_ATTRIBUTE_WAKE_TIME_OFF_US:
+ setup_response.wake_time_off_us = it.get_u32();
+ ALOGI("wake_time_off_us = %d\n", setup_response.wake_time_off_us);
+ break;
+ default:
+ if (attr_type != TWT_ATTRIBUTE_SUB_EVENT) {
+ ALOGE("Unknown attr_type: %d\n", attr_type);
+ }
+ break;
+ }
+ }
+ GET_TWT_HANDLE(twt_info)->mHandlers.EventTwtSetupResponse(&setup_response);
+ break;
+ case TWT_TEARDOWN_COMPLETION:
+ TwtTeardownCompletion teardown_event;
+ for (nl_iterator it(vendor_data); it.has_next(); it.next()) {
+ attr_type = it.get_type();
+ switch (attr_type) {
+ case TWT_ATTRIBUTE_CONFIG_ID:
+ ALOGI("config_id = %u\n", it.get_u8());
+ teardown_event.config_id = it.get_u8();
+ break;
+ case TWT_ATTRIBUTE_STATUS:
+ teardown_event.status = it.get_u8();
+ ALOGI("status = %u\n", teardown_event.status);
+ break;
+ case TWT_ATTRIBUTE_ALL_TWT:
+ teardown_event.all_twt = it.get_u8();
+ ALOGI("all_twt = %d\n", teardown_event.all_twt);
+ break;
+ case TWT_ATTRIBUTE_REASON_CODE:
+ teardown_event.reason = (TwtTeardownReason)it.get_u8();
+ ALOGI("reason = %u\n", teardown_event.reason);
+ break;
+ default:
+ if (attr_type != TWT_ATTRIBUTE_SUB_EVENT) {
+ ALOGE("Unknown attr_type: %d\n", attr_type);
+ }
+ break;
+ }
+ }
+ GET_TWT_HANDLE(twt_info)->mHandlers.EventTwtTeardownCompletion(&teardown_event);
+ break;
+ case TWT_INFORM_FRAME:
+ TwtInfoFrameReceived info_frame_event;
+ for (nl_iterator it(vendor_data); it.has_next(); it.next()) {
+ attr_type = it.get_type();
+ switch (attr_type) {
+ case TWT_ATTRIBUTE_CONFIG_ID:
+ ALOGI("config_id = %u\n", it.get_u8());
+ info_frame_event.config_id = it.get_u8();
+ break;
+ case TWT_ATTRIBUTE_REASON_CODE:
+ info_frame_event.reason = (TwtInfoFrameReason)it.get_u8();
+ ALOGI("reason = %u\n", info_frame_event.reason);
+ break;
+ case TWT_ATTRIBUTE_STATUS:
+ info_frame_event.status = it.get_u8();
+ ALOGI("status = %u\n", info_frame_event.status);
+ break;
+ case TWT_ATTRIBUTE_ALL_TWT:
+ info_frame_event.all_twt = it.get_u8();
+ ALOGI("all_twt = %d\n", info_frame_event.all_twt);
+ break;
+ case TWT_ATTRIBUTE_RESUMED:
+ info_frame_event.twt_resumed = it.get_u8();
+ ALOGI("twt_resumed = %u\n", info_frame_event.twt_resumed);
+ break;
+ default:
+ if (attr_type != TWT_ATTRIBUTE_SUB_EVENT) {
+ ALOGE("Unknown attr_type: %d\n", attr_type);
+ }
+ break;
+ }
+ }
+ GET_TWT_HANDLE(twt_info)->mHandlers.EventTwtInfoFrameReceived(&info_frame_event);
+ break;
+ case TWT_NOTIFY:
+ TwtDeviceNotify notif_event;
+ for (nl_iterator it(vendor_data); it.has_next(); it.next()) {
+ attr_type = it.get_type();
+ switch (attr_type) {
+ case TWT_ATTRIBUTE_NOTIFICATION:
+ notif_event.notification = (TwtNotification)it.get_u8();
+ ALOGI("notification = %u\n", notif_event.notification);
+ break;
+ default:
+ if (attr_type != TWT_ATTRIBUTE_SUB_EVENT) {
+ ALOGE("Unknown attr_type: %d\n", attr_type);
+ }
+ break;
+ }
+ }
+ GET_TWT_HANDLE(twt_info)->mHandlers.EventTwtDeviceNotify(&notif_event);
+ break;
+ default:
+ ALOGE("Unknown event_type: %d\n", sub_event_type);
+ break;
+ }
+ return;
+}
+
+void HandleTwtEvent(nlattr *vendor_data) {
+ u8 sub_event_type = 0;
+ u8 event_type = 0;
+
+ for (nl_iterator it(vendor_data); it.has_next(); it.next()) {
+ event_type = it.get_type();
+ if (event_type == TWT_ATTRIBUTE_SUB_EVENT) {
+ sub_event_type = it.get_u8();
+ if (is_twt_sub_event(sub_event_type)) {
+ EventGetAttributeData(sub_event_type, vendor_data);
+ }
+ }
+ }
+ return;
+}
+
+class TwtEventCap : public WifiCommand
+{
+ public:
+ TwtEventCap(wifi_interface_handle iface, int id)
+ : WifiCommand("TwtCommand", iface, id)
+ {}
+
+ int start()
+ {
+ registerTwtVendorEvents();
+ return WIFI_SUCCESS;
+ }
+
+ int handleResponse(WifiEvent& reply) {
+ return NL_SKIP;
+ }
+
+ void registerTwtVendorEvents()
+ {
+ registerVendorHandler(BRCM_OUI, BRCM_VENDOR_EVENT_TWT);
+ }
+
+ void unregisterTwtVendorEvents()
+ {
+ unregisterVendorHandler(BRCM_OUI, BRCM_VENDOR_EVENT_TWT);
+ }
+
+ int handleEvent(WifiEvent& event) {
+ u16 attr_type;
+ TwtEventType twt_event;
+
+ nlattr *vendor_data = event.get_attribute(NL80211_ATTR_VENDOR_DATA);
+ int len = event.get_vendor_data_len();
+ int event_id = event.get_vendor_subcmd();
+
+ ALOGI("EventCapture: Received TWT event: %d\n", event_id);
+ if (!vendor_data || len == 0) {
+ ALOGE("No event data found");
+ return NL_SKIP;
+ }
+
+ switch (event_id) {
+ case BRCM_VENDOR_EVENT_TWT: {
+ ALOGE("Handle TWT event: %d\n", event_id);
+ HandleTwtEvent(vendor_data);
+ break;
+ }
+ default:
+ break;
+ }
+ return NL_SKIP;
+ }
+};
+
+/* To see event prints in console */
+wifi_error twt_event_check_request(transaction_id id, wifi_interface_handle iface)
+{
+ TwtEventCap *cmd = new TwtEventCap(iface, id);
+ if (cmd == NULL) {
+ return WIFI_ERROR_NOT_SUPPORTED;
+ }
+ return (wifi_error)cmd->start();
+}
+
+//////////////////////////////////////////////////////////////////////////
+class GetTwtCapabilitiesCommand : public WifiCommand
+{
+ TwtCapabilitySet *mCapabilities;
+public:
+ GetTwtCapabilitiesCommand(wifi_interface_handle iface, TwtCapabilitySet *capabilities)
+ : WifiCommand("GetTwtCapabilitiesCommand", iface, 0), mCapabilities(capabilities)
+ {
+ memset(mCapabilities, 0, sizeof(*mCapabilities));
+ }
+
+ virtual int create() {
+ ALOGD("Creating message to get twt capabilities; iface\n");
+
+ int ret = mMsg.create(GOOGLE_OUI, TWT_SUBCMD_GETCAPABILITY);
+ if (ret < 0) {
+ ALOGE("Failed to send the twt cap cmd, err = %d\n", ret);
+ }
+ ALOGD("Success to send twt cap cmd, err = %d\n", ret);
+ return ret;
+ }
+
+private:
+ TwtCapability parseTwtCap(uint32_t twt_peer_cap) {
+ TwtCapability cap;
+ cap.requester_supported = (twt_peer_cap & WL_TWT_CAP_FLAGS_REQ_SUPPORT) ? 1 : 0;
+ cap.responder_supported = (twt_peer_cap & WL_TWT_CAP_FLAGS_RESP_SUPPORT) ? 1 : 0;
+ cap.broadcast_twt_supported = (twt_peer_cap & WL_TWT_CAP_FLAGS_BTWT_SUPPORT) ? 1 : 0;
+ cap.flexibile_twt_supported = (twt_peer_cap & WL_TWT_CAP_FLAGS_FLEX_SUPPORT) ? 1 : 0;
+ return cap;
+ }
+
+protected:
+ virtual int handleResponse(WifiEvent& reply) {
+
+ ALOGI("In GetTwtCapabilitiesCommand::handleResponse");
+
+ if (reply.get_cmd() != NL80211_CMD_VENDOR) {
+ ALOGD("Ignoring reply with cmd = %d", reply.get_cmd());
+ return NL_SKIP;
+ }
+
+ int id = reply.get_vendor_id();
+ int subcmd = reply.get_vendor_subcmd();
+ uint32_t twt_device_cap, twt_peer_cap;
+
+ nlattr *data = reply.get_attribute(NL80211_ATTR_VENDOR_DATA);
+ int len = reply.get_vendor_data_len();
+
+ ALOGD("Id = %0x, subcmd = %d, len = %d, expected len = %d", id, subcmd, len);
+ if (data == NULL || len == 0) {
+ ALOGE("no vendor data in GetTwtCapabilitiesCommand response; ignoring it\n");
+ return NL_SKIP;
+ }
+
+ for (nl_iterator it(data); it.has_next(); it.next()) {
+ switch (it.get_type()) {
+ case TWT_ATTRIBUTE_DEVICE_CAP:
+ twt_device_cap = it.get_u32();
+ mCapabilities->device_capability = parseTwtCap(twt_device_cap);
+ break;
+ case TWT_ATTRIBUTE_PEER_CAP:
+ twt_peer_cap = it.get_u32();
+ mCapabilities->peer_capability = parseTwtCap(twt_peer_cap);
+ break;
+ default:
+ ALOGE("Ignoring invalid attribute type = %d, size = %d\n",
+ it.get_type(), it.get_len());
+ break;
+ }
+ }
+
+ ALOGE("Out GetTwtCapabilitiesCommand::handleResponse\n");
+ return NL_OK;
+ }
+};
+
+/* API to get TWT capability */
+wifi_error twt_get_capability(wifi_interface_handle iface,
+ TwtCapabilitySet *twt_cap_set)
+{
+ if (iface == NULL) {
+ ALOGE("twt_get_capability: NULL iface pointer provided."
+ " Exit.");
+ return WIFI_ERROR_INVALID_ARGS;
+ }
+
+ if (twt_cap_set == NULL) {
+ ALOGE("twt_get_capability: NULL capabilities pointer provided."
+ " Exit.");
+ return WIFI_ERROR_INVALID_ARGS;
+ }
+
+ GetTwtCapabilitiesCommand command(iface, twt_cap_set);
+ return (wifi_error) command.requestResponse();
+}
+
+//////////////////////////////////////////////////////////////////////////
+class GetTwtStatsCommand : public WifiCommand
+{
+ TwtStats* mStats;
+ u8 mConfig_id;
+public:
+ GetTwtStatsCommand(wifi_interface_handle iface, u8 config_id, TwtStats *stats)
+ : WifiCommand("GetTwtStatsCommand", iface, 0), mConfig_id(config_id), mStats(stats)
+ {
+ memset(mStats, 0, sizeof(*mStats));
+ }
+
+ virtual int create() {
+ ALOGD("Creating message to get twt stats; iface = %d", mIfaceInfo->id);
+
+ int ret = mMsg.create(GOOGLE_OUI, TWT_SUBCMD_GETSTATS);
+ if (ret < 0) {
+ return ret;
+ }
+
+ nlattr *data = mMsg.attr_start(NL80211_ATTR_VENDOR_DATA);
+ ret = mMsg.put_u8(TWT_ATTRIBUTE_CONFIG_ID, mConfig_id);
+ if (ret < 0) {
+ ALOGE("Failed to set mConfig_id %d\n", mConfig_id);
+ return ret;
+ }
+
+ ALOGI("Successfully configured config id %d\n", mConfig_id);
+ mMsg.attr_end(data);
+ return WIFI_SUCCESS;
+ }
+
+protected:
+ virtual int handleResponse(WifiEvent& reply) {
+
+ ALOGI("In GetTwtStatsCommand::handleResponse");
+
+ if (reply.get_cmd() != NL80211_CMD_VENDOR) {
+ ALOGD("Ignoring reply with cmd = %d", reply.get_cmd());
+ return NL_SKIP;
+ }
+
+ int id = reply.get_vendor_id();
+ int subcmd = reply.get_vendor_subcmd();
+
+ nlattr *data = reply.get_attribute(NL80211_ATTR_VENDOR_DATA);
+ int len = reply.get_vendor_data_len();
+
+ ALOGD("Id = %0x, subcmd = %d, len = %d, expected len = %d", id, subcmd, len);
+ if (data == NULL || len == 0) {
+ ALOGE("no vendor data in GetTwtStatsCommand response; ignoring it\n");
+ return NL_SKIP;
+ }
+
+ for (nl_iterator it(data); it.has_next(); it.next()) {
+ switch (it.get_type()) {
+ case TWT_ATTRIBUTE_CONFIG_ID:
+ mStats->config_id = it.get_u8();
+ break;
+ case TWT_ATTRIBUTE_AVG_PKT_NUM_TX:
+ mStats->avg_pkt_num_tx = it.get_u32();
+ break;
+ case TWT_ATTRIBUTE_AVG_PKT_NUM_RX:
+ mStats->avg_pkt_num_rx = it.get_u32();
+ break;
+ case TWT_ATTRIBUTE_AVG_PKT_SIZE_TX:
+ mStats->avg_tx_pkt_size = it.get_u32();
+ break;
+ case TWT_ATTRIBUTE_AVG_PKT_SIZE_RX:
+ mStats->avg_rx_pkt_size = it.get_u32();
+ break;
+ case TWT_ATTRIBUTE_AVG_EOSP_DUR:
+ mStats->avg_eosp_dur_us = it.get_u32();
+ break;
+ case TWT_ATTRIBUTE_EOSP_COUNT:
+ mStats->eosp_count = it.get_u32();
+ break;
+ case TWT_ATTRIBUTE_NUM_SP:
+ mStats->num_sp = it.get_u32();
+ break;
+ default:
+ ALOGE("Ignoring invalid attribute type = %d, size = %d\n",
+ it.get_type(), it.get_len());
+ break;
+ }
+ }
+
+ return NL_OK;
+ }
+};
+
+/* API to get TWT stats */
+wifi_error twt_get_stats(wifi_interface_handle iface, u8 config_id, TwtStats* stats)
+{
+ if (iface == NULL) {
+ ALOGE("twt_get_stats: NULL iface pointer provided."
+ " Exit.");
+ return WIFI_ERROR_INVALID_ARGS;
+ }
+
+ if (stats == NULL) {
+ ALOGE("TwtCapabilitySet: NULL capabilities pointer provided."
+ " Exit.");
+ return WIFI_ERROR_INVALID_ARGS;
+ }
+
+ GetTwtStatsCommand command(iface, config_id, stats);
+ return (wifi_error) command.requestResponse();
+}
+
+//////////////////////////////////////////////////////////////////////////////////////
+class ClearTwtStatsCommand : public WifiCommand
+{
+ u8 mConfig_id;
+public:
+ ClearTwtStatsCommand(wifi_interface_handle iface, u8 config_id)
+ : WifiCommand("ClearTwtStatsCommand", iface, 0), mConfig_id(config_id)
+ {
+ }
+
+ virtual int create() {
+ ALOGD("Creating message to clear twt stats; config_id = %d\n", mConfig_id);
+
+ int ret = mMsg.create(GOOGLE_OUI, TWT_SUBCMD_CLR_STATS);
+ if (ret < 0) {
+ return ret;
+ }
+
+ nlattr *data = mMsg.attr_start(NL80211_ATTR_VENDOR_DATA);
+ ret = mMsg.put_u8(TWT_ATTRIBUTE_CONFIG_ID, mConfig_id);
+ if (ret < 0) {
+ ALOGE("Failed to set mConfig_id %d\n", mConfig_id);
+ return ret;
+ }
+
+ ALOGI("Successfully configured config id %d\n", mConfig_id);
+ mMsg.attr_end(data);
+ return WIFI_SUCCESS;
+ }
+
+protected:
+ virtual int handleResponse(WifiEvent& reply) {
+ ALOGD("In ClearTwtStatsCommand::handleResponse");
+ /* Nothing to do on response! */
+ return NL_SKIP;
+ }
+};
+
+/* API to clear TWT stats */
+wifi_error twt_clear_stats(wifi_interface_handle iface, u8 config_id)
+{
+ if (iface == NULL || !config_id) {
+ ALOGE("twt_clear_stats: NULL iface pointer provided."
+ " Exit.");
+ return WIFI_ERROR_INVALID_ARGS;
+ }
+ ALOGE("twt_clear_stats: config id: %d\n", config_id);
+
+ ClearTwtStatsCommand command(iface, config_id);
+ return (wifi_error) command.requestResponse();
+}
+
+////////////////////////////////////////////////////////////////////////////////
+class TwtFeatureRequest : public WifiCommand
+{
+ TwtRequest reqContext;
+ TwtRequestType mType;
+
+ public:
+ TwtFeatureRequest(wifi_interface_handle iface,
+ TwtRequest params, TwtRequestType cmdType)
+ : WifiCommand("TwtFeatureRequest", iface, 0), reqContext(params), mType(cmdType)
+ {
+ }
+
+ int createRequest(WifiRequest& request)
+ {
+ ALOGI("TWT CMD: %s\n", TwtCmdToString(mType));
+ if (mType == TWT_SETUP_REQUEST) {
+ return createTwtSetupRequest(request, (TwtSetupRequest *)reqContext);
+ } else if (mType == TWT_INFO_FRAME_REQUEST) {
+ return createInfoFrameRequest(request, (TwtInfoFrameRequest *)reqContext);
+ } else if (mType == TWT_TEAR_DOWN_REQUEST) {
+ return createTearDownRequest(request, (TwtTeardownRequest *)reqContext);
+ } else {
+ ALOGE("%s: Unknown TWT request: %d\n", __func__, mType);
+ return WIFI_ERROR_UNKNOWN;
+ }
+
+ return WIFI_SUCCESS;
+ }
+
+ int createTwtSetupRequest(WifiRequest& request, TwtSetupRequest *mParams)
+ {
+ int result = request.create(GOOGLE_OUI, TWT_SUBCMD_SETUP_REQUEST);
+ if (result < 0) {
+ ALOGE("%s Failed to create request, result = %d\n", __func__, result);
+ return result;
+ }
+
+ /* If handle is 0xFFFF, then update instance_id in response of this request
+ * otherwise, update not needed
+ */
+ nlattr *data = request.attr_start(NL80211_ATTR_VENDOR_DATA);
+ if (mParams->config_id) {
+ result = request.put_u8(TWT_ATTRIBUTE_CONFIG_ID, mParams->config_id);
+ if (result < 0) {
+ ALOGE("%s: Failed to fill config_id = %d, result = %d\n",
+ __func__, mParams->config_id, result);
+ return result;
+ }
+ }
+
+ if (mParams->negotiation_type) {
+ result = request.put_u8(TWT_ATTRIBUTE_NEG_TYPE, mParams->negotiation_type);
+ if (result < 0) {
+ ALOGE("%s: Failed to fill negotiation_type = %d, result = %d\n",
+ __func__, mParams->negotiation_type, result);
+ return result;
+ }
+ }
+ if (mParams->trigger_type) {
+ result = request.put_u8(TWT_ATTRIBUTE_TRIGGER_TYPE, mParams->trigger_type);
+ if (result < 0) {
+ ALOGE("%s: Failed to fill trigger_type = %d, result = %d\n",
+ __func__, mParams->trigger_type, result);
+ return result;
+ }
+ }
+ if (mParams->wake_dur_us) {
+ result = request.put_u32(TWT_ATTRIBUTE_WAKE_DUR_US, mParams->wake_dur_us);
+ if (result < 0) {
+ ALOGE("%s: Failed to fill wake_dur_us = %d, result = %d\n",
+ __func__, mParams->wake_dur_us, result);
+ return result;
+ }
+ }
+ if (mParams->wake_int_us) {
+ result = request.put_u32(TWT_ATTRIBUTE_WAKE_INT_US, mParams->wake_int_us);
+ if (result < 0) {
+ ALOGE("%s: Failed to fill wake_int_us = %d, result = %d\n",
+ __func__, mParams->wake_int_us, result);
+ return result;
+ }
+ }
+ if (mParams->wake_int_min_us) {
+ result = request.put_u32(TWT_ATTRIBUTE_WAKE_INT_MIN_US, mParams->wake_int_min_us);
+ if (result < 0) {
+ ALOGE("%s: Failed to fill wake_int_min_us = %d, result = %d\n",
+ __func__, mParams->wake_int_min_us, result);
+ return result;
+ }
+ }
+ if (mParams->wake_int_max_us) {
+ result = request.put_u32(TWT_ATTRIBUTE_WAKE_INT_MAX_US, mParams->wake_int_max_us);
+ if (result < 0) {
+ ALOGE("%s: Failed to fill wake_int_max_us = %d, result = %d\n",
+ __func__, mParams->wake_int_max_us, result);
+ return result;
+ }
+ }
+ if (mParams->wake_dur_min_us) {
+ result = request.put_u32(TWT_ATTRIBUTE_WAKE_DUR_MIN_US, mParams->wake_dur_min_us);
+ if (result < 0) {
+ ALOGE("%s: Failed to fill wake_dur_min_us = %d, result = %d\n",
+ __func__, mParams->wake_dur_min_us, result);
+ return result;
+ }
+ }
+ if (mParams->wake_dur_max_us) {
+ result = request.put_u32(TWT_ATTRIBUTE_WAKE_DUR_MAX_US, mParams->wake_dur_max_us);
+ if (result < 0) {
+ ALOGE("%s: Failed to fill wake_dur_max_us = %d, result = %d\n",
+ __func__, mParams->wake_dur_max_us, result);
+ return result;
+ }
+ }
+ if (mParams->avg_pkt_size) {
+ result = request.put_u32(TWT_ATTRIBUTE_AVG_PKT_SIZE, mParams->avg_pkt_size);
+ if (result < 0) {
+ ALOGE("%s: Failed to fill avg_pkt_size = %d, result = %d\n",
+ __func__, mParams->avg_pkt_size, result);
+ return result;
+ }
+ }
+ if (mParams->avg_pkt_num) {
+ result = request.put_u32(TWT_ATTRIBUTE_AVG_PKT_NUM, mParams->avg_pkt_num);
+ if (result < 0) {
+ ALOGE("%s: Failed to fill avg_pkt_num = %d, result = %d\n",
+ __func__, mParams->avg_pkt_num, result);
+ return result;
+ }
+ }
+ if (mParams->wake_time_off_us) {
+ result = request.put_u32(TWT_ATTRIBUTE_WAKE_TIME_OFF_US, mParams->wake_time_off_us);
+ if (result < 0) {
+ ALOGE("%s: Failed to fill wake_time_off_us = %d, result = %d\n",
+ __func__, mParams->wake_time_off_us, result);
+ return result;
+ }
+ }
+ request.attr_end(data);
+
+ ALOGI("Returning successfully\n");
+ return result;
+ }
+
+ int createInfoFrameRequest(WifiRequest& request, TwtInfoFrameRequest *mParams)
+ {
+ int result = request.create(GOOGLE_OUI, TWT_SUBCMD_INFO_FRAME_REQUEST);
+ if (result < 0) {
+ ALOGE("%s: Failed to create request, result = %d\n", __func__, result);
+ return result;
+ }
+
+ nlattr *data = request.attr_start(NL80211_ATTR_VENDOR_DATA);
+ if (mParams->config_id) {
+ result = request.put_u8(TWT_ATTRIBUTE_CONFIG_ID, mParams->config_id);
+ if (result < 0) {
+ ALOGE("%s: Failed to fill config_id = %d, result = %d\n",
+ __func__, mParams->config_id, result);
+ return result;
+ }
+ }
+ if (mParams->resume_time_us) {
+ result = request.put_u32(TWT_ATTRIBUTE_RESUME_TIME_US, mParams->resume_time_us);
+ if (result < 0) {
+ ALOGE("%s: Failed to fill resume_time_us = %d, result = %d\n",
+ __func__, mParams->resume_time_us, result);
+ return result;
+ }
+ }
+ if (mParams->all_twt) {
+ result = request.put_u8(TWT_ATTRIBUTE_ALL_TWT, mParams->all_twt);
+ if (result < 0) {
+ ALOGE("%s: Failed to fill all_twt = %d, result = %d\n",
+ __func__, mParams->all_twt, result);
+ return result;
+ }
+ }
+ request.attr_end(data);
+ return WIFI_SUCCESS;
+ }
+
+ int createTearDownRequest(WifiRequest& request, TwtTeardownRequest *mParams)
+ {
+ int result = request.create(GOOGLE_OUI, TWT_SUBCMD_TEAR_DOWN_REQUEST);
+ if (result < 0) {
+ ALOGE("%s: Failed to create request, result = %d\n", __func__, result);
+ return result;
+ }
+
+ nlattr *data = request.attr_start(NL80211_ATTR_VENDOR_DATA);
+ if (mParams->config_id) {
+ result = request.put_u8(TWT_ATTRIBUTE_CONFIG_ID, mParams->config_id);
+ if (result < 0) {
+ ALOGE("%s: Failed to fill config_id = %d, result = %d\n",
+ __func__, mParams->config_id, result);
+ return result;
+ }
+ }
+ if (mParams->negotiation_type) {
+ result = request.put_u8(TWT_ATTRIBUTE_NEG_TYPE, mParams->negotiation_type);
+ if (result < 0) {
+ ALOGE("%s: Failed to fill negotiation_type = %d, result = %d\n",
+ __func__, mParams->negotiation_type, result);
+ return result;
+ }
+ }
+ if (mParams->all_twt) {
+ result = request.put_u8(TWT_ATTRIBUTE_ALL_TWT, mParams->all_twt);
+ if (result < 0) {
+ ALOGE("%s: Failed to fill all_twt = %d, result = %d\n",
+ __func__, mParams->all_twt, result);
+ return result;
+ }
+ }
+ request.attr_end(data);
+ return WIFI_SUCCESS;
+ }
+
+ int open()
+ {
+ WifiRequest request(familyId(), ifaceId());
+ int result = createRequest(request);
+ if (result != WIFI_SUCCESS) {
+ ALOGE("%s: failed to create setup request; result = %d", __func__, result);
+ return result;
+ }
+
+ result = requestResponse(request);
+ if (result != WIFI_SUCCESS) {
+ ALOGE("%s: failed to configure setup; result = %d", __func__, result);
+ return result;
+ }
+
+ request.destroy();
+ return WIFI_SUCCESS;
+ }
+
+ void registerTwtVendorEvents()
+ {
+ registerVendorHandler(BRCM_OUI, BRCM_VENDOR_EVENT_TWT);
+ }
+
+ void unregisterTwtVendorEvents()
+ {
+ unregisterVendorHandler(BRCM_OUI, BRCM_VENDOR_EVENT_TWT);
+ }
+
+ virtual int handleResponse(WifiEvent& reply) {
+ ALOGD("Request complete!");
+ /* Nothing to do on response! */
+ return NL_SKIP;
+ }
+
+ int handleEvent(WifiEvent& event) {
+ u16 attr_type;
+ TwtEventType twt_event;
+
+ nlattr *vendor_data = event.get_attribute(NL80211_ATTR_VENDOR_DATA);
+ int len = event.get_vendor_data_len();
+ int event_id = event.get_vendor_subcmd();
+ ALOGI("Received TWT event: %d\n", event_id);
+
+ if (!vendor_data || len == 0) {
+ ALOGE("No event data found");
+ return NL_SKIP;
+ }
+
+ switch (event_id) {
+ case BRCM_VENDOR_EVENT_TWT: {
+ HandleTwtEvent(vendor_data);
+ break;
+ }
+ default:
+ ALOGE("Unknown event: %d\n", event_id);
+ break;
+ }
+ return NL_SKIP;
+ }
+
+};
+
+void twt_deinit_handler()
+{
+ if (twt_info.twt_feature_request) {
+ /* register for Twt vendor events with info mac class*/
+ TwtFeatureRequest *cmd_event = (TwtFeatureRequest*)(twt_info.twt_feature_request);
+ cmd_event->unregisterTwtVendorEvents();
+ delete (TwtFeatureRequest*)twt_info.twt_feature_request;
+ twt_info.twt_feature_request = NULL;
+ }
+ if (TWT_HANDLE(twt_info)) {
+ delete GET_TWT_HANDLE(twt_info);
+ TWT_HANDLE(twt_info) = NULL;
+ }
+ ALOGI("wifi twt internal clean up done");
+ return;
+}
+
+wifi_error twt_register_handler(wifi_interface_handle iface,
+ TwtCallbackHandler handlers)
+{
+ wifi_handle handle = getWifiHandle(iface);
+ if (TWT_HANDLE(twt_info)) {
+ /* cleanup and re-register */
+ twt_deinit_handler();
+ }
+ memset(&twt_info, 0, sizeof(twt_info));
+ TWT_HANDLE(twt_info) = new TwtHandle(handle, handlers);
+ twt_info.twt_feature_request =
+ (void*)new TwtFeatureRequest(iface, NULL, TWT_LAST);
+ NULL_CHECK_RETURN(twt_info.twt_feature_request,
+ "memory allocation failure", WIFI_ERROR_OUT_OF_MEMORY);
+ TwtFeatureRequest *cmd_event = (TwtFeatureRequest*)(twt_info.twt_feature_request);
+ cmd_event->registerTwtVendorEvents();
+ return WIFI_SUCCESS;
+}
+
+wifi_error twt_setup_request(wifi_interface_handle iface, TwtSetupRequest* msg)
+{
+ wifi_error ret = WIFI_SUCCESS;
+ TwtFeatureRequest *cmd;
+ TwtRequestType cmdType = TWT_SETUP_REQUEST;
+
+ cmd = new TwtFeatureRequest(iface, (void *)msg, cmdType);
+ NULL_CHECK_RETURN(cmd, "memory allocation failure", WIFI_ERROR_OUT_OF_MEMORY);
+
+ ret = (wifi_error)cmd->open();
+ if (ret != WIFI_SUCCESS) {
+ ALOGE("%s : failed in open, error = %d\n", __func__, ret);
+ }
+ cmd->releaseRef();
+ return ret;
+}
+
+wifi_error twt_info_frame_request(wifi_interface_handle iface, TwtInfoFrameRequest* msg)
+{
+ wifi_error ret = WIFI_SUCCESS;
+ TwtFeatureRequest *cmd;
+ TwtRequestType cmdType = TWT_INFO_FRAME_REQUEST;
+
+ cmd = new TwtFeatureRequest(iface, (void *)msg, cmdType);
+ NULL_CHECK_RETURN(cmd, "memory allocation failure", WIFI_ERROR_OUT_OF_MEMORY);
+
+ ret = (wifi_error)cmd->open();
+ if (ret != WIFI_SUCCESS) {
+ ALOGE("%s : failed in open, error = %d\n", __func__, ret);
+ }
+ cmd->releaseRef();
+ return ret;
+}
+
+wifi_error twt_teardown_request(wifi_interface_handle iface, TwtTeardownRequest* msg)
+{
+ wifi_error ret = WIFI_SUCCESS;
+ TwtFeatureRequest *cmd;
+ TwtRequestType cmdType = TWT_TEAR_DOWN_REQUEST;
+
+ cmd = new TwtFeatureRequest(iface, (void *)msg, cmdType);
+ NULL_CHECK_RETURN(cmd, "memory allocation failure", WIFI_ERROR_OUT_OF_MEMORY);
+
+ ret = (wifi_error)cmd->open();
+ if (ret != WIFI_SUCCESS) {
+ ALOGE("%s : failed in open, error = %d\n", __func__, ret);
+ }
+ cmd->releaseRef();
+ return ret;
+}
diff --git a/synadhd/wifi_hal/wifi_hal.cpp b/synadhd/wifi_hal/wifi_hal.cpp
new file mode 100755
index 0000000..239a0c1
--- /dev/null
+++ b/synadhd/wifi_hal/wifi_hal.cpp
@@ -0,0 +1,3053 @@
+/*
+ * Copyright (C) 2017 The Android Open Source Project
+ *
+ * Portions copyright (C) 2017 Broadcom Limited
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <stdint.h>
+#include <fcntl.h>
+#include <sys/socket.h>
+#include <netlink/genl/genl.h>
+#include <netlink/genl/family.h>
+#include <netlink/genl/ctrl.h>
+#include <linux/rtnetlink.h>
+#include <netpacket/packet.h>
+#include <linux/filter.h>
+#include <linux/errqueue.h>
+#include <errno.h>
+
+#include <linux/pkt_sched.h>
+#include <netlink/object-api.h>
+#include <netlink/netlink.h>
+#include <netlink/socket.h>
+#include <netlink/attr.h>
+#include <netlink/handlers.h>
+#include <netlink/msg.h>
+
+#include <dirent.h>
+#include <net/if.h>
+
+#include <sys/types.h>
+#include <unistd.h>
+
+#include "sync.h"
+
+#define LOG_TAG "WifiHAL"
+#include <log/log.h>
+
+#include "wifi_hal.h"
+#include "common.h"
+#include "cpp_bindings.h"
+#include "rtt.h"
+#include "syna_version.h"
+#include <stdio.h>
+#include <string>
+#include <vector>
+/*
+ BUGBUG: normally, libnl allocates ports for all connections it makes; but
+ being a static library, it doesn't really know how many other netlink connections
+ are made by the same process, if connections come from different shared libraries.
+ These port assignments exist to solve that problem - temporarily. We need to fix
+ libnl to try and allocate ports across the entire process.
+ */
+
+#define WIFI_HAL_CMD_SOCK_PORT 644
+#define WIFI_HAL_EVENT_SOCK_PORT 645
+#define MAX_VIRTUAL_IFACES 5
+#define WIFI_HAL_EVENT_BUFFER_NOT_AVAILABLE 105
+
+/*
+ * Defines for wifi_wait_for_driver_ready()
+ * Specify durations between polls and max wait time
+ */
+#define POLL_DRIVER_DURATION_US (100000)
+#define POLL_DRIVER_MAX_TIME_MS (10000)
+#define EVENT_BUF_SIZE 2048
+#define C2S(x) case x: return #x;
+
+static int internal_no_seq_check(nl_msg *msg, void *arg);
+static int internal_valid_message_handler(nl_msg *msg, void *arg);
+static int wifi_get_multicast_id(wifi_handle handle, const char *name, const char *group);
+static int wifi_add_membership(wifi_handle handle, const char *group);
+static wifi_error wifi_init_interfaces(wifi_handle handle);
+static wifi_error wifi_start_rssi_monitoring(wifi_request_id id, wifi_interface_handle
+ iface, s8 max_rssi, s8 min_rssi, wifi_rssi_event_handler eh);
+static wifi_error wifi_stop_rssi_monitoring(wifi_request_id id, wifi_interface_handle iface);
+static wifi_error wifi_set_packet_filter(wifi_interface_handle handle,
+ const u8 *program, u32 len);
+static wifi_error wifi_read_packet_filter(wifi_interface_handle handle, u32 src_offset,
+ u8 *host_dst, u32 length);
+static wifi_error wifi_get_packet_filter_capabilities(wifi_interface_handle handle,
+ u32 *version, u32 *max_len);
+static wifi_error wifi_configure_nd_offload(wifi_interface_handle iface, u8 enable);
+static wifi_error wifi_get_usable_channels(wifi_handle handle, u32 band_mask, u32 iface_mode_mask,
+ u32 filter_mask, u32 max_size, u32* size, wifi_usable_channel* channels);
+static wifi_error wifi_get_supported_radio_combinations_matrix(wifi_handle handle,
+ u32 max_size, u32* size, wifi_radio_combination_matrix *radio_combination_matrix);
+static wifi_error wifi_set_indoor_state(wifi_handle handle, bool isIndoor);
+
+static void wifi_cleanup_dynamic_ifaces(wifi_handle handle);
+typedef enum wifi_attr {
+ ANDR_WIFI_ATTRIBUTE_INVALID = 0,
+ ANDR_WIFI_ATTRIBUTE_NUM_FEATURE_SET = 1,
+ ANDR_WIFI_ATTRIBUTE_FEATURE_SET = 2,
+ ANDR_WIFI_ATTRIBUTE_PNO_RANDOM_MAC_OUI = 3,
+ ANDR_WIFI_ATTRIBUTE_NODFS_SET = 4,
+ ANDR_WIFI_ATTRIBUTE_COUNTRY = 5,
+ ANDR_WIFI_ATTRIBUTE_ND_OFFLOAD_VALUE = 6,
+ ANDR_WIFI_ATTRIBUTE_TCPACK_SUP_VALUE = 7,
+ ANDR_WIFI_ATTRIBUTE_LATENCY_MODE = 8,
+ ANDR_WIFI_ATTRIBUTE_RANDOM_MAC = 9,
+ ANDR_WIFI_ATTRIBUTE_TX_POWER_SCENARIO = 10,
+ ANDR_WIFI_ATTRIBUTE_THERMAL_MITIGATION = 11,
+ ANDR_WIFI_ATTRIBUTE_THERMAL_COMPLETION_WINDOW = 12,
+ ANDR_WIFI_ATTRIBUTE_VOIP_MODE = 13,
+ ANDR_WIFI_ATTRIBUTE_DTIM_MULTIPLIER = 14,
+ ANDR_WIFI_ATTRIBUTE_INDOOR = 15,
+ // Add more attribute here
+ ANDR_WIFI_ATTRIBUTE_MAX
+} wifi_attr_t;
+
+enum wifi_radio_combo_attributes {
+ ANDR_WIFI_ATTRIBUTE_RADIO_COMBO_INVALID = 0,
+ ANDR_WIFI_ATTRIBUTE_RADIO_COMBO_MATRIX = 1,
+ // Add more attribute here
+ ANDR_WIFI_ATTRIBUTE_RADIO_COMBO_MAX
+};
+
+enum wifi_rssi_monitor_attr {
+ RSSI_MONITOR_ATTRIBUTE_INVALID = 0,
+ RSSI_MONITOR_ATTRIBUTE_MAX_RSSI = 1,
+ RSSI_MONITOR_ATTRIBUTE_MIN_RSSI = 2,
+ RSSI_MONITOR_ATTRIBUTE_START = 3,
+ // Add more attribute here
+ RSSI_MONITOR_ATTRIBUTE_MAX
+};
+
+enum wifi_apf_attr {
+ APF_ATTRIBUTE_VERSION,
+ APF_ATTRIBUTE_MAX_LEN,
+ APF_ATTRIBUTE_PROGRAM,
+ APF_ATTRIBUTE_PROGRAM_LEN
+};
+
+enum apf_request_type {
+ GET_APF_CAPABILITIES,
+ SET_APF_PROGRAM,
+ READ_APF_PROGRAM
+};
+
+enum wifi_dscp_attr {
+ DSCP_ATTRIBUTE_INVALID = 0,
+ DSCP_ATTRIBUTE_START = 1,
+ DSCP_ATTRIBUTE_END = 2,
+ DSCP_ATTRIBUTE_AC = 3,
+ /* Add more attributes here */
+ DSCP_ATTRIBUTE_MAX
+};
+
+enum wifi_dscp_request_type {
+ SET_DSCP_TABLE,
+ RESET_DSCP_TABLE
+};
+
+enum wifi_chavoid_attr {
+ CHAVOID_ATTRIBUTE_INVALID = 0,
+ CHAVOID_ATTRIBUTE_CNT = 1,
+ CHAVOID_ATTRIBUTE_CONFIG = 2,
+ CHAVOID_ATTRIBUTE_BAND = 3,
+ CHAVOID_ATTRIBUTE_CHANNEL = 4,
+ CHAVOID_ATTRIBUTE_PWRCAP = 5,
+ CHAVOID_ATTRIBUTE_MANDATORY = 6,
+ /* Add more attributes here */
+ CHAVOID_ATTRIBUTE_MAX
+};
+
+enum wifi_usable_channel_attributes {
+ USABLECHAN_ATTRIBUTE_INVALID = 0,
+ USABLECHAN_ATTRIBUTE_BAND = 1,
+ USABLECHAN_ATTRIBUTE_IFACE = 2,
+ USABLECHAN_ATTRIBUTE_FILTER = 3,
+ USABLECHAN_ATTRIBUTE_MAX_SIZE = 4,
+ USABLECHAN_ATTRIBUTE_SIZE = 5,
+ USABLECHAN_ATTRIBUTE_CHANNELS = 6,
+ USABLECHAN_ATTRIBUTE_MAX
+};
+
+enum wifi_multista_attr {
+ MULTISTA_ATTRIBUTE_PRIM_CONN_IFACE,
+ MULTISTA_ATTRIBUTE_USE_CASE,
+ /* Add more attributes here */
+ MULTISTA_ATTRIBUTE_MAX
+};
+
+enum multista_request_type {
+ SET_PRIMARY_CONNECTION,
+ SET_USE_CASE
+};
+
+/* Initialize/Cleanup */
+
+void wifi_socket_set_local_port(struct nl_sock *sock, uint32_t port)
+{
+ uint32_t pid = getpid() & 0x3FFFFF;
+ nl_socket_set_local_port(sock, pid + (port << 22));
+}
+
+static nl_sock * wifi_create_nl_socket(int port)
+{
+ // ALOGI("Creating socket");
+ struct nl_sock *sock = nl_socket_alloc();
+ if (sock == NULL) {
+ ALOGE("Could not create handle");
+ return NULL;
+ }
+
+ wifi_socket_set_local_port(sock, port);
+
+ if (nl_connect(sock, NETLINK_GENERIC)) {
+ ALOGE("Could not connect handle");
+ nl_socket_free(sock);
+ return NULL;
+ }
+ return sock;
+}
+
+static const char *IfaceTypeToString(wifi_interface_type iface_type)
+{
+ switch (iface_type) {
+ C2S(WIFI_INTERFACE_TYPE_STA)
+ C2S(WIFI_INTERFACE_TYPE_AP)
+ C2S(WIFI_INTERFACE_TYPE_P2P)
+ C2S(WIFI_INTERFACE_TYPE_NAN)
+ default:
+ return "UNKNOWN_WIFI_INTERFACE_TYPE";
+ }
+}
+
+/*initialize function pointer table with Broadcom HHAL API*/
+wifi_error init_wifi_vendor_hal_func_table(wifi_hal_fn *fn)
+{
+ if (fn == NULL) {
+ return WIFI_ERROR_UNKNOWN;
+ }
+ fn->wifi_initialize = wifi_initialize;
+ fn->wifi_wait_for_driver_ready = wifi_wait_for_driver_ready;
+ fn->wifi_cleanup = wifi_cleanup;
+ fn->wifi_event_loop = wifi_event_loop;
+ fn->wifi_get_supported_feature_set = wifi_get_supported_feature_set;
+ fn->wifi_get_concurrency_matrix = wifi_get_concurrency_matrix;
+ fn->wifi_set_scanning_mac_oui = wifi_set_scanning_mac_oui;
+ fn->wifi_get_ifaces = wifi_get_ifaces;
+ fn->wifi_get_iface_name = wifi_get_iface_name;
+ fn->wifi_start_gscan = wifi_start_gscan;
+ fn->wifi_stop_gscan = wifi_stop_gscan;
+ fn->wifi_get_cached_gscan_results = wifi_get_cached_gscan_results;
+ fn->wifi_set_bssid_hotlist = wifi_set_bssid_hotlist;
+ fn->wifi_reset_bssid_hotlist = wifi_reset_bssid_hotlist;
+ fn->wifi_set_significant_change_handler = wifi_set_significant_change_handler;
+ fn->wifi_reset_significant_change_handler = wifi_reset_significant_change_handler;
+ fn->wifi_get_gscan_capabilities = wifi_get_gscan_capabilities;
+ fn->wifi_get_link_stats = wifi_get_link_stats;
+ fn->wifi_set_link_stats = wifi_set_link_stats;
+ fn->wifi_clear_link_stats = wifi_clear_link_stats;
+ fn->wifi_get_valid_channels = wifi_get_valid_channels;
+ fn->wifi_rtt_range_request = wifi_rtt_range_request;
+ fn->wifi_rtt_range_cancel = wifi_rtt_range_cancel;
+ fn->wifi_get_rtt_capabilities = wifi_get_rtt_capabilities;
+ fn->wifi_rtt_get_responder_info = wifi_rtt_get_responder_info;
+ fn->wifi_enable_responder = wifi_enable_responder;
+ fn->wifi_disable_responder = wifi_disable_responder;
+ fn->wifi_set_nodfs_flag = wifi_set_nodfs_flag;
+ fn->wifi_start_logging = wifi_start_logging;
+ fn->wifi_set_epno_list = wifi_set_epno_list;
+ fn->wifi_reset_epno_list = wifi_reset_epno_list;
+ fn->wifi_set_country_code = wifi_set_country_code;
+ fn->wifi_get_firmware_memory_dump = wifi_get_firmware_memory_dump;
+ fn->wifi_set_log_handler = wifi_set_log_handler;
+ fn->wifi_reset_log_handler = wifi_reset_log_handler;
+ fn->wifi_set_alert_handler = wifi_set_alert_handler;
+ fn->wifi_reset_alert_handler = wifi_reset_alert_handler;
+ fn->wifi_get_firmware_version = wifi_get_firmware_version;
+ fn->wifi_get_ring_buffers_status = wifi_get_ring_buffers_status;
+ fn->wifi_get_logger_supported_feature_set = wifi_get_logger_supported_feature_set;
+ fn->wifi_get_ring_data = wifi_get_ring_data;
+ fn->wifi_get_driver_version = wifi_get_driver_version;
+ fn->wifi_start_rssi_monitoring = wifi_start_rssi_monitoring;
+ fn->wifi_stop_rssi_monitoring = wifi_stop_rssi_monitoring;
+ fn->wifi_configure_nd_offload = wifi_configure_nd_offload;
+ fn->wifi_start_sending_offloaded_packet = wifi_start_sending_offloaded_packet;
+ fn->wifi_stop_sending_offloaded_packet = wifi_stop_sending_offloaded_packet;
+ fn->wifi_start_pkt_fate_monitoring = wifi_start_pkt_fate_monitoring;
+ fn->wifi_get_tx_pkt_fates = wifi_get_tx_pkt_fates;
+ fn->wifi_get_rx_pkt_fates = wifi_get_rx_pkt_fates;
+ fn->wifi_get_packet_filter_capabilities = wifi_get_packet_filter_capabilities;
+ fn->wifi_get_wake_reason_stats = wifi_get_wake_reason_stats;
+ fn->wifi_set_packet_filter = wifi_set_packet_filter;
+ fn->wifi_enable_firmware_roaming = wifi_enable_firmware_roaming;
+ fn->wifi_get_roaming_capabilities = wifi_get_roaming_capabilities;
+ fn->wifi_configure_roaming = wifi_configure_roaming;
+ fn->wifi_nan_register_handler = nan_register_handler;
+ fn->wifi_nan_enable_request = nan_enable_request;
+ fn->wifi_nan_disable_request = nan_disable_request;
+ fn->wifi_nan_publish_request = nan_publish_request;
+ fn->wifi_nan_publish_cancel_request = nan_publish_cancel_request;
+ fn->wifi_nan_subscribe_request = nan_subscribe_request;
+ fn->wifi_nan_subscribe_cancel_request = nan_subscribe_cancel_request;
+ fn->wifi_nan_transmit_followup_request = nan_transmit_followup_request;
+ fn->wifi_nan_stats_request = nan_stats_request;
+ fn->wifi_nan_config_request = nan_config_request;
+ fn->wifi_nan_tca_request = nan_tca_request;
+ fn->wifi_nan_beacon_sdf_payload_request = nan_beacon_sdf_payload_request;
+ fn->wifi_nan_get_version = nan_get_version;
+ fn->wifi_nan_get_capabilities = nan_get_capabilities;
+ fn->wifi_nan_data_interface_create = nan_data_interface_create;
+ fn->wifi_nan_data_interface_delete = nan_data_interface_delete;
+ fn->wifi_nan_data_request_initiator = nan_data_request_initiator;
+ fn->wifi_nan_data_indication_response = nan_data_indication_response;
+ fn->wifi_nan_data_end = nan_data_end;
+ fn->wifi_set_latency_mode = wifi_set_latency_mode;
+ fn->wifi_select_tx_power_scenario = wifi_select_tx_power_scenario;
+ fn->wifi_reset_tx_power_scenario = wifi_reset_tx_power_scenario;
+ fn->wifi_read_packet_filter = wifi_read_packet_filter;
+ fn->wifi_set_subsystem_restart_handler = wifi_set_subsystem_restart_handler;
+ fn->wifi_set_thermal_mitigation_mode = wifi_set_thermal_mitigation_mode;
+ fn->wifi_map_dscp_access_category = wifi_map_dscp_access_category;
+ fn->wifi_reset_dscp_mapping = wifi_reset_dscp_mapping;
+ fn->wifi_virtual_interface_create = wifi_virtual_interface_create;
+ fn->wifi_virtual_interface_delete = wifi_virtual_interface_delete;
+ fn->wifi_set_coex_unsafe_channels = wifi_set_coex_unsafe_channels;
+ fn->wifi_twt_get_capability = twt_get_capability;
+ fn->wifi_twt_register_handler = twt_register_handler;
+ fn->wifi_twt_setup_request = twt_setup_request;
+ fn->wifi_twt_teardown_request = twt_teardown_request;
+ fn->wifi_twt_info_frame_request = twt_info_frame_request;
+ fn->wifi_twt_get_stats = twt_get_stats;
+ fn->wifi_twt_clear_stats = twt_clear_stats;
+ fn->wifi_multi_sta_set_primary_connection = wifi_multi_sta_set_primary_connection;
+ fn->wifi_multi_sta_set_use_case = wifi_multi_sta_set_use_case;
+ fn->wifi_set_voip_mode = wifi_set_voip_mode;
+ fn->wifi_set_dtim_config = wifi_set_dtim_config;
+ fn->wifi_get_usable_channels = wifi_get_usable_channels;
+ fn->wifi_trigger_subsystem_restart = wifi_trigger_subsystem_restart;
+ fn->wifi_get_supported_radio_combinations_matrix = wifi_get_supported_radio_combinations_matrix;
+ fn->wifi_set_indoor_state = wifi_set_indoor_state;
+
+ return WIFI_SUCCESS;
+}
+#ifdef GOOGLE_WIFI_FW_CONFIG_VERSION_C_WRAPPER
+#include <google_wifi_firmware_config_version_info.h>
+
+static void
+wifi_check_valid_ota_version(wifi_interface_handle handle)
+{
+ bool valid = false;
+ int32_t default_ver = get_google_default_vendor_wifi_config_version();
+ int32_t ota_ver = get_google_ota_updated_wifi_config_version();
+ ALOGE("default_ver %d, ota_ver %d", default_ver, ota_ver);
+
+ if (ota_ver > default_ver) {
+ valid = verify_google_ota_updated_wifi_config_integrity();
+ }
+
+ if (valid) {
+ ALOGE("Valid config files of OTA.");
+ wifi_hal_ota_update(handle, ota_ver);
+ }
+ else {
+ ALOGE("Do not valid config files of OTA.");
+ }
+}
+#endif // GOOGLE_WIFI_FW_CONFIG_VERSION_C_WRAPPER
+
+hal_info *halInfo = NULL;
+wifi_error wifi_pre_initialize(void)
+{
+ srand(getpid());
+
+ int numIfaceHandles = 0;
+ wifi_interface_handle *ifaceHandles = NULL;
+ wifi_interface_handle wlan0Handle;
+ wifi_error result = WIFI_SUCCESS;
+ wifi_handle handle;
+
+ ALOGE("wifi_pre_initialize");
+ ALOGE("--- HAL version: %s ---\n", HAL_VERSION);
+ halInfo = (hal_info *)malloc(sizeof(hal_info));
+ if (halInfo == NULL) {
+ ALOGE("Could not allocate hal_info");
+ return WIFI_ERROR_UNKNOWN;
+ }
+
+ memset(halInfo, 0, sizeof(*halInfo));
+
+ ALOGI("Creating socket");
+ if (socketpair(AF_UNIX, SOCK_STREAM, 0, halInfo->cleanup_socks) == -1) {
+ ALOGE("Could not create cleanup sockets");
+ free(halInfo);
+ return WIFI_ERROR_UNKNOWN;
+ }
+
+ struct nl_sock *cmd_sock = wifi_create_nl_socket(WIFI_HAL_CMD_SOCK_PORT);
+ if (cmd_sock == NULL) {
+ ALOGE("Could not create handle");
+ free(halInfo);
+ return WIFI_ERROR_UNKNOWN;
+ }
+
+ /* Set the socket buffer size */
+ if (nl_socket_set_buffer_size(cmd_sock, (256*1024), 0) < 0) {
+ ALOGE("Could not set size for cmd_sock: %s",
+ strerror(errno));
+ } else {
+ ALOGV("nl_socket_set_buffer_size successful for cmd_sock");
+ }
+ struct nl_sock *event_sock = wifi_create_nl_socket(WIFI_HAL_EVENT_SOCK_PORT);
+ if (event_sock == NULL) {
+ ALOGE("Could not create handle");
+ nl_socket_free(cmd_sock);
+ free(halInfo);
+ return WIFI_ERROR_UNKNOWN;
+ }
+
+ /* Set the socket buffer size */
+ if (nl_socket_set_buffer_size(event_sock, (4*1024*1024), 0) < 0) {
+ ALOGE("Could not set size for event_sock: %s",
+ strerror(errno));
+ } else {
+ ALOGV("nl_socket_set_buffer_size successful for event_sock");
+ }
+
+ struct nl_cb *cb = nl_socket_get_cb(event_sock);
+ if (cb == NULL) {
+ ALOGE("Could not create handle");
+ nl_socket_free(cmd_sock);
+ nl_socket_free(event_sock);
+ free(halInfo);
+ return WIFI_ERROR_UNKNOWN;
+ }
+
+ nl_cb_set(cb, NL_CB_SEQ_CHECK, NL_CB_CUSTOM, internal_no_seq_check, halInfo);
+ nl_cb_set(cb, NL_CB_VALID, NL_CB_CUSTOM, internal_valid_message_handler, halInfo);
+ nl_cb_put(cb);
+
+ halInfo->cmd_sock = cmd_sock;
+ halInfo->event_sock = event_sock;
+ halInfo->clean_up = false;
+ halInfo->in_event_loop = false;
+
+ halInfo->event_cb = (cb_info *)malloc(sizeof(cb_info) * DEFAULT_EVENT_CB_SIZE);
+ halInfo->alloc_event_cb = DEFAULT_EVENT_CB_SIZE;
+ halInfo->num_event_cb = 0;
+
+ halInfo->cmd = (cmd_info *)malloc(sizeof(cmd_info) * DEFAULT_CMD_SIZE);
+ halInfo->alloc_cmd = DEFAULT_CMD_SIZE;
+ halInfo->num_cmd = 0;
+
+ halInfo->nl80211_family_id = genl_ctrl_resolve(cmd_sock, "nl80211");
+ if (halInfo->nl80211_family_id < 0) {
+ ALOGE("Could not resolve nl80211 familty id");
+ nl_socket_free(cmd_sock);
+ nl_socket_free(event_sock);
+ free(halInfo);
+ return WIFI_ERROR_UNKNOWN;
+ }
+
+ pthread_mutex_init(&halInfo->cb_lock, NULL);
+ InitResponseLock();
+
+ handle = (wifi_handle) halInfo;
+
+ if (wifi_init_interfaces(handle) != WIFI_SUCCESS) {
+ ALOGE("No wifi interface found");
+ nl_socket_free(cmd_sock);
+ nl_socket_free(event_sock);
+ pthread_mutex_destroy(&halInfo->cb_lock);
+ free(halInfo);
+ return WIFI_ERROR_NOT_AVAILABLE;
+ }
+
+ if ((wifi_add_membership(handle, "scan") < 0) ||
+ (wifi_add_membership(handle, "mlme") < 0) ||
+ (wifi_add_membership(handle, "regulatory") < 0) ||
+ (wifi_add_membership(handle, "vendor") < 0)) {
+ ALOGE("Add membership failed");
+ nl_socket_free(cmd_sock);
+ nl_socket_free(event_sock);
+ pthread_mutex_destroy(&halInfo->cb_lock);
+ free(halInfo);
+ return WIFI_ERROR_NOT_AVAILABLE;
+ }
+
+ ALOGI("Initialized Wifi HAL Successfully; vendor cmd = %d", NL80211_CMD_VENDOR);
+ wlan0Handle = wifi_get_wlan_interface((wifi_handle)halInfo, ifaceHandles, numIfaceHandles);
+
+ if (wlan0Handle != NULL) {
+ ALOGE("Calling preInit");
+ if (!get_halutil_mode()) {
+#ifdef GOOGLE_WIFI_FW_CONFIG_VERSION_C_WRAPPER
+ (void) wifi_check_valid_ota_version(wlan0Handle);
+#endif // GOOGLE_WIFI_FW_CONFIG_VERSION_C_WRAPPER
+ result = wifi_hal_preInit(wlan0Handle);
+ if (result != WIFI_SUCCESS) {
+ ALOGE("wifi_hal_preInit failed");
+ }
+ }
+ }
+
+ return WIFI_SUCCESS;
+}
+
+wifi_error wifi_initialize(wifi_handle *handle)
+{
+
+ int numIfaceHandles = 0;
+ wifi_interface_handle *ifaceHandles = NULL;
+ wifi_interface_handle wlan0Handle;
+ wifi_error result = WIFI_SUCCESS;
+
+ ALOGE("wifi_initialize");
+
+ if (halInfo == NULL) {
+ result = wifi_pre_initialize();
+ if (result != WIFI_SUCCESS) {
+ ALOGE("wifi_initialize wifi_pre_initialize failed");
+ return result;
+ } else {
+ ALOGE("wifi_initialize wifi_pre_initialize succeeded");
+ }
+ }
+
+ *handle = (wifi_handle) halInfo;
+ wlan0Handle = wifi_get_wlan_interface((wifi_handle)halInfo, ifaceHandles, numIfaceHandles);
+
+ if (wlan0Handle != NULL) {
+ ALOGE("Calling Hal_init");
+ if (!get_halutil_mode()) {
+ result = wifi_start_hal(wlan0Handle);
+ if (result != WIFI_SUCCESS) {
+ ALOGE("wifi_start_hal failed");
+ }
+ }
+ } else {
+ ALOGI("Not Calling set alert handler as global_iface is NULL");
+ return WIFI_ERROR_UNKNOWN;
+ }
+ return WIFI_SUCCESS;
+}
+
+wifi_error wifi_wait_for_driver_ready(void)
+{
+ // This function will wait to make sure basic client netdev is created
+ // Function times out after 10 seconds
+ int count = (POLL_DRIVER_MAX_TIME_MS * 1000) / POLL_DRIVER_DURATION_US;
+ FILE *fd;
+
+ do {
+ if ((fd = fopen("/sys/class/net/wlan0", "r")) != NULL) {
+ fclose(fd);
+ wifi_pre_initialize();
+ return WIFI_SUCCESS;
+ }
+ usleep(POLL_DRIVER_DURATION_US);
+ } while(--count > 0);
+
+ ALOGE("Timed out waiting on Driver ready ... ");
+ return WIFI_ERROR_TIMED_OUT;
+}
+
+static int wifi_add_membership(wifi_handle handle, const char *group)
+{
+ hal_info *info = getHalInfo(handle);
+
+ int id = wifi_get_multicast_id(handle, "nl80211", group);
+ if (id < 0) {
+ ALOGE("Could not find group %s", group);
+ return id;
+ }
+
+ int ret = nl_socket_add_membership(info->event_sock, id);
+ if (ret < 0) {
+ ALOGE("Could not add membership to group %s", group);
+ }
+
+ // ALOGI("Successfully added membership for group %s", group);
+ return ret;
+}
+
+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;
+
+ ALOGI("internal clean up");
+
+ if (info->cmd_sock != 0) {
+ ALOGI("cmd_sock non null. clean up");
+ close(info->cleanup_socks[0]);
+ close(info->cleanup_socks[1]);
+ nl_socket_free(info->cmd_sock);
+ nl_socket_free(info->event_sock);
+ info->cmd_sock = NULL;
+ info->event_sock = NULL;
+ }
+
+ if (cleaned_up_handler) {
+ ALOGI("cleanup_handler cb");
+ (*cleaned_up_handler)(handle);
+ } else {
+ ALOGI("!! clean up handler is null!!");
+ }
+ DestroyResponseLock();
+ pthread_mutex_destroy(&info->cb_lock);
+ free(info);
+
+ ALOGI("Internal cleanup completed");
+}
+
+void wifi_internal_module_cleanup()
+{
+ nan_deinit_handler();
+ twt_deinit_handler();
+}
+
+void wifi_cleanup(wifi_handle handle, wifi_cleaned_up_handler handler)
+{
+ if (!handle) {
+ ALOGE("Handle is null");
+ return;
+ }
+
+ hal_info *info = getHalInfo(handle);
+ wifi_error result;
+
+ int numIfaceHandles = 0;
+ wifi_interface_handle *ifaceHandles = NULL;
+ wifi_interface_handle wlan0Handle;
+
+ info->cleaned_up_handler = handler;
+
+ wlan0Handle = wifi_get_wlan_interface((wifi_handle) info, ifaceHandles, numIfaceHandles);
+
+ if (wlan0Handle != NULL) {
+ ALOGE("Calling hal cleanup");
+ if (!get_halutil_mode()) {
+ result = wifi_stop_hal(wlan0Handle);
+ if (result != WIFI_SUCCESS) {
+ ALOGE("wifi_stop_hal failed");
+ }
+ }
+
+ } else {
+ ALOGE("Not cleaning up hal as global_iface is NULL");
+ }
+
+ /* calling internal modules or cleanup */
+ wifi_internal_module_cleanup();
+ pthread_mutex_lock(&info->cb_lock);
+
+ int bad_commands = 0;
+
+ ALOGI("event_cb callbacks left: %d ", info->num_event_cb);
+ for (int i = 0; i < info->num_event_cb; i++) {
+ ALOGI("event_cb cleanup. index:%d", i);
+ cb_info *cbi = &(info->event_cb[i]);
+ if (!cbi) {
+ ALOGE("cbi null for index %d", i);
+ continue;
+ }
+ ALOGI("event_cb cleanup. vendor cmd:%d sub_cmd:%d", cbi->vendor_id, cbi->vendor_subcmd);
+ WifiCommand *cmd = (WifiCommand *)cbi->cb_arg;
+ if (cmd != NULL) {
+ ALOGI("Command left in event_cb %p", cmd);
+ }
+ }
+
+ ALOGI("Check bad commands: num_cmd:%d bad_commands:%d", info->num_cmd, bad_commands);
+ while (info->num_cmd > bad_commands) {
+ int num_cmd = info->num_cmd;
+ cmd_info *cmdi = &(info->cmd[bad_commands]);
+ WifiCommand *cmd = cmdi->cmd;
+ if (cmd != NULL) {
+ ALOGI("Cancelling command %p:%s", cmd, cmd->getType());
+ pthread_mutex_unlock(&info->cb_lock);
+ cmd->cancel();
+ pthread_mutex_lock(&info->cb_lock);
+ if (num_cmd == info->num_cmd) {
+ ALOGI("Cancelling command %p:%s did not work", cmd, (cmd ? cmd->getType(): ""));
+ bad_commands++;
+ }
+ /* release reference added when command is saved */
+ cmd->releaseRef();
+ }
+ }
+
+ for (int i = 0; i < info->num_event_cb; i++) {
+ cb_info *cbi = &(info->event_cb[i]);
+ if (!cbi) {
+ ALOGE("cbi null for index %d", i);
+ continue;
+ }
+ WifiCommand *cmd = (WifiCommand *)cbi->cb_arg;
+ ALOGE("Leaked command %p", cmd);
+ }
+ if (!get_halutil_mode()) {
+ wifi_cleanup_dynamic_ifaces(handle);
+ }
+ pthread_mutex_unlock(&info->cb_lock);
+
+ info->clean_up = true;
+
+ if (TEMP_FAILURE_RETRY(write(info->cleanup_socks[0], "Exit", 4)) < 1) {
+ // As a fallback set the cleanup flag to TRUE
+ ALOGE("could not write to the cleanup socket");
+ }
+ ALOGE("wifi_clean_up done");
+}
+
+static int internal_pollin_handler(wifi_handle handle)
+{
+ hal_info *info = getHalInfo(handle);
+ struct nl_cb *cb = nl_socket_get_cb(info->event_sock);
+ int res = nl_recvmsgs(info->event_sock, cb);
+ // ALOGD("nl_recvmsgs returned %d", res);
+ nl_cb_put(cb);
+ return res;
+}
+
+/* Run event handler */
+void wifi_event_loop(wifi_handle handle)
+{
+ hal_info *info = getHalInfo(handle);
+ if (info->in_event_loop) {
+ return;
+ } else {
+ info->in_event_loop = true;
+ }
+
+ pollfd pfd[2];
+ memset(&pfd[0], 0, sizeof(pollfd) * 2);
+
+ pfd[0].fd = nl_socket_get_fd(info->event_sock);
+ pfd[0].events = POLLIN;
+ pfd[1].fd = info->cleanup_socks[1];
+ pfd[1].events = POLLIN;
+
+ char buf[2048];
+ /* TODO: Add support for timeouts */
+
+ do {
+ int timeout = -1; /* Infinite timeout */
+ pfd[0].revents = 0;
+ pfd[1].revents = 0;
+ // ALOGI("Polling socket");
+ int result = TEMP_FAILURE_RETRY(poll(pfd, 2, timeout));
+ if (result < 0) {
+ // ALOGE("Error polling socket");
+ } else if (pfd[0].revents & POLLERR) {
+ ALOGE("POLL Error; error no = %d (%s)", errno, strerror(errno));
+ ssize_t result2 = TEMP_FAILURE_RETRY(read(pfd[0].fd, buf, sizeof(buf)));
+ ALOGE("Read after POLL returned %zd, error no = %d (%s)", result2,
+ errno, strerror(errno));
+ if (errno == WIFI_HAL_EVENT_BUFFER_NOT_AVAILABLE) {
+ ALOGE("Exit, No buffer space");
+ break;
+ }
+ } else if (pfd[0].revents & POLLHUP) {
+ ALOGE("Remote side hung up");
+ break;
+ } else if (pfd[0].revents & POLLIN && !info->clean_up) {
+ // ALOGI("Found some events!!!");
+ internal_pollin_handler(handle);
+ } else if (pfd[1].revents & POLLIN) {
+ ALOGI("Got a signal to exit!!!");
+ } else {
+ ALOGE("Unknown event - %0x, %0x", pfd[0].revents, pfd[1].revents);
+ }
+ } while (!info->clean_up);
+
+ internal_cleaned_up_handler(handle);
+ ALOGE("Exit %s", __FUNCTION__);
+}
+
+///////////////////////////////////////////////////////////////////////////////////////
+
+static int internal_no_seq_check(struct nl_msg *msg, void *arg)
+{
+ return NL_OK;
+}
+
+static int internal_valid_message_handler(nl_msg *msg, void *arg)
+{
+ // ALOGI("got an event");
+
+ wifi_handle handle = (wifi_handle)arg;
+ hal_info *info = getHalInfo(handle);
+
+ WifiEvent event(msg);
+ int res = event.parse();
+ if (res < 0) {
+ ALOGE("Failed to parse event: %d", res);
+ return NL_SKIP;
+ }
+
+ int cmd = event.get_cmd();
+ uint32_t vendor_id = 0;
+ int subcmd = 0;
+
+ if (cmd == NL80211_CMD_VENDOR) {
+ vendor_id = event.get_u32(NL80211_ATTR_VENDOR_ID);
+ subcmd = event.get_u32(NL80211_ATTR_VENDOR_SUBCMD);
+ ALOGV("event received %s, vendor_id = 0x%0x, subcmd = 0x%0x",
+ event.get_cmdString(), vendor_id, subcmd);
+ } else {
+ // ALOGV("event received %s", event.get_cmdString());
+ }
+
+ // ALOGV("event received %s, vendor_id = 0x%0x", event.get_cmdString(), vendor_id);
+ // event.log();
+
+ pthread_mutex_lock(&info->cb_lock);
+
+ for (int i = 0; i < info->num_event_cb; i++) {
+ if (cmd == info->event_cb[i].nl_cmd) {
+ if (cmd == NL80211_CMD_VENDOR
+ && ((vendor_id != info->event_cb[i].vendor_id)
+ || (subcmd != info->event_cb[i].vendor_subcmd)))
+ {
+ /* event for a different vendor, ignore it */
+ continue;
+ }
+
+ cb_info *cbi = &(info->event_cb[i]);
+ nl_recvmsg_msg_cb_t cb_func = cbi->cb_func;
+ void *cb_arg = cbi->cb_arg;
+ WifiCommand *cmd = (WifiCommand *)cbi->cb_arg;
+ if (cmd != NULL) {
+ cmd->addRef();
+ }
+ pthread_mutex_unlock(&info->cb_lock);
+ if (cb_func)
+ (*cb_func)(msg, cb_arg);
+ if (cmd != NULL) {
+ cmd->releaseRef();
+ }
+
+ return NL_OK;
+ }
+ }
+
+ pthread_mutex_unlock(&info->cb_lock);
+ return NL_OK;
+}
+
+///////////////////////////////////////////////////////////////////////////////////////
+
+class GetMulticastIdCommand : public WifiCommand
+{
+private:
+ const char *mName;
+ const char *mGroup;
+ int mId;
+public:
+ GetMulticastIdCommand(wifi_handle handle, const char *name, const char *group)
+ : WifiCommand("GetMulticastIdCommand", handle, 0)
+ {
+ mName = name;
+ mGroup = group;
+ mId = -1;
+ }
+
+ int getId() {
+ return mId;
+ }
+
+ virtual int create() {
+ int nlctrlFamily = genl_ctrl_resolve(mInfo->cmd_sock, "nlctrl");
+ // ALOGI("ctrl family = %d", nlctrlFamily);
+ int ret = mMsg.create(nlctrlFamily, CTRL_CMD_GETFAMILY, 0, 0);
+ if (ret < 0) {
+ return ret;
+ }
+ ret = mMsg.put_string(CTRL_ATTR_FAMILY_NAME, mName);
+ return ret;
+ }
+
+ virtual int handleResponse(WifiEvent& reply) {
+
+ // ALOGI("handling response in %s", __func__);
+
+ struct nlattr **tb = reply.attributes();
+ struct nlattr *mcgrp = NULL;
+ int i;
+
+ if (!tb[CTRL_ATTR_MCAST_GROUPS]) {
+ ALOGI("No multicast groups found");
+ return NL_SKIP;
+ } else {
+ // ALOGI("Multicast groups attr size = %d", nla_len(tb[CTRL_ATTR_MCAST_GROUPS]));
+ }
+
+ for_each_attr(mcgrp, tb[CTRL_ATTR_MCAST_GROUPS], i) {
+
+ // ALOGI("Processing group");
+ struct nlattr *tb2[CTRL_ATTR_MCAST_GRP_MAX + 1];
+ nla_parse(tb2, CTRL_ATTR_MCAST_GRP_MAX, (nlattr *)nla_data(mcgrp),
+ nla_len(mcgrp), NULL);
+ if (!tb2[CTRL_ATTR_MCAST_GRP_NAME] || !tb2[CTRL_ATTR_MCAST_GRP_ID]) {
+ continue;
+ }
+
+ char *grpName = (char *)nla_data(tb2[CTRL_ATTR_MCAST_GRP_NAME]);
+ int grpNameLen = nla_len(tb2[CTRL_ATTR_MCAST_GRP_NAME]);
+
+ // ALOGI("Found group name %s", grpName);
+
+ if (strncmp(grpName, mGroup, grpNameLen) != 0)
+ continue;
+
+ mId = nla_get_u32(tb2[CTRL_ATTR_MCAST_GRP_ID]);
+ break;
+ }
+
+ return NL_SKIP;
+ }
+
+};
+
+class SetPnoMacAddrOuiCommand : public WifiCommand {
+
+private:
+ byte *mOui;
+ feature_set *fset;
+ feature_set *feature_matrix;
+ int *fm_size;
+ int set_size_max;
+public:
+ SetPnoMacAddrOuiCommand(wifi_interface_handle handle, oui scan_oui)
+ : WifiCommand("SetPnoMacAddrOuiCommand", handle, 0)
+ {
+ mOui = scan_oui;
+ fset = NULL;
+ feature_matrix = NULL;
+ fm_size = NULL;
+ set_size_max = 0;
+ }
+
+ int createRequest(WifiRequest& request, int subcmd, byte *scan_oui) {
+ int result = request.create(GOOGLE_OUI, subcmd);
+ if (result < 0) {
+ return result;
+ }
+
+ nlattr *data = request.attr_start(NL80211_ATTR_VENDOR_DATA);
+ result = request.put(ANDR_WIFI_ATTRIBUTE_PNO_RANDOM_MAC_OUI, scan_oui, DOT11_OUI_LEN);
+ if (result < 0) {
+ return result;
+ }
+
+ request.attr_end(data);
+ return WIFI_SUCCESS;
+
+ }
+
+ int start() {
+ ALOGD("Sending mac address OUI");
+ WifiRequest request(familyId(), ifaceId());
+ int result = createRequest(request, WIFI_SUBCMD_SET_PNO_RANDOM_MAC_OUI, mOui);
+ if (result != WIFI_SUCCESS) {
+ ALOGE("failed to create request; result = %d", result);
+ return result;
+ }
+
+ result = requestResponse(request);
+ if (result != WIFI_SUCCESS) {
+ ALOGE("failed to set scanning mac OUI; result = %d", result);
+ }
+
+ return result;
+ }
+protected:
+ virtual int handleResponse(WifiEvent& reply) {
+ ALOGD("Request complete!");
+ /* Nothing to do on response! */
+ return NL_SKIP;
+ }
+};
+
+class SetNodfsCommand : public WifiCommand {
+
+private:
+ u32 mNoDfs;
+public:
+ SetNodfsCommand(wifi_interface_handle handle, u32 nodfs)
+ : WifiCommand("SetNodfsCommand", handle, 0) {
+ mNoDfs = nodfs;
+ }
+ virtual int create() {
+ int ret;
+
+ ret = mMsg.create(GOOGLE_OUI, WIFI_SUBCMD_NODFS_SET);
+ if (ret < 0) {
+ ALOGE("Can't create message to send to driver - %d", ret);
+ return ret;
+ }
+
+ nlattr *data = mMsg.attr_start(NL80211_ATTR_VENDOR_DATA);
+ ret = mMsg.put_u32(ANDR_WIFI_ATTRIBUTE_NODFS_SET, mNoDfs);
+ if (ret < 0) {
+ return ret;
+ }
+
+ mMsg.attr_end(data);
+ return WIFI_SUCCESS;
+ }
+};
+
+class SetCountryCodeCommand : public WifiCommand {
+private:
+ const char *mCountryCode;
+public:
+ SetCountryCodeCommand(wifi_interface_handle handle, const char *country_code)
+ : WifiCommand("SetCountryCodeCommand", handle, 0) {
+ mCountryCode = country_code;
+ }
+ virtual int create() {
+ int ret;
+
+ ret = mMsg.create(GOOGLE_OUI, WIFI_SUBCMD_SET_COUNTRY_CODE);
+ if (ret < 0) {
+ ALOGE("Can't create message to send to driver - %d", ret);
+ return ret;
+ }
+
+ nlattr *data = mMsg.attr_start(NL80211_ATTR_VENDOR_DATA);
+ ret = mMsg.put_string(ANDR_WIFI_ATTRIBUTE_COUNTRY, mCountryCode);
+ if (ret < 0) {
+ return ret;
+ }
+
+ mMsg.attr_end(data);
+ return WIFI_SUCCESS;
+
+ }
+};
+
+class SetRSSIMonitorCommand : public WifiCommand {
+private:
+ s8 mMax_rssi;
+ s8 mMin_rssi;
+ wifi_rssi_event_handler mHandler;
+public:
+ SetRSSIMonitorCommand(wifi_request_id id, wifi_interface_handle handle,
+ s8 max_rssi, s8 min_rssi, wifi_rssi_event_handler eh)
+ : WifiCommand("SetRSSIMonitorCommand", handle, id), mMax_rssi(max_rssi), mMin_rssi
+ (min_rssi), mHandler(eh)
+ {
+ ALOGI("SetRSSIMonitorCommand %p created", this);
+ }
+
+ virtual ~SetRSSIMonitorCommand() {
+ /*
+ * Mostly, this call will be no effect. However, this could be valid
+ * when object destroy without calling unregisterVendorHandler().
+ * This is added to protect hal crash due to use-after-free.
+ */
+ ALOGI("Try to remove event handler if exist, vendor 0x%0x, subcmd 0x%x",
+ GOOGLE_OUI, GOOGLE_RSSI_MONITOR_EVENT);
+ unregisterVendorHandlerWithoutLock(GOOGLE_OUI, GOOGLE_RSSI_MONITOR_EVENT);
+ ALOGI("SetRSSIMonitorCommand %p destroyed", this);
+ }
+
+ virtual void addRef() {
+ int refs = __sync_add_and_fetch(&mRefs, 1);
+ ALOGI("addRef: WifiCommand %p has %d references", this, refs);
+ }
+
+ virtual void releaseRef() {
+ int refs = __sync_sub_and_fetch(&mRefs, 1);
+ if (refs == 0) {
+ ALOGI("releaseRef: WifiCommand %p has deleted", this);
+ delete this;
+ } else {
+ ALOGI("releaseRef: WifiCommand %p has %d references", this, refs);
+ }
+ }
+
+ int createRequest(WifiRequest& request, int enable) {
+ int result = request.create(GOOGLE_OUI, WIFI_SUBCMD_SET_RSSI_MONITOR);
+ if (result < 0) {
+ return result;
+ }
+
+ nlattr *data = request.attr_start(NL80211_ATTR_VENDOR_DATA);
+ result = request.put_u32(RSSI_MONITOR_ATTRIBUTE_MAX_RSSI, (enable ? mMax_rssi: 0));
+ if (result < 0) {
+ return result;
+ }
+ ALOGD("create request");
+ result = request.put_u32(RSSI_MONITOR_ATTRIBUTE_MIN_RSSI, (enable? mMin_rssi: 0));
+ if (result < 0) {
+ return result;
+ }
+ result = request.put_u32(RSSI_MONITOR_ATTRIBUTE_START, enable);
+ if (result < 0) {
+ return result;
+ }
+ request.attr_end(data);
+ return result;
+ }
+
+ int start() {
+ WifiRequest request(familyId(), ifaceId());
+ int result = createRequest(request, 1);
+ if (result != WIFI_SUCCESS) {
+ ALOGE("Failed to create request; result = %d", result);
+ return result;
+ }
+
+ registerVendorHandler(GOOGLE_OUI, GOOGLE_RSSI_MONITOR_EVENT);
+ ALOGI("Register GOOGLE_RSSI_MONITOR_EVENT handler");
+
+ result = requestResponse(request);
+ if (result != WIFI_SUCCESS) {
+ unregisterVendorHandler(GOOGLE_OUI, GOOGLE_RSSI_MONITOR_EVENT);
+ ALOGE("Failed to set RSSI Monitor, result = %d", result);
+ return result;
+ }
+
+ ALOGI("Successfully set RSSI monitoring");
+ return result;
+ }
+
+ virtual int cancel() {
+ unregisterVendorHandler(GOOGLE_OUI, GOOGLE_RSSI_MONITOR_EVENT);
+
+ WifiRequest request(familyId(), ifaceId());
+ int result = createRequest(request, 0);
+ if (result != WIFI_SUCCESS) {
+ ALOGE("failed to create request; result = %d", result);
+ } else {
+ result = requestResponse(request);
+ if (result != WIFI_SUCCESS) {
+ ALOGE("failed to stop RSSI monitoring = %d", result);
+ }
+ }
+ return WIFI_SUCCESS;
+ }
+
+ virtual int handleResponse(WifiEvent& reply) {
+ /* Nothing to do on response! */
+ return NL_SKIP;
+ }
+
+ virtual int handleEvent(WifiEvent& event) {
+ ALOGI("Got a RSSI monitor event");
+
+ nlattr *vendor_data = event.get_attribute(NL80211_ATTR_VENDOR_DATA);
+ int len = event.get_vendor_data_len();
+
+ if (vendor_data == NULL || len == 0) {
+ ALOGI("RSSI monitor: No data");
+ return NL_SKIP;
+ }
+ /* driver<->HAL event structure */
+ #define RSSI_MONITOR_EVT_VERSION 1
+ typedef struct {
+ u8 version;
+ s8 cur_rssi;
+ mac_addr BSSID;
+ } rssi_monitor_evt;
+
+ rssi_monitor_evt *data = (rssi_monitor_evt *)event.get_vendor_data();
+
+ if (data->version != RSSI_MONITOR_EVT_VERSION) {
+ ALOGI("Event version mismatch %d, expected %d", data->version, RSSI_MONITOR_EVT_VERSION);
+ return NL_SKIP;
+ }
+
+ if (*mHandler.on_rssi_threshold_breached) {
+ (*mHandler.on_rssi_threshold_breached)(id(), data->BSSID, data->cur_rssi);
+ } else {
+ ALOGW("No RSSI monitor handler registered");
+ }
+
+ return NL_SKIP;
+ }
+
+};
+
+class AndroidPktFilterCommand : public WifiCommand {
+ private:
+ const u8* mProgram;
+ u8* mReadProgram;
+ u32 mProgramLen;
+ u32* mVersion;
+ u32* mMaxLen;
+ int mReqType;
+ public:
+ AndroidPktFilterCommand(wifi_interface_handle handle,
+ u32* version, u32* max_len)
+ : WifiCommand("AndroidPktFilterCommand", handle, 0),
+ mVersion(version), mMaxLen(max_len),
+ mReqType(GET_APF_CAPABILITIES)
+ {
+ mProgram = NULL;
+ mProgramLen = 0;
+ }
+
+ AndroidPktFilterCommand(wifi_interface_handle handle,
+ const u8* program, u32 len)
+ : WifiCommand("AndroidPktFilterCommand", handle, 0),
+ mProgram(program), mProgramLen(len),
+ mReqType(SET_APF_PROGRAM)
+ {
+ mVersion = NULL;
+ mMaxLen = NULL;
+ }
+
+ AndroidPktFilterCommand(wifi_interface_handle handle,
+ u8* host_dst, u32 length)
+ : WifiCommand("AndroidPktFilterCommand", handle, 0),
+ mReadProgram(host_dst), mProgramLen(length),
+ mReqType(READ_APF_PROGRAM)
+ {
+ }
+
+ int createRequest(WifiRequest& request) {
+ if (mReqType == SET_APF_PROGRAM) {
+ ALOGI("\n%s: APF set program request\n", __FUNCTION__);
+ return createSetPktFilterRequest(request);
+ } else if (mReqType == GET_APF_CAPABILITIES) {
+ ALOGI("\n%s: APF get capabilities request\n", __FUNCTION__);
+ return createGetPktFilterCapabilitesRequest(request);
+ } else if (mReqType == READ_APF_PROGRAM) {
+ ALOGI("\n%s: APF read packet filter request\n", __FUNCTION__);
+ return createReadPktFilterRequest(request);
+ } else {
+ ALOGE("\n%s Unknown APF request\n", __FUNCTION__);
+ return WIFI_ERROR_NOT_SUPPORTED;
+ }
+ return WIFI_SUCCESS;
+ }
+
+ int createSetPktFilterRequest(WifiRequest& request) {
+ u8 *program = new u8[mProgramLen];
+ NULL_CHECK_RETURN(program, "memory allocation failure", WIFI_ERROR_OUT_OF_MEMORY);
+ int result = request.create(GOOGLE_OUI, APF_SUBCMD_SET_FILTER);
+ if (result < 0) {
+ delete[] program;
+ return result;
+ }
+
+ nlattr *data = request.attr_start(NL80211_ATTR_VENDOR_DATA);
+ result = request.put_u32(APF_ATTRIBUTE_PROGRAM_LEN, mProgramLen);
+ if (result < 0) {
+ goto exit;
+ }
+ memcpy(program, mProgram, mProgramLen);
+ result = request.put(APF_ATTRIBUTE_PROGRAM, program, mProgramLen);
+ if (result < 0) {
+ goto exit;
+ }
+exit: request.attr_end(data);
+ delete[] program;
+ return result;
+ }
+
+ int createGetPktFilterCapabilitesRequest(WifiRequest& request) {
+ int result = request.create(GOOGLE_OUI, APF_SUBCMD_GET_CAPABILITIES);
+ if (result < 0) {
+ return result;
+ }
+
+ nlattr *data = request.attr_start(NL80211_ATTR_VENDOR_DATA);
+ request.attr_end(data);
+ return result;
+ }
+
+ int createReadPktFilterRequest(WifiRequest& request) {
+ int result = request.create(GOOGLE_OUI, APF_SUBCMD_READ_FILTER);
+ if (result < 0) {
+ return result;
+ }
+ nlattr *data = request.attr_start(NL80211_ATTR_VENDOR_DATA);
+ request.attr_end(data);
+ return result;
+ }
+
+ int start() {
+ WifiRequest request(familyId(), ifaceId());
+ int result = createRequest(request);
+ if (result < 0) {
+ return result;
+ }
+ result = requestResponse(request);
+ if (result < 0) {
+ ALOGI("Request Response failed for APF, result = %d", result);
+ return result;
+ }
+ ALOGI("Done!");
+ return result;
+ }
+
+ int cancel() {
+ return WIFI_SUCCESS;
+ }
+
+ int handleResponse(WifiEvent& reply) {
+ ALOGD("In SetAPFCommand::handleResponse");
+
+ if (reply.get_cmd() != NL80211_CMD_VENDOR) {
+ ALOGD("Ignoring reply with cmd = %d", reply.get_cmd());
+ return NL_SKIP;
+ }
+
+ int id = reply.get_vendor_id();
+ int subcmd = reply.get_vendor_subcmd();
+
+ nlattr *vendor_data = reply.get_attribute(NL80211_ATTR_VENDOR_DATA);
+ int len = reply.get_vendor_data_len();
+
+ ALOGD("Id = %0x, subcmd = %d, len = %d", id, subcmd, len);
+ if (vendor_data == NULL || len == 0) {
+ ALOGE("no vendor data in SetAPFCommand response; ignoring it");
+ return NL_SKIP;
+ }
+ if( mReqType == SET_APF_PROGRAM) {
+ ALOGD("Response received for set packet filter command\n");
+ } else if (mReqType == GET_APF_CAPABILITIES) {
+ *mVersion = 0;
+ *mMaxLen = 0;
+ ALOGD("Response received for get packet filter capabilities command\n");
+ for (nl_iterator it(vendor_data); it.has_next(); it.next()) {
+ if (it.get_type() == APF_ATTRIBUTE_VERSION) {
+ *mVersion = it.get_u32();
+ ALOGI("APF version is %d\n", *mVersion);
+ } else if (it.get_type() == APF_ATTRIBUTE_MAX_LEN) {
+ *mMaxLen = it.get_u32();
+ ALOGI("APF max len is %d\n", *mMaxLen);
+ } else {
+ ALOGE("Ignoring invalid attribute type = %d, size = %d",
+ it.get_type(), it.get_len());
+ }
+ }
+ } else if (mReqType == READ_APF_PROGRAM) {
+ ALOGD("Read packet filter, mProgramLen = %d\n", mProgramLen);
+ for (nl_iterator it(vendor_data); it.has_next(); it.next()) {
+ if (it.get_type() == APF_ATTRIBUTE_PROGRAM) {
+ u8 *buffer = NULL;
+ buffer = (u8 *)it.get_data();
+ memcpy(mReadProgram, buffer, mProgramLen);
+ } else if (it.get_type() == APF_ATTRIBUTE_PROGRAM_LEN) {
+ int apf_length = it.get_u32();
+ ALOGD("apf program length = %d\n", apf_length);
+ }
+ }
+ }
+ return NL_OK;
+ }
+
+ int handleEvent(WifiEvent& event) {
+ /* No Event to receive for APF commands */
+ return NL_SKIP;
+ }
+};
+
+class SetNdoffloadCommand : public WifiCommand {
+
+private:
+ u8 mEnable;
+public:
+ SetNdoffloadCommand(wifi_interface_handle handle, u8 enable)
+ : WifiCommand("SetNdoffloadCommand", handle, 0) {
+ mEnable = enable;
+ }
+ virtual int create() {
+ int ret;
+
+ ret = mMsg.create(GOOGLE_OUI, WIFI_SUBCMD_CONFIG_ND_OFFLOAD);
+ if (ret < 0) {
+ ALOGE("Can't create message to send to driver - %d", ret);
+ return ret;
+ }
+
+ nlattr *data = mMsg.attr_start(NL80211_ATTR_VENDOR_DATA);
+ ret = mMsg.put_u8(ANDR_WIFI_ATTRIBUTE_ND_OFFLOAD_VALUE, mEnable);
+ if (ret < 0) {
+ return ret;
+ }
+
+ mMsg.attr_end(data);
+ return WIFI_SUCCESS;
+ }
+};
+
+class GetFeatureSetCommand : public WifiCommand {
+
+private:
+ int feature_type;
+ feature_set *fset;
+ feature_set *feature_matrix;
+ int *fm_size;
+ int set_size_max;
+public:
+ GetFeatureSetCommand(wifi_interface_handle handle, int feature, feature_set *set,
+ feature_set set_matrix[], int *size, int max_size)
+ : WifiCommand("GetFeatureSetCommand", handle, 0) {
+ feature_type = feature;
+ fset = set;
+ feature_matrix = set_matrix;
+ fm_size = size;
+ set_size_max = max_size;
+ }
+
+ virtual int create() {
+ int ret;
+
+ if(feature_type == ANDR_WIFI_ATTRIBUTE_NUM_FEATURE_SET) {
+ ret = mMsg.create(GOOGLE_OUI, WIFI_SUBCMD_GET_FEATURE_SET);
+ } else if (feature_type == ANDR_WIFI_ATTRIBUTE_FEATURE_SET) {
+ ret = mMsg.create(GOOGLE_OUI, WIFI_SUBCMD_GET_FEATURE_SET_MATRIX);
+ } else {
+ ALOGE("Unknown feature type %d", feature_type);
+ return -1;
+ }
+
+ if (ret < 0) {
+ ALOGE("Can't create message to send to driver - %d", ret);
+ }
+
+ return ret;
+ }
+
+protected:
+ virtual int handleResponse(WifiEvent& reply) {
+
+ ALOGV("In GetFeatureSetCommand::handleResponse");
+
+ if (reply.get_cmd() != NL80211_CMD_VENDOR) {
+ ALOGD("Ignoring reply with cmd = %d", reply.get_cmd());
+ return NL_SKIP;
+ }
+
+ int id = reply.get_vendor_id();
+ int subcmd = reply.get_vendor_subcmd();
+
+ nlattr *vendor_data = reply.get_attribute(NL80211_ATTR_VENDOR_DATA);
+ int len = reply.get_vendor_data_len();
+
+ ALOGV("Id = %0x, subcmd = %d, len = %d", id, subcmd, len);
+ if (vendor_data == NULL || len == 0) {
+ ALOGE("no vendor data in GetFeatureSetCommand response; ignoring it");
+ return NL_SKIP;
+ }
+ if(feature_type == ANDR_WIFI_ATTRIBUTE_NUM_FEATURE_SET) {
+ void *data = reply.get_vendor_data();
+ if(!fset) {
+ ALOGE("Buffers pointers not set");
+ return NL_SKIP;
+ }
+ memcpy(fset, data, min(len, (int) sizeof(*fset)));
+ } else {
+ int num_features_set = 0;
+ int i = 0;
+
+ if(!feature_matrix || !fm_size) {
+ ALOGE("Buffers pointers not set");
+ return NL_SKIP;
+ }
+
+ for (nl_iterator it(vendor_data); it.has_next(); it.next()) {
+ if (it.get_type() == ANDR_WIFI_ATTRIBUTE_NUM_FEATURE_SET) {
+ num_features_set = it.get_u32();
+ ALOGV("Got feature list with %d concurrent sets", num_features_set);
+ if(set_size_max && (num_features_set > set_size_max))
+ num_features_set = set_size_max;
+ *fm_size = num_features_set;
+ } else if ((it.get_type() == ANDR_WIFI_ATTRIBUTE_FEATURE_SET) &&
+ i < num_features_set) {
+ feature_matrix[i] = it.get_u32();
+ i++;
+ } else {
+ ALOGW("Ignoring invalid attribute type = %d, size = %d",
+ it.get_type(), it.get_len());
+ }
+ }
+
+ }
+ return NL_OK;
+ }
+
+};
+/////////////////////////////////////////////////////////////////////
+class GetRadioComboCommand : public WifiCommand {
+private:
+ wifi_radio_combination_matrix *rcmatrix;
+ u32* rc_size;
+ u32 set_size_max;
+ int ret = 0;
+
+public:
+ GetRadioComboCommand(wifi_interface_handle handle, u32 max_size, u32* size,
+ wifi_radio_combination_matrix *radio_combination_matrix)
+ : WifiCommand("GetRadioComboCommand", handle, 0), rcmatrix(radio_combination_matrix),
+ rc_size(size), set_size_max(max_size)
+ {
+ }
+
+ virtual int createRequest(WifiRequest& mMsg) {
+ ret = mMsg.create(GOOGLE_OUI, WIFI_SUBCMD_GET_RADIO_COMBO_MATRIX);
+ if (ret < 0) {
+ ALOGE("Can't create message to send to driver - %d", ret);
+ }
+ nlattr *data = mMsg.attr_start(NL80211_ATTR_VENDOR_DATA);
+ mMsg.attr_end(data);
+
+ return ret;
+ }
+
+ int start() {
+ WifiRequest request(familyId(), ifaceId());
+ ret = createRequest(request);
+ if (ret < 0) {
+ ALOGE("Request failed for radio_combo_matrix, result = %d", ret);
+ return ret;
+ }
+ ret = requestResponse(request);
+ if (ret < 0) {
+ ALOGE("Request Response failed for radio_combo_matrix, result = %d", ret);
+ return ret;
+ }
+ ALOGD("Done! %s", __FUNCTION__);
+ return ret;
+ }
+
+protected:
+ virtual int handleResponse(WifiEvent& reply) {
+ ALOGD("In GetRadioComboCommand::handleResponse");
+ if (reply.get_cmd() != NL80211_CMD_VENDOR) {
+ ALOGD("Ignoring reply with cmd = %d", reply.get_cmd());
+ return NL_SKIP;
+ }
+
+ int id = reply.get_vendor_id();
+ int subcmd = reply.get_vendor_subcmd();
+
+ nlattr *vendor_data = reply.get_attribute(NL80211_ATTR_VENDOR_DATA);
+ int len = reply.get_vendor_data_len();
+
+ ALOGV("Id = %0x, subcmd = %d, len = %d", id, subcmd, len);
+ if (vendor_data == NULL || len == 0) {
+ ALOGE("no vendor data in GetRadioComboCommand response; ignoring it");
+ return NL_SKIP;
+ }
+
+ for (nl_iterator it(vendor_data); it.has_next(); it.next()) {
+ if (it.get_type() == ANDR_WIFI_ATTRIBUTE_RADIO_COMBO_MATRIX) {
+ void *data = it.get_data();
+ *rc_size = it.get_len();
+ if (!data || !*rc_size) {
+ ALOGE("Buffers pointers not set");
+ return NL_SKIP;
+ }
+ if (set_size_max < *rc_size) {
+ ALOGE("Unexpected buffers size");
+ return NL_SKIP;
+ }
+ memcpy(rcmatrix, data, min(len, *rc_size));
+ } else {
+ ALOGW("Ignoring invalid attribute type = %d, size = %d",
+ it.get_type(), it.get_len());
+ }
+ }
+
+ ALOGD("GetRadioComboCommand::Success");
+ return NL_OK;
+ }
+};
+/////////////////////////////////////////////////////////////////////
+
+class SetLatencyModeCommand : public WifiCommand {
+private:
+ u32 mLatencyMode;
+public:
+ SetLatencyModeCommand(wifi_interface_handle handle, u32 LatencyMode)
+ : WifiCommand("SetLatencyModeCommand", handle, 0) {
+ mLatencyMode = LatencyMode;
+ }
+
+ virtual int create() {
+ int ret;
+
+ /* Check for invalid latency Mode */
+ if ((mLatencyMode != WIFI_LATENCY_MODE_NORMAL) &&
+ (mLatencyMode != WIFI_LATENCY_MODE_LOW)) {
+ ALOGE("SetLatencyModeCommand: Invalid mode: %d", mLatencyMode);
+ return WIFI_ERROR_UNKNOWN;
+ }
+
+ ret = mMsg.create(GOOGLE_OUI, WIFI_SUBCMD_SET_LATENCY_MODE);
+ if (ret < 0) {
+ ALOGE("Can't create message to send to driver - %d", ret);
+ return ret;
+ }
+
+ nlattr *data = mMsg.attr_start(NL80211_ATTR_VENDOR_DATA);
+ ret = mMsg.put_u32(ANDR_WIFI_ATTRIBUTE_LATENCY_MODE, mLatencyMode);
+ if (ret < 0) {
+ return ret;
+ }
+
+ mMsg.attr_end(data);
+ return WIFI_SUCCESS;
+ }
+};
+
+class SetIndoorCommand : public WifiCommand {
+ private:
+ bool mIndoor;
+ public:
+ SetIndoorCommand(wifi_interface_handle handle, bool isIndoor)
+ : WifiCommand("SetIndoorCommand", handle, 0) {
+ mIndoor = isIndoor;
+ }
+
+ virtual int create() {
+ int ret;
+
+ if ((mIndoor != 0) &&
+ (mIndoor != 1)) {
+ ALOGE("SetIndoorCommand: Invalid mode: %d", mIndoor);
+ return WIFI_ERROR_UNKNOWN;
+ }
+
+ ret = mMsg.create(GOOGLE_OUI, WIFI_SUBCMD_CONFIG_INDOOR_STATE);
+ if (ret < 0) {
+ ALOGE("Can't create message to send to driver - %d", ret);
+ return ret;
+ }
+
+ nlattr *data = mMsg.attr_start(NL80211_ATTR_VENDOR_DATA);
+ ret = mMsg.put_u8(ANDR_WIFI_ATTRIBUTE_INDOOR, mIndoor);
+ if (ret < 0) {
+ return ret;
+ }
+
+ mMsg.attr_end(data);
+ return WIFI_SUCCESS;
+ }
+};
+
+static int wifi_get_multicast_id(wifi_handle handle, const char *name, const char *group)
+{
+ GetMulticastIdCommand cmd(handle, name, group);
+ int res = cmd.requestResponse();
+ if (res < 0)
+ return res;
+ else
+ return cmd.getId();
+}
+
+/////////////////////////////////////////////////////////////////////////
+
+static bool is_wifi_interface(const char *name)
+{
+ if (strncmp(name, "wlan", 4) != 0 && strncmp(name, "swlan", 5) != 0 &&
+ strncmp(name, "p2p", 3) != 0 && strncmp(name, "aware", 5) != 0) {
+ /* not a wifi interface; ignore it */
+ return false;
+ } else {
+ return true;
+ }
+}
+
+static int get_interface(const char *name, interface_info *info)
+{
+ int size = 0;
+ size = strlcpy(info->name, name, sizeof(info->name));
+ if (size >= sizeof(info->name)) {
+ return WIFI_ERROR_OUT_OF_MEMORY;
+ }
+ info->id = if_nametoindex(name);
+ // ALOGI("found an interface : %s, id = %d", name, info->id);
+ return WIFI_SUCCESS;
+}
+
+wifi_error wifi_init_interfaces(wifi_handle handle)
+{
+ hal_info *info = (hal_info *)handle;
+
+ struct dirent *de;
+
+ DIR *d = opendir("/sys/class/net");
+ if (d == 0)
+ return WIFI_ERROR_UNKNOWN;
+
+ int n = 0;
+ while ((de = readdir(d))) {
+ if (de->d_name[0] == '.')
+ continue;
+ if (is_wifi_interface(de->d_name) ) {
+ n++;
+ }
+ }
+
+ closedir(d);
+
+ if (n == 0)
+ return WIFI_ERROR_NOT_AVAILABLE;
+
+ d = opendir("/sys/class/net");
+ if (d == 0)
+ return WIFI_ERROR_UNKNOWN;
+
+ /* Have place holder for 3 virtual interfaces */
+ n += MAX_VIRTUAL_IFACES;
+ info->interfaces = (interface_info **)calloc(n, sizeof(interface_info *) * n);
+ if (!info->interfaces) {
+ info->num_interfaces = 0;
+ closedir(d);
+ return WIFI_ERROR_OUT_OF_MEMORY;
+ }
+
+ int i = 0;
+ while ((de = readdir(d))) {
+ if (de->d_name[0] == '.')
+ continue;
+ if (is_wifi_interface(de->d_name)) {
+ interface_info *ifinfo = (interface_info *)malloc(sizeof(interface_info));
+ if (!ifinfo) {
+ free(info->interfaces);
+ info->num_interfaces = 0;
+ closedir(d);
+ return WIFI_ERROR_OUT_OF_MEMORY;
+ }
+ memset(ifinfo, 0, sizeof(interface_info));
+ if (get_interface(de->d_name, ifinfo) != WIFI_SUCCESS) {
+ continue;
+ }
+ /* Mark as static iface */
+ ifinfo->is_virtual = false;
+ ifinfo->handle = handle;
+ info->interfaces[i] = ifinfo;
+ i++;
+ }
+ }
+
+ closedir(d);
+
+ info->num_interfaces = i;
+ info->max_num_interfaces = n;
+ return WIFI_SUCCESS;
+}
+
+wifi_error wifi_get_ifaces(wifi_handle handle, int *num, wifi_interface_handle **interfaces)
+{
+ hal_info *info = (hal_info *)handle;
+
+ *interfaces = (wifi_interface_handle *)info->interfaces;
+ *num = info->num_interfaces;
+
+ return WIFI_SUCCESS;
+}
+
+wifi_error wifi_add_iface_hal_info(wifi_handle handle, const char* ifname)
+{
+ hal_info *info = NULL;
+ int i = 0;
+
+ info = (hal_info *)handle;
+ if (info == NULL) {
+ ALOGE("Could not find info\n");
+ return WIFI_ERROR_UNKNOWN;
+ }
+
+ ALOGI("%s: add interface_info for iface: %s\n", __FUNCTION__, ifname);
+ if (info->num_interfaces == MAX_VIRTUAL_IFACES) {
+ ALOGE("No space. max limit reached for virtual interfaces %d\n", info->num_interfaces);
+ return WIFI_ERROR_OUT_OF_MEMORY;
+ }
+
+ interface_info *ifinfo = (interface_info *)malloc(sizeof(interface_info));
+ if (!ifinfo) {
+ free(info->interfaces);
+ info->num_interfaces = 0;
+ return WIFI_ERROR_OUT_OF_MEMORY;
+ }
+
+ ifinfo->handle = handle;
+ while (i < info->max_num_interfaces) {
+ if (info->interfaces[i] == NULL) {
+ if (get_interface(ifname, ifinfo) != WIFI_SUCCESS) {
+ continue;
+ }
+ ifinfo->is_virtual = true;
+ info->interfaces[i] = ifinfo;
+ info->num_interfaces++;
+ ALOGI("%s: Added iface: %s at the index %d\n", __FUNCTION__, ifname, i);
+ break;
+ }
+ i++;
+ }
+ return WIFI_SUCCESS;
+}
+
+wifi_error wifi_clear_iface_hal_info(wifi_handle handle, const char* ifname)
+{
+ hal_info *info = (hal_info *)handle;
+ int i = 0;
+
+ ALOGI("%s: clear hal info for iface: %s\n", __FUNCTION__, ifname);
+ while (i < info->max_num_interfaces) {
+ if ((info->interfaces[i] != NULL) &&
+ strncmp(info->interfaces[i]->name, ifname,
+ sizeof(info->interfaces[i]->name)) == 0) {
+ free(info->interfaces[i]);
+ info->interfaces[i] = NULL;
+ info->num_interfaces--;
+ ALOGI("%s: Cleared the index = %d for iface: %s\n", __FUNCTION__, i, ifname);
+ break;
+ }
+ i++;
+ }
+ if (i < info->num_interfaces) {
+ for (int j = i; j < info->num_interfaces; j++) {
+ info->interfaces[j] = info->interfaces[j+1];
+ }
+ info->interfaces[info->num_interfaces] = NULL;
+ }
+ return WIFI_SUCCESS;
+}
+
+wifi_interface_handle wifi_get_wlan_interface(wifi_handle info, wifi_interface_handle *ifaceHandles, int numIfaceHandles)
+{
+ char buf[EVENT_BUF_SIZE];
+ wifi_interface_handle wlan0Handle;
+ wifi_error res = wifi_get_ifaces((wifi_handle)info, &numIfaceHandles, &ifaceHandles);
+ if (res < 0) {
+ return NULL;
+ }
+ for (int i = 0; i < numIfaceHandles; i++) {
+ if (wifi_get_iface_name(ifaceHandles[i], buf, sizeof(buf)) == WIFI_SUCCESS) {
+ if (strncmp(buf, "wlan0", 5) == 0) {
+ ALOGI("found interface %s\n", buf);
+ wlan0Handle = ifaceHandles[i];
+ return wlan0Handle;
+ }
+ }
+ }
+ return NULL;
+}
+wifi_error wifi_get_iface_name(wifi_interface_handle handle, char *name, size_t size)
+{
+ interface_info *info = (interface_info *)handle;
+ strncpy(name, info->name, (IFNAMSIZ));
+ name[IFNAMSIZ - 1] = '\0';
+ return WIFI_SUCCESS;
+}
+
+wifi_interface_handle wifi_get_iface_handle(wifi_handle handle, char *name)
+{
+ char buf[EVENT_BUF_SIZE];
+ wifi_interface_handle *ifaceHandles;
+ int numIfaceHandles;
+ wifi_interface_handle ifHandle;
+
+ wifi_error res = wifi_get_ifaces((wifi_handle)handle, &numIfaceHandles, &ifaceHandles);
+ if (res < 0) {
+ return NULL;
+ }
+ for (int i = 0; i < numIfaceHandles; i++) {
+ if (wifi_get_iface_name(ifaceHandles[i], buf, sizeof(buf)) == WIFI_SUCCESS) {
+ if (strcmp(buf, name) == 0) {
+ ALOGI("found interface %s\n", buf);
+ ifHandle = ifaceHandles[i];
+ return ifHandle;
+ }
+ }
+ }
+ return NULL;
+}
+
+wifi_error wifi_get_supported_feature_set(wifi_interface_handle handle, feature_set *set)
+{
+ GetFeatureSetCommand command(handle, ANDR_WIFI_ATTRIBUTE_NUM_FEATURE_SET, set, NULL, NULL, 1);
+ return (wifi_error) command.requestResponse();
+}
+
+wifi_error wifi_get_concurrency_matrix(wifi_interface_handle handle, int set_size_max,
+ feature_set set[], int *set_size)
+{
+ GetFeatureSetCommand command(handle, ANDR_WIFI_ATTRIBUTE_FEATURE_SET, NULL,
+ set, set_size, set_size_max);
+ return (wifi_error) command.requestResponse();
+}
+
+wifi_error wifi_get_supported_radio_combinations_matrix(wifi_handle handle,
+ u32 max_size, u32* size, wifi_radio_combination_matrix *radio_combination_matrix)
+{
+ int numIfaceHandles = 0;
+ wifi_interface_handle *ifaceHandles = NULL;
+ wifi_interface_handle wlan0Handle;
+
+ wlan0Handle = wifi_get_wlan_interface((wifi_handle)handle, ifaceHandles, numIfaceHandles);
+ GetRadioComboCommand *cmd = new GetRadioComboCommand(wlan0Handle, max_size,
+ size, radio_combination_matrix);
+ NULL_CHECK_RETURN(cmd, "memory allocation failure", WIFI_ERROR_OUT_OF_MEMORY);
+ wifi_error result = (wifi_error)cmd->start();
+ if (result == WIFI_SUCCESS) {
+ ALOGD("Get radio combo matrix success");
+ } else {
+ ALOGE("Get radio combo matrix failed\n");
+ }
+ cmd->releaseRef();
+ return result;
+}
+
+wifi_error wifi_set_scanning_mac_oui(wifi_interface_handle handle, oui scan_oui)
+{
+ SetPnoMacAddrOuiCommand command(handle, scan_oui);
+ return (wifi_error)command.start();
+
+}
+
+wifi_error wifi_set_nodfs_flag(wifi_interface_handle handle, u32 nodfs)
+{
+ SetNodfsCommand command(handle, nodfs);
+ return (wifi_error) command.requestResponse();
+}
+
+wifi_error wifi_set_country_code(wifi_interface_handle handle, const char *country_code)
+{
+ SetCountryCodeCommand command(handle, country_code);
+ return (wifi_error) command.requestResponse();
+}
+
+static wifi_error wifi_start_rssi_monitoring(wifi_request_id id, wifi_interface_handle
+ iface, s8 max_rssi, s8 min_rssi, wifi_rssi_event_handler eh)
+{
+ ALOGI("Starting RSSI monitor %d", id);
+ wifi_handle handle = getWifiHandle(iface);
+ SetRSSIMonitorCommand *cmd = new SetRSSIMonitorCommand(id, iface, max_rssi, min_rssi, eh);
+ NULL_CHECK_RETURN(cmd, "memory allocation failure", WIFI_ERROR_OUT_OF_MEMORY);
+ wifi_error result = wifi_register_cmd(handle, id, cmd);
+ if (result != WIFI_SUCCESS) {
+ ALOGI("wifi_register_cmd() is failed %d", id);
+ cmd->releaseRef();
+ return result;
+ }
+ result = (wifi_error)cmd->start();
+ if (result != WIFI_SUCCESS) {
+ ALOGI("start() is failed %d", id);
+ wifi_unregister_cmd(handle, id);
+ cmd->releaseRef();
+ return result;
+ }
+ return result;
+}
+
+static wifi_error wifi_stop_rssi_monitoring(wifi_request_id id, wifi_interface_handle iface)
+{
+ ALOGI("Stopping RSSI monitor %d", id);
+
+ if(id == -1) {
+ wifi_rssi_event_handler handler;
+ s8 max_rssi = 0, min_rssi = 0;
+ memset(&handler, 0, sizeof(handler));
+ SetRSSIMonitorCommand *cmd = new SetRSSIMonitorCommand(id, iface,
+ max_rssi, min_rssi, handler);
+ NULL_CHECK_RETURN(cmd, "memory allocation failure", WIFI_ERROR_OUT_OF_MEMORY);
+ cmd->cancel();
+ cmd->releaseRef();
+ return WIFI_SUCCESS;
+ }
+ return wifi_cancel_cmd(id, iface);
+}
+
+static wifi_error wifi_get_packet_filter_capabilities(wifi_interface_handle handle,
+ u32 *version, u32 *max_len)
+{
+ ALOGD("Getting APF capabilities, halHandle = %p\n", handle);
+ AndroidPktFilterCommand *cmd = new AndroidPktFilterCommand(handle, version, max_len);
+ NULL_CHECK_RETURN(cmd, "memory allocation failure", WIFI_ERROR_OUT_OF_MEMORY);
+ wifi_error result = (wifi_error)cmd->start();
+ if (result == WIFI_SUCCESS) {
+ ALOGD("Getting APF capability, version = %d, max_len = %d\n", *version, *max_len);
+ }
+ cmd->releaseRef();
+ return result;
+}
+
+static wifi_error wifi_set_packet_filter(wifi_interface_handle handle,
+ const u8 *program, u32 len)
+{
+ ALOGD("Setting APF program, halHandle = %p\n", handle);
+ AndroidPktFilterCommand *cmd = new AndroidPktFilterCommand(handle, program, len);
+ NULL_CHECK_RETURN(cmd, "memory allocation failure", WIFI_ERROR_OUT_OF_MEMORY);
+ wifi_error result = (wifi_error)cmd->start();
+ cmd->releaseRef();
+ return result;
+}
+
+static wifi_error wifi_read_packet_filter(wifi_interface_handle handle,
+ u32 src_offset, u8 *host_dst, u32 length)
+{
+ ALOGD("Read APF program, halHandle = %p, length = %d\n", handle, length);
+ AndroidPktFilterCommand *cmd = new AndroidPktFilterCommand(handle, host_dst, length);
+ NULL_CHECK_RETURN(cmd, "memory allocation failure", WIFI_ERROR_OUT_OF_MEMORY);
+ wifi_error result = (wifi_error)cmd->start();
+ if (result == WIFI_SUCCESS) {
+ ALOGI("Read APF program success\n");
+ }
+ cmd->releaseRef();
+ return result;
+}
+static wifi_error wifi_configure_nd_offload(wifi_interface_handle handle, u8 enable)
+{
+ SetNdoffloadCommand command(handle, enable);
+ return (wifi_error) command.requestResponse();
+}
+
+wifi_error wifi_set_indoor_state(wifi_handle handle, bool isIndoor)
+{
+ ALOGD("Setting Wifi Indoor state, halHandle = %p isIndoor = %d\n", handle, isIndoor);
+ int numIfaceHandles = 0;
+ wifi_interface_handle *ifaceHandles = NULL;
+ wifi_interface_handle wlan0Handle;
+
+ wlan0Handle = wifi_get_wlan_interface((wifi_handle)handle, ifaceHandles, numIfaceHandles);
+
+ SetIndoorCommand command(wlan0Handle, isIndoor);
+ return (wifi_error) command.requestResponse();
+}
+
+wifi_error wifi_set_latency_mode(wifi_interface_handle handle, wifi_latency_mode mode)
+{
+ ALOGD("Setting Wifi Latency mode, halHandle = %p LatencyMode = %d\n", handle, mode);
+ SetLatencyModeCommand command(handle, mode);
+ return (wifi_error) command.requestResponse();
+}
+
+/////////////////////////////////////////////////////////////////////////
+class TxPowerScenario : public WifiCommand {
+ wifi_power_scenario mScenario;
+public:
+ // constructor for tx power scenario setting
+ TxPowerScenario(wifi_interface_handle handle, wifi_power_scenario scenario)
+ : WifiCommand("TxPowerScenario", handle, 0), mScenario(scenario)
+ {
+ mScenario = scenario;
+ }
+
+ // constructor for tx power scenario resetting
+ TxPowerScenario(wifi_interface_handle handle)
+ : WifiCommand("TxPowerScenario", handle, 0)
+ {
+ mScenario = WIFI_POWER_SCENARIO_DEFAULT;
+ }
+
+ int createRequest(WifiRequest& request, int subcmd, wifi_power_scenario mScenario) {
+ int result = request.create(GOOGLE_OUI, subcmd);
+ if (result < 0) {
+ return result;
+ }
+
+ if ((mScenario <= WIFI_POWER_SCENARIO_INVALID) ||
+ (mScenario >= SAR_CONFIG_SCENARIO_COUNT)) {
+ ALOGE("Unsupported tx power value:%d\n", mScenario);
+ return WIFI_ERROR_NOT_SUPPORTED;
+ }
+
+ nlattr *data = request.attr_start(NL80211_ATTR_VENDOR_DATA);
+ result = request.put_s8(ANDR_WIFI_ATTRIBUTE_TX_POWER_SCENARIO, mScenario);
+ if (result < 0) {
+ ALOGE("Failed to put tx power scenario request; result = %d", result);
+ return result;
+ }
+ request.attr_end(data);
+ return WIFI_SUCCESS;
+ }
+
+ int start(wifi_power_scenario mScenario) {
+ WifiRequest request(familyId(), ifaceId());
+ int result = createRequest(request, WIFI_SUBCMD_TX_POWER_SCENARIO, mScenario);
+ if (result != WIFI_SUCCESS) {
+ ALOGE("failed to create request; result = %d", result);
+ return result;
+ }
+
+ result = requestResponse(request);
+ if (result != WIFI_SUCCESS) {
+ ALOGE("failed to send tx power scenario; result = %d", result);
+ }
+ return result;
+ }
+protected:
+ virtual int handleResponse(WifiEvent& reply) {
+ ALOGD("Request complete!");
+ /* Nothing to do on response! */
+ return NL_SKIP;
+ }
+};
+
+
+wifi_error wifi_select_tx_power_scenario(wifi_interface_handle handle, wifi_power_scenario scenario)
+{
+ ALOGE("wifi_select_tx_power_scenario");
+ TxPowerScenario command(handle);
+ return (wifi_error)command.start(scenario);
+}
+
+wifi_error wifi_reset_tx_power_scenario(wifi_interface_handle handle)
+{
+ wifi_power_scenario scenario = WIFI_POWER_SCENARIO_DEFAULT;
+ ALOGE("wifi_reset_tx_power_scenario");
+ TxPowerScenario command(handle);
+ return (wifi_error)command.start(scenario);
+}
+
+/////////////////////////////////////////////////////////////////////////////
+
+class ThermalMitigation : public WifiCommand {
+private:
+ wifi_thermal_mode mMitigation;
+ u32 mCompletionWindow;
+public:
+ // constructor for thermal mitigation setting
+ ThermalMitigation(wifi_interface_handle handle,
+ wifi_thermal_mode mitigation, u32 completion_window)
+ : WifiCommand("ThermalMitigation", handle, 0)
+ {
+ mMitigation = mitigation;
+ mCompletionWindow = completion_window;
+ }
+
+ int createRequest(WifiRequest& request, int subcmd,
+ wifi_thermal_mode mitigation, u32 completion_window) {
+ int result = request.create(GOOGLE_OUI, subcmd);
+ if (result < 0) {
+ return result;
+ }
+
+ if ((mitigation < WIFI_MITIGATION_NONE) ||
+ (mitigation > WIFI_MITIGATION_EMERGENCY)) {
+ ALOGE("Unsupported tx mitigation value:%d\n", mitigation);
+ return WIFI_ERROR_NOT_SUPPORTED;
+ }
+
+ nlattr *data = request.attr_start(NL80211_ATTR_VENDOR_DATA);
+ result = request.put_s8(ANDR_WIFI_ATTRIBUTE_THERMAL_MITIGATION, mitigation);
+ if (result < 0) {
+ ALOGE("Failed to put tx power scenario request; result = %d", result);
+ return result;
+ }
+ result = request.put_u32(ANDR_WIFI_ATTRIBUTE_THERMAL_COMPLETION_WINDOW,
+ completion_window);
+ if (result < 0) {
+ ALOGE("Failed to put tx power scenario request; result = %d", result);
+ return result;
+ }
+
+ request.attr_end(data);
+ return WIFI_SUCCESS;
+ }
+
+ int start() {
+ WifiRequest request(familyId(), ifaceId());
+ int result = createRequest(request, WIFI_SUBCMD_THERMAL_MITIGATION, mMitigation,
+ mCompletionWindow);
+ if (result != WIFI_SUCCESS) {
+ ALOGE("failed to create request; result = %d", result);
+ return result;
+ }
+
+ ALOGD("try to get resp; mitigation=%d, delay=%d", mMitigation, mCompletionWindow);
+ result = requestResponse(request);
+ if (result != WIFI_SUCCESS) {
+ ALOGE("failed to send thermal mitigation; result = %d", result);
+ }
+ return result;
+ }
+protected:
+ virtual int handleResponse(WifiEvent& reply) {
+ ALOGD("Request complete!");
+ /* Nothing to do on response! */
+ return NL_SKIP;
+ }
+};
+
+wifi_error wifi_set_thermal_mitigation_mode(wifi_handle handle,
+ wifi_thermal_mode mode,
+ u32 completion_window)
+{
+ int numIfaceHandles = 0;
+ wifi_interface_handle *ifaceHandles = NULL;
+ wifi_interface_handle wlan0Handle;
+
+ wlan0Handle = wifi_get_wlan_interface((wifi_handle)handle, ifaceHandles, numIfaceHandles);
+ ThermalMitigation command(wlan0Handle, mode, completion_window);
+ return (wifi_error)command.start();
+}
+
+/////////////////////////////////////////////////////////////////////////////
+
+class ChAvoidCommand : public WifiCommand {
+ private:
+ u32 mNumParams;
+ wifi_coex_unsafe_channel *chavoidParams;
+ u32 mMandatory;
+
+ public:
+ ChAvoidCommand(wifi_interface_handle handle,
+ u32 num, wifi_coex_unsafe_channel channels[], u32 mandatory)
+ : WifiCommand("ChAvoidCommand", handle, 0),
+ mNumParams(num), chavoidParams(channels), mMandatory(mandatory)
+ {
+ }
+
+ int createRequest(WifiRequest& request) {
+ return createSetChAvoidRequest(request);
+ }
+
+ int createSetChAvoidRequest(WifiRequest& request) {
+ int result = request.create(GOOGLE_OUI, CHAVOID_SUBCMD_SET_CONFIG);
+ if (result < 0) {
+ ALOGE("%s : Failed to create SUBCMD\n", __func__);
+ return result;
+ }
+
+ nlattr *data = request.attr_start(NL80211_ATTR_VENDOR_DATA);
+ result = request.put_u32(CHAVOID_ATTRIBUTE_CNT, mNumParams);
+ if (result < 0) {
+ ALOGE("%s : Failed to set cound\n", __func__);
+ return result;
+ }
+ result = request.put_u32(CHAVOID_ATTRIBUTE_MANDATORY, mMandatory);
+ if (result < 0) {
+ ALOGE("%s : Failed to set mandatory cap\n", __func__);
+ return result;
+ }
+
+ nlattr *chavoid_config = request.attr_start(CHAVOID_ATTRIBUTE_CONFIG);
+ for (int i = 0; i< mNumParams; i++) {
+ nlattr *item = request.attr_start(i);
+ if (item == NULL) {
+ ALOGE("%s : Failed to alloc item\n", __func__);
+ return WIFI_ERROR_OUT_OF_MEMORY;
+ }
+ result = request.put_u32(CHAVOID_ATTRIBUTE_BAND, chavoidParams[i].band);
+ if (result < 0) {
+ ALOGE("%s : Failed to set band\n", __func__);
+ return result;
+ }
+ result = request.put_u32(CHAVOID_ATTRIBUTE_CHANNEL, chavoidParams[i].channel);
+ if (result < 0) {
+ ALOGE("%s : Failed to set channel\n", __func__);
+ return result;
+ }
+ result = request.put_u32(CHAVOID_ATTRIBUTE_PWRCAP, chavoidParams[i].power_cap_dbm);
+ if (result < 0) {
+ ALOGE("%s : Failed to set power cap\n", __func__);
+ return result;
+ }
+ request.attr_end(item);
+ }
+ request.attr_end(chavoid_config);
+ request.attr_end(data);
+ return WIFI_SUCCESS;
+ }
+
+ int start() {
+ WifiRequest request(familyId(), ifaceId());
+ int result = createRequest(request);
+ if (result < 0) {
+ return result;
+ }
+ result = requestResponse(request);
+ if (result < 0) {
+ ALOGI("Request Response failed for ChAvoid, result = %d", result);
+ return result;
+ }
+ return result;
+ }
+
+ int handleResponse(WifiEvent& reply) {
+ ALOGD("In ChAvoidCommand::handleResponse");
+
+ if (reply.get_cmd() != NL80211_CMD_VENDOR) {
+ ALOGD("Ignoring reply with cmd = %d", reply.get_cmd());
+ return NL_SKIP;
+ }
+
+ nlattr *vendor_data = reply.get_attribute(NL80211_ATTR_VENDOR_DATA);
+ int len = reply.get_vendor_data_len();
+
+ if (vendor_data == NULL || len == 0) {
+ ALOGE("no vendor data in ChAvoidCommand response; ignoring it");
+ return NL_SKIP;
+ }
+ ALOGD("Response received for ChAvoid command\n");
+ return NL_OK;
+ }
+
+ int handleEvent(WifiEvent& event) {
+ /* No Event to receive for ChAvoid commands */
+ ALOGD("ChAvoid command %s\n", __FUNCTION__);
+ return NL_SKIP;
+ }
+};
+
+wifi_error wifi_set_coex_unsafe_channels(wifi_handle handle,
+ u32 num, wifi_coex_unsafe_channel channels[], u32 mandatory)
+{
+ int numIfaceHandles = 0;
+ wifi_interface_handle *ifaceHandles = NULL;
+ wifi_interface_handle wlan0Handle;
+
+ wlan0Handle = wifi_get_wlan_interface((wifi_handle)handle, ifaceHandles, numIfaceHandles);
+
+ ChAvoidCommand *cmd = new ChAvoidCommand(wlan0Handle, num, channels, mandatory);
+ NULL_CHECK_RETURN(cmd, "memory allocation failure", WIFI_ERROR_OUT_OF_MEMORY);
+ wifi_error result = (wifi_error)cmd->start();
+ if (result == WIFI_SUCCESS) {
+ ALOGI("Setting Channel Avoidance success\n");
+ } else {
+ ALOGE("Setting Channel Avoidance failed\n");
+ }
+ cmd->releaseRef();
+ return result;
+}
+
+/////////////////////////////////////////////////////////////////////////////
+
+class DscpCommand : public WifiCommand {
+ private:
+ u32 mStart;
+ u32 mEnd;
+ u32 mAc;
+ int mReqType;
+ public:
+ DscpCommand(wifi_interface_handle handle,
+ u32 start, u32 end, u32 ac)
+ : WifiCommand("DscpCommand", handle, 0),
+ mStart(start), mEnd(end), mAc(ac),
+ mReqType(SET_DSCP_TABLE)
+ {
+ }
+
+ DscpCommand(wifi_interface_handle handle)
+ : WifiCommand("DscpCommand", handle, 0),
+ mReqType(RESET_DSCP_TABLE)
+ {
+ }
+
+ int createRequest(WifiRequest& request) {
+ if (mReqType == SET_DSCP_TABLE) {
+ ALOGI("\n%s: DSCP set table request\n", __FUNCTION__);
+ return createSetDscpRequest(request);
+ } else if (mReqType == RESET_DSCP_TABLE) {
+ ALOGI("\n%s: DSCP reset table request\n", __FUNCTION__);
+ return createResetDscpRequest(request);
+ } else {
+ ALOGE("\n%s Unknown DSCP request\n", __FUNCTION__);
+ return WIFI_ERROR_NOT_SUPPORTED;
+ }
+ return WIFI_SUCCESS;
+ }
+
+ int createSetDscpRequest(WifiRequest& request) {
+ int result = request.create(GOOGLE_OUI, DSCP_SUBCMD_SET_TABLE);
+ if (result < 0) {
+ return result;
+ }
+
+ nlattr *data = request.attr_start(NL80211_ATTR_VENDOR_DATA);
+ result = request.put_u32(DSCP_ATTRIBUTE_START, mStart);
+ if (result < 0) {
+ goto exit;
+ }
+ result = request.put_u32(DSCP_ATTRIBUTE_END, mEnd);
+ if (result < 0) {
+ goto exit;
+ }
+ result = request.put_u32(DSCP_ATTRIBUTE_AC, mAc);
+ if (result < 0) {
+ goto exit;
+ }
+ request.attr_end(data);
+exit:
+ return result;
+ }
+
+ int createResetDscpRequest(WifiRequest& request) {
+ int result = request.create(GOOGLE_OUI, DSCP_SUBCMD_RESET_TABLE);
+ if (result < 0) {
+ return result;
+ }
+
+ nlattr *data = request.attr_start(NL80211_ATTR_VENDOR_DATA);
+ request.attr_end(data);
+ return result;
+ }
+
+ int start() {
+ WifiRequest request(familyId(), ifaceId());
+ int result = createRequest(request);
+ if (result < 0) {
+ return result;
+ }
+ result = requestResponse(request);
+ if (result < 0) {
+ ALOGI("Request Response failed for DSCP, result = %d", result);
+ return result;
+ }
+ return result;
+ }
+
+ int handleResponse(WifiEvent& reply) {
+ ALOGD("In DscpCommand::handleResponse");
+
+ if (reply.get_cmd() != NL80211_CMD_VENDOR) {
+ ALOGD("Ignoring reply with cmd = %d", reply.get_cmd());
+ return NL_SKIP;
+ }
+
+ nlattr *vendor_data = reply.get_attribute(NL80211_ATTR_VENDOR_DATA);
+ int len = reply.get_vendor_data_len();
+
+ if (vendor_data == NULL || len == 0) {
+ ALOGE("no vendor data in DscpCommand response; ignoring it");
+ return NL_SKIP;
+ }
+ if( mReqType == SET_DSCP_TABLE) {
+ ALOGD("Response received for Set DSCP command\n");
+ } else if (mReqType == RESET_DSCP_TABLE) {
+ ALOGD("Response received for Reset DSCP command\n");
+ }
+ return NL_OK;
+ }
+
+ int handleEvent(WifiEvent& event) {
+ /* No Event to receive for DSCP commands */
+ ALOGD("DSCP command %s\n", __FUNCTION__);
+ return NL_SKIP;
+ }
+};
+
+wifi_error wifi_map_dscp_access_category(wifi_handle handle,
+ u32 start, u32 end, u32 ac)
+{
+ int numIfaceHandles = 0;
+ wifi_interface_handle *ifaceHandles = NULL;
+ wifi_interface_handle wlan0Handle;
+
+ wlan0Handle = wifi_get_wlan_interface((wifi_handle)handle, ifaceHandles, numIfaceHandles);
+
+ DscpCommand *cmd = new DscpCommand(wlan0Handle, start, end, ac);
+ NULL_CHECK_RETURN(cmd, "memory allocation failure", WIFI_ERROR_OUT_OF_MEMORY);
+ wifi_error result = (wifi_error)cmd->start();
+ if (result == WIFI_SUCCESS) {
+ ALOGI("Mapping DSCP table success\n");
+ } else {
+ ALOGE("Mapping DSCP table fail\n");
+ }
+ cmd->releaseRef();
+ return result;
+}
+
+wifi_error wifi_reset_dscp_mapping(wifi_handle handle)
+{
+ int numIfaceHandles = 0;
+ wifi_interface_handle *ifaceHandles = NULL;
+ wifi_interface_handle wlan0Handle;
+
+ wlan0Handle = wifi_get_wlan_interface((wifi_handle)handle, ifaceHandles, numIfaceHandles);
+
+ DscpCommand *cmd = new DscpCommand(wlan0Handle);
+ NULL_CHECK_RETURN(cmd, "memory allocation failure", WIFI_ERROR_OUT_OF_MEMORY);
+ wifi_error result = (wifi_error)cmd->start();
+ if (result == WIFI_SUCCESS) {
+ ALOGI("Resetting DSCP table success\n");
+ } else {
+ ALOGE("Resetting DSCP table fail\n");
+ }
+ cmd->releaseRef();
+ return result;
+}
+
+class VirtualIfaceConfig : public WifiCommand {
+ const char *mIfname;
+ nl80211_iftype mType;
+ u32 mwlan0_id;
+
+public:
+ VirtualIfaceConfig(wifi_interface_handle handle, const char* ifname,
+ nl80211_iftype iface_type, u32 wlan0_id)
+ : WifiCommand("VirtualIfaceConfig", handle, 0), mIfname(ifname), mType(iface_type),
+ mwlan0_id(wlan0_id)
+ {
+ mIfname = ifname;
+ mType = iface_type;
+ mwlan0_id = wlan0_id;
+ }
+ int createRequest(WifiRequest& request, const char* ifname,
+ nl80211_iftype iface_type, u32 wlan0_id) {
+ ALOGD("add ifname = %s, iface_type = %d, wlan0_id = %d",
+ ifname, iface_type, wlan0_id);
+
+ int result = request.create(NL80211_CMD_NEW_INTERFACE);
+ if (result < 0) {
+ ALOGE("failed to create NL80211_CMD_NEW_INTERFACE; result = %d", result);
+ return result;
+ }
+
+ result = request.put_u32(NL80211_ATTR_IFINDEX, wlan0_id);
+ if (result < 0) {
+ ALOGE("failed to put NL80211_ATTR_IFINDEX; result = %d", result);
+ return result;
+ }
+
+ result = request.put_string(NL80211_ATTR_IFNAME, ifname);
+ if (result < 0) {
+ ALOGE("failed to put NL80211_ATTR_IFNAME = %s; result = %d", ifname, result);
+ return result;
+ }
+
+ result = request.put_u32(NL80211_ATTR_IFTYPE, iface_type);
+ if (result < 0) {
+ ALOGE("failed to put NL80211_ATTR_IFTYPE = %d; result = %d", iface_type, result);
+ return result;
+ }
+ return WIFI_SUCCESS;
+ }
+
+ int deleteRequest(WifiRequest& request, const char* ifname) {
+ ALOGD("delete ifname = %s\n", ifname);
+ int result = request.create(NL80211_CMD_DEL_INTERFACE);
+ if (result < 0) {
+ ALOGE("failed to create NL80211_CMD_DEL_INTERFACE; result = %d", result);
+ return result;
+ }
+ result = request.put_u32(NL80211_ATTR_IFINDEX, if_nametoindex(ifname));
+ if (result < 0) {
+ ALOGE("failed to put NL80211_ATTR_IFINDEX = %d; result = %d",
+ if_nametoindex(ifname), result);
+ return result;
+ }
+ result = request.put_string(NL80211_ATTR_IFNAME, ifname);
+ if (result < 0) {
+ ALOGE("failed to put NL80211_ATTR_IFNAME = %s; result = %d", ifname, result);
+ return result;
+ }
+ return WIFI_SUCCESS;
+ }
+
+ int createIface() {
+ ALOGE("Creating virtual interface");
+ WifiRequest request(familyId(), ifaceId());
+ int result = createRequest(request, mIfname, mType, mwlan0_id);
+ if (result != WIFI_SUCCESS) {
+ ALOGE("failed to create virtual iface request; result = %d\n", result);
+ return result;
+ }
+
+ result = requestResponse(request);
+ if (result != WIFI_SUCCESS) {
+ ALOGE("failed to get the virtual iface create response; result = %d\n", result);
+ return result;
+ }
+ ALOGE("Created virtual interface");
+ return WIFI_SUCCESS;
+ }
+
+ int deleteIface() {
+ ALOGD("Deleting virtual interface");
+ WifiRequest request(familyId(), ifaceId());
+ int result = deleteRequest(request, mIfname);
+ if (result != WIFI_SUCCESS) {
+ ALOGE("failed to create virtual iface delete request; result = %d\n", result);
+ return result;
+ }
+
+ result = requestResponse(request);
+ if (result != WIFI_SUCCESS) {
+ ALOGE("failed to get response of delete virtual interface; result = %d\n", result);
+ return result;
+ }
+ return WIFI_SUCCESS;
+ }
+protected:
+ virtual int handleResponse(WifiEvent& reply) {
+ ALOGD("Request complete!");
+ /* Nothing to do on response! */
+ return NL_SKIP;
+ }
+};
+
+static std::vector<std::string> added_ifaces;
+
+static void wifi_cleanup_dynamic_ifaces(wifi_handle handle)
+{
+ int len = added_ifaces.size();
+ while (len--) {
+ wifi_virtual_interface_delete(handle, added_ifaces.front().c_str());
+ }
+ added_ifaces.clear();
+}
+
+wifi_error wifi_virtual_interface_create(wifi_handle handle, const char* ifname,
+ wifi_interface_type iface_type)
+{
+ int numIfaceHandles = 0;
+ wifi_error ret = WIFI_SUCCESS;
+ wifi_interface_handle *ifaceHandles = NULL;
+ wifi_interface_handle wlan0Handle;
+ nl80211_iftype type = NL80211_IFTYPE_UNSPECIFIED;
+ u32 wlan0_id = if_nametoindex("wlan0");
+
+ if (!handle || !wlan0_id) {
+ ALOGE("%s: Error wifi_handle NULL or wlan0 not present\n", __FUNCTION__);
+ return WIFI_ERROR_UNKNOWN;
+ }
+
+ /* Do not create interface if already exist. */
+ if (if_nametoindex(ifname)) {
+ ALOGD("%s: if_nametoindex(%s) = %d already exists, skip create \n",
+ __FUNCTION__, ifname, if_nametoindex(ifname));
+ return WIFI_SUCCESS;
+ }
+
+ ALOGD("%s: ifname name = %s, type = %s\n", __FUNCTION__, ifname,
+ IfaceTypeToString(iface_type));
+
+ switch (iface_type) {
+ case WIFI_INTERFACE_TYPE_STA:
+ type = NL80211_IFTYPE_STATION;
+ break;
+ case WIFI_INTERFACE_TYPE_AP:
+ type = NL80211_IFTYPE_AP;
+ break;
+ case WIFI_INTERFACE_TYPE_P2P:
+ type = NL80211_IFTYPE_P2P_DEVICE;
+ break;
+ case WIFI_INTERFACE_TYPE_NAN:
+ type = NL80211_IFTYPE_NAN;
+ break;
+ default:
+ ALOGE("%s: Wrong interface type %u\n", __FUNCTION__, iface_type);
+ return WIFI_ERROR_UNKNOWN;
+ }
+
+ wlan0Handle = wifi_get_wlan_interface((wifi_handle)handle, ifaceHandles, numIfaceHandles);
+ VirtualIfaceConfig command(wlan0Handle, ifname, type, wlan0_id);
+
+ ret = (wifi_error)command.createIface();
+ if (ret != WIFI_SUCCESS) {
+ ALOGE("%s: Iface add Error:%d", __FUNCTION__,ret);
+ return ret;
+ }
+ /* Update dynamic interface list */
+ added_ifaces.push_back(std::string(ifname));
+ ret = wifi_add_iface_hal_info((wifi_handle)handle, ifname);
+ return ret;
+}
+
+wifi_error wifi_virtual_interface_delete(wifi_handle handle, const char* ifname)
+{
+ int numIfaceHandles = 0;
+ int i = 0;
+ wifi_error ret = WIFI_SUCCESS;
+ wifi_interface_handle *ifaceHandles = NULL;
+ wifi_interface_handle wlan0Handle;
+ hal_info *info = (hal_info *)handle;
+ u32 wlan0_id = if_nametoindex("wlan0");
+
+ if (!handle || !wlan0_id) {
+ ALOGE("%s: Error wifi_handle NULL or wlan0 not present\n", __FUNCTION__);
+ return WIFI_ERROR_UNKNOWN;
+ }
+
+ while (i < info->max_num_interfaces) {
+ if (info->interfaces[i] != NULL &&
+ strncmp(info->interfaces[i]->name,
+ ifname, sizeof(info->interfaces[i]->name)) == 0) {
+ if (info->interfaces[i]->is_virtual == false) {
+ ALOGI("%s: %s is static iface, skip delete\n",
+ __FUNCTION__, ifname);
+ return WIFI_SUCCESS;
+ }
+ }
+ i++;
+ }
+
+ ALOGD("%s: iface name=%s\n", __FUNCTION__, ifname);
+ wlan0Handle = wifi_get_wlan_interface((wifi_handle)handle, ifaceHandles, numIfaceHandles);
+ VirtualIfaceConfig command(wlan0Handle, ifname, (nl80211_iftype)0, 0);
+ ret = (wifi_error)command.deleteIface();
+ if (ret != WIFI_SUCCESS) {
+ ALOGE("%s: Iface delete Error:%d", __FUNCTION__,ret);
+ return ret;
+ }
+ /* Update dynamic interface list */
+ added_ifaces.erase(std::remove(added_ifaces.begin(), added_ifaces.end(), std::string(ifname)),
+ added_ifaces.end());
+ ret = wifi_clear_iface_hal_info((wifi_handle)handle, ifname);
+ return ret;
+}
+/////////////////////////////////////////////////////////////////////////////
+
+class MultiStaConfig : public WifiCommand {
+ wifi_multi_sta_use_case mUseCase;
+ int mReqType;
+
+public:
+ MultiStaConfig(wifi_interface_handle handle)
+ : WifiCommand("MultiStaConfig", handle, 0), mReqType(SET_PRIMARY_CONNECTION)
+ {
+ }
+ MultiStaConfig(wifi_interface_handle handle, wifi_multi_sta_use_case use_case)
+ : WifiCommand("MultiStaConfig", handle, 0), mUseCase(use_case), mReqType(SET_USE_CASE)
+ {
+ mUseCase = use_case;
+ }
+
+ int createRequest(WifiRequest& request) {
+ if (mReqType == SET_PRIMARY_CONNECTION) {
+ ALOGI("\n%s: MultiSta set primary connection\n", __FUNCTION__);
+ return createSetPrimaryConnectionRequest(request);
+ } else if (mReqType == SET_USE_CASE) {
+ ALOGI("\n%s: MultiSta set use case\n", __FUNCTION__);
+ return createSetUsecaseRequest(request);
+ } else {
+ ALOGE("\n%s Unknown MultiSta request\n", __FUNCTION__);
+ return WIFI_ERROR_NOT_SUPPORTED;
+ }
+ return WIFI_SUCCESS;
+ }
+
+ int createSetPrimaryConnectionRequest(WifiRequest& request) {
+ int result = request.create(GOOGLE_OUI, WIFI_SUBCMD_SET_MULTISTA_PRIMARY_CONNECTION);
+ if (result < 0) {
+ return result;
+ }
+
+ nlattr *data = request.attr_start(NL80211_ATTR_VENDOR_DATA);
+ request.attr_end(data);
+
+ return result;
+ }
+
+ int createSetUsecaseRequest(WifiRequest& request) {
+ int result = request.create(GOOGLE_OUI, WIFI_SUBCMD_SET_MULTISTA_USE_CASE);
+ if (result < 0) {
+ return result;
+ }
+
+ nlattr *data = request.attr_start(NL80211_ATTR_VENDOR_DATA);
+ result = request.put_u32(MULTISTA_ATTRIBUTE_USE_CASE, mUseCase);
+ if (result < 0) {
+ ALOGE("failed to put MULTISTA_ATTRIBUTE_USE_CASE = %d; result = %d", mUseCase, result);
+ goto exit;
+ }
+
+exit: request.attr_end(data);
+ return result;
+ }
+
+ int start() {
+ WifiRequest request(familyId(), ifaceId());
+ int result = createRequest(request);
+ if (result < 0) {
+ return result;
+ }
+ result = requestResponse(request);
+ if (result < 0) {
+ ALOGI("Request Response failed for MultiSta, result = %d", result);
+ return result;
+ }
+ ALOGI("Done!");
+ return result;
+ }
+protected:
+ virtual int handleResponse(WifiEvent& reply) {
+ ALOGD("Request complete!");
+ /* Nothing to do on response! */
+ return NL_SKIP;
+ }
+};
+
+wifi_error wifi_multi_sta_set_primary_connection(wifi_handle handle, wifi_interface_handle iface)
+{
+ wifi_error ret = WIFI_SUCCESS;
+ char buf[IFNAMSIZ];
+
+ if (!handle || !iface) {
+ ALOGE("%s: Error wifi_handle NULL or invalid wifi interface handle\n", __FUNCTION__);
+ return WIFI_ERROR_UNKNOWN;
+ }
+
+ if (wifi_get_iface_name(iface, buf, sizeof(buf)) != WIFI_SUCCESS) {
+ ALOGE("%s : Invalid interface handle\n", __func__);
+ return WIFI_ERROR_INVALID_ARGS;
+ }
+
+ ALOGD("Setting Multista primary connection for iface = %s\n", buf);
+
+ MultiStaConfig *cmd = new MultiStaConfig(iface);
+ NULL_CHECK_RETURN(cmd, "memory allocation failure", WIFI_ERROR_OUT_OF_MEMORY);
+ ret = (wifi_error)cmd->start();
+ cmd->releaseRef();
+ return ret;
+}
+
+wifi_error wifi_multi_sta_set_use_case(wifi_handle handle, wifi_multi_sta_use_case use_case)
+{
+ int numIfaceHandles = 0;
+ wifi_error ret = WIFI_SUCCESS;
+ wifi_interface_handle *ifaceHandles = NULL;
+ wifi_interface_handle wlan0Handle;
+
+ if (!handle) {
+ ALOGE("%s: Error wifi_handle NULL\n", __FUNCTION__);
+ return WIFI_ERROR_UNKNOWN;
+ }
+
+ if (!(use_case >= WIFI_DUAL_STA_TRANSIENT_PREFER_PRIMARY &&
+ use_case <= WIFI_DUAL_STA_NON_TRANSIENT_UNBIASED)) {
+ ALOGE("%s: Invalid multi_sta usecase %d\n", __FUNCTION__, use_case);
+ return WIFI_ERROR_INVALID_ARGS;
+ }
+
+ wlan0Handle = wifi_get_wlan_interface((wifi_handle)handle, ifaceHandles, numIfaceHandles);
+ ALOGD("Setting Multista usecase = %d\n", use_case);
+ MultiStaConfig *cmd = new MultiStaConfig(wlan0Handle, use_case);
+ NULL_CHECK_RETURN(cmd, "memory allocation failure", WIFI_ERROR_OUT_OF_MEMORY);
+ ret = (wifi_error)cmd->start();
+ cmd->releaseRef();
+ return ret;
+}
+/////////////////////////////////////////////////////////////////////////////////////////////////
+
+class SetVoipModeCommand : public WifiCommand {
+
+private:
+ wifi_voip_mode mMode;
+public:
+ SetVoipModeCommand(wifi_interface_handle handle, wifi_voip_mode mode)
+ : WifiCommand("SetVoipModeCommand", handle, 0) {
+ mMode = mode;
+ }
+ virtual int create() {
+ int ret;
+
+ ret = mMsg.create(GOOGLE_OUI, WIFI_SUBCMD_CONFIG_VOIP_MODE);
+ if (ret < 0) {
+ ALOGE("Can't create message to send to driver - %d", ret);
+ return ret;
+ }
+
+ nlattr *data = mMsg.attr_start(NL80211_ATTR_VENDOR_DATA);
+ ret = mMsg.put_u32(ANDR_WIFI_ATTRIBUTE_VOIP_MODE, mMode);
+ ALOGE("mMode - %d", mMode);
+ if (ret < 0) {
+ ALOGE("Failed to set voip mode %d\n", mMode);
+ return ret;
+ }
+
+ ALOGI("Successfully configured voip mode %d\n", mMode);
+ mMsg.attr_end(data);
+ return WIFI_SUCCESS;
+ }
+};
+
+wifi_error wifi_set_voip_mode(wifi_interface_handle handle, wifi_voip_mode mode)
+{
+ ALOGD("Setting VOIP mode, halHandle = %p Mode = %d\n", handle, mode);
+ SetVoipModeCommand command(handle, mode);
+ return (wifi_error) command.requestResponse();
+}
+
+/////////////////////////////////////////////////////////////////////////////////////////////////
+class SetDtimConfigCommand : public WifiCommand {
+
+private:
+ uint32_t multiplier;
+public:
+ SetDtimConfigCommand(wifi_interface_handle handle, u32 dtim_multiplier)
+ : WifiCommand("SetDtimConfigCommand", handle, 0) {
+ multiplier = dtim_multiplier;
+ }
+ virtual int create() {
+ int ret;
+
+ ret = mMsg.create(GOOGLE_OUI, WIFI_SUBCMD_SET_DTIM_CONFIG);
+ if (ret < 0) {
+ ALOGE("Can't create message to send to driver - %d", ret);
+ return ret;
+ }
+
+ nlattr *data = mMsg.attr_start(NL80211_ATTR_VENDOR_DATA);
+ ret = mMsg.put_u32(ANDR_WIFI_ATTRIBUTE_DTIM_MULTIPLIER, multiplier);
+ if (ret < 0) {
+ ALOGE("Failed to set dtim multiplier %d\n", multiplier);
+ return ret;
+ }
+
+ ALOGI("Successfully configured dtim multiplier %d\n", multiplier);
+ mMsg.attr_end(data);
+ return WIFI_SUCCESS;
+ }
+};
+
+wifi_error wifi_set_dtim_config(wifi_interface_handle handle, u32 multiplier)
+{
+ ALOGD("Setting DTIM config , halHandle = %p Multiplier = %d\n", handle, multiplier);
+ SetDtimConfigCommand command(handle, multiplier);
+ return (wifi_error) command.requestResponse();
+}
+
+/////////////////////////////////////////////////////////////////////////////////////////////////
+class UsableChannelCommand : public WifiCommand {
+
+private:
+ u32 mBandMask;
+ u32 mIfaceModeMask;
+ u32 mFilterMask;
+ u32 mMaxSize;
+ u32* mSize;
+ wifi_usable_channel* mChannels;
+
+public:
+ UsableChannelCommand(wifi_interface_handle handle, u32 band_mask, u32 iface_mode_mask,
+ u32 filter_mask, u32 max_size, u32* size, wifi_usable_channel* channels)
+ : WifiCommand("UsableChannelCommand", handle, 0),
+ mBandMask(band_mask), mIfaceModeMask(iface_mode_mask),
+ mFilterMask(filter_mask), mMaxSize(max_size),
+ mSize(size), mChannels(channels)
+ {
+ }
+
+ int createRequest(WifiRequest& request) {
+ createUsableChannelRequest(request);
+ return WIFI_SUCCESS;
+ }
+
+ int createUsableChannelRequest(WifiRequest& request) {
+ int result = request.create(GOOGLE_OUI, WIFI_SUBCMD_USABLE_CHANNEL);
+ if (result < 0) {
+ ALOGE("Failed to create UsableChannel request; result = %d", result);
+ return result;
+ }
+
+ nlattr *data = request.attr_start(NL80211_ATTR_VENDOR_DATA);
+
+ result = request.put_u32(USABLECHAN_ATTRIBUTE_BAND, mBandMask);
+ if (result != WIFI_SUCCESS) {
+ ALOGE("Failed to put log level; result = %d", result);
+ return result;
+ }
+ result = request.put_u32(USABLECHAN_ATTRIBUTE_IFACE, mIfaceModeMask);
+ if (result != WIFI_SUCCESS) {
+ ALOGE("Failed to put ring flags; result = %d", result);
+ return result;
+ }
+ result = request.put_u32(USABLECHAN_ATTRIBUTE_FILTER, mFilterMask);
+ if (result != WIFI_SUCCESS) {
+ ALOGE("Failed to put usablechan filter; result = %d", result);
+ return result;
+ }
+ result = request.put_u32(USABLECHAN_ATTRIBUTE_MAX_SIZE, mMaxSize);
+ if (result != WIFI_SUCCESS) {
+ ALOGE("Failed to put usablechan max_size; result = %d", result);
+ return result;
+ }
+ request.attr_end(data);
+
+ return WIFI_SUCCESS;
+ }
+
+ int start() {
+ WifiRequest request(familyId(), ifaceId());
+ int result = createRequest(request);
+ if (result != WIFI_SUCCESS) {
+ ALOGE("failed to create request; result = %d", result);
+ return result;
+ }
+
+ result = requestResponse(request);
+ if (result != WIFI_SUCCESS) {
+ ALOGE("failed to set scanning mac OUI; result = %d", result);
+ }
+
+ return result;
+ }
+
+ virtual int handleResponse(WifiEvent& reply) {
+ ALOGD("In DebugCommand::handleResponse");
+
+ if (reply.get_cmd() != NL80211_CMD_VENDOR) {
+ ALOGD("Ignoring reply with cmd = %d", reply.get_cmd());
+ return NL_SKIP;
+ }
+
+ nlattr *vendor_data = reply.get_attribute(NL80211_ATTR_VENDOR_DATA);
+ int len = reply.get_vendor_data_len();
+ wifi_usable_channel *channels(mChannels);
+
+ if (vendor_data == NULL || len == 0) {
+ ALOGE("No Debug data found");
+ return NL_SKIP;
+ }
+
+ nl_iterator it(vendor_data);
+ if (it.get_type() == USABLECHAN_ATTRIBUTE_SIZE) {
+ *mSize = it.get_u32();
+ } else {
+ ALOGE("Unknown attribute: %d expecting %d",
+ it.get_type(), USABLECHAN_ATTRIBUTE_SIZE);
+ return NL_SKIP;
+ }
+
+ it.next();
+ if (it.get_type() == USABLECHAN_ATTRIBUTE_CHANNELS) {
+ memcpy(channels, it.get_data(), sizeof(wifi_usable_channel) * *mSize);
+ } else {
+ ALOGE("Unknown attribute: %d expecting %d",
+ it.get_type(), USABLECHAN_ATTRIBUTE_SIZE);
+ return NL_SKIP;
+ }
+
+ return NL_OK;
+ }
+
+ virtual int handleEvent(WifiEvent& event) {
+ /* NO events! */
+ return NL_SKIP;
+ }
+};
+
+wifi_error wifi_get_usable_channels(wifi_handle handle, u32 band_mask, u32 iface_mode_mask,
+ u32 filter_mask, u32 max_size, u32* size, wifi_usable_channel* channels)
+{
+ int numIfaceHandles = 0;
+ wifi_interface_handle *ifaceHandles = NULL;
+ wifi_interface_handle wlan0Handle;
+
+ wlan0Handle = wifi_get_wlan_interface((wifi_handle)handle, ifaceHandles, numIfaceHandles);
+ UsableChannelCommand command(wlan0Handle, band_mask, iface_mode_mask,
+ filter_mask, max_size, size, channels);
+ return (wifi_error)command.start();
+}
diff --git a/synadhd/wifi_hal/wifi_logger.cpp b/synadhd/wifi_hal/wifi_logger.cpp
new file mode 100755
index 0000000..0338270
--- /dev/null
+++ b/synadhd/wifi_hal/wifi_logger.cpp
@@ -0,0 +1,2831 @@
+/*
+ * Copyright (C) 2017 The Android Open Source Project
+ *
+ * Portions copyright (C) 2017 Broadcom Limited
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <stdint.h>
+#include <fcntl.h>
+#include <sys/socket.h>
+#include <netlink/genl/genl.h>
+#include <netlink/genl/family.h>
+#include <netlink/genl/ctrl.h>
+#include <linux/rtnetlink.h>
+#include <netpacket/packet.h>
+#include <linux/filter.h>
+#include <linux/errqueue.h>
+#include <errno.h>
+
+#include <linux/pkt_sched.h>
+#include <netlink/object-api.h>
+#include <netlink/netlink.h>
+#include <netlink/socket.h>
+#include <netlink-private/object-api.h>
+#include <netlink-private/types.h>
+#include <unistd.h>
+#include <cutils/properties.h>
+
+
+#include "nl80211_copy.h"
+#include "sync.h"
+
+#define LOG_TAG "WifiHAL"
+
+#include <log/log.h>
+
+#include "wifi_hal.h"
+#include "common.h"
+#include "cpp_bindings.h"
+#include <sys/stat.h>
+#include "syna_version.h"
+#define WIFI_HAL_EVENT_SOCK_PORT 645
+
+#define ARRAYSIZE(a) (u8)(sizeof(a) / sizeof(a[0]))
+typedef enum {
+ LOGGER_START_LOGGING = ANDROID_NL80211_SUBCMD_DEBUG_RANGE_START,
+ LOGGER_TRIGGER_MEM_DUMP,
+ LOGGER_GET_MEM_DUMP,
+ LOGGER_GET_VER,
+ LOGGER_GET_RING_STATUS,
+ LOGGER_GET_RING_DATA,
+ LOGGER_GET_FEATURE,
+ LOGGER_RESET_LOGGING,
+ LOGGER_TRIGGER_DRIVER_MEM_DUMP,
+ LOGGER_GET_DRIVER_MEM_DUMP,
+ LOGGER_START_PKT_FATE_MONITORING,
+ LOGGER_GET_TX_PKT_FATES,
+ LOGGER_GET_RX_PKT_FATES,
+ LOGGER_GET_WAKE_REASON_STATS,
+ LOGGER_DEBUG_GET_DUMP,
+ LOGGER_FILE_DUMP_DONE_IND,
+ LOGGER_SET_HAL_START,
+ LOGGER_HAL_STOP,
+ LOGGER_SET_HAL_PID,
+ LOGGER_SET_TPUT_DEBUG_DUMP_CMD,
+ LOGGER_GET_BUF_RING_MAP
+} DEBUG_SUB_COMMAND;
+
+#define MAX_NV_FILE 4
+#define MAX_SKU_NAME_LEN 5
+#define OTA_PATH "/data/vendor/firmware/wifi/"
+#define OTA_CLM_FILE "bcmdhd_clm.blob"
+#define OTA_NVRAM_FILE "bcmdhd.cal"
+#define HW_DEV_PROP "ro.revision"
+#define HW_SKU_PROP "ro.boot.hardware.sku"
+
+typedef enum {
+ NVRAM,
+ CLM_BLOB
+} OTA_TYPE;
+
+char ota_nvram_ext[10];
+typedef struct ota_info_buf {
+ u32 ota_clm_len;
+ const void *ota_clm_buf[1];
+ u32 ota_nvram_len;
+ const void *ota_nvram_buf[1];
+} ota_info_buf_t;
+u32 applied_ota_version = 0;
+
+typedef enum {
+ LOGGER_ATTRIBUTE_INVALID = 0,
+ LOGGER_ATTRIBUTE_DRIVER_VER = 1,
+ LOGGER_ATTRIBUTE_FW_VER = 2,
+ LOGGER_ATTRIBUTE_RING_ID = 3,
+ LOGGER_ATTRIBUTE_RING_NAME = 4,
+ LOGGER_ATTRIBUTE_RING_FLAGS = 5,
+ LOGGER_ATTRIBUTE_LOG_LEVEL = 6,
+ LOGGER_ATTRIBUTE_LOG_TIME_INTVAL = 7,
+ LOGGER_ATTRIBUTE_LOG_MIN_DATA_SIZE = 8,
+ LOGGER_ATTRIBUTE_FW_DUMP_LEN = 9,
+ LOGGER_ATTRIBUTE_FW_DUMP_DATA = 10,
+ LOGGER_ATTRIBUTE_FW_ERR_CODE = 11,
+ LOGGER_ATTRIBUTE_RING_DATA = 12,
+ LOGGER_ATTRIBUTE_RING_STATUS = 13,
+ LOGGER_ATTRIBUTE_RING_NUM = 14,
+ LOGGER_ATTRIBUTE_DRIVER_DUMP_LEN = 15,
+ LOGGER_ATTRIBUTE_DRIVER_DUMP_DATA = 16,
+ LOGGER_ATTRIBUTE_PKT_FATE_NUM = 17,
+ LOGGER_ATTRIBUTE_PKT_FATE_DATA = 18,
+ LOGGER_ATTRIBUTE_HANG_REASON = 19,
+ LOGGER_ATTRIBUTE_BUF_RING_NUM = 20,
+ LOGGER_ATTRIBUTE_BUF_RING_MAP = 21,
+ /* Add new attributes just above this */
+ LOGGER_ATTRIBUTE_MAX
+} LOGGER_ATTRIBUTE;
+
+typedef enum {
+ DEBUG_OFF = 0,
+ DEBUG_NORMAL,
+ DEBUG_VERBOSE,
+ DEBUG_VERY,
+ DEBUG_VERY_VERY,
+} LOGGER_LEVEL;
+
+typedef enum {
+ GET_FW_VER,
+ GET_DRV_VER,
+ GET_RING_DATA,
+ GET_RING_STATUS,
+ GET_FEATURE,
+ START_RING_LOG,
+ GET_BUF_RING_MAP,
+} GetCmdType;
+
+typedef enum {
+ PACKET_MONITOR_START,
+ TX_PACKET_FATE,
+ RX_PACKET_FATE,
+} PktFateReqType;
+
+enum wake_stat_attributes {
+ WAKE_STAT_ATTRIBUTE_INVALID,
+ WAKE_STAT_ATTRIBUTE_TOTAL,
+ WAKE_STAT_ATTRIBUTE_WAKE,
+ WAKE_STAT_ATTRIBUTE_COUNT,
+ WAKE_STAT_ATTRIBUTE_CMD_COUNT_USED,
+ WAKE_STAT_ATTRIBUTE_TOTAL_DRIVER_FW,
+ WAKE_STAT_ATTRIBUTE_DRIVER_FW_WAKE,
+ WAKE_STAT_ATTRIBUTE_DRIVER_FW_COUNT,
+ WAKE_STAT_ATTRIBUTE_DRIVER_FW_COUNT_USED,
+ WAKE_STAT_ATTRIBUTE_TOTAL_RX_DATA_WAKE,
+ WAKE_STAT_ATTRIBUTE_RX_UNICAST_COUNT,
+ WAKE_STAT_ATTRIBUTE_RX_MULTICAST_COUNT,
+ WAKE_STAT_ATTRIBUTE_RX_BROADCAST_COUNT,
+ WAKE_STAT_ATTRIBUTE_RX_ICMP_PKT,
+ WAKE_STAT_ATTRIBUTE_RX_ICMP6_PKT,
+ WAKE_STAT_ATTRIBUTE_RX_ICMP6_RA,
+ WAKE_STAT_ATTRIBUTE_RX_ICMP6_NA,
+ WAKE_STAT_ATTRIBUTE_RX_ICMP6_NS,
+ WAKE_STAT_ATTRIBUTE_IPV4_RX_MULTICAST_ADD_CNT,
+ WAKE_STAT_ATTRIBUTE_IPV6_RX_MULTICAST_ADD_CNT,
+ WAKE_STAT_ATTRIBUTE_OTHER_RX_MULTICAST_ADD_CNT,
+ WAKE_STAT_ATTRIBUTE_RX_MULTICAST_PKT_INFO,
+ WAKE_STAT_ATTRIBUTE_MAX
+};
+
+typedef enum {
+ SET_HAL_START_ATTRIBUTE_DEINIT = 0x0001,
+ SET_HAL_START_ATTRIBUTE_PRE_INIT = 0x0002,
+ SET_HAL_START_ATTRIBUTE_EVENT_SOCK_PID = 0x0003
+} SET_HAL_START_ATTRIBUTE;
+
+typedef enum {
+ OTA_DOWNLOAD_CLM_LENGTH_ATTR = 0x0001,
+ OTA_DOWNLOAD_CLM_ATTR = 0x0002,
+ OTA_DOWNLOAD_NVRAM_LENGTH_ATTR = 0x0003,
+ OTA_DOWNLOAD_NVRAM_ATTR = 0x0004,
+ OTA_SET_FORCE_REG_ON = 0x0005,
+ OTA_CUR_NVRAM_EXT_ATTR = 0x0006,
+} OTA_DOWNLOAD_ATTRIBUTE;
+
+#define HAL_START_REQUEST_ID 2
+#define HAL_RESTART_ID 3
+#define FILE_NAME_LEN 256
+#define RING_NAME_LEN 32
+#if defined(RING_DUMP)
+/* Loglevel */
+#define DUMP_DEBUG(x)
+#define DUMP_INFO(x) ALOGI x
+#define FILE_DUMP_REQUEST_ID 2
+#define C2S(x) case x: return #x;
+static const char *EWP_EventAttrToString(int len_attr);
+static const char *EWP_CmdAttrToString(int data_attr);
+
+typedef struct buf_data {
+ u32 ver; /* version of struct */
+ u32 len; /* Total len */
+ /* size of each buffer in case of split buffers (0 - single buffer). */
+ u32 buf_threshold;
+ const void *data_buf[1]; /* array of user space buffer pointers.*/
+} buf_data_t;
+
+/* Attributes associated with GOOGLE_FILE_DUMP_EVENT */
+typedef enum {
+ DUMP_LEN_ATTR_INVALID = 0,
+ DUMP_LEN_ATTR_MEMDUMP = 1,
+ DUMP_LEN_ATTR_SSSR_C0_BEFORE = 2,
+ DUMP_LEN_ATTR_SSSR_C0_AFTER = 3,
+ DUMP_LEN_ATTR_SSSR_C1_BEFORE = 4,
+ DUMP_LEN_ATTR_SSSR_C1_AFTER = 5,
+ DUMP_LEN_ATTR_SSSR_C2_BEFORE = 6,
+ DUMP_LEN_ATTR_SSSR_C2_AFTER = 7,
+ DUMP_LEN_ATTR_SSSR_DIG_BEFORE = 8,
+ DUMP_LEN_ATTR_SSSR_DIG_AFTER = 9,
+ DUMP_LEN_ATTR_TIMESTAMP = 10,
+ DUMP_LEN_ATTR_GENERAL_LOG = 11,
+ DUMP_LEN_ATTR_ECNTRS = 12,
+ DUMP_LEN_ATTR_SPECIAL_LOG = 13,
+ DUMP_LEN_ATTR_DHD_DUMP = 14,
+ DUMP_LEN_ATTR_EXT_TRAP = 15,
+ DUMP_LEN_ATTR_HEALTH_CHK = 16,
+ DUMP_LEN_ATTR_PRESERVE_LOG = 17,
+ DUMP_LEN_ATTR_COOKIE = 18,
+ DUMP_LEN_ATTR_FLOWRING_DUMP = 19,
+ DUMP_LEN_ATTR_PKTLOG = 20,
+ DUMP_LEN_ATTR_PKTLOG_DEBUG = 21,
+ DUMP_FILENAME_ATTR_DEBUG_DUMP = 22,
+ DUMP_FILENAME_ATTR_MEM_DUMP = 23,
+ DUMP_FILENAME_ATTR_SSSR_CORE_0_BEFORE_DUMP = 24,
+ DUMP_FILENAME_ATTR_SSSR_CORE_0_AFTER_DUMP = 25,
+ DUMP_FILENAME_ATTR_SSSR_CORE_1_BEFORE_DUMP = 26,
+ DUMP_FILENAME_ATTR_SSSR_CORE_1_AFTER_DUMP = 27,
+ DUMP_FILENAME_ATTR_SSSR_CORE_2_BEFORE_DUMP = 28,
+ DUMP_FILENAME_ATTR_SSSR_CORE_2_AFTER_DUMP = 29,
+ DUMP_FILENAME_ATTR_SSSR_DIG_BEFORE_DUMP = 30,
+ DUMP_FILENAME_ATTR_SSSR_DIG_AFTER_DUMP = 31,
+ DUMP_FILENAME_ATTR_PKTLOG_DUMP = 32,
+ DUMP_FILENAME_ATTR_PKTLOG_DEBUG_DUMP = 33,
+ DUMP_LEN_ATTR_STATUS_LOG = 34,
+ DUMP_LEN_ATTR_AXI_ERROR = 35,
+ DUMP_FILENAME_ATTR_AXI_ERROR_DUMP = 36,
+ DUMP_LEN_ATTR_RTT_LOG = 37,
+ DUMP_LEN_ATTR_SDTC_ETB_DUMP = 38,
+ DUMP_FILENAME_ATTR_SDTC_ETB_DUMP = 39,
+ DUMP_LEN_ATTR_PKTID_MAP_LOG = 40,
+ DUMP_LEN_ATTR_PKTID_UNMAP_LOG = 41,
+ DUMP_LEN_ATTR_EWP_HW_INIT_LOG = 42,
+ DUMP_LEN_ATTR_EWP_HW_MOD_DUMP = 43,
+ DUMP_LEN_ATTR_EWP_HW_REG_DUMP = 44,
+ /* Please add new attributes from here to sync up old DHD */
+ DUMP_EVENT_ATTR_MAX = 45,
+} EWP_DUMP_EVENT_ATTRIBUTE;
+
+/* Attributes associated with DEBUG_GET_DUMP_BUF */
+typedef enum {
+ DUMP_BUF_ATTR_INVALID = 0,
+ DUMP_BUF_ATTR_MEMDUMP = 1,
+ DUMP_BUF_ATTR_SSSR_C0_BEFORE = 2,
+ DUMP_BUF_ATTR_SSSR_C0_AFTER = 3,
+ DUMP_BUF_ATTR_SSSR_C1_BEFORE = 4,
+ DUMP_BUF_ATTR_SSSR_C1_AFTER = 5,
+ DUMP_BUF_ATTR_SSSR_C2_BEFORE = 6,
+ DUMP_BUF_ATTR_SSSR_C2_AFTER = 7,
+ DUMP_BUF_ATTR_SSSR_DIG_BEFORE = 8,
+ DUMP_BUF_ATTR_SSSR_DIG_AFTER = 9,
+ DUMP_BUF_ATTR_TIMESTAMP = 10,
+ DUMP_BUF_ATTR_GENERAL_LOG = 11,
+ DUMP_BUF_ATTR_ECNTRS = 12,
+ DUMP_BUF_ATTR_SPECIAL_LOG = 13,
+ DUMP_BUF_ATTR_DHD_DUMP = 14,
+ DUMP_BUF_ATTR_EXT_TRAP = 15,
+ DUMP_BUF_ATTR_HEALTH_CHK = 16,
+ DUMP_BUF_ATTR_PRESERVE_LOG = 17,
+ DUMP_BUF_ATTR_COOKIE = 18,
+ DUMP_BUF_ATTR_FLOWRING_DUMP = 19,
+ DUMP_BUF_ATTR_PKTLOG = 20,
+ DUMP_BUF_ATTR_PKTLOG_DEBUG = 21,
+ DUMP_BUF_ATTR_STATUS_LOG = 22,
+ DUMP_BUF_ATTR_AXI_ERROR = 23,
+ DUMP_BUF_ATTR_RTT_LOG = 24,
+ DUMP_BUF_ATTR_SDTC_ETB_DUMP = 25,
+ DUMP_BUF_ATTR_PKTID_MAP_LOG = 26,
+ DUMP_BUF_ATTR_PKTID_UNMAP_LOG = 27,
+ DUMP_BUF_ATTR_EWP_HW_INIT_LOG = 28,
+ DUMP_BUF_ATTR_EWP_HW_MOD_DUMP = 29,
+ DUMP_BUF_ATTR_EWP_HW_REG_DUMP = 30,
+ /* Please add new attributes from here to sync up old DHD */
+ DUMP_BUF_ATTR_MAX = 31,
+} EWP_DUMP_CMD_ATTRIBUTE;
+
+typedef enum {
+ DUMP_TYPE_MEM_DUMP = 0,
+ DUMP_TYPE_DEBUG_DUMP = 1,
+ DUMP_TYPE_SSSR_CORE0_BEF_DUMP = 2,
+ DUMP_TYPE_SSSR_CORE0_AFT_DUMP = 3,
+ DUMP_TYPE_SSSR_CORE1_BEF_DUMP = 4,
+ DUMP_TYPE_SSSR_CORE1_AFT_DUMP = 5,
+ DUMP_TYPE_SSSR_CORE2_BEF_DUMP = 6,
+ DUMP_TYPE_SSSR_CORE2_AFT_DUMP = 7,
+ DUMP_TYPE_SSSR_DIG_BEF_DUMP = 8,
+ DUMP_TYPE_SSSR_DIG_AFT_DUMP = 9,
+ DUMP_TYPE_PKTLOG_DUMP = 10,
+ DUMP_TYPE_PKTLOG_DEBUG_DUMP = 11,
+ DUMP_TYPE_AXI_ERROR_DUMP = 12,
+ DUMP_TYPE_D2H_MINI_DUMP = 13,
+ DUMP_TYPE_SDTC_ETB_DUMP = 14,
+ /* Please add new attributes from here to sync up old DHD */
+ DUMP_TYPE_MAX = 15,
+} EWP_DUMP_TYPE;
+
+/* Struct for table which has len_attr, data_attr and dump file type attr */
+typedef struct logger_attr_entry {
+ u8 attr_type; /* Type of attribute */
+ u8 buf_attr; /* Buffer associated with the attribute */
+ u8 dump_type; /* Each attribute will be linked to a dump type */
+} logger_attr_entry_t;
+
+logger_attr_entry_t attr_lookup_tbl[] = {
+ /* Mem Dump Block */
+ {DUMP_FILENAME_ATTR_MEM_DUMP, 0, DUMP_TYPE_MEM_DUMP},
+ {DUMP_LEN_ATTR_MEMDUMP, DUMP_BUF_ATTR_MEMDUMP, DUMP_TYPE_MEM_DUMP},
+ /* SSSR Dump Block */
+ {DUMP_FILENAME_ATTR_SSSR_CORE_0_BEFORE_DUMP, 0, DUMP_TYPE_SSSR_CORE0_BEF_DUMP},
+ {DUMP_LEN_ATTR_SSSR_C0_BEFORE, DUMP_BUF_ATTR_SSSR_C0_BEFORE, DUMP_TYPE_SSSR_CORE0_BEF_DUMP},
+
+ {DUMP_FILENAME_ATTR_SSSR_CORE_0_AFTER_DUMP, 0, DUMP_TYPE_SSSR_CORE0_AFT_DUMP},
+ {DUMP_LEN_ATTR_SSSR_C0_AFTER, DUMP_BUF_ATTR_SSSR_C0_AFTER, DUMP_TYPE_SSSR_CORE0_AFT_DUMP},
+
+ {DUMP_FILENAME_ATTR_SSSR_CORE_1_BEFORE_DUMP, 0, DUMP_TYPE_SSSR_CORE1_BEF_DUMP},
+ {DUMP_LEN_ATTR_SSSR_C1_BEFORE, DUMP_BUF_ATTR_SSSR_C1_BEFORE, DUMP_TYPE_SSSR_CORE1_BEF_DUMP},
+
+ {DUMP_FILENAME_ATTR_SSSR_CORE_1_AFTER_DUMP, 0, DUMP_TYPE_SSSR_CORE1_AFT_DUMP},
+ {DUMP_LEN_ATTR_SSSR_C1_AFTER, DUMP_BUF_ATTR_SSSR_C1_AFTER, DUMP_TYPE_SSSR_CORE1_AFT_DUMP},
+
+ {DUMP_FILENAME_ATTR_SSSR_CORE_2_BEFORE_DUMP, 0, DUMP_TYPE_SSSR_CORE2_BEF_DUMP},
+ {DUMP_LEN_ATTR_SSSR_C2_BEFORE, DUMP_BUF_ATTR_SSSR_C2_BEFORE, DUMP_TYPE_SSSR_CORE2_BEF_DUMP},
+
+ {DUMP_FILENAME_ATTR_SSSR_CORE_2_AFTER_DUMP, 0, DUMP_TYPE_SSSR_CORE2_AFT_DUMP},
+ {DUMP_LEN_ATTR_SSSR_C2_AFTER, DUMP_BUF_ATTR_SSSR_C2_AFTER, DUMP_TYPE_SSSR_CORE2_AFT_DUMP},
+
+ {DUMP_FILENAME_ATTR_SSSR_DIG_BEFORE_DUMP, 0, DUMP_TYPE_SSSR_DIG_BEF_DUMP},
+ {DUMP_LEN_ATTR_SSSR_DIG_BEFORE, DUMP_BUF_ATTR_SSSR_DIG_BEFORE, DUMP_TYPE_SSSR_DIG_BEF_DUMP},
+
+ {DUMP_FILENAME_ATTR_SSSR_DIG_AFTER_DUMP, 0, DUMP_TYPE_SSSR_DIG_AFT_DUMP},
+ {DUMP_LEN_ATTR_SSSR_DIG_AFTER, DUMP_BUF_ATTR_SSSR_DIG_AFTER, DUMP_TYPE_SSSR_DIG_AFT_DUMP},
+
+ /* Debug Dump Block */
+ {DUMP_FILENAME_ATTR_DEBUG_DUMP, 0, DUMP_TYPE_DEBUG_DUMP},
+ {DUMP_LEN_ATTR_TIMESTAMP, DUMP_BUF_ATTR_TIMESTAMP, DUMP_TYPE_DEBUG_DUMP},
+ {DUMP_LEN_ATTR_GENERAL_LOG, DUMP_BUF_ATTR_GENERAL_LOG, DUMP_TYPE_DEBUG_DUMP},
+ {DUMP_LEN_ATTR_ECNTRS, DUMP_BUF_ATTR_ECNTRS, DUMP_TYPE_DEBUG_DUMP},
+ {DUMP_LEN_ATTR_SPECIAL_LOG, DUMP_BUF_ATTR_SPECIAL_LOG, DUMP_TYPE_DEBUG_DUMP},
+ {DUMP_LEN_ATTR_DHD_DUMP, DUMP_BUF_ATTR_DHD_DUMP, DUMP_TYPE_DEBUG_DUMP},
+ {DUMP_LEN_ATTR_EXT_TRAP, DUMP_BUF_ATTR_EXT_TRAP, DUMP_TYPE_DEBUG_DUMP},
+ {DUMP_LEN_ATTR_HEALTH_CHK, DUMP_BUF_ATTR_HEALTH_CHK, DUMP_TYPE_DEBUG_DUMP},
+ {DUMP_LEN_ATTR_PRESERVE_LOG, DUMP_BUF_ATTR_PRESERVE_LOG, DUMP_TYPE_DEBUG_DUMP},
+ {DUMP_LEN_ATTR_COOKIE, DUMP_BUF_ATTR_COOKIE, DUMP_TYPE_DEBUG_DUMP},
+ {DUMP_LEN_ATTR_FLOWRING_DUMP, DUMP_BUF_ATTR_FLOWRING_DUMP, DUMP_TYPE_DEBUG_DUMP},
+ {DUMP_LEN_ATTR_STATUS_LOG, DUMP_BUF_ATTR_STATUS_LOG, DUMP_TYPE_DEBUG_DUMP},
+ {DUMP_LEN_ATTR_RTT_LOG, DUMP_BUF_ATTR_RTT_LOG, DUMP_TYPE_DEBUG_DUMP},
+ {DUMP_LEN_ATTR_PKTID_MAP_LOG, DUMP_BUF_ATTR_PKTID_MAP_LOG, DUMP_TYPE_DEBUG_DUMP},
+ {DUMP_LEN_ATTR_PKTID_UNMAP_LOG, DUMP_BUF_ATTR_PKTID_UNMAP_LOG, DUMP_TYPE_DEBUG_DUMP},
+ {DUMP_LEN_ATTR_EWP_HW_INIT_LOG, DUMP_BUF_ATTR_EWP_HW_INIT_LOG, DUMP_TYPE_DEBUG_DUMP},
+ {DUMP_LEN_ATTR_EWP_HW_MOD_DUMP, DUMP_BUF_ATTR_EWP_HW_MOD_DUMP, DUMP_TYPE_DEBUG_DUMP},
+ {DUMP_LEN_ATTR_EWP_HW_REG_DUMP, DUMP_BUF_ATTR_EWP_HW_REG_DUMP, DUMP_TYPE_DEBUG_DUMP},
+
+ /* PKT log dump block */
+ {DUMP_FILENAME_ATTR_PKTLOG_DUMP, 0, DUMP_TYPE_PKTLOG_DUMP},
+ {DUMP_LEN_ATTR_PKTLOG, DUMP_BUF_ATTR_PKTLOG, DUMP_TYPE_PKTLOG_DUMP},
+ {DUMP_FILENAME_ATTR_PKTLOG_DEBUG_DUMP, 0, DUMP_TYPE_PKTLOG_DEBUG_DUMP},
+ {DUMP_LEN_ATTR_PKTLOG_DEBUG, DUMP_BUF_ATTR_PKTLOG_DEBUG, DUMP_TYPE_PKTLOG_DEBUG_DUMP},
+ /* AXI error log dump block */
+ {DUMP_FILENAME_ATTR_AXI_ERROR_DUMP, 0, DUMP_TYPE_AXI_ERROR_DUMP},
+ {DUMP_LEN_ATTR_AXI_ERROR, DUMP_BUF_ATTR_AXI_ERROR, DUMP_TYPE_AXI_ERROR_DUMP},
+ /* SDTC etb log dump block */
+ {DUMP_FILENAME_ATTR_SDTC_ETB_DUMP, 0, DUMP_TYPE_SDTC_ETB_DUMP},
+ {DUMP_LEN_ATTR_SDTC_ETB_DUMP, DUMP_BUF_ATTR_SDTC_ETB_DUMP, DUMP_TYPE_SDTC_ETB_DUMP},
+ {DUMP_EVENT_ATTR_MAX, 0, 0},
+};
+
+static const char *EWP_EventAttrToString(int len_attr)
+{
+ switch (len_attr) {
+ C2S(DUMP_LEN_ATTR_MEMDUMP)
+ C2S(DUMP_LEN_ATTR_SSSR_C0_BEFORE)
+ C2S(DUMP_LEN_ATTR_SSSR_C0_AFTER)
+ C2S(DUMP_LEN_ATTR_SSSR_C1_BEFORE)
+ C2S(DUMP_LEN_ATTR_SSSR_C1_AFTER)
+ C2S(DUMP_LEN_ATTR_SSSR_C2_BEFORE)
+ C2S(DUMP_LEN_ATTR_SSSR_C2_AFTER)
+ C2S(DUMP_LEN_ATTR_SSSR_DIG_BEFORE)
+ C2S(DUMP_LEN_ATTR_SSSR_DIG_AFTER)
+ C2S(DUMP_LEN_ATTR_TIMESTAMP)
+ C2S(DUMP_LEN_ATTR_GENERAL_LOG)
+ C2S(DUMP_LEN_ATTR_ECNTRS)
+ C2S(DUMP_LEN_ATTR_SPECIAL_LOG)
+ C2S(DUMP_LEN_ATTR_DHD_DUMP)
+ C2S(DUMP_LEN_ATTR_EXT_TRAP)
+ C2S(DUMP_LEN_ATTR_HEALTH_CHK)
+ C2S(DUMP_LEN_ATTR_PRESERVE_LOG)
+ C2S(DUMP_LEN_ATTR_COOKIE)
+ C2S(DUMP_LEN_ATTR_FLOWRING_DUMP)
+ C2S(DUMP_LEN_ATTR_PKTLOG)
+ C2S(DUMP_LEN_ATTR_PKTLOG_DEBUG)
+ C2S(DUMP_LEN_ATTR_STATUS_LOG)
+ C2S(DUMP_FILENAME_ATTR_DEBUG_DUMP)
+ C2S(DUMP_FILENAME_ATTR_MEM_DUMP)
+ C2S(DUMP_FILENAME_ATTR_SSSR_CORE_0_BEFORE_DUMP)
+ C2S(DUMP_FILENAME_ATTR_SSSR_CORE_0_AFTER_DUMP)
+ C2S(DUMP_FILENAME_ATTR_SSSR_CORE_1_BEFORE_DUMP)
+ C2S(DUMP_FILENAME_ATTR_SSSR_CORE_1_AFTER_DUMP)
+ C2S(DUMP_FILENAME_ATTR_SSSR_CORE_2_BEFORE_DUMP)
+ C2S(DUMP_FILENAME_ATTR_SSSR_CORE_2_AFTER_DUMP)
+ C2S(DUMP_FILENAME_ATTR_SSSR_DIG_BEFORE_DUMP)
+ C2S(DUMP_FILENAME_ATTR_SSSR_DIG_AFTER_DUMP)
+ C2S(DUMP_FILENAME_ATTR_PKTLOG_DUMP)
+ C2S(DUMP_FILENAME_ATTR_PKTLOG_DEBUG_DUMP)
+ C2S(DUMP_LEN_ATTR_AXI_ERROR)
+ C2S(DUMP_FILENAME_ATTR_AXI_ERROR_DUMP)
+ C2S(DUMP_LEN_ATTR_RTT_LOG)
+ C2S(DUMP_FILENAME_ATTR_SDTC_ETB_DUMP)
+ C2S(DUMP_LEN_ATTR_SDTC_ETB_DUMP)
+ C2S(DUMP_LEN_ATTR_PKTID_MAP_LOG)
+ C2S(DUMP_LEN_ATTR_PKTID_UNMAP_LOG)
+ C2S(DUMP_LEN_ATTR_EWP_HW_INIT_LOG)
+ C2S(DUMP_LEN_ATTR_EWP_HW_MOD_DUMP)
+ C2S(DUMP_LEN_ATTR_EWP_HW_REG_DUMP)
+ default:
+ return "DUMP_LEN_ATTR_INVALID";
+ }
+}
+
+static const char *EWP_CmdAttrToString(int attr)
+{
+ switch (attr) {
+ C2S(DUMP_BUF_ATTR_MEMDUMP)
+ C2S(DUMP_BUF_ATTR_SSSR_C0_BEFORE)
+ C2S(DUMP_BUF_ATTR_SSSR_C0_AFTER)
+ C2S(DUMP_BUF_ATTR_SSSR_C1_BEFORE)
+ C2S(DUMP_BUF_ATTR_SSSR_C1_AFTER)
+ C2S(DUMP_BUF_ATTR_SSSR_C2_BEFORE)
+ C2S(DUMP_BUF_ATTR_SSSR_C2_AFTER)
+ C2S(DUMP_BUF_ATTR_SSSR_DIG_BEFORE)
+ C2S(DUMP_BUF_ATTR_SSSR_DIG_AFTER)
+ C2S(DUMP_BUF_ATTR_TIMESTAMP)
+ C2S(DUMP_BUF_ATTR_GENERAL_LOG)
+ C2S(DUMP_BUF_ATTR_ECNTRS)
+ C2S(DUMP_BUF_ATTR_SPECIAL_LOG)
+ C2S(DUMP_BUF_ATTR_DHD_DUMP)
+ C2S(DUMP_BUF_ATTR_EXT_TRAP)
+ C2S(DUMP_BUF_ATTR_HEALTH_CHK)
+ C2S(DUMP_BUF_ATTR_PRESERVE_LOG)
+ C2S(DUMP_BUF_ATTR_COOKIE)
+ C2S(DUMP_BUF_ATTR_FLOWRING_DUMP)
+ C2S(DUMP_BUF_ATTR_PKTLOG)
+ C2S(DUMP_BUF_ATTR_PKTLOG_DEBUG)
+ C2S(DUMP_BUF_ATTR_STATUS_LOG)
+ C2S(DUMP_BUF_ATTR_AXI_ERROR)
+ C2S(DUMP_BUF_ATTR_RTT_LOG)
+ C2S(DUMP_BUF_ATTR_SDTC_ETB_DUMP)
+ C2S(DUMP_BUF_ATTR_PKTID_MAP_LOG)
+ C2S(DUMP_BUF_ATTR_PKTID_UNMAP_LOG)
+ C2S(DUMP_BUF_ATTR_EWP_HW_INIT_LOG)
+ C2S(DUMP_BUF_ATTR_EWP_HW_MOD_DUMP)
+ C2S(DUMP_BUF_ATTR_EWP_HW_REG_DUMP)
+ default:
+ return "DUMP_BUF_ATTR_INVALID";
+ }
+}
+
+/* Return index for matching buffer attribute */
+static int logger_attr_buffer_lookup(u8 attr) {
+ for (u8 i = 0; i < ARRAYSIZE(attr_lookup_tbl); i++) {
+ if (attr == attr_lookup_tbl[i].buf_attr) {
+ return i;
+ }
+ }
+ ALOGE("Lookup for buf attr = %s failed\n",
+ EWP_CmdAttrToString(attr));
+ return -1;
+}
+
+/* Return index matching the length attribute */
+static int logger_attr_lookup(u8 attr) {
+ for (u8 i = 0; i < ARRAYSIZE(attr_lookup_tbl); i++) {
+ if (attr == attr_lookup_tbl[i].attr_type) {
+ return i;
+ }
+ }
+ ALOGE("Lookup for len attr = %s failed\n",
+ EWP_EventAttrToString(attr));
+ return -1;
+}
+#endif /* RING_DUMP */
+
+#define DBGRING_NAME_MAX 32 //Copy from legacy hal
+typedef struct wifi_buf_ring_map_entry {
+ uint32_t type;
+ uint32_t ring_id;
+ char ring_name[DBGRING_NAME_MAX];
+} wifi_buf_ring_map_entry_t;
+
+typedef struct {
+ char hw_id[PROPERTY_VALUE_MAX];
+ char sku[MAX_SKU_NAME_LEN];
+} sku_info_t;
+
+sku_info_t sku_table[] = {
+ { {"G9S9B"}, {"MMW"} },
+ { {"G8V0U"}, {"MMW"} },
+ { {"GFQM1"}, {"MMW"} },
+ { {"GB62Z"}, {"MMW"} },
+ { {"GB7N6"}, {"ROW"} },
+ { {"GLU0G"}, {"ROW"} },
+ { {"GNA8F"}, {"ROW"} },
+ { {"GX7AS"}, {"ROW"} },
+ { {"GR1YH"}, {"JPN"} },
+ { {"GF5KQ"}, {"JPN"} },
+ { {"GPQ72"}, {"JPN"} },
+ { {"GB17L"}, {"JPN"} },
+ { {"G1AZG"}, {"EU"} }
+};
+///////////////////////////////////////////////////////////////////////////////
+class DebugCommand : public WifiCommand
+{
+ char *mBuff;
+ int *mBuffSize;
+ u32 *mNumRings;
+ wifi_ring_buffer_status *mStatus;
+ u32 *mNumMaps;
+ wifi_buf_ring_map_entry_t *mMaps;
+ unsigned int *mSupport;
+ u32 mVerboseLevel;
+ u32 mFlags;
+ u32 mMaxIntervalSec;
+ u32 mMinDataSize;
+ char *mRingName;
+ GetCmdType mType;
+
+public:
+
+ // constructor for get version
+ DebugCommand(wifi_interface_handle iface, char *buffer, int *buffer_size,
+ GetCmdType cmdType)
+ : WifiCommand("DebugCommand", iface, 0), mBuff(buffer), mBuffSize(buffer_size), mType
+ (cmdType)
+ {
+ mNumRings = NULL;
+ mStatus = NULL;
+ mSupport = NULL;
+ mVerboseLevel = 0;
+ mFlags = 0;
+ mMaxIntervalSec = 0;
+ mMinDataSize = 0;
+ mRingName = NULL;
+ memset(mBuff, 0, *mBuffSize);
+ }
+
+ // constructor for ring data
+ DebugCommand(wifi_interface_handle iface, char *ring_name, GetCmdType cmdType)
+ : WifiCommand("DebugCommand", iface, 0), mRingName(ring_name), mType(cmdType)
+ {
+ mBuff = NULL;
+ mBuffSize = NULL;
+ mNumRings = NULL;
+ mStatus = NULL;
+ mSupport = NULL;
+ mVerboseLevel = 0;
+ mFlags = 0;
+ mMaxIntervalSec = 0;
+ mMinDataSize = 0;
+ }
+
+ // constructor for ring status
+ DebugCommand(wifi_interface_handle iface, u32 *num_rings,
+ wifi_ring_buffer_status *status, GetCmdType cmdType)
+ : WifiCommand("DebugCommand", iface, 0), mNumRings(num_rings), mStatus(status), mType(cmdType)
+ {
+ mBuff = NULL;
+ mBuffSize = NULL;
+ mSupport = NULL;
+ mVerboseLevel = 0;
+ mFlags = 0;
+ mMaxIntervalSec = 0;
+ mMinDataSize = 0;
+ mRingName = NULL;
+ memset(mStatus, 0, sizeof(wifi_ring_buffer_status) * (*mNumRings));
+ }
+
+ // constructor for feature set
+ DebugCommand(wifi_interface_handle iface, unsigned int *support, GetCmdType cmdType)
+ : WifiCommand("DebugCommand", iface, 0), mSupport(support), mType(cmdType)
+ {
+ mBuff = NULL;
+ mBuffSize = NULL;
+ mNumRings = NULL;
+ mStatus = NULL;
+ mVerboseLevel = 0;
+ mFlags = 0;
+ mMaxIntervalSec = 0;
+ mMinDataSize = 0;
+ mRingName = NULL;
+ }
+
+ // constructor for buf ring map
+ DebugCommand(wifi_interface_handle iface, u32 *num_maps,
+ wifi_buf_ring_map_entry_t *map, GetCmdType cmdType)
+ : WifiCommand("DebugCommand", iface, 0), mNumMaps(num_maps), mMaps(map), mType(cmdType)
+ {
+ memset(mMaps, 0, sizeof(wifi_buf_ring_map_entry_t) * (*mNumMaps));
+ }
+
+ // constructor for ring params
+ DebugCommand(wifi_interface_handle iface, u32 verbose_level, u32 flags,
+ u32 max_interval_sec, u32 min_data_size, char *ring_name, GetCmdType cmdType)
+ : WifiCommand("DebugCommand", iface, 0), mVerboseLevel(verbose_level), mFlags(flags),
+ mMaxIntervalSec(max_interval_sec), mMinDataSize(min_data_size),
+ mRingName(ring_name), mType(cmdType)
+ {
+ mBuff = NULL;
+ mBuffSize = NULL;
+ mNumRings = NULL;
+ mStatus = NULL;
+ mSupport = NULL;
+ }
+
+ int createRingRequest(WifiRequest& request) {
+ int result = request.create(GOOGLE_OUI, LOGGER_START_LOGGING);
+ if (result != WIFI_SUCCESS) {
+ ALOGE("Failed to create start ring logger request; result = %d", result);
+ return result;
+ }
+
+ nlattr *data = request.attr_start(NL80211_ATTR_VENDOR_DATA);
+
+ result = request.put_u32(LOGGER_ATTRIBUTE_LOG_LEVEL, mVerboseLevel);
+ if (result != WIFI_SUCCESS) {
+ ALOGE("Failed to put log level; result = %d", result);
+ return result;
+ }
+ result = request.put_u32(LOGGER_ATTRIBUTE_RING_FLAGS, mFlags);
+ if (result != WIFI_SUCCESS) {
+ ALOGE("Failed to put ring flags; result = %d", result);
+ return result;
+ }
+ result = request.put_u32(LOGGER_ATTRIBUTE_LOG_TIME_INTVAL, mMaxIntervalSec);
+ if (result != WIFI_SUCCESS) {
+ ALOGE("Failed to put log time interval; result = %d", result);
+ return result;
+ }
+ result = request.put_u32(LOGGER_ATTRIBUTE_LOG_MIN_DATA_SIZE, mMinDataSize);
+ if (result != WIFI_SUCCESS) {
+ ALOGE("Failed to put min data size; result = %d", result);
+ return result;
+ }
+ result = request.put_string(LOGGER_ATTRIBUTE_RING_NAME, mRingName);
+ if (result != WIFI_SUCCESS) {
+ ALOGE("Failed to put ringbuffer name; result = %d", result);
+ return result;
+ }
+ request.attr_end(data);
+
+ return WIFI_SUCCESS;
+ }
+
+ int createRequest(WifiRequest &request) {
+ int result;
+
+ switch (mType) {
+ case GET_FW_VER:
+ {
+ result = request.create(GOOGLE_OUI, LOGGER_GET_VER);
+ if (result != WIFI_SUCCESS) {
+ ALOGE("Failed to create get fw version request; result = %d", result);
+ return result;
+ }
+
+ nlattr *data = request.attr_start(NL80211_ATTR_VENDOR_DATA);
+
+ // Driver expecting only attribute type, passing mbuff as data with
+ // length 0 to avoid undefined state
+ result = request.put(LOGGER_ATTRIBUTE_FW_VER, mBuff, 0);
+ if (result != WIFI_SUCCESS) {
+ ALOGE("Failed to put get fw version request; result = %d", result);
+ return result;
+ }
+ request.attr_end(data);
+ break;
+ }
+
+ case GET_DRV_VER:
+ {
+ result = request.create(GOOGLE_OUI, LOGGER_GET_VER);
+ if (result != WIFI_SUCCESS) {
+ ALOGE("Failed to create get drv version request; result = %d", result);
+ return result;
+ }
+
+ nlattr *data = request.attr_start(NL80211_ATTR_VENDOR_DATA);
+
+ // Driver expecting only attribute type, passing mbuff as data with
+ // length 0 to avoid undefined state
+ result = request.put(LOGGER_ATTRIBUTE_DRIVER_VER, mBuff, 0);
+
+ if (result != WIFI_SUCCESS) {
+ ALOGE("Failed to put get drv version request; result = %d", result);
+ return result;
+ }
+ request.attr_end(data);
+ break;
+ }
+
+ case GET_RING_DATA:
+ {
+ result = request.create(GOOGLE_OUI, LOGGER_GET_RING_DATA);
+ if (result != WIFI_SUCCESS) {
+ ALOGE("Failed to create get ring data request; result = %d", result);
+ return result;
+ }
+
+ nlattr *data = request.attr_start(NL80211_ATTR_VENDOR_DATA);
+ result = request.put_string(LOGGER_ATTRIBUTE_RING_NAME, mRingName);
+ if (result != WIFI_SUCCESS) {
+ ALOGE("Failed to put ring data request; result = %d", result);
+ return result;
+ }
+ request.attr_end(data);
+ break;
+ }
+
+ case GET_RING_STATUS:
+ {
+ result = request.create(GOOGLE_OUI, LOGGER_GET_RING_STATUS);
+ if (result != WIFI_SUCCESS) {
+ ALOGE("Failed to create get ring status request; result = %d", result);
+ return result;
+ }
+ break;
+ }
+
+ case GET_FEATURE:
+ {
+ result = request.create(GOOGLE_OUI, LOGGER_GET_FEATURE);
+ if (result != WIFI_SUCCESS) {
+ ALOGE("Failed to create get feature request; result = %d", result);
+ return result;
+ }
+ break;
+ }
+
+ case GET_BUF_RING_MAP:
+ {
+ result = request.create(GOOGLE_OUI, LOGGER_GET_BUF_RING_MAP);
+ if (result != WIFI_SUCCESS) {
+ ALOGE("Failed to create get ring status request; result = %d", result);
+ return result;
+ }
+ break;
+ }
+
+ case START_RING_LOG:
+ result = createRingRequest(request);
+ break;
+
+ default:
+ ALOGE("Unknown Debug command");
+ result = WIFI_ERROR_UNKNOWN;
+ }
+ return result;
+ }
+
+ int start() {
+ ALOGD("Start debug command");
+ WifiRequest request(familyId(), ifaceId());
+ int result = createRequest(request);
+ if (result != WIFI_SUCCESS) {
+ ALOGE("Failed to create debug request; result = %d", result);
+ return result;
+ }
+
+ result = requestResponse(request);
+ if (result != WIFI_SUCCESS) {
+ ALOGE("Failed to register debug response; result = %d", result);
+ }
+ return result;
+ }
+
+ virtual int handleResponse(WifiEvent& reply) {
+ ALOGD("In DebugCommand::handleResponse, mType:%d\n", mType);
+
+ if (reply.get_cmd() != NL80211_CMD_VENDOR) {
+ ALOGD("Ignoring reply with cmd = %d", reply.get_cmd());
+ return NL_SKIP;
+ }
+
+ switch (mType) {
+ case GET_DRV_VER:
+ case GET_FW_VER:
+ {
+ void *data = reply.get_vendor_data();
+ int len = reply.get_vendor_data_len();
+
+ ALOGD("len = %d, expected len = %d", len, *mBuffSize);
+ memcpy(mBuff, data, min(len, *mBuffSize));
+ if (*mBuffSize < len)
+ return NL_SKIP;
+ *mBuffSize = len;
+ break;
+ }
+
+ case START_RING_LOG:
+ case GET_RING_DATA:
+ break;
+
+ case GET_RING_STATUS:
+ {
+ nlattr *vendor_data = reply.get_attribute(NL80211_ATTR_VENDOR_DATA);
+ int len = reply.get_vendor_data_len();
+ wifi_ring_buffer_status *status(mStatus);
+
+ if (vendor_data == NULL || len == 0) {
+ ALOGE("No Debug data found");
+ return NL_SKIP;
+ }
+
+ nl_iterator it(vendor_data);
+ if (it.get_type() == LOGGER_ATTRIBUTE_RING_NUM) {
+ unsigned int num_rings = it.get_u32();
+ if (*mNumRings < num_rings) {
+ ALOGE("Not enough status buffers provided, available: %d required: %d",
+ *mNumRings, num_rings);
+ } else {
+ *mNumRings = num_rings;
+ }
+ } else {
+ ALOGE("Unknown attribute: %d expecting %d",
+ it.get_type(), LOGGER_ATTRIBUTE_RING_NUM);
+ return NL_SKIP;
+ }
+
+ it.next();
+ for (unsigned int i = 0; it.has_next() && i < *mNumRings; it.next()) {
+ if (it.get_type() == LOGGER_ATTRIBUTE_RING_STATUS) {
+ if (it.get_len() > sizeof(wifi_ring_buffer_status)) {
+ ALOGE("ring status unexpected len = %d, dest len = %lu",
+ it.get_len(), sizeof(wifi_ring_buffer_status));
+ return NL_SKIP;
+ } else {
+ memcpy(status, it.get_data(), sizeof(wifi_ring_buffer_status));
+ i++;
+ status++;
+ }
+ } else {
+ ALOGW("Ignoring invalid attribute type = %d, size = %d",
+ it.get_type(), it.get_len());
+ }
+ }
+ break;
+ }
+
+ case GET_FEATURE:
+ {
+ void *data = reply.get_vendor_data();
+ int len = reply.get_vendor_data_len();
+
+ ALOGD("len = %d, expected len = %lu", len, sizeof(unsigned int));
+ memcpy(mSupport, data, sizeof(unsigned int));
+ break;
+ }
+
+ case GET_BUF_RING_MAP:
+ {
+ nlattr *vendor_data = reply.get_attribute(NL80211_ATTR_VENDOR_DATA);
+ int len = reply.get_vendor_data_len();
+ wifi_buf_ring_map_entry_t *map(mMaps);
+
+ if (vendor_data == NULL || len == 0) {
+ ALOGE("No Debug data found");
+ return NL_SKIP;
+ }
+
+ nl_iterator it(vendor_data);
+ if (it.get_type() == LOGGER_ATTRIBUTE_BUF_RING_NUM) {
+ unsigned int num_maps = it.get_u32();
+ if (*mNumMaps < num_maps) {
+ ALOGE("Not enough status buffers provided, available: %d required: %d",
+ *mNumMaps, num_maps);
+ } else {
+ *mNumMaps = num_maps;
+ }
+ } else {
+ ALOGE("Unknown attribute: %d expecting %d",
+ it.get_type(), LOGGER_ATTRIBUTE_BUF_RING_NUM);
+ return NL_SKIP;
+ }
+
+ it.next();
+ for (unsigned int i = 0; it.has_next() && i < *mNumMaps; it.next()) {
+ if (it.get_type() == LOGGER_ATTRIBUTE_BUF_RING_MAP) {
+ if (it.get_len() > sizeof(wifi_buf_ring_map_entry_t)) {
+ ALOGE("GET_BUF_RING_MAP: unexpected len = %d, dest len = %lu",
+ it.get_len(), sizeof(wifi_buf_ring_map_entry_t));
+ return NL_SKIP;
+ } else {
+ memcpy(map, it.get_data(), sizeof(wifi_buf_ring_map_entry_t));
+ }
+ i++;
+ map++;
+ } else {
+ ALOGW("Ignoring invalid attribute type = %d, size = %d",
+ it.get_type(), it.get_len());
+ }
+ }
+ break;
+ }
+
+ default:
+ ALOGW("Unknown Debug command");
+ }
+ return NL_OK;
+ }
+
+ virtual int handleEvent(WifiEvent& event) {
+ /* NO events! */
+ return NL_SKIP;
+ }
+};
+
+/* API to collect a firmware version string */
+wifi_error wifi_get_firmware_version(wifi_interface_handle iface, char *buffer,
+ int buffer_size)
+{
+ if (buffer && (buffer_size > 0)) {
+ DebugCommand *cmd = new DebugCommand(iface, buffer, &buffer_size, GET_FW_VER);
+ NULL_CHECK_RETURN(cmd, "memory allocation failure", WIFI_ERROR_OUT_OF_MEMORY);
+ wifi_error result = (wifi_error)cmd->start();
+ cmd->releaseRef();
+ return result;
+ } else {
+ ALOGE("FW version buffer NULL");
+ return WIFI_ERROR_INVALID_ARGS;
+ }
+}
+
+/* API to collect a driver version string */
+wifi_error wifi_get_driver_version(wifi_interface_handle iface, char *buffer, int buffer_size)
+{
+ if (buffer && (buffer_size > 0)) {
+ DebugCommand *cmd = new DebugCommand(iface, buffer, &buffer_size, GET_DRV_VER);
+ NULL_CHECK_RETURN(cmd, "memory allocation failure", WIFI_ERROR_OUT_OF_MEMORY);
+ wifi_error result = (wifi_error)cmd->start();
+ cmd->releaseRef();
+ return result;
+ } else {
+ ALOGE("Driver version buffer NULL");
+ return WIFI_ERROR_INVALID_ARGS;
+ }
+}
+
+/* API to collect driver records */
+wifi_error wifi_get_ring_data(wifi_interface_handle iface, char *ring_name)
+{
+ DebugCommand *cmd = new DebugCommand(iface, ring_name, GET_RING_DATA);
+ NULL_CHECK_RETURN(cmd, "memory allocation failure", WIFI_ERROR_OUT_OF_MEMORY);
+ wifi_error result = (wifi_error)cmd->start();
+ cmd->releaseRef();
+ return result;
+}
+
+/* API to get the status of all ring buffers supported by driver */
+wifi_error wifi_get_ring_buffers_status(wifi_interface_handle iface,
+ u32 *num_rings, wifi_ring_buffer_status *status)
+{
+ if (status && num_rings) {
+ DebugCommand *cmd = new DebugCommand(iface, num_rings, status, GET_RING_STATUS);
+ NULL_CHECK_RETURN(cmd, "memory allocation failure", WIFI_ERROR_OUT_OF_MEMORY);
+ wifi_error result = (wifi_error)cmd->start();
+ cmd->releaseRef();
+ return result;
+ } else {
+ ALOGE("Ring status buffer NULL");
+ return WIFI_ERROR_INVALID_ARGS;
+ }
+}
+
+/* API to get supportable feature */
+wifi_error wifi_get_logger_supported_feature_set(wifi_interface_handle iface,
+ unsigned int *support)
+{
+ if (support) {
+ DebugCommand *cmd = new DebugCommand(iface, support, GET_FEATURE);
+ NULL_CHECK_RETURN(cmd, "memory allocation failure", WIFI_ERROR_OUT_OF_MEMORY);
+ wifi_error result = (wifi_error)cmd->start();
+ cmd->releaseRef();
+ return result;
+ } else {
+ ALOGE("Get support buffer NULL");
+ return WIFI_ERROR_INVALID_ARGS;
+ }
+}
+
+wifi_error wifi_start_logging(wifi_interface_handle iface, u32 verbose_level,
+ u32 flags, u32 max_interval_sec, u32 min_data_size, char *ring_name)
+{
+ if (ring_name) {
+ ALOGE("Ring name: level:%d sec:%d ring_name:%s",
+ verbose_level, max_interval_sec, ring_name);
+ DebugCommand *cmd = new DebugCommand(iface, verbose_level, flags, max_interval_sec,
+ min_data_size, ring_name, START_RING_LOG);
+ NULL_CHECK_RETURN(cmd, "memory allocation failure", WIFI_ERROR_OUT_OF_MEMORY);
+ wifi_error result = (wifi_error)cmd->start();
+ cmd->releaseRef();
+ return result;
+ } else {
+ ALOGE("Ring name NULL");
+ return WIFI_ERROR_INVALID_ARGS;
+ }
+}
+
+
+///////////////////////////////////////////////////////////////////////////////
+class SetLogHandler : public WifiCommand
+{
+ wifi_ring_buffer_data_handler mHandler;
+
+public:
+ SetLogHandler(wifi_interface_handle iface, int id, wifi_ring_buffer_data_handler handler)
+ : WifiCommand("SetLogHandler", iface, id), mHandler(handler)
+ { }
+
+ int start() {
+ ALOGV("Register loghandler");
+ int result;
+ uint32_t event_sock_pid = getpid() + (WIFI_HAL_EVENT_SOCK_PORT << 22);
+
+ WifiRequest request(familyId(), ifaceId());
+
+ /* set hal event socket port to driver */
+ result = request.create(GOOGLE_OUI, LOGGER_SET_HAL_PID);
+ if (result != WIFI_SUCCESS) {
+ ALOGV("Failed to set Hal preInit; result = %d", result);
+ return result;
+ }
+ registerVendorHandler(GOOGLE_OUI, GOOGLE_DEBUG_RING_EVENT);
+
+ nlattr *data = request.attr_start(NL80211_ATTR_VENDOR_DATA);
+ result = request.put_u32(SET_HAL_START_ATTRIBUTE_EVENT_SOCK_PID, event_sock_pid);
+ if (result != WIFI_SUCCESS) {
+ unregisterVendorHandler(GOOGLE_OUI, GOOGLE_DEBUG_RING_EVENT);
+ ALOGV("Hal preInit Failed to put pic = %d", result);
+ return result;
+ }
+
+ if (result != WIFI_SUCCESS) {
+ unregisterVendorHandler(GOOGLE_OUI, GOOGLE_DEBUG_RING_EVENT);
+ ALOGV("Hal preInit Failed to put pid= %d", result);
+ return result;
+ }
+
+ request.attr_end(data);
+
+ result = requestResponse(request);
+ if (result != WIFI_SUCCESS) {
+ unregisterVendorHandler(GOOGLE_OUI, GOOGLE_DEBUG_RING_EVENT);
+ ALOGE("Failed to register set Hal preInit; result = %d", result);
+ return result;
+ }
+ return result;
+ }
+
+ virtual int cancel() {
+ /* Send a command to driver to stop generating logging events */
+ ALOGV("Clear loghandler");
+
+ /* unregister event handler */
+ unregisterVendorHandler(GOOGLE_OUI, GOOGLE_DEBUG_RING_EVENT);
+ wifi_unregister_cmd(wifiHandle(), id());
+
+ WifiRequest request(familyId(), ifaceId());
+ int result = request.create(GOOGLE_OUI, LOGGER_RESET_LOGGING);
+ if (result != WIFI_SUCCESS) {
+ ALOGE("failed to create reset request; result = %d", result);
+ return result;
+ }
+
+ result = requestResponse(request);
+ if (result != WIFI_SUCCESS) {
+ ALOGE("failed to request reset; result = %d", result);
+ return result;
+ }
+
+ ALOGD("Success to clear loghandler");
+ return WIFI_SUCCESS;
+ }
+
+ virtual int handleEvent(WifiEvent& event) {
+ char *buffer = NULL;
+ int buffer_size = 0;
+
+ // ALOGD("In SetLogHandler::handleEvent");
+ nlattr *vendor_data = event.get_attribute(NL80211_ATTR_VENDOR_DATA);
+ int len = event.get_vendor_data_len();
+ int event_id = event.get_vendor_subcmd();
+ // ALOGI("Got Logger event: %d", event_id);
+
+ if (vendor_data == NULL || len == 0) {
+ ALOGE("No Debug data found");
+ return NL_SKIP;
+ }
+
+ if (event_id == GOOGLE_DEBUG_RING_EVENT) {
+ wifi_ring_buffer_status status;
+ memset(&status, 0, sizeof(status));
+
+ for (nl_iterator it(vendor_data); it.has_next(); it.next()) {
+ if (it.get_type() == LOGGER_ATTRIBUTE_RING_STATUS) {
+ if (it.get_len() > sizeof(wifi_ring_buffer_status)) {
+ ALOGE("SetLogHandler: ring status unexpected len = %d, dest len = %lu",
+ it.get_len(), sizeof(wifi_ring_buffer_status));
+ return NL_SKIP;
+ } else {
+ memcpy(&status, it.get_data(), sizeof(wifi_ring_buffer_status));
+ }
+ } else if (it.get_type() == LOGGER_ATTRIBUTE_RING_DATA) {
+ buffer_size = it.get_len();
+ buffer = (char *)it.get_data();
+ ALOGV("SetLogHandler: ring data size = %d", buffer_size);
+ } else {
+ ALOGW("Ignoring invalid attribute type = %d, size = %d",
+ it.get_type(), it.get_len());
+ }
+ }
+
+ // ALOGI("Retrieved Debug data");
+ if (mHandler.on_ring_buffer_data) {
+ /* Skip msg header. Retrieved log */
+ char *pBuff;
+ wifi_ring_buffer_entry *buffer_entry =
+ (wifi_ring_buffer_entry *) buffer;
+ pBuff = (char *) (buffer_entry + 1);
+ (*mHandler.on_ring_buffer_data)((char *)status.name, pBuff,
+ buffer_entry->entry_size, &status);
+ }
+ } else {
+ ALOGE("Unknown Event");
+ return NL_SKIP;
+ }
+ return NL_OK;
+ }
+};
+
+wifi_error wifi_set_log_handler(wifi_request_id id, wifi_interface_handle iface,
+ wifi_ring_buffer_data_handler handler)
+{
+ wifi_handle handle = getWifiHandle(iface);
+ ALOGE("Loghandler start, handle = %p", handle);
+
+ SetLogHandler *cmd = new SetLogHandler(iface, id, handler);
+ NULL_CHECK_RETURN(cmd, "memory allocation failure", WIFI_ERROR_OUT_OF_MEMORY);
+ wifi_error result = wifi_register_cmd(handle, id, cmd);
+ if (result != WIFI_SUCCESS) {
+ cmd->releaseRef();
+ return result;
+ }
+ result = (wifi_error)cmd->start();
+ if (result != WIFI_SUCCESS) {
+ wifi_unregister_cmd(handle, id);
+ cmd->releaseRef();
+ return result;
+ }
+
+#ifdef RING_DUMP
+ wifi_start_ring_dump(iface, handler);
+#endif /* RING_DUMP */
+ return result;
+}
+
+wifi_error wifi_reset_log_handler(wifi_request_id id, wifi_interface_handle iface)
+{
+ wifi_handle handle = getWifiHandle(iface);
+ ALOGE("Loghandler reset, wifi_request_id = %d, handle = %p", id, handle);
+
+#ifdef RING_DUMP
+ wifi_stop_ring_dump(iface);
+#endif /* RING_DUMP */
+
+ if (id == -1) {
+ wifi_ring_buffer_data_handler handler;
+ memset(&handler, 0, sizeof(handler));
+
+ SetLogHandler *cmd = new SetLogHandler(iface, id, handler);
+ NULL_CHECK_RETURN(cmd, "memory allocation failure", WIFI_ERROR_OUT_OF_MEMORY);
+ cmd->cancel();
+ cmd->releaseRef();
+
+ return WIFI_SUCCESS;
+ }
+
+ return wifi_get_cancel_cmd(id, iface);
+}
+
+///////////////////////////////////////////////////////////////////////////////
+class SetAlertHandler : public WifiCommand
+{
+ wifi_alert_handler mHandler;
+ int mBuffSize;
+ char *mBuff;
+ int mErrCode;
+
+public:
+ SetAlertHandler(wifi_interface_handle iface, int id, wifi_alert_handler handler)
+ : WifiCommand("SetAlertHandler", iface, id), mHandler(handler), mBuffSize(0), mBuff(NULL),
+ mErrCode(0)
+ { }
+
+ int start() {
+ ALOGV("Start Alerting");
+ registerVendorHandler(GOOGLE_OUI, GOOGLE_DEBUG_MEM_DUMP_EVENT);
+ return WIFI_SUCCESS;
+ }
+
+ virtual int cancel() {
+ ALOGV("Clear alerthandler");
+
+ /* unregister alert handler */
+ unregisterVendorHandler(GOOGLE_OUI, GOOGLE_DEBUG_MEM_DUMP_EVENT);
+ wifi_unregister_cmd(wifiHandle(), id());
+ ALOGD("Success to clear alerthandler");
+ return WIFI_SUCCESS;
+ }
+
+ virtual int handleResponse(WifiEvent& reply) {
+ ALOGD("In SetAlertHandler::handleResponse");
+
+ if (reply.get_cmd() != NL80211_CMD_VENDOR) {
+ ALOGD("Ignoring reply with cmd = %d", reply.get_cmd());
+ return NL_SKIP;
+ }
+
+ nlattr *vendor_data = reply.get_attribute(NL80211_ATTR_VENDOR_DATA);
+ int len = reply.get_vendor_data_len();
+
+ ALOGD("len = %d", len);
+ if (vendor_data == NULL || len == 0) {
+ ALOGE("no vendor data in memory dump response; ignoring it");
+ return NL_SKIP;
+ }
+
+ for (nl_iterator it(vendor_data); it.has_next(); it.next()) {
+ if (it.get_type() == LOGGER_ATTRIBUTE_FW_DUMP_DATA) {
+ ALOGI("Initiating alert callback");
+ if (mHandler.on_alert) {
+ (*mHandler.on_alert)(id(), mBuff, mBuffSize, mErrCode);
+ }
+ if (mBuff) {
+ free(mBuff);
+ mBuff = NULL;
+ }
+ }
+ }
+ return NL_OK;
+ }
+
+ virtual int handleEvent(WifiEvent& event) {
+ char *buffer = NULL;
+ int buffer_size = 0;
+ bool is_err_alert = false;
+
+ nlattr *vendor_data = event.get_attribute(NL80211_ATTR_VENDOR_DATA);
+ int len = event.get_vendor_data_len();
+ int event_id = event.get_vendor_subcmd();
+ ALOGI("Got event: %d", event_id);
+
+ if (vendor_data == NULL || len == 0) {
+ ALOGE("No Debug data found");
+ return NL_SKIP;
+ }
+
+ if (event_id == GOOGLE_DEBUG_MEM_DUMP_EVENT) {
+ for (nl_iterator it(vendor_data); it.has_next(); it.next()) {
+ if (it.get_type() == LOGGER_ATTRIBUTE_FW_DUMP_LEN) {
+ mBuffSize = it.get_u32();
+ } else if (it.get_type() == LOGGER_ATTRIBUTE_RING_DATA) {
+ buffer_size = it.get_len();
+ buffer = (char *)it.get_data();
+ } else if (it.get_type() == LOGGER_ATTRIBUTE_FW_ERR_CODE) {
+ /* Error code is for error alert event only */
+ mErrCode = it.get_u32();
+ is_err_alert = true;
+ } else {
+ ALOGW("Ignoring invalid attribute type = %d, size = %d",
+ it.get_type(), it.get_len());
+ }
+ }
+
+ if (is_err_alert) {
+ mBuffSize = sizeof(mErrCode);
+ if (mBuff) free(mBuff);
+ mBuff = (char *)malloc(mBuffSize);
+ if (!mBuff) {
+ ALOGE("Buffer allocation failed");
+ return NL_SKIP;
+ }
+ memcpy(mBuff, (char *)&mErrCode, mBuffSize);
+ ALOGI("Initiating alert callback");
+ if (mHandler.on_alert) {
+ (*mHandler.on_alert)(id(), mBuff, mBuffSize, mErrCode);
+ }
+ if (mBuff) {
+ free(mBuff);
+ mBuff = NULL;
+ }
+ mBuffSize = 0;
+ return NL_OK;
+ }
+
+ if (mBuffSize) {
+ ALOGD("dump size: %d meta data size: %d", mBuffSize, buffer_size);
+ if (mBuff) free(mBuff);
+ mBuff = (char *)malloc(mBuffSize + buffer_size);
+ if (!mBuff) {
+ ALOGE("Buffer allocation failed");
+ return NL_SKIP;
+ }
+ memcpy(mBuff, buffer, buffer_size);
+
+ WifiRequest request(familyId(), ifaceId());
+ int result = request.create(GOOGLE_OUI, LOGGER_GET_MEM_DUMP);
+ if (result != WIFI_SUCCESS) {
+ ALOGE("Failed to create get memory dump request; result = %d", result);
+ free(mBuff);
+ return NL_SKIP;
+ }
+ nlattr *data = request.attr_start(NL80211_ATTR_VENDOR_DATA);
+ result = request.put_u32(LOGGER_ATTRIBUTE_FW_DUMP_LEN, mBuffSize);
+ if (result != WIFI_SUCCESS) {
+ ALOGE("Failed to put get memory dump request; result = %d", result);
+ return result;
+ }
+
+ result = request.put_u64(LOGGER_ATTRIBUTE_FW_DUMP_DATA,
+ (uint64_t)(mBuff+buffer_size));
+ if (result != WIFI_SUCCESS) {
+ ALOGE("Failed to put get memory dump request; result = %d", result);
+ return result;
+ }
+
+ request.attr_end(data);
+ mBuffSize += buffer_size;
+
+ result = requestResponse(request);
+
+ if (result != WIFI_SUCCESS) {
+ ALOGE("Failed to register get momory dump response; result = %d", result);
+ }
+ } else {
+ ALOGE("dump event missing dump length attribute");
+ return NL_SKIP;
+ }
+ }
+ return NL_OK;
+ }
+};
+
+class SetRestartHandler : public WifiCommand
+{
+ wifi_subsystem_restart_handler mHandler;
+ char *mBuff;
+public:
+ SetRestartHandler(wifi_handle handle, wifi_request_id id, wifi_subsystem_restart_handler handler)
+ : WifiCommand("SetRestartHandler", handle, id), mHandler(handler), mBuff(NULL)
+ { }
+ int start() {
+ ALOGI("Start Restart Handler handler");
+ registerVendorHandler(BRCM_OUI, BRCM_VENDOR_EVENT_HANGED);
+ return WIFI_SUCCESS;
+ }
+ virtual int cancel() {
+ ALOGI("Clear Restart Handler");
+
+ /* unregister alert handler */
+ unregisterVendorHandler(BRCM_OUI, BRCM_VENDOR_EVENT_HANGED);
+ wifi_unregister_cmd(wifiHandle(), id());
+ ALOGI("Success to clear restarthandler");
+ return WIFI_SUCCESS;
+ }
+
+ virtual int handleResponse(WifiEvent& reply) {
+ /* Nothing to do on response! */
+ return NL_OK;
+ }
+
+ virtual int handleEvent(WifiEvent& event) {
+ nlattr *vendor_data = event.get_attribute(NL80211_ATTR_VENDOR_DATA);
+ int len = event.get_vendor_data_len();
+ int event_id = event.get_vendor_subcmd();
+ ALOGI("Got event: %d", event_id);
+
+ if (vendor_data == NULL || len == 0) {
+ ALOGE("No Debug data found");
+ return NL_SKIP;
+ }
+ if (event_id == BRCM_VENDOR_EVENT_HANGED) {
+ for (nl_iterator it(vendor_data); it.has_next(); it.next()) {
+ if (it.get_type() == LOGGER_ATTRIBUTE_HANG_REASON) {
+ mBuff = (char *)it.get_data();
+ } else {
+ ALOGI("Ignoring invalid attribute type = %d, size = %d",
+ it.get_type(), it.get_len());
+ }
+ }
+
+ if (*mHandler.on_subsystem_restart) {
+ (*mHandler.on_subsystem_restart)(mBuff);
+ ALOGI("Hang event received. Trigger SSR handler:%p",
+ mHandler.on_subsystem_restart);
+ } else {
+ ALOGI("No Restart handler registered");
+ }
+ }
+ return NL_OK;
+ }
+};
+
+///////////////////////////////////////////////////////////////////////////////
+class SubSystemRestart : public WifiCommand
+{
+ public:
+ SubSystemRestart(wifi_interface_handle iface)
+ : WifiCommand("SubSystemRestart", iface, 0)
+ { }
+
+ int createRequest(WifiRequest& request) {
+ int result = request.create(GOOGLE_OUI, WIFI_SUBCMD_TRIGGER_SSR);
+ if (result < 0) {
+ return result;
+ }
+
+ nlattr *data = request.attr_start(NL80211_ATTR_VENDOR_DATA);
+
+ request.attr_end(data);
+ return WIFI_SUCCESS;
+ }
+
+ int create() {
+ WifiRequest request(familyId(), ifaceId());
+
+ int result = createRequest(request);
+ if (result < 0) {
+ ALOGE("Failed to create ssr request result = %d\n", result);
+ return result;
+ }
+
+ result = requestResponse(request);
+ if (result != WIFI_SUCCESS) {
+ ALOGE("Failed to register ssr response; result = %d\n", result);
+ }
+ return result;
+ }
+
+ protected:
+ int handleResponse(WifiEvent& reply) {
+ /* Nothing to do on response! */
+ return NL_OK;
+ }
+
+ int handleEvent(WifiEvent& event) {
+ /* NO events to handle here! */
+ return NL_SKIP;
+ }
+
+};
+///////////////////////////////////////////////////////////////////////////////
+class HalInit : public WifiCommand
+{
+ int mErrCode;
+
+ public:
+ HalInit(wifi_interface_handle iface, int id)
+ : WifiCommand("HalInit", iface, id), mErrCode(0)
+ { }
+
+ int start() {
+ ALOGE("Start Set Hal");
+ WifiRequest request(familyId(), ifaceId());
+
+ int result = request.create(GOOGLE_OUI, LOGGER_SET_HAL_START);
+ if (result != WIFI_SUCCESS) {
+ ALOGE("Failed to set hal start; result = %d", result);
+ return result;
+ }
+
+ result = requestResponse(request);
+ if (result != WIFI_SUCCESS) {
+ ALOGE("Failed to register set hal start response; result = %d", result);
+ }
+ return result;
+ }
+
+
+ virtual int cancel() {
+ ALOGE("Cancel: Stop Hal");
+ WifiRequest request(familyId(), ifaceId());
+
+ int result = request.create(GOOGLE_OUI, LOGGER_HAL_STOP);
+ if (result != WIFI_SUCCESS) {
+ ALOGE("Failed to stop hal ; result = %d", result);
+ return result;
+ }
+
+ result = requestResponse(request);
+ if (result != WIFI_SUCCESS) {
+ ALOGE("Failed to register set hal start response; result = %d", result);
+ }
+ wifi_unregister_cmd(wifiHandle(), id());
+ ALOGV("Stop HAL Successfully Completed, mErrCode = %d\n", mErrCode);
+ return result;
+ }
+
+ int preInit() {
+ ALOGE("Hal preInit");
+ WifiRequest request(familyId(), ifaceId());
+
+ int result = request.create(GOOGLE_OUI, LOGGER_SET_HAL_START);
+ if (result != WIFI_SUCCESS) {
+ ALOGE("Failed to set Hal preInit; result = %d", result);
+ return result;
+ }
+
+ nlattr *data = request.attr_start(NL80211_ATTR_VENDOR_DATA);
+ result = request.put_string(SET_HAL_START_ATTRIBUTE_PRE_INIT, (char *)HAL_VERSION);
+ if (result != WIFI_SUCCESS) {
+ ALOGE("Hal preInit Failed to put data= %d", result);
+ return result;
+ }
+ request.attr_end(data);
+
+ result = requestResponse(request);
+ if (result != WIFI_SUCCESS) {
+ ALOGE("Failed to register set Hal preInit; result = %d", result);
+ }
+ return result;
+ }
+
+ virtual int handleResponse(WifiEvent& reply) {
+ ALOGE("In SetHalStarted::handleResponse");
+
+ if (reply.get_cmd() != NL80211_CMD_VENDOR) {
+ ALOGD("Ignoring reply with cmd = %d", reply.get_cmd());
+ return NL_SKIP;
+ }
+ return NL_OK;
+ }
+
+ virtual int handleEvent(WifiEvent& event) {
+ /* NO events! */
+ return NL_SKIP;
+ }
+};
+
+#ifdef RING_DUMP
+///////////////////////////////////////////////////////////////////////////////
+class RingDump : public WifiCommand
+{
+ int mLargestBuffSize;
+ char *mBuff;
+ int mErrCode;
+ int mNumMaps;
+ wifi_buf_ring_map_entry_t *mMap;
+ int attr_type_len[DUMP_EVENT_ATTR_MAX];
+ char *ring_name[DUMP_BUF_ATTR_MAX];
+ wifi_ring_buffer_data_handler mHandle;
+
+public:
+ RingDump(wifi_interface_handle iface, int id, int num_maps, wifi_buf_ring_map_entry_t *map,
+ wifi_ring_buffer_data_handler ring_handle)
+ : WifiCommand("RingDump", iface, id), mLargestBuffSize(0), mBuff(NULL),
+ mErrCode(0), mNumMaps(num_maps), mMap(map), mHandle(ring_handle)
+ {
+ memset(attr_type_len, 0, sizeof(attr_type_len));
+ for (int i = 0; i < DUMP_BUF_ATTR_MAX; i++) {
+ ring_name[i] = NULL;
+ }
+ }
+ RingDump(wifi_interface_handle iface, int id)
+ : WifiCommand("RingDump", iface, id), mLargestBuffSize(0), mBuff(NULL),
+ mErrCode(0)
+ {
+ }
+
+ int start() {
+ DUMP_INFO(("Start Ring Dump Map_cnt:%d\n", mNumMaps));
+ registerVendorHandler(GOOGLE_OUI, GOOGLE_FILE_DUMP_EVENT);
+
+ //Set ringname to buf hashmap
+ for (int i = 0; i < mNumMaps; i++) {
+ int type = mMap[i].type;
+ ring_name[type] = (char *)malloc(DBGRING_NAME_MAX);
+ memset(ring_name[type], 0, DBGRING_NAME_MAX);
+ memcpy(ring_name[type], mMap[i].ring_name, strlen(mMap[i].ring_name));
+ DUMP_DEBUG(("Set ringname Buf:%s Ringname:%s len:%lu",
+ EWP_CmdAttrToString(type), ring_name[type], strlen(mMap[i].ring_name)));
+ }
+ return WIFI_SUCCESS;
+ }
+
+ virtual int freeup() {
+ DUMP_DEBUG(("freeup:Enter\n"));
+ if (mBuff) {
+ free(mBuff);
+ mBuff = NULL;
+ DUMP_INFO(("freed allocated memory\n"));
+ }
+ return WIFI_SUCCESS;
+ }
+
+ virtual int cancel() {
+ /* unregister file dump handler */
+ unregisterVendorHandler(GOOGLE_OUI, GOOGLE_FILE_DUMP_EVENT);
+ wifi_unregister_cmd(wifiHandle(), id());
+
+ /* Free up the ring names allocated */
+ for (u8 i = 0; i < DUMP_BUF_ATTR_MAX; i++) {
+ if (ring_name[i]) {
+ free(ring_name[i]);
+ ring_name[i] = NULL;
+ }
+ }
+ if (mBuff) {
+ free(mBuff);
+ }
+
+ DUMP_INFO(("Stop Ring Dump Successfully Completed, mErrCode = %d\n", mErrCode));
+ return WIFI_SUCCESS;
+ }
+
+ virtual int handleResponse(WifiEvent& reply) {
+ DUMP_DEBUG(("RingDump::handleResponse\n"));
+ int buf_attr = DUMP_BUF_ATTR_INVALID;
+ int len_attr = DUMP_LEN_ATTR_INVALID;
+ int index = -1;
+
+ if (reply.get_cmd() != NL80211_CMD_VENDOR) {
+ ALOGD("Ignoring reply with cmd = %d", reply.get_cmd());
+ return NL_SKIP;
+ }
+
+ nlattr *vendor_data = reply.get_attribute(NL80211_ATTR_VENDOR_DATA);
+ int len = reply.get_vendor_data_len();
+
+ if (vendor_data == NULL || len == 0) {
+ ALOGE("no vendor data in memory dump response; ignoring it");
+ return NL_SKIP;
+ }
+
+ for (nl_iterator it(vendor_data); it.has_next(); it.next()) {
+ buf_attr = it.get_type();
+ switch (buf_attr) {
+ case DUMP_BUF_ATTR_MEMDUMP:
+ case DUMP_BUF_ATTR_TIMESTAMP:
+ case DUMP_BUF_ATTR_ECNTRS:
+ case DUMP_BUF_ATTR_DHD_DUMP:
+ case DUMP_BUF_ATTR_EXT_TRAP:
+ case DUMP_BUF_ATTR_HEALTH_CHK:
+ case DUMP_BUF_ATTR_COOKIE:
+ case DUMP_BUF_ATTR_FLOWRING_DUMP:
+ case DUMP_BUF_ATTR_STATUS_LOG:
+ case DUMP_BUF_ATTR_RTT_LOG: {
+ if (it.get_u32()) {
+ ALOGE("Copying data to userspace failed, status = %d\n", it.get_u32());
+ return WIFI_ERROR_UNKNOWN;
+ }
+ index = logger_attr_buffer_lookup(buf_attr);
+ if (index == -1) {
+ ALOGE("Invalid index. buf attr = %s\n", EWP_CmdAttrToString(buf_attr));
+ return WIFI_ERROR_UNKNOWN;
+ }
+ len_attr = attr_lookup_tbl[index].attr_type;
+ if (len_attr == DUMP_EVENT_ATTR_MAX) {
+ ALOGE("Invalid len attr = %s\n", EWP_EventAttrToString(len_attr));
+ return WIFI_ERROR_UNKNOWN;
+ }
+ if (!mBuff || attr_type_len[len_attr] <= 0) {
+ return WIFI_ERROR_UNKNOWN;
+ }
+
+ if (!ring_name[buf_attr]) {
+ ALOGE("Not allocated buf attr = %s\n", EWP_CmdAttrToString(buf_attr));
+ return WIFI_ERROR_UNKNOWN;
+ }
+ DUMP_INFO(("RingDump:: buf_attr:%s size = %d ring_name:%s\n",
+ EWP_CmdAttrToString(buf_attr), attr_type_len[len_attr],
+ ring_name[buf_attr]));
+ if (mHandle.on_ring_buffer_data) {
+ /* on_ring_buffer_data callback requires status memory
+ * so should pass status memory */
+ wifi_ring_buffer_status status;
+ memset(&status, 0, sizeof(status));
+ /* Skip msg header. Retrieved log */
+ (*mHandle.on_ring_buffer_data)(ring_name[buf_attr], mBuff,
+ attr_type_len[len_attr], &status);
+ }
+ if (mBuff) {
+ memset(mBuff, 0, mLargestBuffSize);
+ }
+ break;
+ }
+ default: {
+ DUMP_DEBUG(("Ignoring invalid attribute buf_attr = %d, size = %d",
+ buf_attr, it.get_len()));
+ break;
+ }
+ }
+ }
+ return NL_OK;
+ }
+
+ virtual int request_logger_dump(WifiRequest& request,
+ buf_data_t *buf, int len_attr) {
+
+ int result = 0;
+ int buf_attr = DUMP_BUF_ATTR_INVALID;
+ int index = -1;
+ nlattr *data = request.attr_start(NL80211_ATTR_VENDOR_DATA);
+
+ index = logger_attr_lookup(len_attr);
+ if (index == -1) {
+ ALOGE("Invalid index\n");
+ return WIFI_ERROR_UNKNOWN;
+ }
+ buf_attr = attr_lookup_tbl[index].buf_attr;
+
+ if (buf_attr != DUMP_BUF_ATTR_INVALID) {
+ result = request.put(buf_attr, buf, sizeof(buf_data_t));
+ if (result != WIFI_SUCCESS) {
+ ALOGE("Failed to put get memory dump request; result = %d", result);
+ return result;
+ }
+ } else {
+ ALOGE("Invalid buf attr = %s, index = %d\n",
+ EWP_CmdAttrToString(buf_attr), index);
+ return WIFI_ERROR_UNKNOWN;
+ }
+ DUMP_INFO(("Trigger get dump for buf attr = %s\n",
+ EWP_CmdAttrToString(buf_attr)));
+
+ request.attr_end(data);
+ return result;
+ }
+
+ virtual int handleEvent(WifiEvent& event) {
+ mLargestBuffSize = 0;
+ mBuff = NULL;
+ memset(attr_type_len, 0, sizeof(attr_type_len));
+ u8 i = 0;
+ int result = 0;
+ int mActualBuffSize = 0;
+ int index = -1;
+
+ nlattr *vendor_data = event.get_attribute(NL80211_ATTR_VENDOR_DATA);
+ int len = event.get_vendor_data_len();
+ int event_id = event.get_vendor_subcmd();
+ int req_attr_cnt = 0;
+ int req_attr[DUMP_EVENT_ATTR_MAX];
+ int buf_attr = DUMP_BUF_ATTR_INVALID;
+
+ if (vendor_data == NULL || len == 0) {
+ ALOGE("No Debug data found");
+ return NL_SKIP;
+ }
+ DUMP_INFO(("Ring Dump handler. Got event: %d", event_id));
+
+ buf_data_t buf;
+
+ memset(&buf, 0, sizeof(buf_data_t));
+ buf.ver = 0;
+ buf.buf_threshold = 0;
+
+ if (event_id == GOOGLE_FILE_DUMP_EVENT) {
+ for (nl_iterator it(vendor_data); it.has_next(); it.next()) {
+ int attr = it.get_type();
+ switch (attr) {
+ case DUMP_LEN_ATTR_MEMDUMP:
+ case DUMP_LEN_ATTR_TIMESTAMP:
+ case DUMP_LEN_ATTR_ECNTRS:
+ case DUMP_LEN_ATTR_DHD_DUMP:
+ case DUMP_LEN_ATTR_EXT_TRAP:
+ case DUMP_LEN_ATTR_HEALTH_CHK:
+ case DUMP_LEN_ATTR_COOKIE:
+ case DUMP_LEN_ATTR_FLOWRING_DUMP:
+ case DUMP_LEN_ATTR_STATUS_LOG:
+ case DUMP_LEN_ATTR_RTT_LOG: {
+ mActualBuffSize = it.get_u32();
+ DUMP_DEBUG(("len attr %s, len %d\n",
+ EWP_EventAttrToString(attr), mActualBuffSize));
+ if (mActualBuffSize > mLargestBuffSize)
+ mLargestBuffSize = mActualBuffSize;
+ attr_type_len[attr] = mActualBuffSize;
+
+ /* Store the order in which attributes are received
+ * so that file dump can be done in the same order
+ */
+ req_attr[req_attr_cnt++] = attr;
+ break;
+ }
+ default: {
+ ALOGE("Ignoring invalid attribute type = %d, size = %d",
+ attr, it.get_len());
+ break;
+ }
+ }
+ }
+ /* Allocation for the largest buffer size to use it recursively for other buf attr. */
+ if (mLargestBuffSize) {
+ DUMP_INFO(("Max dump size: %d", mLargestBuffSize));
+ mBuff = (char *)malloc(mLargestBuffSize);
+ if (!mBuff) {
+ ALOGE("Buffer allocation failed");
+ return NL_SKIP;
+ }
+ memset(mBuff, 0, mLargestBuffSize);
+ }
+
+ WifiRequest request(familyId(), ifaceId());
+ result = request.create(GOOGLE_OUI, LOGGER_DEBUG_GET_DUMP);
+ if (result != WIFI_SUCCESS) {
+ ALOGE("Failed to create get memory dump request; result = %d", result);
+ freeup();
+ goto exit;
+ }
+
+ /* Requesting logger dump for each received attr */
+ for (i = 0; i < req_attr_cnt; i++) {
+ int attr = req_attr[i];
+
+ if (attr_type_len[attr] == 0) {
+ continue;
+ }
+
+ index = logger_attr_lookup(attr);
+ buf_attr = attr_lookup_tbl[index].buf_attr;
+ if (!ring_name[buf_attr]) {
+ ALOGE("Failed to find ringname index:%d buf_attr:%d", index, buf_attr);
+ continue;
+ }
+
+ buf.len = attr_type_len[attr];
+ buf.data_buf[0] = mBuff;
+ DUMP_DEBUG(("buf len = %d, buf ptr= %p for attr = %s\n",
+ buf.len, buf.data_buf[0], EWP_EventAttrToString(attr)));
+ result = request_logger_dump(request, &buf, attr);
+ if (result != WIFI_SUCCESS) {
+ /* Proceeding further for other attributes */
+ ALOGE("Failed to request the logger dump for attr = %s; result = %d",
+ EWP_EventAttrToString(attr), result);
+ continue;
+ }
+ result = requestResponse(request);
+ if (result != WIFI_SUCCESS) {
+ ALOGE("Failed to register get memory dump response for attr = %s; result = %d",
+ EWP_EventAttrToString(attr), result);
+ /* Proceeding further for other attributes */
+ continue;
+ }
+ }
+
+ WifiRequest request2(familyId(), ifaceId());
+ result = request2.create(GOOGLE_OUI, LOGGER_FILE_DUMP_DONE_IND);
+ if (result != WIFI_SUCCESS) {
+ ALOGE("Failed to trigger dev close; result = %d", result);
+ freeup();
+ goto exit;
+ }
+ requestResponse(request2);
+ freeup();
+ } else {
+ ALOGE("dump event missing dump length attribute");
+ return NL_SKIP;
+ }
+ exit:
+ if (result != WIFI_SUCCESS) {
+ return NL_SKIP;
+ }
+ return NL_OK;
+ }
+};
+///////////////////////////////////////////////////////////////////////////////
+#endif /* RING_DUMP */
+
+wifi_error wifi_start_hal(wifi_interface_handle iface)
+{
+ wifi_handle handle = getWifiHandle(iface);
+ ALOGV("HAL INIT start, handle = %p", handle);
+
+ HalInit *cmd = new HalInit(iface, HAL_START_REQUEST_ID);
+ NULL_CHECK_RETURN(cmd, "memory allocation failure", WIFI_ERROR_OUT_OF_MEMORY);
+ wifi_error result = wifi_register_cmd(handle, HAL_START_REQUEST_ID, cmd);
+ if (result != WIFI_SUCCESS) {
+ cmd->releaseRef();
+ return result;
+ }
+ result = (wifi_error)cmd->start();
+ if (result != WIFI_SUCCESS) {
+ wifi_unregister_cmd(handle,HAL_START_REQUEST_ID);
+ cmd->releaseRef();
+ return result;
+ }
+ return result;
+}
+
+wifi_error wifi_hal_preInit(wifi_interface_handle iface)
+{
+ wifi_handle handle = getWifiHandle(iface);
+ ALOGV("wifi_hal_preInit, handle = %p", handle);
+
+ HalInit *cmd = new HalInit(iface, HAL_START_REQUEST_ID);
+ NULL_CHECK_RETURN(cmd, "memory allocation failure", WIFI_ERROR_OUT_OF_MEMORY);
+ wifi_error result = wifi_register_cmd(handle, HAL_START_REQUEST_ID, cmd);
+ if (result != WIFI_SUCCESS) {
+ cmd->releaseRef();
+ return result;
+ }
+ result = (wifi_error)cmd->preInit();
+ if (result != WIFI_SUCCESS) {
+ wifi_unregister_cmd(handle,HAL_START_REQUEST_ID);
+ cmd->releaseRef();
+ return result;
+ }
+ return result;
+}
+
+#ifdef RING_DUMP
+wifi_error wifi_start_ring_dump(wifi_interface_handle iface,
+ wifi_ring_buffer_data_handler ring_handle)
+{
+ wifi_handle handle = getWifiHandle(iface);
+ DUMP_INFO(("start ring dump, handle = %p", handle));
+ wifi_buf_ring_map_entry_t map[DUMP_BUF_ATTR_MAX];
+ unsigned int num_maps = DUMP_BUF_ATTR_MAX;
+ wifi_error result;
+
+ /* Get mapping table from driver */
+ DebugCommand *debug_cmd = new DebugCommand(iface, &num_maps, map, GET_BUF_RING_MAP);
+ NULL_CHECK_RETURN(debug_cmd, "memory allocation failure", WIFI_ERROR_OUT_OF_MEMORY);
+ result = (wifi_error)debug_cmd->start();
+ debug_cmd->releaseRef();
+
+ /* Set ringname to corresponding buf attr */
+ RingDump *cmd = new RingDump(iface, FILE_DUMP_REQUEST_ID, num_maps, map, ring_handle);
+ NULL_CHECK_RETURN(cmd, "memory allocation failure", WIFI_ERROR_OUT_OF_MEMORY);
+ result = wifi_register_cmd(handle, FILE_DUMP_REQUEST_ID, cmd);
+ if (result != WIFI_SUCCESS) {
+ cmd->releaseRef();
+ return result;
+ }
+
+ result = (wifi_error)cmd->start();
+ if (result != WIFI_SUCCESS) {
+ wifi_unregister_cmd(handle, FILE_DUMP_REQUEST_ID);
+ cmd->releaseRef();
+ return result;
+ }
+ return result;
+}
+
+wifi_error wifi_stop_ring_dump(wifi_interface_handle iface)
+{
+ RingDump *cmd = new RingDump(iface, FILE_DUMP_REQUEST_ID);
+ NULL_CHECK_RETURN(cmd, "memory allocation failure", WIFI_ERROR_OUT_OF_MEMORY);
+ DUMP_INFO(("stop ring dump"));
+ cmd->cancel();
+ cmd->releaseRef();
+ return WIFI_SUCCESS;
+}
+#endif /* RING_DUMP */
+
+wifi_error wifi_stop_hal(wifi_interface_handle iface)
+{
+ HalInit *cmd = new HalInit(iface, HAL_START_REQUEST_ID);
+ NULL_CHECK_RETURN(cmd, "memory allocation failure", WIFI_ERROR_OUT_OF_MEMORY);
+ cmd->cancel();
+ cmd->releaseRef();
+ return WIFI_SUCCESS;
+}
+
+
+wifi_error wifi_set_subsystem_restart_handler(wifi_handle handle,
+ wifi_subsystem_restart_handler handler)
+{
+ hal_info *info = NULL;
+
+ info = (hal_info *)handle;
+ if (info == NULL) {
+ ALOGE("Could not find hal info\n");
+ return WIFI_ERROR_UNKNOWN;
+ }
+
+ SetRestartHandler *cmd = new SetRestartHandler(handle, HAL_RESTART_ID, handler);
+ NULL_CHECK_RETURN(cmd, "memory allocation failure", WIFI_ERROR_OUT_OF_MEMORY);
+ wifi_error result = wifi_register_cmd(handle, HAL_RESTART_ID, cmd);
+ if (result != WIFI_SUCCESS) {
+ cmd->releaseRef();
+ return result;
+ }
+
+ result = (wifi_error)cmd->start();
+ if (result != WIFI_SUCCESS) {
+ wifi_unregister_cmd(handle, HAL_RESTART_ID);
+ cmd->releaseRef();
+ return result;
+ }
+
+ /* Cache the handler to use it for trigger subsystem restart */
+ ALOGI("Register SSR handler:%p", handler);
+ info->restart_handler = handler;
+ return result;
+}
+
+wifi_error wifi_trigger_subsystem_restart(wifi_handle handle)
+{
+ wifi_error result = WIFI_SUCCESS;
+ hal_info *info = NULL;
+ char error_str[20];
+ SubSystemRestart *cmd = NULL;
+ wifi_interface_handle *ifaceHandles = NULL;
+ wifi_interface_handle wlan0Handle;
+ int numIfaceHandles = 0;
+
+ info = (hal_info *)handle;
+ if (handle == NULL || info == NULL) {
+ ALOGE("Could not find hal info\n");
+ result = WIFI_ERROR_UNKNOWN;
+ goto exit;
+ }
+
+ ALOGI("Trigger subsystem restart\n");
+
+ wlan0Handle = wifi_get_wlan_interface((wifi_handle)handle, ifaceHandles, numIfaceHandles);
+
+ cmd = new SubSystemRestart(wlan0Handle);
+ NULL_CHECK_RETURN(cmd, "memory allocation failure", WIFI_ERROR_OUT_OF_MEMORY);
+
+ result = (wifi_error)cmd->create();
+ if (result != WIFI_SUCCESS) {
+ cmd->releaseRef();
+ strncpy(error_str, "WIFI_ERROR_UNKNOWN", sizeof(error_str));
+ ALOGE("Failed to create SSR");
+ goto exit;
+ }
+
+ strncpy(error_str, "WIFI_SUCCESS", sizeof(error_str));
+
+exit:
+ if (result == WIFI_SUCCESS) {
+ if (info->restart_handler.on_subsystem_restart) {
+ ALOGI("Trigger ssr handler registered handler:%p",
+ info->restart_handler.on_subsystem_restart);
+ (info->restart_handler.on_subsystem_restart)(error_str);
+ } else {
+ ALOGI("No trigger ssr handler registered");
+ }
+ }
+
+ return result;
+}
+
+wifi_error wifi_set_alert_handler(wifi_request_id id, wifi_interface_handle iface,
+ wifi_alert_handler handler)
+{
+ wifi_handle handle = getWifiHandle(iface);
+ ALOGV("Alerthandler start, handle = %p", handle);
+
+ SetAlertHandler *cmd = new SetAlertHandler(iface, id, handler);
+ NULL_CHECK_RETURN(cmd, "memory allocation failure", WIFI_ERROR_OUT_OF_MEMORY);
+ wifi_error result = wifi_register_cmd(handle, id, cmd);
+ if (result != WIFI_SUCCESS) {
+ cmd->releaseRef();
+ return result;
+ }
+ result = (wifi_error)cmd->start();
+ if (result != WIFI_SUCCESS) {
+ wifi_unregister_cmd(handle, id);
+ cmd->releaseRef();
+ return result;
+ }
+ return result;
+}
+
+wifi_error wifi_reset_alert_handler(wifi_request_id id, wifi_interface_handle iface)
+{
+ wifi_handle handle = getWifiHandle(iface);
+ ALOGV("Alerthandler reset, wifi_request_id = %d, handle = %p", id, handle);
+
+ if (id == -1) {
+ wifi_alert_handler handler;
+ memset(&handler, 0, sizeof(handler));
+
+ SetAlertHandler *cmd = new SetAlertHandler(iface, id, handler);
+ NULL_CHECK_RETURN(cmd, "memory allocation failure", WIFI_ERROR_OUT_OF_MEMORY);
+ cmd->cancel();
+ cmd->releaseRef();
+ return WIFI_SUCCESS;
+ }
+
+ return wifi_get_cancel_cmd(id, iface);
+}
+
+///////////////////////////////////////////////////////////////////////////////
+class MemoryDumpCommand: public WifiCommand
+{
+ wifi_firmware_memory_dump_handler mHandler;
+ int mBuffSize;
+ char *mBuff;
+
+public:
+ MemoryDumpCommand(wifi_interface_handle iface, wifi_firmware_memory_dump_handler handler)
+ : WifiCommand("MemoryDumpCommand", iface, 0), mHandler(handler), mBuffSize(0), mBuff(NULL)
+ { }
+
+ int start() {
+ ALOGD("Start memory dump command");
+ WifiRequest request(familyId(), ifaceId());
+
+ int result = request.create(GOOGLE_OUI, LOGGER_TRIGGER_MEM_DUMP);
+ if (result != WIFI_SUCCESS) {
+ ALOGE("Failed to create trigger fw memory dump request; result = %d", result);
+ return result;
+ }
+
+ result = requestResponse(request);
+ if (result != WIFI_SUCCESS) {
+ ALOGE("Failed to register trigger memory dump response; result = %d", result);
+ }
+ return result;
+ }
+
+ virtual int handleResponse(WifiEvent& reply) {
+ ALOGD("In MemoryDumpCommand::handleResponse");
+
+ if (reply.get_cmd() != NL80211_CMD_VENDOR) {
+ ALOGD("Ignoring reply with cmd = %d", reply.get_cmd());
+ return NL_SKIP;
+ }
+
+ nlattr *vendor_data = reply.get_attribute(NL80211_ATTR_VENDOR_DATA);
+ int len = reply.get_vendor_data_len();
+
+ ALOGD("len = %d", len);
+ if (vendor_data == NULL || len == 0) {
+ ALOGE("no vendor data in memory dump response; ignoring it");
+ return NL_SKIP;
+ }
+
+ for (nl_iterator it(vendor_data); it.has_next(); it.next()) {
+ if (it.get_type() == LOGGER_ATTRIBUTE_FW_DUMP_LEN) {
+ mBuffSize = it.get_u32();
+
+ if (mBuff)
+ free(mBuff);
+ mBuff = (char *)malloc(mBuffSize);
+ if (!mBuff) {
+ ALOGE("Buffer allocation failed");
+ return NL_SKIP;
+ }
+ WifiRequest request(familyId(), ifaceId());
+ int result = request.create(GOOGLE_OUI, LOGGER_GET_MEM_DUMP);
+ if (result != WIFI_SUCCESS) {
+ ALOGE("Failed to create get memory dump request; result = %d", result);
+ free(mBuff);
+ return NL_SKIP;
+ }
+
+ nlattr *data = request.attr_start(NL80211_ATTR_VENDOR_DATA);
+ result = request.put_u32(LOGGER_ATTRIBUTE_FW_DUMP_LEN, mBuffSize);
+ if (result != WIFI_SUCCESS) {
+ ALOGE("Failed to put get memory dump request; result = %d", result);
+ return result;
+ }
+
+ result = request.put_u64(LOGGER_ATTRIBUTE_FW_DUMP_DATA, (uint64_t)mBuff);
+ if (result != WIFI_SUCCESS) {
+ ALOGE("Failed to put get memory dump request; result = %d", result);
+ return result;
+ }
+ request.attr_end(data);
+
+ result = requestResponse(request);
+ if (result != WIFI_SUCCESS) {
+ ALOGE("Failed to register get momory dump response; result = %d", result);
+ }
+ } else if (it.get_type() == LOGGER_ATTRIBUTE_FW_DUMP_DATA) {
+ ALOGI("Initiating memory dump callback");
+ if (mHandler.on_firmware_memory_dump) {
+ (*mHandler.on_firmware_memory_dump)(mBuff, mBuffSize);
+ }
+ if (mBuff) {
+ free(mBuff);
+ mBuff = NULL;
+ }
+ } else {
+ ALOGW("Ignoring invalid attribute type = %d, size = %d",
+ it.get_type(), it.get_len());
+ }
+ }
+ return NL_OK;
+ }
+
+ virtual int handleEvent(WifiEvent& event) {
+ /* NO events! */
+ return NL_SKIP;
+ }
+};
+
+/* API to collect a firmware memory dump for a given iface */
+wifi_error wifi_get_firmware_memory_dump( wifi_interface_handle iface,
+ wifi_firmware_memory_dump_handler handler)
+{
+ MemoryDumpCommand *cmd = new MemoryDumpCommand(iface, handler);
+ NULL_CHECK_RETURN(cmd, "memory allocation failure", WIFI_ERROR_OUT_OF_MEMORY);
+ wifi_error result = (wifi_error)cmd->start();
+ cmd->releaseRef();
+ return result;
+}
+
+class PacketFateCommand: public WifiCommand
+{
+ void *mReportBufs;
+ size_t mNoReqFates;
+ size_t *mNoProvidedFates;
+ PktFateReqType mReqType;
+
+public:
+ PacketFateCommand(wifi_interface_handle handle)
+ : WifiCommand("PacketFateCommand", handle, 0), mReqType(PACKET_MONITOR_START)
+ {
+ mReportBufs = NULL;
+ mNoReqFates = 0;
+ mNoProvidedFates = NULL;
+ }
+
+ PacketFateCommand(wifi_interface_handle handle, wifi_tx_report *tx_report_bufs,
+ size_t n_requested_fates, size_t *n_provided_fates)
+ : WifiCommand("PacketFateCommand", handle, 0), mReportBufs(tx_report_bufs),
+ mNoReqFates(n_requested_fates), mNoProvidedFates(n_provided_fates),
+ mReqType(TX_PACKET_FATE)
+ { }
+
+ PacketFateCommand(wifi_interface_handle handle, wifi_rx_report *rx_report_bufs,
+ size_t n_requested_fates, size_t *n_provided_fates)
+ : WifiCommand("PacketFateCommand", handle, 0), mReportBufs(rx_report_bufs),
+ mNoReqFates(n_requested_fates), mNoProvidedFates(n_provided_fates),
+ mReqType(RX_PACKET_FATE)
+ { }
+
+ int createRequest(WifiRequest& request) {
+ if (mReqType == TX_PACKET_FATE) {
+ ALOGD("%s Get Tx packet fate request\n", __FUNCTION__);
+ return createTxPktFateRequest(request);
+ } else if (mReqType == RX_PACKET_FATE) {
+ ALOGD("%s Get Rx packet fate request\n", __FUNCTION__);
+ return createRxPktFateRequest(request);
+ } else if (mReqType == PACKET_MONITOR_START) {
+ ALOGD("%s Monitor packet fate request\n", __FUNCTION__);
+ return createMonitorPktFateRequest(request);
+ } else {
+ ALOGE("%s Unknown packet fate request\n", __FUNCTION__);
+ return WIFI_ERROR_NOT_SUPPORTED;
+ }
+ return WIFI_SUCCESS;
+ }
+
+ int createMonitorPktFateRequest(WifiRequest& request) {
+ int result = request.create(GOOGLE_OUI, LOGGER_START_PKT_FATE_MONITORING);
+ if (result < 0) {
+ return result;
+ }
+
+ nlattr *data = request.attr_start(NL80211_ATTR_VENDOR_DATA);
+ request.attr_end(data);
+ return result;
+ }
+
+ int createTxPktFateRequest(WifiRequest& request) {
+ int result = request.create(GOOGLE_OUI, LOGGER_GET_TX_PKT_FATES);
+ if (result < 0) {
+ return result;
+ }
+
+ memset(mReportBufs, 0, (mNoReqFates * sizeof(wifi_tx_report)));
+ nlattr *data = request.attr_start(NL80211_ATTR_VENDOR_DATA);
+ result = request.put_u32(LOGGER_ATTRIBUTE_PKT_FATE_NUM, mNoReqFates);
+ if (result < 0) {
+ return result;
+ }
+ result = request.put_u64(LOGGER_ATTRIBUTE_PKT_FATE_DATA, (uint64_t)mReportBufs);
+ if (result < 0) {
+ return result;
+ }
+ request.attr_end(data);
+ return result;
+ }
+
+ int createRxPktFateRequest(WifiRequest& request) {
+ int result = request.create(GOOGLE_OUI, LOGGER_GET_RX_PKT_FATES);
+ if (result < 0) {
+ return result;
+ }
+
+ memset(mReportBufs, 0, (mNoReqFates * sizeof(wifi_rx_report)));
+ nlattr *data = request.attr_start(NL80211_ATTR_VENDOR_DATA);
+ result = request.put_u32(LOGGER_ATTRIBUTE_PKT_FATE_NUM, mNoReqFates);
+ if (result < 0) {
+ return result;
+ }
+ result = request.put_u64(LOGGER_ATTRIBUTE_PKT_FATE_DATA, (uint64_t)mReportBufs);
+ if (result < 0) {
+ return result;
+ }
+ request.attr_end(data);
+ return result;
+ }
+
+ int start() {
+ ALOGD("Start get packet fate command\n");
+ WifiRequest request(familyId(), ifaceId());
+
+ int result = createRequest(request);
+ if (result < 0) {
+ ALOGE("Failed to create get pkt fate request; result = %d\n", result);
+ return result;
+ }
+
+ result = requestResponse(request);
+ if (result != WIFI_SUCCESS) {
+ ALOGE("Failed to register get pkt fate response; result = %d\n", result);
+ }
+ return result;
+ }
+
+ int handleResponse(WifiEvent& reply) {
+ ALOGD("In GetPktFateCommand::handleResponse\n");
+
+ if (reply.get_cmd() != NL80211_CMD_VENDOR) {
+ ALOGI("Ignoring reply with cmd = %d", reply.get_cmd());
+ return NL_SKIP;
+ }
+
+ int id = reply.get_vendor_id();
+ int subcmd = reply.get_vendor_subcmd();
+ nlattr *vendor_data = reply.get_attribute(NL80211_ATTR_VENDOR_DATA);
+ int len = reply.get_vendor_data_len();
+
+ ALOGI("Id = %0x, subcmd = %d, len = %d", id, subcmd, len);
+
+ if (mReqType == TX_PACKET_FATE) {
+ ALOGI("Response received for get TX pkt fate command\n");
+ } else if (mReqType == RX_PACKET_FATE) {
+ ALOGI("Response received for get RX pkt fate command\n");
+ } else if (mReqType == PACKET_MONITOR_START) {
+ ALOGI("Response received for monitor pkt fate command\n");
+ return NL_OK;
+ } else {
+ ALOGE("Response received for unknown pkt fate command\n");
+ return NL_SKIP;
+ }
+
+ if (vendor_data == NULL || len == 0) {
+ ALOGE("no vendor data in GetPktFateCommand response; ignoring it\n");
+ return NL_SKIP;
+ }
+
+ for (nl_iterator it(vendor_data); it.has_next(); it.next()) {
+ if (it.get_type() == LOGGER_ATTRIBUTE_PKT_FATE_NUM) {
+ *mNoProvidedFates = it.get_u32();
+ ALOGI("No: of pkt fates provided is %zu\n", *mNoProvidedFates);
+ } else {
+ ALOGE("Ignoring invalid attribute type = %d, size = %d\n",
+ it.get_type(), it.get_len());
+ }
+ }
+
+ return NL_OK;
+ }
+
+ int handleEvent(WifiEvent& event) {
+ /* NO events to handle here! */
+ return NL_SKIP;
+ }
+};
+
+class GetWakeReasonCountCommand : public WifiCommand {
+ WLAN_DRIVER_WAKE_REASON_CNT *mWakeReasonCnt;
+ void *mCmdEventWakeCount;
+ public:
+ GetWakeReasonCountCommand(wifi_interface_handle handle,
+ WLAN_DRIVER_WAKE_REASON_CNT *wlanDriverWakeReasonCount) :
+ WifiCommand("GetWakeReasonCountCommand", handle, 0),
+ mWakeReasonCnt(wlanDriverWakeReasonCount)
+ {
+ mCmdEventWakeCount = mWakeReasonCnt->cmd_event_wake_cnt;
+ }
+
+ int createRequest(WifiRequest& request) {
+ int result = request.create(GOOGLE_OUI, LOGGER_GET_WAKE_REASON_STATS);
+ if (result < 0) {
+ return result;
+ }
+
+ nlattr *data = request.attr_start(NL80211_ATTR_VENDOR_DATA);
+
+ request.attr_end(data);
+ return WIFI_SUCCESS;
+ }
+
+ int start() {
+ ALOGD("Start get wake stats command\n");
+ WifiRequest request(familyId(), ifaceId());
+
+ int result = createRequest(request);
+ if (result < 0) {
+ ALOGE("Failed to create request result = %d\n", result);
+ return result;
+ }
+
+ result = requestResponse(request);
+ if (result != WIFI_SUCCESS) {
+ ALOGE("Failed to register wake stats response; result = %d\n", result);
+ }
+ return result;
+ }
+
+ protected:
+ int handleResponse(WifiEvent& reply) {
+ ALOGE("In GetWakeReasonCountCommand::handleResponse");
+
+ if (reply.get_cmd() != NL80211_CMD_VENDOR) {
+ ALOGD("Ignoring reply with cmd = %d", reply.get_cmd());
+ return NL_SKIP;
+ }
+
+ int id = reply.get_vendor_id();
+ int subcmd = reply.get_vendor_subcmd();
+
+ nlattr *vendor_data = reply.get_attribute(NL80211_ATTR_VENDOR_DATA);
+ int len = reply.get_vendor_data_len();
+
+ ALOGV("Id = %0x, subcmd = %d, len = %d", id, subcmd, len);
+ if (vendor_data == NULL || len == 0) {
+ ALOGE("no vendor data in GetGetWakeReasonCountCommand response; ignoring it");
+ return NL_SKIP;
+ }
+
+ for (nl_iterator it(vendor_data); it.has_next(); it.next()) {
+ switch (it.get_type()) {
+ case WAKE_STAT_ATTRIBUTE_TOTAL_DRIVER_FW:
+ mWakeReasonCnt->total_driver_fw_local_wake =
+ it.get_u32();
+ break;
+ case WAKE_STAT_ATTRIBUTE_TOTAL:
+ mWakeReasonCnt->total_cmd_event_wake =
+ it.get_u32();
+ break;
+ case WAKE_STAT_ATTRIBUTE_CMD_COUNT_USED:
+ mWakeReasonCnt->cmd_event_wake_cnt_used =
+ it.get_u32();
+ break;
+ case WAKE_STAT_ATTRIBUTE_WAKE:
+ memcpy(mCmdEventWakeCount, it.get_data(),
+ (mWakeReasonCnt->cmd_event_wake_cnt_used * sizeof(int)));
+ break;
+ case WAKE_STAT_ATTRIBUTE_TOTAL_RX_DATA_WAKE:
+ mWakeReasonCnt->total_rx_data_wake =
+ it.get_u32();
+ break;
+ case WAKE_STAT_ATTRIBUTE_RX_UNICAST_COUNT:
+ mWakeReasonCnt->rx_wake_details.rx_unicast_cnt =
+ it.get_u32();
+ break;
+ case WAKE_STAT_ATTRIBUTE_RX_MULTICAST_COUNT:
+ mWakeReasonCnt->rx_wake_details.rx_multicast_cnt =
+ it.get_u32();
+ break;
+ case WAKE_STAT_ATTRIBUTE_RX_BROADCAST_COUNT:
+ mWakeReasonCnt->rx_wake_details.rx_broadcast_cnt =
+ it.get_u32();
+ break;
+ case WAKE_STAT_ATTRIBUTE_RX_ICMP_PKT:
+ mWakeReasonCnt->rx_wake_pkt_classification_info.icmp_pkt =
+ it.get_u32();
+ break;
+ case WAKE_STAT_ATTRIBUTE_RX_ICMP6_PKT:
+ mWakeReasonCnt->rx_wake_pkt_classification_info.icmp6_pkt =
+ it.get_u32();
+ break;
+ case WAKE_STAT_ATTRIBUTE_RX_ICMP6_RA:
+ mWakeReasonCnt->rx_wake_pkt_classification_info.icmp6_ra =
+ it.get_u32();
+ break;
+ case WAKE_STAT_ATTRIBUTE_RX_ICMP6_NA:
+ mWakeReasonCnt->rx_wake_pkt_classification_info.icmp6_na =
+ it.get_u32();
+ break;
+ case WAKE_STAT_ATTRIBUTE_RX_ICMP6_NS:
+ mWakeReasonCnt->rx_wake_pkt_classification_info.icmp6_ns =
+ it.get_u32();
+ break;
+ case WAKE_STAT_ATTRIBUTE_IPV4_RX_MULTICAST_ADD_CNT:
+ mWakeReasonCnt->rx_multicast_wake_pkt_info.ipv4_rx_multicast_addr_cnt =
+ it.get_u32();
+ break;
+ case WAKE_STAT_ATTRIBUTE_IPV6_RX_MULTICAST_ADD_CNT:
+ mWakeReasonCnt->rx_multicast_wake_pkt_info.ipv6_rx_multicast_addr_cnt =
+ it.get_u32();
+ break;
+ case WAKE_STAT_ATTRIBUTE_OTHER_RX_MULTICAST_ADD_CNT:
+ mWakeReasonCnt->rx_multicast_wake_pkt_info.other_rx_multicast_addr_cnt =
+ it.get_u32();
+ break;
+ default:
+ break;
+ }
+
+ }
+ return NL_OK;
+ }
+};
+
+wifi_error wifi_start_pkt_fate_monitoring(wifi_interface_handle handle)
+{
+ PacketFateCommand *cmd = new PacketFateCommand(handle);
+ NULL_CHECK_RETURN(cmd, "memory allocation failure", WIFI_ERROR_OUT_OF_MEMORY);
+ wifi_error result = (wifi_error)cmd->start();
+ cmd->releaseRef();
+ return result;
+}
+
+wifi_error wifi_get_tx_pkt_fates(wifi_interface_handle handle,
+ wifi_tx_report *tx_report_bufs, size_t n_requested_fates,
+ size_t *n_provided_fates)
+{
+ PacketFateCommand *cmd = new PacketFateCommand(handle, tx_report_bufs,
+ n_requested_fates, n_provided_fates);
+ NULL_CHECK_RETURN(cmd, "memory allocation failure", WIFI_ERROR_OUT_OF_MEMORY);
+ wifi_error result = (wifi_error)cmd->start();
+ cmd->releaseRef();
+ return result;
+}
+
+wifi_error wifi_get_rx_pkt_fates(wifi_interface_handle handle,
+ wifi_rx_report *rx_report_bufs, size_t n_requested_fates,
+ size_t *n_provided_fates)
+{
+ PacketFateCommand *cmd = new PacketFateCommand(handle, rx_report_bufs,
+ n_requested_fates, n_provided_fates);
+ NULL_CHECK_RETURN(cmd, "memory allocation failure", WIFI_ERROR_OUT_OF_MEMORY);
+ wifi_error result = (wifi_error)cmd->start();
+ cmd->releaseRef();
+ return result;
+}
+
+wifi_error wifi_get_wake_reason_stats(wifi_interface_handle handle,
+ WLAN_DRIVER_WAKE_REASON_CNT *wifi_wake_reason_cnt)
+{
+ GetWakeReasonCountCommand *cmd =
+ new GetWakeReasonCountCommand(handle, wifi_wake_reason_cnt);
+ wifi_error result = (wifi_error)cmd->start();
+ cmd->releaseRef();
+ return result;
+}
+
+///////////////////////////////////////////////////////////////////////////////
+class OtaUpdateCommand : public WifiCommand
+{
+
+ public:
+ OtaUpdateCommand(wifi_interface_handle iface)
+ : WifiCommand("OtaUpdateCommand", iface, 0)
+ { }
+
+ int start() {
+ ALOGE("Start OtaUpdateCommand");
+ WifiRequest request(familyId(), ifaceId());
+
+ int result = request.create(GOOGLE_OUI, WIFI_SUBCMD_GET_OTA_CURRUNT_INFO);
+ if (result != WIFI_SUCCESS) {
+ ALOGE("Failed to set hal start; result = %d", result);
+ return result;
+ }
+
+ result = requestResponse(request);
+ if (result != WIFI_SUCCESS) {
+ ALOGE("Failed to register set hal start response; result = %d", result);
+ }
+ return result;
+ }
+
+ int otaDownload(ota_info_buf_t* buf, uint32_t ota_version) {
+ u32 force_reg_on = false;
+ WifiRequest request(familyId(), ifaceId());
+ int result = request.create(GOOGLE_OUI, WIFI_SUBCMD_OTA_UPDATE);
+
+ ALOGE("Download the OTA configuration");
+ if (result != WIFI_SUCCESS) {
+ ALOGE("Failed to set Hal preInit; result = %d", result);
+ return result;
+ }
+
+ nlattr *data = request.attr_start(NL80211_ATTR_VENDOR_DATA);
+
+ result = request.put_u32(OTA_DOWNLOAD_CLM_LENGTH_ATTR, buf->ota_clm_len);
+ if (result != WIFI_SUCCESS) {
+ ALOGE("otaDownload Failed to put data= %d", result);
+ return result;
+ }
+
+ result = request.put(OTA_DOWNLOAD_CLM_ATTR, buf->ota_clm_buf, sizeof(*buf->ota_clm_buf));
+ if (result != WIFI_SUCCESS) {
+ ALOGE("otaDownload Failed to put data= %d", result);
+ return result;
+ }
+
+ result = request.put_u32(OTA_DOWNLOAD_NVRAM_LENGTH_ATTR, buf->ota_nvram_len);
+ if (result != WIFI_SUCCESS) {
+ ALOGE("otaDownload Failed to put data= %d", result);
+ return result;
+ }
+
+ result = request.put(OTA_DOWNLOAD_NVRAM_ATTR,
+ buf->ota_nvram_buf, sizeof(*buf->ota_nvram_buf));
+ if (result != WIFI_SUCCESS) {
+ ALOGE("otaDownload Failed to put data= %d", result);
+ return result;
+ }
+
+ if (applied_ota_version != ota_version) {
+ force_reg_on = true;
+ applied_ota_version = ota_version;
+ }
+ result = request.put_u32(OTA_SET_FORCE_REG_ON, force_reg_on);
+ if (result != WIFI_SUCCESS) {
+ ALOGE("otaDownload Failed to put data= %d", result);
+ return result;
+ }
+
+ request.attr_end(data);
+
+ result = requestResponse(request);
+ if (result != WIFI_SUCCESS) {
+ ALOGE("Failed to register set otaDownload; result = %d", result);
+ }
+
+ return result;
+ }
+
+ virtual int handleResponse(WifiEvent& reply) {
+ ALOGD("In OtaUpdateCommand::handleResponse");
+
+ if (reply.get_cmd() != NL80211_CMD_VENDOR) {
+ ALOGD("Ignoring reply with cmd = %d", reply.get_cmd());
+ return NL_SKIP;
+ }
+
+ int id = reply.get_vendor_id();
+ int subcmd = reply.get_vendor_subcmd();
+ nlattr *vendor_data = reply.get_attribute(NL80211_ATTR_VENDOR_DATA);
+ int len = reply.get_vendor_data_len();
+
+ ALOGI("Id = %0x, subcmd = %d, len = %d", id, subcmd, len);
+
+ if (vendor_data == NULL || len == 0) {
+ ALOGE("no vendor data in GetPktFateCommand response; ignoring it\n");
+ return NL_SKIP;
+ }
+
+ for (nl_iterator it(vendor_data); it.has_next(); it.next()) {
+ switch (it.get_type()) {
+ case OTA_CUR_NVRAM_EXT_ATTR:
+ strncpy(ota_nvram_ext, (char*)it.get_string(), it.get_len());
+ ALOGI("Current Nvram ext [%s]\n", ota_nvram_ext);
+ break;
+ default:
+ ALOGE("Ignoring invalid attribute type = %d, size = %d\n",
+ it.get_type(), it.get_len());
+ break;
+ }
+ }
+ return NL_OK;
+ }
+
+ virtual int handleEvent(WifiEvent& event) {
+ /* NO events! */
+ return NL_SKIP;
+ }
+};
+
+wifi_error read_ota_file(char* file, char** buffer, uint32_t* size)
+{
+ FILE* fp = NULL;
+ int file_size;
+ char* buf;
+ fp = fopen(file, "r");
+
+ if (fp == NULL) {
+ ALOGI("File [%s] doesn't exist.", file);
+ return WIFI_ERROR_NOT_AVAILABLE;
+ }
+
+ fseek(fp, 0, SEEK_END);
+ file_size = ftell(fp);
+
+ buf = (char *)malloc(file_size + 1);
+ if (buf == NULL) {
+ fclose(fp);
+ return WIFI_ERROR_UNKNOWN;
+ }
+ memset(buf, 0, file_size + 1);
+ fseek(fp, 0, SEEK_SET);
+ fread(buf, file_size, 1, fp);
+
+ *buffer = (char*) buf;
+ *size = file_size;
+ fclose(fp);
+ return WIFI_SUCCESS;
+}
+
+wifi_error check_multiple_nvram_clm(uint32_t type, char* hw_revision, char* hw_sku,
+ char** buffer, uint32_t* buffer_len)
+{
+ char file_name[MAX_NV_FILE][FILE_NAME_LEN];
+ char nvram_clmblob_default_file[FILE_NAME_LEN] = {0,};
+ wifi_error result = WIFI_SUCCESS;
+
+ if (type == CLM_BLOB) {
+ sprintf(nvram_clmblob_default_file, "%s%s", OTA_PATH, OTA_CLM_FILE);
+ }
+ else if (type == NVRAM) {
+ sprintf(nvram_clmblob_default_file, "%s%s", OTA_PATH, OTA_NVRAM_FILE);
+ }
+ for (unsigned int i = 0; i < MAX_NV_FILE; i++) {
+ memset(file_name[i], 0, FILE_NAME_LEN);
+ }
+
+ sprintf(file_name[0], "%s_%s_%s", nvram_clmblob_default_file, hw_revision, hw_sku);
+ sprintf(file_name[1], "%s_%s", nvram_clmblob_default_file, hw_revision);
+ sprintf(file_name[2], "%s_%s", nvram_clmblob_default_file, hw_sku);
+ sprintf(file_name[3], "%s", nvram_clmblob_default_file);
+
+ for (unsigned int i = 0; i < MAX_NV_FILE; i++) {
+ result = read_ota_file(file_name[i], buffer, buffer_len);
+ if (result == WIFI_SUCCESS) {
+ ALOGI("[OTA] %s PATH %s", type == NVRAM ? "NVRAM" : "CLM", file_name[i]);
+ break;
+ }
+ }
+ return result;
+}
+
+wifi_error wifi_hal_ota_update(wifi_interface_handle iface, uint32_t ota_version)
+{
+ wifi_handle handle = getWifiHandle(iface);
+ wifi_error result = WIFI_SUCCESS;
+ ota_info_buf_t buf;
+ char *buffer_nvram = NULL;
+ char *buffer_clm = NULL;
+ char prop_revision_buf[PROPERTY_VALUE_MAX] = {0,};
+ char prop_sku_buf[PROPERTY_VALUE_MAX] = {0,};
+ char sku_name[MAX_SKU_NAME_LEN] = {0,};
+
+ OtaUpdateCommand *cmd = new OtaUpdateCommand(iface);
+ NULL_CHECK_RETURN(cmd, "memory allocation failure", WIFI_ERROR_OUT_OF_MEMORY);
+
+ ALOGD("wifi_hal_ota_update, handle = %p, ota_version %d\n", handle, ota_version);
+
+ result = (wifi_error)cmd->start();
+ if (result != WIFI_SUCCESS) {
+ cmd->releaseRef();
+ return result;
+ }
+
+ property_get(HW_DEV_PROP, prop_revision_buf, NULL);
+ property_get(HW_SKU_PROP, prop_sku_buf, NULL);
+
+ strncpy(sku_name, "NA", MAX_SKU_NAME_LEN);
+ for (int i = 0; i < ARRAYSIZE(sku_table); i ++) {
+ if (strcmp(prop_sku_buf, sku_table[i].hw_id) == 0) {
+ strncpy(sku_name, sku_table[i].sku, MAX_SKU_NAME_LEN);
+ break;
+ }
+ }
+ ALOGD("prop_sku_buf is %s, sku_name is %s", prop_sku_buf, sku_name);
+
+ check_multiple_nvram_clm(CLM_BLOB, prop_revision_buf, sku_name, &buffer_clm, &buf.ota_clm_len);
+ if (buffer_clm == NULL) {
+ ALOGE("buffer_clm is null");
+ goto exit;
+ }
+ buf.ota_clm_buf[0] = buffer_clm;
+
+ check_multiple_nvram_clm(NVRAM, prop_revision_buf, sku_name,
+ &buffer_nvram, &buf.ota_nvram_len);
+ if (buffer_nvram == NULL) {
+ ALOGE("buffer_nvram is null");
+ goto exit;
+ }
+ buf.ota_nvram_buf[0] = buffer_nvram;
+ cmd->otaDownload(&buf, ota_version);
+
+exit:
+ if (buffer_clm != NULL) {
+ free(buffer_clm);
+ }
+ if (buffer_nvram != NULL) {
+ free(buffer_nvram);
+ }
+
+ cmd->releaseRef();
+
+ return result;
+}
diff --git a/synadhd/wifi_hal/wifi_offload.cpp b/synadhd/wifi_hal/wifi_offload.cpp
new file mode 100644
index 0000000..1702ffd
--- /dev/null
+++ b/synadhd/wifi_hal/wifi_offload.cpp
@@ -0,0 +1,268 @@
+/*
+ * Copyright (C) 2017 The Android Open Source Project
+ *
+ * Portions copyright (C) 2017 Broadcom Limited
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <stdint.h>
+#include <fcntl.h>
+#include <sys/socket.h>
+#include <netlink/genl/genl.h>
+#include <netlink/genl/family.h>
+#include <netlink/genl/ctrl.h>
+#include <linux/rtnetlink.h>
+#include <netpacket/packet.h>
+#include <linux/filter.h>
+#include <linux/errqueue.h>
+
+#include <linux/pkt_sched.h>
+#include <netlink/object-api.h>
+#include <netlink/netlink.h>
+#include <netlink/socket.h>
+#include <netlink-private/object-api.h>
+#include <netlink-private/types.h>
+
+
+#include "nl80211_copy.h"
+#include "sync.h"
+
+#define LOG_TAG "WifiHAL"
+
+#include <log/log.h>
+
+#include "wifi_hal.h"
+#include "common.h"
+#include "cpp_bindings.h"
+
+typedef enum {
+ WIFI_OFFLOAD_START_MKEEP_ALIVE = ANDROID_NL80211_SUBCMD_WIFI_OFFLOAD_RANGE_START,
+ WIFI_OFFLOAD_STOP_MKEEP_ALIVE,
+} WIFI_OFFLOAD_SUB_COMMAND;
+
+typedef enum {
+ MKEEP_ALIVE_ATTRIBUTE_INVALID = 0,
+ MKEEP_ALIVE_ATTRIBUTE_ID = 1,
+ MKEEP_ALIVE_ATTRIBUTE_IP_PKT = 2,
+ MKEEP_ALIVE_ATTRIBUTE_IP_PKT_LEN = 3,
+ MKEEP_ALIVE_ATTRIBUTE_SRC_MAC_ADDR = 4,
+ MKEEP_ALIVE_ATTRIBUTE_DST_MAC_ADDR = 5,
+ MKEEP_ALIVE_ATTRIBUTE_PERIOD_MSEC = 6,
+ MKEEP_ALIVE_ATTRIBUTE_ETHER_TYPE = 7,
+ /* Add new attributes just above this */
+ MKEEP_ALIVE_ATTRIBUTE_MAX
+} WIFI_MKEEP_ALIVE_ATTRIBUTE;
+
+typedef enum {
+ START_MKEEP_ALIVE,
+ STOP_MKEEP_ALIVE,
+} GetCmdType;
+
+///////////////////////////////////////////////////////////////////////////////
+class MKeepAliveCommand : public WifiCommand
+{
+ u8 mIndex;
+ u8 *mIpPkt;
+ u16 mIpPktLen;
+ u8 *mSrcMacAddr;
+ u8 *mDstMacAddr;
+ u32 mPeriodMsec;
+ GetCmdType mType;
+ u16 mEther_type;
+
+public:
+
+ // constructor for start sending
+ MKeepAliveCommand(wifi_interface_handle iface, u8 index, u16 ether_type, u8 *ip_packet, u16 ip_packet_len,
+ u8 *src_mac_addr, u8 *dst_mac_addr, u32 period_msec, GetCmdType cmdType)
+ : WifiCommand("MKeepAliveCommand", iface, 0), mIndex(index), mEther_type(ether_type), mIpPkt(ip_packet),
+ mIpPktLen(ip_packet_len), mSrcMacAddr(src_mac_addr), mDstMacAddr(dst_mac_addr),
+ mPeriodMsec(period_msec), mType(cmdType)
+ { }
+
+ // constructor for stop sending
+ MKeepAliveCommand(wifi_interface_handle iface, u8 index, GetCmdType cmdType)
+ : WifiCommand("MKeepAliveCommand", iface, 0), mIndex(index), mType(cmdType)
+ {
+ mIpPkt = NULL;
+ mIpPktLen = 0;
+ mSrcMacAddr = NULL;
+ mDstMacAddr = NULL;
+ mPeriodMsec = 0;
+ mEther_type = 0;
+ }
+
+ int createRequest(WifiRequest &request) {
+ int result = WIFI_SUCCESS;
+
+ switch (mType) {
+ case START_MKEEP_ALIVE:
+ {
+ result = request.create(GOOGLE_OUI, WIFI_OFFLOAD_START_MKEEP_ALIVE);
+ if (result != WIFI_SUCCESS) {
+ ALOGE("Failed to create start keep alive request; result = %d", result);
+ return result;
+ }
+
+ nlattr *data = request.attr_start(NL80211_ATTR_VENDOR_DATA);
+
+ result = request.put_u8(MKEEP_ALIVE_ATTRIBUTE_ID, mIndex);
+ if (result < 0) {
+ ALOGE("Failed to put id request; result = %d", result);
+ return result;
+ }
+
+ result = request.put_u16(MKEEP_ALIVE_ATTRIBUTE_IP_PKT_LEN, mIpPktLen);
+ if (result < 0) {
+ ALOGE("Failed to put ip pkt len request; result = %d", result);
+ return result;
+ }
+
+ result = request.put(MKEEP_ALIVE_ATTRIBUTE_IP_PKT, (u8*)mIpPkt, mIpPktLen);
+ if (result < 0) {
+ ALOGE("Failed to put ip pkt request; result = %d", result);
+ return result;
+ }
+
+ result = request.put_addr(MKEEP_ALIVE_ATTRIBUTE_SRC_MAC_ADDR, mSrcMacAddr);
+ if (result < 0) {
+ ALOGE("Failed to put src mac address request; result = %d", result);
+ return result;
+ }
+
+ result = request.put_addr(MKEEP_ALIVE_ATTRIBUTE_DST_MAC_ADDR, mDstMacAddr);
+ if (result < 0) {
+ ALOGE("Failed to put dst mac address request; result = %d", result);
+ return result;
+ }
+
+ result = request.put_u32(MKEEP_ALIVE_ATTRIBUTE_PERIOD_MSEC, mPeriodMsec);
+ if (result < 0) {
+ ALOGE("Failed to put period request; result = %d", result);
+ return result;
+ }
+ result = request.put_u16(MKEEP_ALIVE_ATTRIBUTE_ETHER_TYPE, mEther_type);
+ if (result < 0) {
+ ALOGE("Failed to put ether type; result = %d", result);
+ return result;
+ }
+
+ request.attr_end(data);
+ break;
+ }
+
+ case STOP_MKEEP_ALIVE:
+ {
+ result = request.create(GOOGLE_OUI, WIFI_OFFLOAD_STOP_MKEEP_ALIVE);
+ if (result != WIFI_SUCCESS) {
+ ALOGE("Failed to create stop keep alive request; result = %d", result);
+ return result;
+ }
+
+ nlattr *data = request.attr_start(NL80211_ATTR_VENDOR_DATA);
+
+ result = request.put_u8(MKEEP_ALIVE_ATTRIBUTE_ID, mIndex);
+ if (result < 0) {
+ ALOGE("Failed to put id request; result = %d", result);
+ return result;
+ }
+
+ request.attr_end(data);
+ break;
+ }
+
+ default:
+ ALOGE("Unknown wifi keep alive command");
+ result = WIFI_ERROR_UNKNOWN;
+ }
+ return result;
+ }
+
+ int start() {
+ ALOGD("Start mkeep_alive command");
+ WifiRequest request(familyId(), ifaceId());
+ int result = createRequest(request);
+ if (result != WIFI_SUCCESS) {
+ ALOGE("Failed to create keep alive request; result = %d", result);
+ return result;
+ }
+
+ result = requestResponse(request);
+ if (result != WIFI_SUCCESS) {
+ ALOGE("Failed to register keep alive response; result = %d", result);
+ }
+ return result;
+ }
+
+ virtual int handleResponse(WifiEvent& reply) {
+ ALOGD("In MKeepAliveCommand::handleResponse");
+
+ if (reply.get_cmd() != NL80211_CMD_VENDOR) {
+ ALOGD("Ignoring reply with cmd = %d", reply.get_cmd());
+ return NL_SKIP;
+ }
+
+ switch (mType) {
+ case START_MKEEP_ALIVE:
+ case STOP_MKEEP_ALIVE:
+ break;
+
+ default:
+ ALOGW("Unknown mkeep_alive command");
+ }
+ return NL_OK;
+ }
+
+ virtual int handleEvent(WifiEvent& event) {
+ /* NO events! */
+ return NL_SKIP;
+ }
+};
+
+
+/* API to send specified mkeep_alive packet periodically. */
+wifi_error wifi_start_sending_offloaded_packet(wifi_request_id index, wifi_interface_handle iface,
+ u16 ether_type, u8 *ip_packet, u16 ip_packet_len, u8 *src_mac_addr, u8 *dst_mac_addr,
+ u32 period_msec)
+{
+ if ((index > 0 && index <= N_AVAIL_ID) && (ip_packet != NULL) && (src_mac_addr != NULL)
+ && (dst_mac_addr != NULL) && (period_msec > 0)
+ && (ip_packet_len <= MKEEP_ALIVE_IP_PKT_MAX) && ((ether_type == ETHERTYPE_IP) ||
+ (ether_type == ETHERTYPE_IPV6))) {
+ MKeepAliveCommand *cmd = new MKeepAliveCommand(iface, index, ether_type, ip_packet, ip_packet_len,
+ src_mac_addr, dst_mac_addr, period_msec, START_MKEEP_ALIVE);
+ NULL_CHECK_RETURN(cmd, "memory allocation failure", WIFI_ERROR_OUT_OF_MEMORY);
+ wifi_error result = (wifi_error)cmd->start();
+ cmd->releaseRef();
+ return result;
+ } else {
+ ALOGE("Invalid mkeep_alive parameters");
+ return WIFI_ERROR_INVALID_ARGS;
+ }
+}
+
+/* API to stop sending mkeep_alive packet. */
+wifi_error wifi_stop_sending_offloaded_packet(wifi_request_id index, wifi_interface_handle iface)
+{
+ if (index > 0 && index <= N_AVAIL_ID) {
+ MKeepAliveCommand *cmd = new MKeepAliveCommand(iface, index, STOP_MKEEP_ALIVE);
+ NULL_CHECK_RETURN(cmd, "memory allocation failure", WIFI_ERROR_OUT_OF_MEMORY);
+ wifi_error result = (wifi_error)cmd->start();
+ cmd->releaseRef();
+ return result;
+ } else {
+ ALOGE("Invalid mkeep_alive parameters");
+ return WIFI_ERROR_INVALID_ARGS;
+ }
+}
diff --git a/synadhd/wpa_supplicant_8_lib/Android.mk b/synadhd/wpa_supplicant_8_lib/Android.mk
new file mode 100644
index 0000000..d1f8e55
--- /dev/null
+++ b/synadhd/wpa_supplicant_8_lib/Android.mk
@@ -0,0 +1,81 @@
+#
+# Copyright (C) 2008 The Android Open Source Project
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+#
+LOCAL_PATH := $(call my-dir)
+
+ifeq ($(WPA_SUPPLICANT_VERSION),VER_0_8_X)
+
+ifneq ($(BOARD_WPA_SUPPLICANT_DRIVER),)
+ CONFIG_DRIVER_$(BOARD_WPA_SUPPLICANT_DRIVER) := y
+endif
+
+WPA_SUPPL_DIR = external/wpa_supplicant_8
+WPA_SRC_FILE :=
+
+include $(WPA_SUPPL_DIR)/wpa_supplicant/android.config
+
+WPA_SUPPL_DIR_INCLUDE = $(WPA_SUPPL_DIR)/src \
+ $(WPA_SUPPL_DIR)/src/common \
+ $(WPA_SUPPL_DIR)/src/drivers \
+ $(WPA_SUPPL_DIR)/src/l2_packet \
+ $(WPA_SUPPL_DIR)/src/utils \
+ $(WPA_SUPPL_DIR)/src/wps \
+ $(WPA_SUPPL_DIR)/wpa_supplicant
+
+ifdef CONFIG_DRIVER_NL80211
+WPA_SUPPL_DIR_INCLUDE += external/libnl/include
+WPA_SRC_FILE += driver_cmd_nl80211.c
+endif
+
+ifdef CONFIG_DRIVER_WEXT
+WPA_SRC_FILE += driver_cmd_wext.c
+endif
+
+ifeq ($(TARGET_ARCH),arm)
+# To force sizeof(enum) = 4
+L_CFLAGS += -mabi=aapcs-linux
+endif
+
+ifdef CONFIG_ANDROID_LOG
+L_CFLAGS += -DCONFIG_ANDROID_LOG
+endif
+
+ifdef CONFIG_P2P
+L_CFLAGS += -DCONFIG_P2P
+endif
+
+ifeq ($(TARGET_USES_64_BIT_BCMDHD),true)
+L_CFLAGS += -DBCMDHD_64_BIT_IPC
+endif
+
+L_CFLAGS += -Wall -Werror -Wno-unused-parameter -Wno-macro-redefined
+
+########################
+
+include $(CLEAR_VARS)
+LOCAL_MODULE := lib_driver_cmd_synadhd
+LOCAL_LICENSE_KINDS := SPDX-license-identifier-BSD
+LOCAL_LICENSE_CONDITIONS := notice
+LOCAL_NOTICE_FILE := $(LOCAL_PATH)/NOTICE
+LOCAL_SHARED_LIBRARIES := libc libcutils
+LOCAL_CFLAGS := $(L_CFLAGS)
+LOCAL_SRC_FILES := $(WPA_SRC_FILE)
+LOCAL_C_INCLUDES := $(WPA_SUPPL_DIR_INCLUDE)
+LOCAL_VENDOR_MODULE := true
+include $(BUILD_STATIC_LIBRARY)
+
+########################
+
+endif
diff --git a/synadhd/wpa_supplicant_8_lib/MODULE_LICENSE_BSD b/synadhd/wpa_supplicant_8_lib/MODULE_LICENSE_BSD
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/synadhd/wpa_supplicant_8_lib/MODULE_LICENSE_BSD
diff --git a/synadhd/wpa_supplicant_8_lib/NOTICE b/synadhd/wpa_supplicant_8_lib/NOTICE
new file mode 100644
index 0000000..f9d25ea
--- /dev/null
+++ b/synadhd/wpa_supplicant_8_lib/NOTICE
@@ -0,0 +1,43 @@
+
+Copyright (c) 2005-2010, The Android Open Source Project
+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 Android Open Source Project 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.
+
+ * Copyright (c) 2002-2010, Jouni Malinen <j@w1.fi>
+ * Copyright (c) 2003-2004, Instant802 Networks, Inc.
+ * Copyright (c) 2005-2006, Devicescape Software, Inc.
+ * Copyright (c) 2007, Johannes Berg <johannes@sipsolutions.net>
+ * Copyright (c) 2009-2010, Atheros Communications
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ * Alternatively, this software may be distributed under the terms of BSD
+ * license.
diff --git a/synadhd/wpa_supplicant_8_lib/driver_cmd_nl80211.c b/synadhd/wpa_supplicant_8_lib/driver_cmd_nl80211.c
new file mode 100644
index 0000000..f9dbb95
--- /dev/null
+++ b/synadhd/wpa_supplicant_8_lib/driver_cmd_nl80211.c
@@ -0,0 +1,215 @@
+/*
+ * Driver interaction with extended Linux CFG8021
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ * Alternatively, this software may be distributed under the terms of BSD
+ * license.
+ *
+ */
+
+#include "includes.h"
+#include <sys/types.h>
+#include <fcntl.h>
+#include <net/if.h>
+
+#include "common.h"
+#include "linux_ioctl.h"
+#include "driver_nl80211.h"
+#include "wpa_supplicant_i.h"
+#include "config.h"
+#ifdef ANDROID
+#include "android_drv.h"
+#endif
+
+typedef struct android_wifi_priv_cmd {
+#ifdef BCMDHD_64_BIT_IPC
+ u64 bufaddr;
+#else
+ char *bufaddr;
+#endif
+ int used_len;
+ int total_len;
+} android_wifi_priv_cmd;
+
+static int drv_errors = 0;
+
+static void wpa_driver_send_hang_msg(struct wpa_driver_nl80211_data *drv)
+{
+ drv_errors++;
+ if (drv_errors > DRV_NUMBER_SEQUENTIAL_ERRORS) {
+ drv_errors = 0;
+ wpa_msg(drv->ctx, MSG_INFO, WPA_EVENT_DRIVER_STATE "HANGED");
+ }
+}
+
+static void wpa_driver_notify_country_change(void *ctx, char *cmd)
+{
+ if ((os_strncasecmp(cmd, "COUNTRY", 7) == 0) ||
+ (os_strncasecmp(cmd, "SETBAND", 7) == 0)) {
+ union wpa_event_data event;
+
+ os_memset(&event, 0, sizeof(event));
+ event.channel_list_changed.initiator = REGDOM_SET_BY_USER;
+ if (os_strncasecmp(cmd, "COUNTRY", 7) == 0) {
+ event.channel_list_changed.type = REGDOM_TYPE_COUNTRY;
+ if (os_strlen(cmd) > 9) {
+ event.channel_list_changed.alpha2[0] = cmd[8];
+ event.channel_list_changed.alpha2[1] = cmd[9];
+ }
+ } else {
+ event.channel_list_changed.type = REGDOM_TYPE_UNKNOWN;
+ }
+ wpa_supplicant_event(ctx, EVENT_CHANNEL_LIST_CHANGED, &event);
+ }
+}
+
+int wpa_driver_nl80211_driver_cmd(void *priv, char *cmd, char *buf,
+ size_t buf_len )
+{
+ struct i802_bss *bss = priv;
+ struct wpa_driver_nl80211_data *drv = bss->drv;
+ struct ifreq ifr;
+ android_wifi_priv_cmd priv_cmd;
+ int ret = 0;
+
+ if (bss->ifindex <= 0 && bss->wdev_id > 0) {
+ /* DRIVER CMD received on the DEDICATED P2P Interface which doesn't
+ * have an NETDEVICE associated with it. So we have to re-route the
+ * command to the parent NETDEVICE
+ */
+ struct wpa_supplicant *wpa_s = (struct wpa_supplicant *)(drv->ctx);
+
+ wpa_printf(MSG_DEBUG, "Re-routing DRIVER cmd to parent iface");
+ if (wpa_s && wpa_s->parent) {
+ /* Update the nl80211 pointers corresponding to parent iface */
+ bss = wpa_s->parent->drv_priv;
+ drv = bss->drv;
+ wpa_printf(MSG_DEBUG, "Re-routing command to iface: %s"
+ " cmd (%s)", bss->ifname, cmd);
+ }
+ }
+
+ if (os_strcasecmp(cmd, "STOP") == 0) {
+ linux_set_iface_flags(drv->global->ioctl_sock, bss->ifname, 0);
+ wpa_msg(drv->ctx, MSG_INFO, WPA_EVENT_DRIVER_STATE "STOPPED");
+ } else if (os_strcasecmp(cmd, "START") == 0) {
+ linux_set_iface_flags(drv->global->ioctl_sock, bss->ifname, 1);
+ wpa_msg(drv->ctx, MSG_INFO, WPA_EVENT_DRIVER_STATE "STARTED");
+ } else if (os_strcasecmp(cmd, "MACADDR") == 0) {
+ u8 macaddr[ETH_ALEN] = {};
+
+ ret = linux_get_ifhwaddr(drv->global->ioctl_sock, bss->ifname, macaddr);
+ if (!ret)
+ ret = os_snprintf(buf, buf_len,
+ "Macaddr = " MACSTR "\n", MAC2STR(macaddr));
+ } else { /* Use private command */
+ os_memcpy(buf, cmd, strlen(cmd) + 1);
+ memset(&ifr, 0, sizeof(ifr));
+ memset(&priv_cmd, 0, sizeof(priv_cmd));
+ os_strlcpy(ifr.ifr_name, bss->ifname, IFNAMSIZ);
+
+#ifdef BCMDHD_64_BIT_IPC
+ priv_cmd.bufaddr = (u64)(uintptr_t)buf;
+#else
+ priv_cmd.bufaddr = buf;
+#endif
+ priv_cmd.used_len = buf_len;
+ priv_cmd.total_len = buf_len;
+ ifr.ifr_data = &priv_cmd;
+
+ if ((ret = ioctl(drv->global->ioctl_sock, SIOCDEVPRIVATE + 1, &ifr)) < 0) {
+ wpa_printf(MSG_ERROR, "%s: failed to issue private command: %s", __func__, cmd);
+ wpa_driver_send_hang_msg(drv);
+ } else {
+ drv_errors = 0;
+ ret = 0;
+ if ((os_strcasecmp(cmd, "LINKSPEED") == 0) ||
+ (os_strcasecmp(cmd, "RSSI") == 0) ||
+ (os_strcasecmp(cmd, "GETBAND") == 0) ||
+ (os_strncasecmp(cmd, "WLS_BATCHING", 12) == 0))
+ ret = strlen(buf);
+ wpa_driver_notify_country_change(drv->ctx, cmd);
+ wpa_printf(MSG_DEBUG, "%s %s len = %d, %zu", __func__, buf, ret, strlen(buf));
+ }
+ }
+ return ret;
+}
+
+int wpa_driver_set_p2p_noa(void *priv, u8 count, int start, int duration)
+{
+ char buf[MAX_DRV_CMD_SIZE];
+
+ memset(buf, 0, sizeof(buf));
+ wpa_printf(MSG_DEBUG, "%s: Entry", __func__);
+ snprintf(buf, sizeof(buf), "P2P_SET_NOA %d %d %d", count, start, duration);
+ return wpa_driver_nl80211_driver_cmd(priv, buf, buf, strlen(buf)+1);
+}
+
+int wpa_driver_get_p2p_noa(void *priv __unused, u8 *buf __unused, size_t len __unused)
+{
+ /* Return 0 till we handle p2p_presence request completely in the driver */
+ return 0;
+}
+
+int wpa_driver_set_p2p_ps(void *priv, int legacy_ps, int opp_ps, int ctwindow)
+{
+ char buf[MAX_DRV_CMD_SIZE];
+
+ memset(buf, 0, sizeof(buf));
+ wpa_printf(MSG_DEBUG, "%s: Entry", __func__);
+ snprintf(buf, sizeof(buf), "P2P_SET_PS %d %d %d", legacy_ps, opp_ps, ctwindow);
+ return wpa_driver_nl80211_driver_cmd(priv, buf, buf, strlen(buf) + 1);
+}
+
+int wpa_driver_set_ap_wps_p2p_ie(void *priv, const struct wpabuf *beacon,
+ const struct wpabuf *proberesp,
+ const struct wpabuf *assocresp)
+{
+ char *buf;
+ const struct wpabuf *ap_wps_p2p_ie = NULL;
+
+ char *_cmd = "SET_AP_WPS_P2P_IE";
+ char *pbuf;
+ int ret = 0;
+ int i, buf_len;
+ struct cmd_desc {
+ int cmd;
+ const struct wpabuf *src;
+ } cmd_arr[] = {
+ {0x1, beacon},
+ {0x2, proberesp},
+ {0x4, assocresp},
+ {-1, NULL}
+ };
+
+ wpa_printf(MSG_DEBUG, "%s: Entry", __func__);
+ for (i = 0; cmd_arr[i].cmd != -1; i++) {
+ ap_wps_p2p_ie = cmd_arr[i].src;
+ if (ap_wps_p2p_ie) {
+ buf_len = strlen(_cmd) + 3 + wpabuf_len(ap_wps_p2p_ie);
+ buf = os_zalloc(buf_len);
+ if (NULL == buf) {
+ wpa_printf(MSG_ERROR, "%s: Out of memory",
+ __func__);
+ ret = -1;
+ break;
+ }
+ } else {
+ continue;
+ }
+ pbuf = buf;
+ pbuf += snprintf(pbuf, buf_len - wpabuf_len(ap_wps_p2p_ie),
+ "%s %d",_cmd, cmd_arr[i].cmd);
+ *pbuf++ = '\0';
+ os_memcpy(pbuf, wpabuf_head(ap_wps_p2p_ie), wpabuf_len(ap_wps_p2p_ie));
+ ret = wpa_driver_nl80211_driver_cmd(priv, buf, buf, buf_len);
+ os_free(buf);
+ if (ret < 0)
+ break;
+ }
+
+ return ret;
+}
diff --git a/synadhd/wpa_supplicant_8_lib/driver_cmd_wext.c b/synadhd/wpa_supplicant_8_lib/driver_cmd_wext.c
new file mode 100644
index 0000000..3734cb0
--- /dev/null
+++ b/synadhd/wpa_supplicant_8_lib/driver_cmd_wext.c
@@ -0,0 +1,396 @@
+/*
+ * Driver interaction with extended Linux Wireless Extensions
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ * Alternatively, this software may be distributed under the terms of BSD
+ * license.
+ *
+ */
+
+#include "includes.h"
+#include <sys/ioctl.h>
+#include <net/if_arp.h>
+#include <net/if.h>
+
+#include "linux_wext.h"
+#include "common.h"
+#include "driver.h"
+#include "eloop.h"
+#include "priv_netlink.h"
+#include "driver_wext.h"
+#include "ieee802_11_defs.h"
+#include "wpa_common.h"
+#include "wpa_ctrl.h"
+#include "wpa_supplicant_i.h"
+#include "config.h"
+#include "linux_ioctl.h"
+#include "scan.h"
+
+#include "driver_cmd_wext.h"
+#ifdef ANDROID
+#include "android_drv.h"
+#endif /* ANDROID */
+
+#define RSSI_CMD "RSSI"
+#define LINKSPEED_CMD "LINKSPEED"
+
+/**
+ * wpa_driver_wext_set_scan_timeout - Set scan timeout to report scan completion
+ * @priv: Pointer to private wext data from wpa_driver_wext_init()
+ *
+ * This function can be used to set registered timeout when starting a scan to
+ * generate a scan completed event if the driver does not report this.
+ */
+static void wpa_driver_wext_set_scan_timeout(void *priv)
+{
+ struct wpa_driver_wext_data *drv = priv;
+ int timeout = 10; /* In case scan A and B bands it can be long */
+
+ /* Not all drivers generate "scan completed" wireless event, so try to
+ * read results after a timeout. */
+ if (drv->scan_complete_events) {
+ /*
+ * The driver seems to deliver SIOCGIWSCAN events to notify
+ * when scan is complete, so use longer timeout to avoid race
+ * conditions with scanning and following association request.
+ */
+ timeout = 30;
+ }
+ wpa_printf(MSG_DEBUG, "Scan requested - scan timeout %d seconds",
+ timeout);
+ eloop_cancel_timeout(wpa_driver_wext_scan_timeout, drv, drv->ctx);
+ eloop_register_timeout(timeout, 0, wpa_driver_wext_scan_timeout, drv,
+ drv->ctx);
+}
+
+/**
+ * wpa_driver_wext_combo_scan - Request the driver to initiate combo scan
+ * @priv: Pointer to private wext data from wpa_driver_wext_init()
+ * @params: Scan parameters
+ * Returns: 0 on success, -1 on failure
+ */
+int wpa_driver_wext_combo_scan(void *priv, struct wpa_driver_scan_params *params)
+{
+ char buf[WEXT_CSCAN_BUF_LEN];
+ struct wpa_driver_wext_data *drv = priv;
+ struct iwreq iwr;
+ int ret, bp;
+ unsigned i;
+
+ if (!drv->driver_is_started) {
+ wpa_printf(MSG_DEBUG, "%s: Driver stopped", __func__);
+ return 0;
+ }
+
+ wpa_printf(MSG_DEBUG, "%s: Start", __func__);
+
+ /* Set list of SSIDs */
+ bp = WEXT_CSCAN_HEADER_SIZE;
+ os_memcpy(buf, WEXT_CSCAN_HEADER, bp);
+ for(i=0; i < params->num_ssids; i++) {
+ if ((bp + IW_ESSID_MAX_SIZE + 10) >= (int)sizeof(buf))
+ break;
+ wpa_printf(MSG_DEBUG, "For Scan: %s", params->ssids[i].ssid);
+ buf[bp++] = WEXT_CSCAN_SSID_SECTION;
+ buf[bp++] = params->ssids[i].ssid_len;
+ os_memcpy(&buf[bp], params->ssids[i].ssid, params->ssids[i].ssid_len);
+ bp += params->ssids[i].ssid_len;
+ }
+
+ /* Set list of channels */
+ buf[bp++] = WEXT_CSCAN_CHANNEL_SECTION;
+ buf[bp++] = 0;
+
+ /* Set passive dwell time (default is 250) */
+ buf[bp++] = WEXT_CSCAN_PASV_DWELL_SECTION;
+ buf[bp++] = (u8)WEXT_CSCAN_PASV_DWELL_TIME;
+ buf[bp++] = (u8)(WEXT_CSCAN_PASV_DWELL_TIME >> 8);
+
+ /* Set home dwell time (default is 40) */
+ buf[bp++] = WEXT_CSCAN_HOME_DWELL_SECTION;
+ buf[bp++] = (u8)WEXT_CSCAN_HOME_DWELL_TIME;
+ buf[bp++] = (u8)(WEXT_CSCAN_HOME_DWELL_TIME >> 8);
+
+ os_memset(&iwr, 0, sizeof(iwr));
+ os_strlcpy(iwr.ifr_name, drv->ifname, IFNAMSIZ);
+ iwr.u.data.pointer = buf;
+ iwr.u.data.length = bp;
+
+ if ((ret = ioctl(drv->ioctl_sock, SIOCSIWPRIV, &iwr)) < 0) {
+ if (!drv->bgscan_enabled)
+ wpa_printf(MSG_ERROR, "ioctl[SIOCSIWPRIV] (cscan): %d", ret);
+ else
+ ret = 0; /* Hide error in case of bg scan */
+ }
+ return ret;
+}
+
+static int wpa_driver_wext_set_cscan_params(char *buf, size_t buf_len, char *cmd)
+{
+ char *pasv_ptr;
+ int bp, i;
+ u16 pasv_dwell = WEXT_CSCAN_PASV_DWELL_TIME_DEF;
+ u8 channel;
+
+ wpa_printf(MSG_DEBUG, "%s: %s", __func__, cmd);
+
+ /* Get command parameters */
+ pasv_ptr = os_strstr(cmd, ",TIME=");
+ if (pasv_ptr) {
+ *pasv_ptr = '\0';
+ pasv_ptr += 6;
+ pasv_dwell = (u16)atoi(pasv_ptr);
+ if (pasv_dwell == 0)
+ pasv_dwell = WEXT_CSCAN_PASV_DWELL_TIME_DEF;
+ }
+ channel = (u8)atoi(cmd + 5);
+
+ bp = WEXT_CSCAN_HEADER_SIZE;
+ os_memcpy(buf, WEXT_CSCAN_HEADER, bp);
+
+ /* Set list of channels */
+ buf[bp++] = WEXT_CSCAN_CHANNEL_SECTION;
+ buf[bp++] = channel;
+ if (channel != 0) {
+ i = (pasv_dwell - 1) / WEXT_CSCAN_PASV_DWELL_TIME_DEF;
+ for (; i > 0; i--) {
+ if ((size_t)(bp + 12) >= buf_len)
+ break;
+ buf[bp++] = WEXT_CSCAN_CHANNEL_SECTION;
+ buf[bp++] = channel;
+ }
+ } else {
+ if (pasv_dwell > WEXT_CSCAN_PASV_DWELL_TIME_MAX)
+ pasv_dwell = WEXT_CSCAN_PASV_DWELL_TIME_MAX;
+ }
+
+ /* Set passive dwell time (default is 250) */
+ buf[bp++] = WEXT_CSCAN_PASV_DWELL_SECTION;
+ if (channel != 0) {
+ buf[bp++] = (u8)WEXT_CSCAN_PASV_DWELL_TIME_DEF;
+ buf[bp++] = (u8)(WEXT_CSCAN_PASV_DWELL_TIME_DEF >> 8);
+ } else {
+ buf[bp++] = (u8)pasv_dwell;
+ buf[bp++] = (u8)(pasv_dwell >> 8);
+ }
+
+ /* Set home dwell time (default is 40) */
+ buf[bp++] = WEXT_CSCAN_HOME_DWELL_SECTION;
+ buf[bp++] = (u8)WEXT_CSCAN_HOME_DWELL_TIME;
+ buf[bp++] = (u8)(WEXT_CSCAN_HOME_DWELL_TIME >> 8);
+
+ /* Set cscan type */
+ buf[bp++] = WEXT_CSCAN_TYPE_SECTION;
+ buf[bp++] = WEXT_CSCAN_TYPE_PASSIVE;
+ return bp;
+}
+
+static char *wpa_driver_get_country_code(int channels)
+{
+ char *country = "US"; /* WEXT_NUMBER_SCAN_CHANNELS_FCC */
+
+ if (channels == WEXT_NUMBER_SCAN_CHANNELS_ETSI)
+ country = "EU";
+ else if( channels == WEXT_NUMBER_SCAN_CHANNELS_MKK1)
+ country = "JP";
+ return country;
+}
+
+static int wpa_driver_set_backgroundscan_params(void *priv)
+{
+ struct wpa_driver_wext_data *drv = priv;
+ struct wpa_supplicant *wpa_s;
+ struct iwreq iwr;
+ int ret = 0, i = 0, bp;
+ char buf[WEXT_PNO_MAX_COMMAND_SIZE];
+ struct wpa_ssid *ssid_conf;
+
+ if (drv == NULL) {
+ wpa_printf(MSG_ERROR, "%s: drv is NULL. Exiting", __func__);
+ return -1;
+ }
+ if (drv->ctx == NULL) {
+ wpa_printf(MSG_ERROR, "%s: drv->ctx is NULL. Exiting", __func__);
+ return -1;
+ }
+ wpa_s = (struct wpa_supplicant *)(drv->ctx);
+ if (wpa_s->conf == NULL) {
+ wpa_printf(MSG_ERROR, "%s: wpa_s->conf is NULL. Exiting", __func__);
+ return -1;
+ }
+ ssid_conf = wpa_s->conf->ssid;
+
+ bp = WEXT_PNOSETUP_HEADER_SIZE;
+ os_memcpy(buf, WEXT_PNOSETUP_HEADER, bp);
+ buf[bp++] = WEXT_PNO_TLV_PREFIX;
+ buf[bp++] = WEXT_PNO_TLV_VERSION;
+ buf[bp++] = WEXT_PNO_TLV_SUBVERSION;
+ buf[bp++] = WEXT_PNO_TLV_RESERVED;
+
+ while ((i < WEXT_PNO_AMOUNT) && (ssid_conf != NULL)) {
+ /* Check that there is enough space needed for 1 more SSID, the other sections and null termination */
+ if ((bp + WEXT_PNO_SSID_HEADER_SIZE + IW_ESSID_MAX_SIZE + WEXT_PNO_NONSSID_SECTIONS_SIZE + 1) >= (int)sizeof(buf))
+ break;
+ if ((!ssid_conf->disabled) && (ssid_conf->ssid_len <= IW_ESSID_MAX_SIZE)){
+ wpa_printf(MSG_DEBUG, "For PNO Scan: %s", ssid_conf->ssid);
+ buf[bp++] = WEXT_PNO_SSID_SECTION;
+ buf[bp++] = ssid_conf->ssid_len;
+ os_memcpy(&buf[bp], ssid_conf->ssid, ssid_conf->ssid_len);
+ bp += ssid_conf->ssid_len;
+ i++;
+ }
+ ssid_conf = ssid_conf->next;
+ }
+
+ buf[bp++] = WEXT_PNO_SCAN_INTERVAL_SECTION;
+ os_snprintf(&buf[bp], WEXT_PNO_SCAN_INTERVAL_LENGTH + 1, "%x", WEXT_PNO_SCAN_INTERVAL);
+ bp += WEXT_PNO_SCAN_INTERVAL_LENGTH;
+
+ buf[bp++] = WEXT_PNO_REPEAT_SECTION;
+ os_snprintf(&buf[bp], WEXT_PNO_REPEAT_LENGTH + 1, "%x", WEXT_PNO_REPEAT);
+ bp += WEXT_PNO_REPEAT_LENGTH;
+
+ buf[bp++] = WEXT_PNO_MAX_REPEAT_SECTION;
+ os_snprintf(&buf[bp], WEXT_PNO_MAX_REPEAT_LENGTH + 1, "%x", WEXT_PNO_MAX_REPEAT);
+ bp += WEXT_PNO_MAX_REPEAT_LENGTH + 1;
+
+ os_memset(&iwr, 0, sizeof(iwr));
+ os_strlcpy(iwr.ifr_name, drv->ifname, IFNAMSIZ);
+ iwr.u.data.pointer = buf;
+ iwr.u.data.length = bp;
+
+ ret = ioctl(drv->ioctl_sock, SIOCSIWPRIV, &iwr);
+
+ if (ret < 0) {
+ wpa_printf(MSG_ERROR, "ioctl[SIOCSIWPRIV] (pnosetup): %d", ret);
+ drv->errors++;
+ if (drv->errors > DRV_NUMBER_SEQUENTIAL_ERRORS) {
+ drv->errors = 0;
+ wpa_msg(drv->ctx, MSG_INFO, WPA_EVENT_DRIVER_STATE "HANGED");
+ }
+ } else {
+ drv->errors = 0;
+ }
+ return ret;
+
+}
+
+int wpa_driver_wext_driver_cmd( void *priv, char *cmd, char *buf, size_t buf_len )
+{
+ struct wpa_driver_wext_data *drv = priv;
+ struct wpa_supplicant *wpa_s = (struct wpa_supplicant *)(drv->ctx);
+ struct iwreq iwr;
+ int ret = 0, flags;
+
+ wpa_printf(MSG_DEBUG, "%s %s len = %d", __func__, cmd, buf_len);
+
+ if (!drv->driver_is_started && (os_strcasecmp(cmd, "START") != 0)) {
+ wpa_printf(MSG_ERROR,"WEXT: Driver not initialized yet");
+ return -1;
+ }
+
+ if (os_strcasecmp(cmd, "RSSI-APPROX") == 0) {
+ os_strlcpy(cmd, RSSI_CMD, MAX_DRV_CMD_SIZE);
+ } else if( os_strncasecmp(cmd, "SCAN-CHANNELS", 13) == 0 ) {
+ int no_of_chan;
+
+ no_of_chan = atoi(cmd + 13);
+ os_snprintf(cmd, MAX_DRV_CMD_SIZE, "COUNTRY %s",
+ wpa_driver_get_country_code(no_of_chan));
+ } else if (os_strcasecmp(cmd, "STOP") == 0) {
+ linux_set_iface_flags(drv->ioctl_sock, drv->ifname, 0);
+ } else if( os_strcasecmp(cmd, "RELOAD") == 0 ) {
+ wpa_printf(MSG_DEBUG,"Reload command");
+ wpa_msg(drv->ctx, MSG_INFO, WPA_EVENT_DRIVER_STATE "HANGED");
+ return ret;
+ } else if( os_strcasecmp(cmd, "BGSCAN-START") == 0 ) {
+ ret = wpa_driver_set_backgroundscan_params(priv);
+ if (ret < 0) {
+ return ret;
+ }
+ os_strlcpy(cmd, "PNOFORCE 1", MAX_DRV_CMD_SIZE);
+ drv->bgscan_enabled = 1;
+ } else if( os_strcasecmp(cmd, "BGSCAN-STOP") == 0 ) {
+ os_strlcpy(cmd, "PNOFORCE 0", MAX_DRV_CMD_SIZE);
+ drv->bgscan_enabled = 0;
+ }
+
+ os_memset(&iwr, 0, sizeof(iwr));
+ os_strlcpy(iwr.ifr_name, drv->ifname, IFNAMSIZ);
+ os_memcpy(buf, cmd, strlen(cmd) + 1);
+ iwr.u.data.pointer = buf;
+ iwr.u.data.length = buf_len;
+
+ if( os_strncasecmp(cmd, "CSCAN", 5) == 0 ) {
+ if (!wpa_s->scanning && ((wpa_s->wpa_state <= WPA_SCANNING) ||
+ (wpa_s->wpa_state >= WPA_COMPLETED))) {
+ iwr.u.data.length = wpa_driver_wext_set_cscan_params(buf, buf_len, cmd);
+ } else {
+ wpa_printf(MSG_ERROR, "Ongoing Scan action...");
+ return ret;
+ }
+ }
+
+ ret = ioctl(drv->ioctl_sock, SIOCSIWPRIV, &iwr);
+
+ if (ret < 0) {
+ wpa_printf(MSG_ERROR, "%s failed (%d): %s", __func__, ret, cmd);
+ drv->errors++;
+ if (drv->errors > DRV_NUMBER_SEQUENTIAL_ERRORS) {
+ drv->errors = 0;
+ wpa_msg(drv->ctx, MSG_INFO, WPA_EVENT_DRIVER_STATE "HANGED");
+ }
+ } else {
+ drv->errors = 0;
+ ret = 0;
+ if ((os_strcasecmp(cmd, RSSI_CMD) == 0) ||
+ (os_strcasecmp(cmd, LINKSPEED_CMD) == 0) ||
+ (os_strcasecmp(cmd, "MACADDR") == 0) ||
+ (os_strcasecmp(cmd, "GETPOWER") == 0) ||
+ (os_strcasecmp(cmd, "GETBAND") == 0)) {
+ ret = strlen(buf);
+ } else if (os_strcasecmp(cmd, "START") == 0) {
+ drv->driver_is_started = TRUE;
+ linux_set_iface_flags(drv->ioctl_sock, drv->ifname, 1);
+ /* os_sleep(0, WPA_DRIVER_WEXT_WAIT_US);
+ wpa_msg(drv->ctx, MSG_INFO, WPA_EVENT_DRIVER_STATE "STARTED"); */
+ } else if (os_strcasecmp(cmd, "STOP") == 0) {
+ drv->driver_is_started = FALSE;
+ /* wpa_msg(drv->ctx, MSG_INFO, WPA_EVENT_DRIVER_STATE "STOPPED"); */
+ } else if (os_strncasecmp(cmd, "CSCAN", 5) == 0) {
+ wpa_driver_wext_set_scan_timeout(priv);
+ wpa_supplicant_notify_scanning(wpa_s, 1);
+ }
+ wpa_printf(MSG_DEBUG, "%s %s len = %d, %d", __func__, buf, ret, strlen(buf));
+ }
+ return ret;
+}
+
+int wpa_driver_signal_poll(void *priv, struct wpa_signal_info *si)
+{
+ char buf[MAX_DRV_CMD_SIZE];
+ struct wpa_driver_wext_data *drv = priv;
+ char *prssi;
+ int res;
+
+ os_memset(si, 0, sizeof(*si));
+ res = wpa_driver_wext_driver_cmd(priv, RSSI_CMD, buf, sizeof(buf));
+ /* Answer: SSID rssi -Val */
+ if (res < 0)
+ return res;
+ prssi = strcasestr(buf, RSSI_CMD);
+ if (!prssi)
+ return -1;
+ si->current_signal = atoi(prssi + strlen(RSSI_CMD) + 1);
+
+ res = wpa_driver_wext_driver_cmd(priv, LINKSPEED_CMD, buf, sizeof(buf));
+ /* Answer: LinkSpeed Val */
+ if (res < 0)
+ return res;
+ si->current_txrate = atoi(buf + strlen(LINKSPEED_CMD) + 1) * 1000;
+
+ return 0;
+}
diff --git a/synadhd/wpa_supplicant_8_lib/driver_cmd_wext.h b/synadhd/wpa_supplicant_8_lib/driver_cmd_wext.h
new file mode 100644
index 0000000..56d54fc
--- /dev/null
+++ b/synadhd/wpa_supplicant_8_lib/driver_cmd_wext.h
@@ -0,0 +1,37 @@
+/*
+ * Driver interaction with extended Linux Wireless Extensions
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ * Alternatively, this software may be distributed under the terms of BSD
+ * license.
+ *
+ */
+#ifndef DRIVER_CMD_WEXT_H
+#define DRIVER_CMD_WEXT_H
+
+#define WEXT_NUMBER_SCAN_CHANNELS_FCC 11
+#define WEXT_NUMBER_SCAN_CHANNELS_ETSI 13
+#define WEXT_NUMBER_SCAN_CHANNELS_MKK1 14
+
+#define WPA_DRIVER_WEXT_WAIT_US 400000
+#define WEXT_CSCAN_BUF_LEN 360
+#define WEXT_CSCAN_HEADER "CSCAN S\x01\x00\x00S\x00"
+#define WEXT_CSCAN_HEADER_SIZE 12
+#define WEXT_CSCAN_SSID_SECTION 'S'
+#define WEXT_CSCAN_CHANNEL_SECTION 'C'
+#define WEXT_CSCAN_NPROBE_SECTION 'N'
+#define WEXT_CSCAN_ACTV_DWELL_SECTION 'A'
+#define WEXT_CSCAN_PASV_DWELL_SECTION 'P'
+#define WEXT_CSCAN_HOME_DWELL_SECTION 'H'
+#define WEXT_CSCAN_TYPE_SECTION 'T'
+#define WEXT_CSCAN_TYPE_DEFAULT 0
+#define WEXT_CSCAN_TYPE_PASSIVE 1
+#define WEXT_CSCAN_PASV_DWELL_TIME 130
+#define WEXT_CSCAN_PASV_DWELL_TIME_DEF 250
+#define WEXT_CSCAN_PASV_DWELL_TIME_MAX 3000
+#define WEXT_CSCAN_HOME_DWELL_TIME 130
+
+#endif /* DRIVER_CMD_WEXT_H */