summaryrefslogtreecommitdiff
path: root/wcn6740/qcwcn/wifi_hal/common.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'wcn6740/qcwcn/wifi_hal/common.cpp')
-rw-r--r--wcn6740/qcwcn/wifi_hal/common.cpp430
1 files changed, 430 insertions, 0 deletions
diff --git a/wcn6740/qcwcn/wifi_hal/common.cpp b/wcn6740/qcwcn/wifi_hal/common.cpp
new file mode 100644
index 0000000..263043b
--- /dev/null
+++ b/wcn6740/qcwcn/wifi_hal/common.cpp
@@ -0,0 +1,430 @@
+/*
+ * Copyright (C) 2014 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.
+ */
+
+#include <stdlib.h>
+#include <linux/pkt_sched.h>
+#include <linux-private/linux/fib_rules.h>
+#include <netlink/object-api.h>
+#include <netlink-private/object-api.h>
+#include <netlink-private/types.h>
+#include <dlfcn.h>
+#include <pthread.h>
+#include "wifi_hal.h"
+#include "common.h"
+#include <errno.h>
+
+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;
+
+ pthread_mutex_lock(&info->cb_lock);
+
+ wifi_error result = WIFI_ERROR_OUT_OF_MEMORY;
+
+ for (int i = 0; i < info->num_event_cb; i++) {
+ if(info->event_cb[i].nl_cmd == cmd &&
+ info->event_cb[i].cb_arg == arg) {
+ info->event_cb[i].cb_func = func;
+ ALOGV("Updated event handler %p for nl_cmd 0x%0x"
+ " and arg %p", func, cmd, arg);
+ pthread_mutex_unlock(&info->cb_lock);
+ return WIFI_SUCCESS;
+ }
+ }
+
+ 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;
+ info->num_event_cb++;
+ ALOGV("Successfully added event handler %p for command %d", func, cmd);
+ result = WIFI_SUCCESS;
+ } else {
+ result = WIFI_ERROR_OUT_OF_MEMORY;
+ }
+
+ 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;
+
+ pthread_mutex_lock(&info->cb_lock);
+
+ wifi_error result = WIFI_ERROR_OUT_OF_MEMORY;
+
+ for (int i = 0; i < info->num_event_cb; i++) {
+ if(info->event_cb[i].vendor_id == id &&
+ info->event_cb[i].vendor_subcmd == subcmd)
+ {
+ info->event_cb[i].cb_func = func;
+ info->event_cb[i].cb_arg = arg;
+ ALOGV("Updated event handler %p for vendor 0x%0x, subcmd 0x%0x"
+ " and arg %p", func, id, subcmd, arg);
+ pthread_mutex_unlock(&info->cb_lock);
+ return WIFI_SUCCESS;
+ }
+ }
+
+ if (info->num_event_cb < info->alloc_event_cb) {
+ 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++;
+ ALOGV("Added event handler %p for vendor 0x%0x, subcmd 0x%0x and arg"
+ " %p", func, id, subcmd, arg);
+ result = WIFI_SUCCESS;
+ } else {
+ result = WIFI_ERROR_OUT_OF_MEMORY;
+ }
+
+ 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) {
+ if(i < info->num_event_cb-1) {
+ /* No need to memmove if only one entry exist and deleting
+ * the same, as the num_event_cb will become 0 in this case.
+ */
+ memmove(&info->event_cb[i], &info->event_cb[i+1],
+ (info->num_event_cb - i) * sizeof(cb_info));
+ }
+ info->num_event_cb--;
+ ALOGV("Successfully removed event handler for command %d", cmd);
+ break;
+ }
+ }
+
+ pthread_mutex_unlock(&info->cb_lock);
+}
+
+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);
+
+ 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) {
+ if(i < info->num_event_cb-1) {
+ /* No need to memmove if only one entry exist and deleting
+ * the same, as the num_event_cb will become 0 in this case.
+ */
+ memmove(&info->event_cb[i], &info->event_cb[i+1],
+ (info->num_event_cb - i) * sizeof(cb_info));
+ }
+ info->num_event_cb--;
+ ALOGV("Successfully removed event handler for vendor 0x%0x", id);
+ break;
+ }
+ }
+
+ pthread_mutex_unlock(&info->cb_lock);
+}
+
+
+#ifdef __cplusplus
+extern "C"
+{
+#endif /* __cplusplus */
+
+void hexdump(void *buf, u16 len)
+{
+ int i=0;
+ char *bytes = (char *)buf;
+
+ if (len) {
+ ALOGV("******HexDump len:%d*********", len);
+ for (i = 0; ((i + 7) < len); i+=8) {
+ ALOGV("%02x %02x %02x %02x %02x %02x %02x %02x",
+ bytes[i], bytes[i+1],
+ bytes[i+2], bytes[i+3],
+ bytes[i+4], bytes[i+5],
+ bytes[i+6], bytes[i+7]);
+ }
+ if ((len - i) >= 4) {
+ ALOGV("%02x %02x %02x %02x",
+ bytes[i], bytes[i+1],
+ bytes[i+2], bytes[i+3]);
+ i+=4;
+ }
+ for (;i < len;i++) {
+ ALOGV("%02x", bytes[i]);
+ }
+ ALOGV("******HexDump End***********");
+ } else {
+ return;
+ }
+}
+
+/* Firmware sends RSSI value without noise floor.
+ * Add noise floor to the same and return absolute values.
+ */
+u8 get_rssi(u8 rssi_wo_noise_floor)
+{
+ return abs((int)rssi_wo_noise_floor - 96);
+}
+
+#ifdef __cplusplus
+}
+#endif /* __cplusplus */
+
+/* Pointer to the table of LOWI callback funcs */
+lowi_cb_table_t *LowiWifiHalApi = NULL;
+/* LowiSupportedCapabilities read */
+u32 lowiSupportedCapabilities = 0;
+
+int compareLowiVersion(u16 major, u16 minor, u16 micro)
+{
+ u32 currVersion = 0x10000*(WIFIHAL_LOWI_MAJOR_VERSION) + \
+ 0x100*(WIFIHAL_LOWI_MINOR_VERSION) + \
+ WIFIHAL_LOWI_MICRO_VERSION;
+
+ u32 lowiVersion = 0x10000*(major) + \
+ 0x100*(minor) + \
+ micro;
+
+ return (memcmp(&currVersion, &lowiVersion, sizeof(u32)));
+}
+
+/*
+ * This function will open the lowi shared library and obtain the
+ * Lowi Callback table and the capabilities supported.
+ * A version check is also performed in this function and if the version
+ * check fails then the callback table returned will be NULL.
+ */
+wifi_error fetchLowiCbTableAndCapabilities(lowi_cb_table_t **lowi_wifihal_api,
+ bool *lowi_get_capa_supported)
+{
+ getCbTable_t* lowiCbTable = NULL;
+ int ret = 0;
+ wifi_error retVal = WIFI_SUCCESS;
+
+ *lowi_wifihal_api = NULL;
+ *lowi_get_capa_supported = false;
+
+#if __WORDSIZE == 64
+ void* lowi_handle = dlopen("/vendor/lib64/liblowi_wifihal.so", RTLD_NOW);
+#else
+ void* lowi_handle = dlopen("/vendor/lib/liblowi_wifihal.so", RTLD_NOW);
+#endif
+ if (!lowi_handle) {
+ ALOGE("%s: NULL lowi_handle, err: %s", __FUNCTION__, dlerror());
+ return WIFI_ERROR_UNKNOWN;
+ }
+
+ lowiCbTable = (getCbTable_t*)dlsym(lowi_handle,
+ "lowi_wifihal_get_cb_table");
+ if (!lowiCbTable) {
+ ALOGE("%s: NULL lowi callback table", __FUNCTION__);
+ return WIFI_ERROR_UNKNOWN;
+ }
+
+ *lowi_wifihal_api = lowiCbTable();
+
+ /* First check whether lowi module implements the get_lowi_version
+ * function. All the functions in lowi module starts with
+ * "lowi_wifihal_" prefix thus the below function name.
+ */
+ if ((dlsym(lowi_handle, "lowi_wifihal_get_lowi_version") != NULL) &&
+ ((*lowi_wifihal_api)->get_lowi_version != NULL)) {
+ u16 lowiMajorVersion = WIFIHAL_LOWI_MAJOR_VERSION;
+ u16 lowiMinorVersion = WIFIHAL_LOWI_MINOR_VERSION;
+ u16 lowiMicroVersion = WIFIHAL_LOWI_MICRO_VERSION;
+ int versionCheck = -1;
+
+ ret = (*lowi_wifihal_api)->get_lowi_version(&lowiMajorVersion,
+ &lowiMinorVersion,
+ &lowiMicroVersion);
+ if (ret) {
+ ALOGE("%s: get_lowi_version returned error:%d",
+ __FUNCTION__, ret);
+ retVal = WIFI_ERROR_NOT_SUPPORTED;
+ goto cleanup;
+ }
+ ALOGV("%s: Lowi version:%d.%d.%d", __FUNCTION__,
+ lowiMajorVersion, lowiMinorVersion,
+ lowiMicroVersion);
+
+ /* Compare the version with version in wifihal_internal.h */
+ versionCheck = compareLowiVersion(lowiMajorVersion,
+ lowiMinorVersion,
+ lowiMicroVersion);
+ if (versionCheck < 0) {
+ ALOGE("%s: Version Check failed:%d", __FUNCTION__,
+ versionCheck);
+ retVal = WIFI_ERROR_NOT_SUPPORTED;
+ goto cleanup;
+ }
+ }
+ else {
+ ALOGV("%s: lowi_wifihal_get_lowi_version not present",
+ __FUNCTION__);
+ }
+
+
+ /* Check if get_lowi_capabilities func pointer exists in
+ * the lowi lib and populate lowi_get_capa_supported
+ * All the functions in lowi modules starts with
+ * "lowi_wifihal_ prefix" thus the below function name.
+ */
+ if (dlsym(lowi_handle, "lowi_wifihal_get_lowi_capabilities") != NULL) {
+ *lowi_get_capa_supported = true;
+ }
+ else {
+ ALOGV("lowi_wifihal_get_lowi_capabilities() is not supported.");
+ *lowi_get_capa_supported = false;
+ }
+cleanup:
+ if (retVal) {
+ *lowi_wifihal_api = NULL;
+ }
+ return retVal;
+}
+
+lowi_cb_table_t *getLowiCallbackTable(u32 requested_lowi_capabilities)
+{
+ int ret = WIFI_SUCCESS;
+ bool lowi_get_capabilities_support = false;
+
+ if (LowiWifiHalApi == NULL) {
+ ALOGV("%s: LowiWifiHalApi Null, Initialize Lowi",
+ __FUNCTION__);
+ ret = fetchLowiCbTableAndCapabilities(&LowiWifiHalApi,
+ &lowi_get_capabilities_support);
+ if (ret != WIFI_SUCCESS || LowiWifiHalApi == NULL ||
+ LowiWifiHalApi->init == NULL) {
+ ALOGE("%s: LOWI is not supported.", __FUNCTION__);
+ goto cleanup;
+ }
+ /* Initialize LOWI if it isn't up already. */
+ ret = LowiWifiHalApi->init();
+ if (ret) {
+ ALOGE("%s: failed lowi initialization. "
+ "Returned error:%d. Exit.", __FUNCTION__, ret);
+ goto cleanup;
+ }
+ if (!lowi_get_capabilities_support ||
+ LowiWifiHalApi->get_lowi_capabilities == NULL) {
+ ALOGV("%s: Allow rtt APIs thru LOWI to proceed even though "
+ "get_lowi_capabilities() is not supported. Returning",
+ __FUNCTION__);
+ lowiSupportedCapabilities |=
+ (ONE_SIDED_RANGING_SUPPORTED|DUAL_SIDED_RANGING_SUPPORED);
+ return LowiWifiHalApi;
+ }
+ ret =
+ LowiWifiHalApi->get_lowi_capabilities(&lowiSupportedCapabilities);
+ if (ret) {
+ ALOGV("%s: failed to get lowi supported capabilities."
+ "Returned error:%d. Exit.", __FUNCTION__, ret);
+ goto cleanup;
+ }
+ } else if (lowiSupportedCapabilities == 0 &&
+ LowiWifiHalApi->get_lowi_capabilities) {
+ LowiWifiHalApi->get_lowi_capabilities(&lowiSupportedCapabilities);
+ }
+
+ if ((lowiSupportedCapabilities & requested_lowi_capabilities) == 0) {
+ return NULL;
+ }
+ return LowiWifiHalApi;
+
+cleanup:
+ if (LowiWifiHalApi && LowiWifiHalApi->destroy) {
+ ret = LowiWifiHalApi->destroy();
+ }
+ LowiWifiHalApi = NULL;
+ lowiSupportedCapabilities = 0;
+ return LowiWifiHalApi;
+}
+
+wifi_error mapKernelErrortoWifiHalError(int kern_err)
+{
+ if (kern_err >= 0)
+ return WIFI_SUCCESS;
+
+ switch (kern_err) {
+ case -EOPNOTSUPP:
+ return WIFI_ERROR_NOT_SUPPORTED;
+ case -EAGAIN:
+ return WIFI_ERROR_NOT_AVAILABLE;
+ case -EINVAL:
+ return WIFI_ERROR_INVALID_ARGS;
+ case -ETIMEDOUT:
+ return WIFI_ERROR_TIMED_OUT;
+ case -ENOMEM:
+ return WIFI_ERROR_OUT_OF_MEMORY;
+ case -EBUSY:
+ return WIFI_ERROR_BUSY;
+ case -ENOBUFS:
+ return WIFI_ERROR_TOO_MANY_REQUESTS;
+ }
+ return WIFI_ERROR_UNKNOWN;
+}