From 2d6c60c531ff1e2a2919640245de57b2f881fbc5 Mon Sep 17 00:00:00 2001 From: SGCMarkus Date: Sat, 19 Feb 2022 15:14:24 +0100 Subject: [PATCH] sm8250-common: build libqsap_sdk from source imported from LA.UM.9.12.r1-13800-SMxx50.0 --- proprietary-files.txt | 1 - qsap/Android.mk | 79 + qsap/qsap.c | 710 ++++++++ qsap/qsap.h | 61 + qsap/qsap_api.c | 3666 +++++++++++++++++++++++++++++++++++++++++ qsap/qsap_api.h | 650 ++++++++ sm8250.mk | 1 + 7 files changed, 5167 insertions(+), 1 deletion(-) create mode 100755 qsap/Android.mk create mode 100644 qsap/qsap.c create mode 100644 qsap/qsap.h create mode 100644 qsap/qsap_api.c create mode 100644 qsap/qsap_api.h diff --git a/proprietary-files.txt b/proprietary-files.txt index 7688a2d..c8b8d1c 100644 --- a/proprietary-files.txt +++ b/proprietary-files.txt @@ -749,7 +749,6 @@ vendor/lib64/libqcrildatactl.so vendor/lib64/libqcrilFramework.so vendor/lib64/libqmimotext.so vendor/lib64/libqrtr.so -vendor/lib64/libqsap_sdk.so vendor/lib64/libqsocket.so vendor/lib64/libril-qc-hal-qmi.so vendor/lib64/libril-qc-logger.so diff --git a/qsap/Android.mk b/qsap/Android.mk new file mode 100755 index 0000000..0d9bc46 --- /dev/null +++ b/qsap/Android.mk @@ -0,0 +1,79 @@ + + +LOCAL_PATH := $(call my-dir) + +include $(CLEAR_VARS) + +LOCAL_C_INCLUDES := $(TOP)/hardware/libhardware_legacy/wifi $(TOP)/external/libnl/include $(TOP)/external/wpa_supplicant_8/wpa_supplicant/src/drivers + +LOCAL_MODULE:= libqsap_sdk + +LOCAL_MODULE_TAGS := optional + +ifeq ($(PRODUCT_VENDOR_MOVE_ENABLED), true) +LOCAL_VENDOR_MODULE := true +endif + +LOCAL_CFLAGS += -DSDK_VERSION=\"0.0.1.0\" + +LOCAL_LDLIBS := -llog + +LOCAL_EXPORT_C_INCLUDE_DIRS := $(LOCAL_PATH)/qsap_api.h \ + $(LOCAL_PATH)/qsap.h + +ifdef WIFI_DRIVER_MODULE_PATH +LOCAL_CFLAGS += -DWIFI_DRIVER_MODULE_PATH=\"$(WIFI_DRIVER_MODULE_PATH)\" +endif + +ifdef WIFI_DRIVER_MODULE_ARG +LOCAL_CFLAGS += -DWIFI_DRIVER_MODULE_ARG=\"$(WIFI_DRIVER_MODULE_ARG)\" +endif + +ifdef WIFI_DRIVER_MODULE_NAME +LOCAL_CFLAGS += -DWIFI_DRIVER_MODULE_NAME=\"$(WIFI_DRIVER_MODULE_NAME)\" +endif + +ifdef WIFI_SDIO_IF_DRIVER_MODULE_PATH +LOCAL_CFLAGS += -DWIFI_SDIO_IF_DRIVER_MODULE_PATH=\"$(WIFI_SDIO_IF_DRIVER_MODULE_PATH)\" +endif + +ifdef WIFI_SDIO_IF_DRIVER_MODULE_NAME +LOCAL_CFLAGS += -DWIFI_SDIO_IF_DRIVER_MODULE_NAME=\"$(WIFI_SDIO_IF_DRIVER_MODULE_NAME)\" +endif + +ifdef WIFI_CFG80211_DRIVER_MODULE_PATH +LOCAL_CFLAGS += -DWIFI_CFG80211_DRIVER_MODULE_PATH=\"$(WIFI_CFG80211_DRIVER_MODULE_PATH)\" +endif + +ifdef WIFI_CFG80211_DRIVER_MODULE_ARG +LOCAL_CFLAGS += -DWIFI_CFG80211_DRIVER_MODULE_ARG=\"$(WIFI_CFG80211_DRIVER_MODULE_ARG)\" +endif + +ifdef WIFI_CFG80211_DRIVER_MODULE_NAME +LOCAL_CFLAGS += -DWIFI_CFG80211_DRIVER_MODULE_NAME=\"$(WIFI_CFG80211_DRIVER_MODULE_NAME)\" +endif + +ifdef WIFI_DRIVER_CONF_FILE +LOCAL_CFLAGS += -DWIFI_DRIVER_CONF_FILE=\"$(WIFI_DRIVER_CONF_FILE)\" +endif + +ifdef WIFI_DRIVER_DEF_CONF_FILE +LOCAL_CFLAGS += -DWIFI_DRIVER_DEF_CONF_FILE=\"$(WIFI_DRIVER_DEF_CONF_FILE)\" +endif + +LOCAL_SRC_FILES := qsap_api.c \ + qsap.c + +LOCAL_PRELINK_MODULE := false + +LOCAL_SHARED_LIBRARIES := libnetutils libutils libbinder libcutils libhardware_legacy libnl + +LOCAL_HEADER_LIBRARIES := libcutils_headers + +include $(BUILD_SHARED_LIBRARY) + +include $(CLEAR_VARS) +LOCAL_MODULE := libqsap_headers +LOCAL_EXPORT_C_INCLUDE_DIRS := $(LOCAL_PATH) +LOCAL_VENDOR_MODULE := true +include $(BUILD_HEADER_LIBRARY) diff --git a/qsap/qsap.c b/qsap/qsap.c new file mode 100644 index 0000000..9a885bd --- /dev/null +++ b/qsap/qsap.c @@ -0,0 +1,710 @@ +/* + * Copyright (c) 2010-2013, The Linux Foundation. All rights reserved. + + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials provided + * with the distribution. + * * Neither the name of The Linux Foundation, Inc. nor the names of its + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + + * THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS + * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR + * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, + * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE + * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN + * IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + + +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#define LOG_TAG "QCLDR-" + +#include +#include +#include +#include +#include +#include + +#include "qsap_api.h" +#include "qsap.h" + +#include + +#ifndef WIFI_DRIVER_MODULE_PATH +#define WIFI_DRIVER_MODULE_PATH "/system/lib/modules/wlan.ko" +#endif + +#ifndef WIFI_DRIVER_MODULE_NAME +#define WIFI_DRIVER_MODULE_NAME "wlan" +#endif + +#ifdef WIFI_DRIVER_MODULE_ARG +#undef WIFI_DRIVER_MODULE_ARG +#endif + +#define WIFI_DRIVER_MODULE_ARG "" + +/* WIFI_SDIO_IF_DRIVER_MODULE_NAME must be defined if sdioif driver required */ +#ifdef WIFI_SDIO_IF_DRIVER_MODULE_NAME + +#ifndef WIFI_SDIO_IF_DRIVER_MODULE_PATH +#define WIFI_SDIO_IF_DRIVER_MODULE_PATH "/system/lib/modules/librasdioif.ko" +#endif + + +#ifndef WIFI_SDIO_IF_DRIVER_MODULE_ARG +#define WIFI_SDIO_IF_DRIVER_MODULE_ARG "" +#endif + +#endif + +#ifndef WIFI_CFG80211_DRIVER_MODULE_PATH +#define WIFI_CFG80211_DRIVER_MODULE_PATH "" +#endif +#ifndef WIFI_CFG80211_DRIVER_MODULE_NAME +#define WIFI_CFG80211_DRIVER_MODULE_NAME "" +#endif +#ifndef WIFI_CFG80211_DRIVER_MODULE_ARG +#define WIFI_CFG80211_DRIVER_MODULE_ARG "" +#endif + + +extern int init_module(const char *name, u32, const s8 *); +extern int delete_module(const char *name, int); + +extern struct Command qsap_str[]; + +static s32 check_driver_loaded( const s8 * tag) +{ + FILE *proc; + s8 line[126]; + + if ((proc = fopen("/proc/modules", "r")) == NULL) { + ALOGW("Could not open %s: %s", "/proc/modules", strerror(errno)); + return 0; + } + + while ((fgets(line, sizeof(line), proc)) != NULL) { + if (strncmp(line, tag, strlen(tag)) == 0) { + fclose(proc); + return 1; + } + } + + fclose(proc); + + return 0; +} + +static s32 insmod(const s8 *filename, const s8 *args, const s8 * tag) +{ +#ifndef SDK_TEST + void *module; + s32 size; + s32 ret = 0; + + if ( check_driver_loaded(tag) ) { + ALOGE("Driver: %s already loaded\n", filename); + return ret; + } + + ALOGD("Loading Driver: %s %s\n", filename, args); + + module = (void*)load_file(filename, (unsigned int*)&size); + + if (!module) { + ALOGE("Cannot load file: %s\n", filename); + return -1; + } + + ret = init_module(module, size, args); + + if ( ret ) { + ALOGE("init_module (%s:%d) failed\n", filename, (int)size); + } + + free(module); + + return ret; +#else + return 0; +#endif +} + +static s32 rmmod(const s8 *modname) +{ +#ifndef SDK_TEST + s32 ret = 0; + s32 maxtry = 10; + + while (maxtry-- > 0) { + ret = delete_module(modname, O_NONBLOCK | O_EXCL); + + if (ret < 0 && errno == EAGAIN){ + usleep(50000); + } else { + break; + } + } + + if (ret != 0) { + ALOGD("Unable to unload driver module \"%s\": %s\n", + modname, strerror(errno)); + } + + return ret; +#else + return 0; +#endif +} + +static const s8 SDIO_POLLING_ON[] = "/etc/init.qcom.sdio.sh 1"; +static const s8 SDIO_POLLING_OFF[] = "/etc/init.qcom.sdio.sh 0"; +static const char DRIVER_CFG80211_MODULE_NAME[] = WIFI_CFG80211_DRIVER_MODULE_NAME; +static const char DRIVER_CFG80211_MODULE_PATH[] = WIFI_CFG80211_DRIVER_MODULE_PATH; +static const char DRIVER_CFG80211_MODULE_ARG[] = WIFI_CFG80211_DRIVER_MODULE_ARG; + +s32 wifi_qsap_load_driver(void) +{ + s32 size; + s32 ret = -1; + s32 retry; + + + if (system(SDIO_POLLING_ON)) { +// ALOGE("Could not turn on the polling..."); + } + + if ('\0' != *DRIVER_CFG80211_MODULE_PATH) { + if (insmod(DRIVER_CFG80211_MODULE_PATH, DRIVER_CFG80211_MODULE_ARG,DRIVER_CFG80211_MODULE_NAME) < 0) { + ALOGE("Could not load cfg80211..."); + return ret; + } + } + +#ifdef WIFI_SDIO_IF_DRIVER_MODULE_NAME + ret = insmod(WIFI_SDIO_IF_DRIVER_MODULE_PATH, WIFI_SDIO_IF_DRIVER_MODULE_ARG, WIFI_SDIO_IF_DRIVER_MODULE_NAME " "); + + if ( ret != 0 ) { + ALOGE("init_module failed sdioif\n"); + ret = eERR_LOAD_FAILED_SDIOIF; + goto end; + } + + sched_yield(); +#endif + + ret = insmod(WIFI_DRIVER_MODULE_PATH, WIFI_DRIVER_MODULE_ARG, WIFI_DRIVER_MODULE_NAME " "); + + if ( ret != 0 ) { +#ifdef WIFI_SDIO_IF_DRIVER_MODULE_NAME + if ( check_driver_loaded(WIFI_SDIO_IF_DRIVER_MODULE_NAME " ") ) { + if ( rmmod(WIFI_SDIO_IF_DRIVER_MODULE_NAME) ) { + ALOGE("Unable to unload the station mode librasdioif driver\n"); + } + } +#endif + if ('\0' != *DRIVER_CFG80211_MODULE_NAME) { + rmmod(DRIVER_CFG80211_MODULE_NAME); + } + ALOGE("init_module failed libra_softap\n"); + ret = eERR_LOAD_FAILED_SOFTAP; + goto end; + } + + sched_yield(); + + ret = eSUCCESS; + +end: + if(system(SDIO_POLLING_OFF)) { +// ALOGE("Could not turn off the polling..."); + } + + return ret; +} + +void qsap_send_module_down_indication(void) +{ + int s, ret; + struct iwreq wrq; + + /* + * If the driver is loaded, ask it to broadcast a netlink message + * that it will be closing, so listeners can close their sockets. + * + */ + + + /* Equivalent to: iwpriv wlan0 sendModuleInd */ + if ((s = socket(PF_INET, SOCK_DGRAM, 0)) >= 0) { + strlcpy(wrq.ifr_name, "wlan0", IFNAMSIZ); + wrq.u.data.length = 0; /* No Set arguments */ + wrq.u.mode = 5; /* WE_MODULE_DOWN_IND sub-command */ + ret = ioctl(s, (SIOCIWFIRSTPRIV + 1), &wrq); + if (ret < 0 ) { + strlcpy(wrq.ifr_name, "softap.0", IFNAMSIZ); + ret = ioctl(s, (SIOCIWFIRSTPRIV + 1), &wrq); + if (ret < 0 ) { + ALOGE("ioctl failed: %s", strerror(errno)); + } + } + close(s); + sched_yield(); + } + else { + ALOGE("Socket open failed: %s", strerror(errno)); + } +} + + +s32 qsap_send_init_ap(void) +{ + int s, ret; + struct iwreq wrq; + s32 status = eSUCCESS; + u32 *params = (u32 *)&wrq.u; + + /* Equivalent to: iwpriv wlan0 initAP */ + if ((s = socket(AF_INET, SOCK_DGRAM, 0)) >= 0) { + strlcpy(wrq.ifr_name, "wlan0", IFNAMSIZ); + wrq.u.data.length = 0; /* No Set arguments */ + wrq.u.data.flags = 2; /* WE_INIT_AP sub-command */ + ret = ioctl(s, (SIOCIWFIRSTPRIV + 6), &wrq); + if (ret < 0 ) { + ALOGE("ioctl failed: %s", strerror(errno)); + status = eERR_START_SAP; + } + close(s); + sched_yield(); + } + else { + ALOGE("Socket open failed: %s", strerror(errno)); + status = eERR_START_SAP; + } + return status; +} + + +s32 qsap_send_exit_ap(void) +{ + int s, ret; + struct iwreq wrq; + s32 status = eSUCCESS; + u32 *params = (u32 *)&wrq.u; + + /* Equivalent to: iwpriv wlan0 exitAP */ + if ((s = socket(AF_INET, SOCK_DGRAM, 0)) >= 0) { + strlcpy(wrq.ifr_name, "wlan0", IFNAMSIZ); + wrq.u.data.length = 0; /* No Set arguments */ + wrq.u.data.flags = 3; /*WE_EXIT_AP sub-command */ + + ret = ioctl(s, (SIOCIWFIRSTPRIV + 6), &wrq); + if (ret < 0 ) { + ALOGE("ioctl failed: %s", strerror(errno)); + status = eERR_STOP_SAP; + } + close(s); + sched_yield(); + } + else { + ALOGE("Socket open failed: %s", strerror(errno)); + status = eERR_STOP_SAP; + } + return status; +} + +s32 wifi_qsap_unload_driver() +{ + s32 ret = eSUCCESS; + + if(system(SDIO_POLLING_ON)) { + ALOGE("Could not turn on the polling..."); + } + + if ( check_driver_loaded(WIFI_DRIVER_MODULE_NAME " ") ) { + qsap_send_module_down_indication(); + if ( rmmod(WIFI_DRIVER_MODULE_NAME) ) { + ALOGE("Unable to unload the libra_softap driver\n"); + ret = eERR_UNLOAD_FAILED_SOFTAP; + goto end; + } + } + + sched_yield(); + +#ifdef WIFI_SDIO_IF_DRIVER_MODULE_NAME + if ( check_driver_loaded(WIFI_SDIO_IF_DRIVER_MODULE_NAME " ") ) { + if ( rmmod(WIFI_SDIO_IF_DRIVER_MODULE_NAME) ) { + ALOGE("Unable to unload the librasdioif driver\n"); + ret = eERR_UNLOAD_FAILED_SDIO; + goto end; + } + } +#endif + +end: + if(system(SDIO_POLLING_OFF)) { + ALOGE("Could not turn off the polling..."); + } + + return ret; +} + +s32 wifi_qsap_stop_bss(void) +{ +#define QCIEEE80211_IOCTL_STOPBSS (SIOCIWFIRSTPRIV + 6) + s32 sock; + s32 ret = eERR_STOP_BSS; + s8 cmd[] = "stopbss"; + s8 interface[128]; + s8 *iface; + s32 len = 128; + struct iwreq wrq; + struct iw_priv_args *priv_ptr; + + if(ENABLE != is_softap_enabled()) { + ret = eERR_BSS_NOT_STARTED; + return ret; + } + + if(NULL == (iface = qsap_get_config_value(CONFIG_FILE, &qsap_str[STR_INTERFACE], interface, (u32*)&len))) { + ALOGE("%s :interface error \n", __func__); + return ret; + } + + /* Issue the stopbss command to driver */ + sock = socket(AF_INET, SOCK_DGRAM, 0); + + if (sock < 0) { + ALOGE("Failed to open socket"); + return eERR_STOP_BSS; + } + + strlcpy(wrq.ifr_name, iface, sizeof(wrq.ifr_name)); + wrq.u.data.length = sizeof(cmd); + wrq.u.data.pointer = cmd; + wrq.u.data.flags = 0; + + ret = ioctl(sock, QCIEEE80211_IOCTL_STOPBSS, &wrq); + + /* Here IOCTL is always returning non Zero: temporary fix untill driver is fixed*/ + ret = 0; + close(sock); + + if (ret) { + ALOGE("IOCTL stopbss failed: %ld", ret); + ret = eERR_STOP_BSS; + } else { + ALOGD("STOP BSS ISSUED"); + ret = eSUCCESS; + } + + sched_yield(); + return ret; +} + +s32 is_softap_enabled(void) +{ + s32 mode = 0; + int ret; + + ret = qsap_get_mode(&mode); + if (eSUCCESS != ret) { + ALOGD("Failed to get the mode of operation\n"); + return eERR_UNKNOWN; + } + + if (mode == IW_MODE_MASTER) { + ALOGD("HOSTAPD Enabled\n"); + return ENABLE; + } + + ALOGD("HOSTAPD Disabled\n"); + + return DISABLE; +} + +s32 commit(void) +{ +#ifndef SDK_TEST + s32 ret = eERR_COMMIT; + + if ( is_softap_enabled() ) { + /** Stop BSS */ + if(eSUCCESS != (ret = wifi_qsap_stop_bss())) { + ALOGE("%s: stop bss failed \n", __func__); + return ret; + } + sleep(1); + } + + ret = wifi_qsap_start_softap(); + + if( eSUCCESS != ret ) + wifi_qsap_unload_driver(); + + return ret; +#else + return eSUCCESS; +#endif +} + +s32 wifi_qsap_start_softap() +{ + s32 retry = 4; + FILE * fp; + + ALOGD("Starting Soft AP...\n"); + + /* Check if configuration files are present, if not create the default files */ + check_for_configuration_files(); + + /* Delete control interface if it was left over because of previous crash */ + if ( !is_softap_enabled() ) { + qsap_del_ctrl_iface(); + } + + /* Ensure correct path for ini file name */ + qsap_set_ini_filename(); + + while(retry--) { + /* May be the configuration file is corrupted or not available, */ + /* copy the default configuration file */ + if ( retry == 1 ) + wifi_qsap_reset_to_default(CONFIG_FILE, DEFAULT_CONFIG_FILE_PATH); + + /** Stop hostapd */ + if(0 != property_set("ctl.start", "hostapd")) { + ALOGE("failed \n"); + continue; + } + + sleep(1); + + if ( is_softap_enabled() ) { + ALOGD("success \n"); + return eSUCCESS; + } + } + + ALOGE("Unable to start the SoftAP\n"); + return eERR_START_SAP; +} + +#ifdef QCOM_WLAN_CONCURRENCY +s32 wifi_qsap_start_softap_in_concurrency() +{ + s32 status; + /*Send initAP IOCTL to Driver. Hostapd start is done by Netd.*/ + status = qsap_send_init_ap(); + return status; +} + +s32 wifi_qsap_stop_softap_in_concurrency() +{ + s32 status; + /*Send exitAP IOCTL to Driver. Hostapd stop is done by Netd.*/ + status = qsap_send_exit_ap(); + return status; +} +#endif + + +s32 wifi_qsap_stop_softap() +{ + s32 ret = eSUCCESS; + + if ( is_softap_enabled() ) { + ALOGD("Stopping BSS ..... "); + + /** Stop the BSS */ + if (eSUCCESS != (ret = wifi_qsap_stop_bss()) ) { + ALOGE("failed \n"); + return ret; + } + sleep(1); + } + + return ret; +} + +s32 wifi_qsap_reload_softap() +{ + s32 ret = eERR_RELOAD_SAP; + + /** SDK API to reload the firmware */ + if (eSUCCESS != (ret = wifi_qsap_stop_softap())) { + return ret; + } + + if (eSUCCESS != (ret = wifi_qsap_unload_driver())) { + return ret; + } + + usleep(500000); + + if (eSUCCESS != (ret = wifi_qsap_load_driver())) { + return ret; + } + + sleep(1); + + if (eSUCCESS != (ret = wifi_qsap_start_softap())) { + wifi_qsap_unload_driver(); + return ret; + } + + return eSUCCESS; +} + +static pid_t wigigSoftApPid = 0; +static const char WIGIG_ENTROPY_FILE[] = "/data/misc/wifi/wigig_entropy.bin"; +static unsigned char dummy_key[21] = { 0x02, 0x11, 0xbe, 0x33, 0x43, 0x35, + 0x68, 0x47, 0x84, 0x99, 0xa9, 0x2b, + 0x1c, 0xd3, 0xee, 0xff, 0xf1, 0xe2, + 0xf3, 0xf4, 0xf5 }; +static const char HOSTAPD_BIN_FILE[] = "/system/bin/hostapd"; +static const char WIGIG_HOSTAPD_CONF_FILE[] = "/data/misc/wifi/wigig_hostapd.conf"; +#define AP_BSS_START_DELAY 200000 +#define AP_BSS_STOP_DELAY 500000 + +int wigig_ensure_entropy_file_exists() +{ + int ret; + int destfd; + struct passwd *pw; + struct group *gr; + + ret = access(WIGIG_ENTROPY_FILE, R_OK|W_OK); + if ((ret == 0) || (errno == EACCES)) { + if ((ret != 0) && + (chmod(WIGIG_ENTROPY_FILE, S_IRUSR|S_IWUSR|S_IRGRP|S_IWGRP) != 0)) { + ALOGE("Cannot set RW to \"%s\": %s", WIGIG_ENTROPY_FILE, strerror(errno)); + return -1; + } + return 0; + } + destfd = TEMP_FAILURE_RETRY(open(WIGIG_ENTROPY_FILE, O_CREAT|O_RDWR, 0660)); + if (destfd < 0) { + ALOGE("Cannot create \"%s\": %s", WIGIG_ENTROPY_FILE, strerror(errno)); + return -1; + } + + if (TEMP_FAILURE_RETRY(write(destfd, dummy_key, sizeof(dummy_key))) != sizeof(dummy_key)) { + ALOGE("Error writing \"%s\": %s", WIGIG_ENTROPY_FILE, strerror(errno)); + close(destfd); + return -1; + } + close(destfd); + + /* chmod is needed because open() didn't set permisions properly */ + if (chmod(WIGIG_ENTROPY_FILE, 0660) < 0) { + ALOGE("Error changing permissions of %s to 0660: %s", + WIGIG_ENTROPY_FILE, strerror(errno)); + unlink(WIGIG_ENTROPY_FILE); + return -1; + } + + pw = getpwnam("system"); + gr = getgrnam("wifi"); + if (pw && gr) { + if (chown(WIGIG_ENTROPY_FILE, pw->pw_uid, gr->gr_gid) < 0) { + ALOGE("Error changing group ownership of %s to %d: %s", + WIGIG_ENTROPY_FILE, gr->gr_gid, strerror(errno)); + unlink(WIGIG_ENTROPY_FILE); + return -1; + } + } else { + ALOGE("Cannot get pw_uid or gr_gid : %s", strerror(errno)); + unlink(WIGIG_ENTROPY_FILE); + return -1; + } + return 0; +} + +s32 wifi_qsap_start_wigig_softap(void) +{ + pid_t pid = 1; + + ALOGD("%s", __func__); + + if (wigigSoftApPid) { + ALOGE("Wigig SoftAP is already running"); + return eERR_START_SAP; + } + + if (wigig_ensure_entropy_file_exists() < 0) { + ALOGE("Wigig entropy file was not created"); + } + + if ((pid = fork()) < 0) { + ALOGE("fork failed (%s)", strerror(errno)); + return eERR_START_SAP; + } + + if (!pid) { + if (execl(HOSTAPD_BIN_FILE, HOSTAPD_BIN_FILE, + "-e", WIGIG_ENTROPY_FILE, "-dd", + WIGIG_HOSTAPD_CONF_FILE, (char *) NULL)) { + ALOGE("execl failed (%s)", strerror(errno)); + } + ALOGE("Wigig SoftAP failed to start. Exiting child process..."); + exit(-1); + } + + wigigSoftApPid = pid; + ALOGD("Wigig SoftAP started successfully"); + usleep(AP_BSS_START_DELAY); + + return eSUCCESS; +} + +s32 wifi_qsap_stop_wigig_softap(void) +{ + ALOGD("%s", __func__); + + if (wigigSoftApPid == 0) { + ALOGE("Wigig SoftAP is not running"); + return eSUCCESS; + } + + ALOGD("Stopping the Wigig SoftAP..."); + kill(wigigSoftApPid, SIGTERM); + waitpid(wigigSoftApPid, NULL, 0); + + wigigSoftApPid = 0; + ALOGD("Wigig SoftAP stopped successfully"); + usleep(AP_BSS_STOP_DELAY); + return eSUCCESS; +} diff --git a/qsap/qsap.h b/qsap/qsap.h new file mode 100644 index 0000000..caf8302 --- /dev/null +++ b/qsap/qsap.h @@ -0,0 +1,61 @@ +/* + * Copyright (c) 2010, The Linux Foundation. All rights reserved. + + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials provided + * with the distribution. + * * Neither the name of The Linux Foundation nor the names of its + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + + * THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS + * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR + * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, + * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE + * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN + * IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + + +#ifndef _QSAP_H +#define _QSAP_H + +#if __cplusplus +extern "C" { +#endif + +#include "qsap_api.h" + +s32 wifi_qsap_load_driver(void); +s32 wifi_qsap_unload_driver(void); +s32 wifi_qsap_stop_bss(void); +s32 commit(void); +s32 is_softap_enabled(void); +s32 wifi_qsap_start_softap(void); +s32 wifi_qsap_stop_softap(void); +s32 wifi_qsap_start_wigig_softap(void); +s32 wifi_qsap_stop_wigig_softap(void); +s32 wifi_qsap_reload_softap(void); +s32 wifi_qsap_unload_wifi_sta_driver(void); + +#ifdef QCOM_WLAN_CONCURRENCY +s32 wifi_qsap_start_softap_in_concurrency(void); +s32 wifi_qsap_stop_softap_in_concurrency(void); +#endif + +#if __cplusplus +}; // extern "C" +#endif + +#endif // _QSAP_H diff --git a/qsap/qsap_api.c b/qsap/qsap_api.c new file mode 100644 index 0000000..064e499 --- /dev/null +++ b/qsap/qsap_api.c @@ -0,0 +1,3666 @@ +/* + * Copyright (c) 2010-2013, The Linux Foundation. All rights reserved. + + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials provided + * with the distribution. + * * Neither the name of The Linux Foundation, Inc. nor the names of its + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + + * THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS + * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR + * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, + * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE + * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN + * IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "nl80211_copy.h" + +#include "qsap_api.h" +#include "qsap.h" + +#define QCSAP_IOCTL_GETPARAM (SIOCIWFIRSTPRIV+1) +#define WLAN_PRIV_SET_THREE_INT_GET_NONE (SIOCIWFIRSTPRIV + 4) +#define QCSAP_IOCTL_GET_CHANNEL (SIOCIWFIRSTPRIV+9) +#define QCSAP_IOCTL_ASSOC_STA_MACADDR (SIOCIWFIRSTPRIV+10) +#define QCSAP_IOCTL_DISASSOC_STA (SIOCIWFIRSTPRIV+11) +#define QCSAP_IOCTL_AP_STATS (SIOCIWFIRSTPRIV+12) +#define QCSAP_IOCTL_SET_CHANNEL_RANGE (SIOCIWFIRSTPRIV+17) +#define QCSAP_PARAM_GET_AUTO_CHANNEL 9 +#define WE_SET_SAP_CHANNELS 3 + +#define LOG_TAG "QCSDK" + +#include +#include + +#define SKIP_BLANK_SPACE(x) {while(*x != '\0') { if((*x == ' ') || (*x == '\t')) x++; else break; }} + +/** If this variable is enabled, the soft AP is reloaded, after the commit + * command is received */ +static volatile int gIniUpdated = 0; + +/** Supported command requests. + * WANRING: The enum eCMD_REQ in the file qsap_api.h should be + * updated if Cmd_req[], us updated + */ +s8 *Cmd_req[eCMD_REQ_LAST] = { + "get", + "set" +}; + +/** Supported config file requests. + * WANRING: The enum eConf_req in the file qsap_api.h should be + * updated if Conf_req[], us updated + */ +s8 *Conf_req[CONF_REQ_LAST] = { + "dual2g", + "dual5g", + "owe", + "60g", +}; + +/* + * WARNING: On updating the cmd_list, the enum esap_cmd in file + * qsap_api.h must be updates to reflect the changes + */ +static struct Command cmd_list[eCMD_LAST] = { + { "ssid", "QualcommSoftAP" }, + { "ignore_broadcast_ssid", "0" }, + { "channel", "1" }, + { "beacon_int", "100" }, + { "dtim_period", "2" }, + { "hw_mode", "n" }, + { "auth_algs", "3" }, + { "security_mode", "0" }, + { "wep_key0", NULL }, + { "wep_key1", NULL }, + { "wep_key2", NULL }, + { "wep_key3", NULL }, + { "wep_default_key", NULL }, + { "wpa_passphrase", NULL }, + { "wpa_pairwise", NULL }, + { "rsn_pairwise", NULL }, + { "mac_address", "00deadbeef04" }, + { "reset_ap", NULL }, + { "macaddr_acl", "0" }, + { "add_to_allow_list", NULL }, + { "add_to_deny_list", NULL }, + { "remove_from_allow_list", NULL }, + { "remove_from_deny_list", NULL }, + { "allow_list", "" }, + { "deny_list", "" }, + { "commit", NULL }, + { "enable_softap", NULL }, + { "disassoc_sta", NULL }, + { "reset_to_default", NULL }, + { "protection_flag", "1" }, + { "data_rate", "0" }, + { "sta_mac_list", NULL }, + { "tx_power", "27" }, + { "sdk_version", SDK_VERSION }, + { "wmm_enabled", "0" }, + + /** Warning: Do not change the order of the WPS commands */ + { "wps_state", "0" }, + { "config_methods", NULL }, + { "uuid", NULL }, + { "device_name", NULL }, + { "manufacturer", NULL }, + { "model_name", NULL }, + { "model_number", NULL }, + { "serial_number", NULL }, + { "device_type", NULL }, + { "os_version", NULL }, + { "friendly_name", NULL }, + { "manufacturer_url", NULL }, + { "model_description", NULL }, + { "model_url", NULL }, + { "upc", NULL }, + /************ WPS commands end *********/ + + { "fragm_threshold", NULL }, + { "rts_threshold", NULL }, + { "wpa_group_rekey", NULL }, + { "country_code", NULL }, + { "ap_isolate", NULL }, + { "ieee80211d", NULL }, + { "apstat", NULL }, + { "auto_shut_off_time", NULL }, + { "energy_detect_threshold", "128" }, + { "basic_rates", NULL }, + { "require_ht", NULL }, + { "ieee80211n", "1" }, + { "setchannelrange", NULL }, + { "autochannel", NULL }, + { "ieee80211w", NULL }, + { "wpa_key_mgmt", NULL }, + { "max_num_sta", "8" }, + { "ieee80211ac", NULL }, + { "vht_oper_chwidth", NULL }, + { "chanlist", NULL }, + { "ht_capab", NULL }, + { "ieee80211h", NULL }, + { "enable_wigig_softap", NULL }, + { "interface", NULL }, + { "ssid2", NULL }, + { "bridge", NULL }, + { "ctrl_interface", NULL }, + { "vendor_elements", NULL }, + { "assocresp_elements", NULL }, + { "acs_exclude_dfs", NULL }, + { "wowlan_triggers", "any" }, + { "accept_mac_file", NULL }, + { "deny_mac_file", NULL }, + { "owe_transition_ifname", NULL }, + { "sae_require_mfp", NULL }, + { "ieee80211ax", NULL }, + { "enable_edmg", NULL }, + { "edmg_channel", NULL }, + +}; + +struct Command qsap_str[eSTR_LAST] = { + { "wpa", NULL }, + { "accept_mac_file", NULL }, + { "deny_mac_file", NULL }, + { "gAPMacAddr", "00deadbeef04" },/** AP MAC address */ + { "gEnableApProt", "1" },/** protection flag in ini file */ + { "gFixedRate", "0" },/** Fixed rate in ini */ + { "gTxPowerCap", "27" },/** Tx power in ini */ + { "gFragmentationThreshold", "2346" },/** Fragmentation threshold in ini */ + { "RTSThreshold", "2347" },/** RTS threshold in ini */ + { "gAPCntryCode", "USI" },/** Country code in ini */ + { "gDisableIntraBssFwd", "0" },/** Intra-bss forward in ini */ + { "WmmIsEnabled", "0" },/** WMM */ + { "g11dSupportEnabled", "1" },/** 802.11d support */ + { "ieee80211n", NULL }, + { "ctrl_interface", NULL }, + { "interface", NULL }, + { "eap_server", NULL }, + { "gAPAutoShutOff", "0" }, + { "gEnablePhyAgcListenMode", "128" }, +}; + +/** Supported operating mode */ +char *hw_mode[HW_MODE_UNKNOWN] = { + "b", "g", "n", "g-only", "n-only", "a", "any", "ad" +}; + +/** configuration file path */ +char *pconffile = CONFIG_FILE; +char *fIni = WIFI_DRIVER_CONF_FILE; +s8 ini_file[PROPERTY_VALUE_MAX] = {0}; + +static int qsap_scnprintf(char *str, size_t size, const char *format, ...) +{ + va_list arg_ptr; + int ret = 0; + + if (size < 1) + return 0; + va_start(arg_ptr, format); + ret = vsnprintf(str, size, format, arg_ptr); + va_end(arg_ptr); + return (ret < (int)size) ? ret : (int)(size - 1); +} + +/** + * @brief + * For a give configuration parameter, read the configuration value from the file. + * @param pfile [IN] configuration file path + * @param pcmd [IN] pointer to the comand structure + * @param presp [OUT] buffer to store the configuration value + * @param plen [IN-OUT] The length of the buffer is provided as input. + * The length of the configuration parameter value, stored + * in the 'presp', is provided as the output + * @param ignore_comment [IN] if set, read the commented value also + * @return void +*/ +static s32 qsap_read_cfg(s8 *pfile, struct Command * pcmd, s8 *presp, u32 *plen, s8 *var, s32 ignore_comment) +{ + FILE *fcfg; + s8 buf[MAX_CONF_LINE_LEN]; + u16 len; + s8 *val; + + /** Open the configuration file */ + fcfg = fopen(pfile, "r"); + + if(NULL == fcfg) { + ALOGE("%s : unable to open file \n", __func__); + *plen = qsap_scnprintf(presp, *plen, "%s", ERR_RES_UNAVAILABLE); + return eERR_FILE_OPEN; + } + + /** Read the line from the configuration file */ + len = strlen(pcmd->name); + while(NULL != fgets(buf, MAX_CONF_LINE_LEN, fcfg)) { + s8 *pline = buf; + + if (strlen(buf) == 0) + continue; + + /** Skip the commented lines */ + if(buf[0] == '#') { + if (ignore_comment) { + pline++; + } + else continue; + } + + /** Identify the configuration parameter in the configuration file */ + if(!strncmp(pline, pcmd->name, len) && (pline[len] == '=')) { + int tmp_indx; + + /* Delate all \r \n combinations infront of the config string */ + tmp_indx = strlen(buf)-1; + while( (buf[tmp_indx] == '\r') || (buf[tmp_indx] == '\n') ) tmp_indx--; + + buf[tmp_indx+1] = '\0'; + + if ( NULL != var ) { + val = strchr(pline, '='); + if(NULL == val) + break; + *plen = qsap_scnprintf(presp, *plen, "%s %s%s", SUCCESS, var, val); + } + else { + *plen = qsap_scnprintf(presp, *plen, "%s %s", SUCCESS, pline); + } + fclose(fcfg); + return eSUCCESS; + } + } + +#if 0 + /** Configuration parameter is absent in the file */ + *plen = qsap_scnprintf(presp, *plen, "%s", ERR_FEATURE_NOT_ENABLED); +#else + /** Value not found in the configuration file */ + /** Send the default value, if we are reading from ini file */ + if ( pcmd->default_value ) { + *plen = qsap_scnprintf(presp, *plen, "%s %s=%s", SUCCESS, var?var:pcmd->name, pcmd->default_value); + fclose(fcfg); + return eSUCCESS; + } + else { + /** Configuration parameter is absent in the file */ + *plen = qsap_scnprintf(presp, *plen, "%s", ERR_FEATURE_NOT_ENABLED); + } +#endif + + fclose(fcfg); + + return eERR_CONFIG_PARAM_MISSING; +} + +/** + * @brief + * Write the configuration parameter value into the configuration file. + * @param pfile [IN] configuration file path. + * @param pcmd [IN] command name + * @param pVal [IN] configuration parameter to be written to the file. + * @param presp [OUT] buffer to store the configuration value. + * @param plen [IN-OUT] The length of the buffer is provided as input. + * The length of the configuration parameter value, stored + * in the 'presp', is provided as the output + * @return void +*/ +static s32 qsap_write_cfg(s8 *pfile, struct Command * pcmd, s8 *pVal, s8 *presp, u32 *plen, s32 inifile) +{ + FILE *fcfg, *ftmp; + s8 buf[MAX_CONF_LINE_LEN+1]; + s16 len, result = FALSE; + + ALOGD("cmd=%s, Val:%s, INI:%ld \n", pcmd->name, pVal, inifile); + + /** Open the configuration file */ + fcfg = fopen(pfile, "r"); + if(NULL == fcfg) { + ALOGE("%s : unable to open file \n", __func__); + *plen = qsap_scnprintf(presp, *plen, "%s", ERR_RES_UNAVAILABLE); + return eERR_FILE_OPEN; + } + + qsap_scnprintf(buf, sizeof(buf), "%s~", pfile); + + /** Open a temporary file */ + ftmp = fopen(buf, "w+"); + if(NULL == ftmp) { + ALOGE("%s : unable to open tmp file \n", __func__); + *plen = qsap_scnprintf(presp, *plen, "%s", ERR_RES_UNAVAILABLE); + fclose(fcfg); + return eERR_FILE_OPEN; + } + + /** Read the values from the configuration file */ + len = strlen(pcmd->name); + while(NULL != fgets(buf, MAX_CONF_LINE_LEN, fcfg)) { + s8 *pline = buf; + + /** commented line */ + if(buf[0] == '#') + pline++; + + /** Identify the configuration parameter to be updated */ + if((!strncmp(pline, pcmd->name, len)) && (result == FALSE)) { + if(pline[len] == '=') { + qsap_scnprintf(buf, sizeof(buf), "%s=%s\n", pcmd->name, pVal); + result = TRUE; + ALOGD("Updated:%s\n", buf); + } + } + + if(inifile && (!strncmp(pline, "END", 3))) + break; + + fprintf(ftmp, "%s", buf); + } + + if (result == FALSE) { + /* Configuration line not found */ + /* Add the new line at the end of file */ + qsap_scnprintf(buf, sizeof(buf), "%s=%s\n", pcmd->name, pVal); + fprintf(ftmp, "%s", buf); + ALOGD("Adding a new line in %s file: [%s] \n", inifile ? "inifile" : "hostapd.conf", buf); + } + + if(inifile) { + gIniUpdated = 1; + fprintf(ftmp, "END\n"); + while(NULL != fgets(buf, MAX_CONF_LINE_LEN, fcfg)) + fprintf(ftmp, "%s", buf); + } + + fclose(fcfg); + fclose(ftmp); + + qsap_scnprintf(buf, sizeof(buf), "%s~", pfile); + + /** Restore the updated configuration file */ + result = rename(buf, pfile); + + *plen = qsap_scnprintf(presp, *plen, "%s", (result == eERR_UNKNOWN) ? ERR_FEATURE_NOT_ENABLED : SUCCESS); + + /** Remove the temporary file. Dont care the return value */ + unlink(buf); + + /* chmod is needed because open() didn't set permisions properly */ + if (chmod(pfile, 0660) < 0) { + ALOGE("Error changing permissions of %s to 0660: %s", + pfile, strerror(errno)); + unlink(pfile); + return -1; + } + if(result == eERR_UNKNOWN) + return eERR_FEATURE_NOT_ENABLED; + + return eSUCCESS; +} + +/** + * @brief Read the security mode set in the configuration + * @param pfile [IN] configuration file path. + * @param presp [OUT] buffer to store the security mode. + * @param plen [IN-OUT] The length of the buffer is provided as input. + * The length of the security mode value, stored + * in the 'presp', is provided as the output + * @return void +*/ +static sec_mode_t qsap_read_security_mode(s8 *pfile, s8 *presp, u32 *plen) +{ + sec_mode_t mode; + u32 temp = *plen; + + /** Read the WEP default key */ + qsap_read_cfg(pfile, &cmd_list[eCMD_DEFAULT_KEY], presp, plen, NULL, GET_ENABLED_ONLY); + + if ( !strcmp(presp, ERR_FEATURE_NOT_ENABLED) ) { + *plen = temp; + + /* WEP, is not enabled */ + + /** Read WPA security status */ + qsap_read_cfg(pfile, &qsap_str[STR_WPA], presp, plen, NULL, GET_ENABLED_ONLY); + if ( !strcmp(presp, ERR_FEATURE_NOT_ENABLED) ) { + /** WPA is disabled, No security */ + mode = SEC_MODE_NONE; + } + else { + /** WPA, WPA2 or WPA-WPA2 mixed security */ + s8 * ptmp = presp; + while((*plen)-- && (*ptmp++ != '=') ); + mode = *plen ? ( + *ptmp == '1' ? SEC_MODE_WPA_PSK : + *ptmp == '2' ? SEC_MODE_WPA2_PSK : + *ptmp == '3' ? SEC_MODE_WPA_WPA2_PSK : SEC_MODE_INVALID ): SEC_MODE_INVALID; + } + } + else { + /** Verify if, WPA is disabled */ + *plen = temp; + qsap_read_cfg(pfile, &qsap_str[STR_WPA], presp, plen, NULL, GET_ENABLED_ONLY); + if ( !strcmp(presp, ERR_FEATURE_NOT_ENABLED) ) { + /** WPA is disabled, hence WEP is enabled */ + mode = SEC_MODE_WEP; + } + else { + *plen = qsap_scnprintf(presp, temp, "%s", ERR_UNKNOWN); + return SEC_MODE_INVALID; + } + } + + if(mode != SEC_MODE_INVALID) { + *plen = qsap_scnprintf(presp, temp,"%s %s=%d", SUCCESS, cmd_list[eCMD_SEC_MODE].name, mode); + } + else { + *plen = qsap_scnprintf(presp, temp,"%s", ERR_NOT_SUPPORTED); + } + + return mode; +} + +/** + * @brief + * Enable or disable a configuration parameter in the configuration file. + * @param pfile [IN] configuration file name + * @param pcmd [IN] configuration command structure + * @param status [IN] status to be set. The valid values are 'ENABLE' or 'DISABLE' + * @return On success, return 0 + * On failure, return -1 +*/ +static s32 qsap_change_cfg(s8 *pfile, struct Command * pcmd, u32 status) +{ + FILE *fcfg, *ftmp; + s8 buf[MAX_CONF_LINE_LEN+1]; + u16 len; + + /** Open the configuartion file */ + fcfg = fopen(pfile, "r"); + if(NULL == fcfg) { + ALOGE("%s : unable to open file \n", __func__); + return eERR_UNKNOWN; + } + + qsap_scnprintf(buf, sizeof(buf), "%s~", pfile); + + /** Open a temporary file */ + ftmp = fopen(buf, "w"); + if(NULL == ftmp) { + ALOGE("%s : unable to open tmp file \n", __func__); + fclose(fcfg); + return eERR_UNKNOWN; + } + + /** Read the configuration parameters from the configuration file */ + len = strlen(pcmd->name); + while(NULL != fgets(buf+1, MAX_CONF_LINE_LEN, fcfg)) { + s8 *p = buf+1; + + /** Commented line */ + if(p[0] == '#') + p++; + + /** Identify the configuration parameter */ + if(!strncmp(p, pcmd->name, len)) { + if(p[len] == '=') { + if(status == DISABLE) { + fprintf(ftmp, "#%s", p); + } + else { + fprintf(ftmp, "%s", p); + } + continue; + } + } + fprintf(ftmp, "%s", buf+1); + } + + fclose(fcfg); + fclose(ftmp); + + qsap_scnprintf(buf, sizeof(buf), "%s~", pfile); + + /** Restore the new configuration file */ + if(eERR_UNKNOWN == rename(buf, pfile)) { + ALOGE("unable to rename the file \n"); + return eERR_UNKNOWN; + } + + /** Delete the temporary file */ + unlink(buf); + + /* chmod is needed because open() didn't set permisions properly */ + if (chmod(pfile, 0660) < 0) { + ALOGE("Error changing permissions of %s to 0660: %s", + pfile, strerror(errno)); + unlink(pfile); + return -1; + } + return 0; +} + +/** + * @brief + * Set the security mode in the configuration. The security mode + * can be : + * 1. No security + * 2. WEP + * 3. WPA + * 4. WPA2 + * 5. WPA and WPA2 mixed mode + * @param pfile [IN] configuration file name + * @param sec_mode [IN] security mode to be set + * @param presp [OUTPUT] presp The command output format : + * On success, + * success = + * On failure, + * failure + * @param plen [IN-OUT] plen + * [IN] The length of the buffer, presp + * [OUT] The length of the response in the buffer, presp + * @return void +*/ +static void qsap_set_security_mode(s8 *pfile, u32 sec_mode, s8 *presp, u32 *plen) +{ + s16 wep, wpa; + s8 sec[MAX_INT_STR]; + s32 rsn_status = DISABLE; + s32 ret = eERR_UNKNOWN; + + /** Is valid security mode ? */ + if(sec_mode >= SEC_MODE_INVALID) { + *plen = qsap_scnprintf(presp, *plen, "%s", ERR_UNKNOWN); + return; + } + + /** No security */ + if(SEC_MODE_NONE == sec_mode) { + wep = DISABLE; + wpa = DISABLE; + } + /** WEP security */ + else if(SEC_MODE_WEP == sec_mode) { + wep = ENABLE; + wpa = DISABLE; + } + else { + /** WPA, WPA2 and mixed-mode security */ + u16 wpa_val; + u32 tmp = *plen; + + wep = DISABLE; + wpa = ENABLE; + + if(sec_mode == SEC_MODE_WPA_PSK) + wpa_val = WPA_IN_CONF_FILE; + + else if(sec_mode == SEC_MODE_WPA2_PSK) { + wpa_val = WPA2_IN_CONF_FILE; + rsn_status = ENABLE; + } + + else if(sec_mode == SEC_MODE_WPA_WPA2_PSK) { + wpa_val = WPA_WPA2_IN_CONF_FILE; + rsn_status = ENABLE; + } + + qsap_scnprintf(sec, sizeof(sec), "%u", wpa_val); + qsap_write_cfg(pfile, &qsap_str[STR_WPA], sec, presp, plen, HOSTAPD_CONF_QCOM_FILE); + *plen = tmp; + } + + /** The configuration parameters for the security to be set are enabled + * and the configuration parameters for the other security types are + * disabled in the configuration file + */ + if(eERR_UNKNOWN == qsap_change_cfg(pfile, &cmd_list[eCMD_DEFAULT_KEY], wep)) { + ALOGE("%s: wep_default_key error\n", __func__); + goto end; + } + + if(eERR_UNKNOWN == qsap_change_cfg(pfile, &cmd_list[eCMD_WEP_KEY0], wep)) { + ALOGE("%s: CMD_WEP_KEY0 \n", __func__); + goto end; + } + + if(eERR_UNKNOWN == qsap_change_cfg(pfile, &cmd_list[eCMD_WEP_KEY1], wep)) { + ALOGE("%s: CMD_WEP_KEY1 \n", __func__); + goto end; + } + + if(eERR_UNKNOWN == qsap_change_cfg(pfile, &cmd_list[eCMD_WEP_KEY2], wep)) { + ALOGE("%s: CMD_WEP_KEY2 \n", __func__); + goto end; + } + + if(eERR_UNKNOWN == qsap_change_cfg(pfile, &cmd_list[eCMD_WEP_KEY3], wep)) { + ALOGE("%s: CMD_WEP_KEY3 \n", __func__); + goto end; + } + + if(eERR_UNKNOWN == qsap_change_cfg(pfile, &cmd_list[eCMD_PASSPHRASE], wpa)) { + ALOGE("%s: Passphrase error\n", __func__); + goto end; + } + + if((sec_mode != SEC_MODE_NONE) && (sec_mode != SEC_MODE_WEP)) { + u32 state = !rsn_status; + + if(sec_mode == SEC_MODE_WPA_WPA2_PSK) state = ENABLE; + + if(eERR_UNKNOWN == qsap_change_cfg(pfile, &cmd_list[eCMD_WPA_PAIRWISE], state)) { + ALOGE("%s: WPA Pairwise\n", __func__); + goto end; + } + } + + if(eERR_UNKNOWN == qsap_change_cfg(pfile, &cmd_list[eCMD_RSN_PAIRWISE], rsn_status)) { + ALOGE("%s: WPA2 Pairwise\n", __func__); + goto end; + } + + if(eERR_UNKNOWN == qsap_change_cfg(pfile, &qsap_str[STR_WPA], wpa)) { + ALOGE("%s: WPA\n", __func__); + goto end; + } + + ret = eSUCCESS; + +end: + *plen = qsap_scnprintf(presp, *plen, "%s", (ret == eSUCCESS) ? SUCCESS : ERR_UNKNOWN); + + return; +} + +/** + * @brief + * Get the file path having the allow or deny MAC address list + * @param pcfgfile [IN] configuration file name + * @param pcmd [IN] pcmd pointer to the command string + * @param pfile [OUT] buffer to store the return value, containing the file name + * or the error message. + * @param plen [IN-OUT] size of the buffer 'pfile', is provided as input and + * the length of the file name is returned as output + * @return + * On success, a pointer to the file name in the buffer 'pfile'. + * On failure, NULL is returned +*/ +static s8 *qsap_get_allow_deny_file_name(s8 *pcfgfile, struct Command * pcmd, s8 *pfile, u32 *plen) +{ + if(eSUCCESS == qsap_read_cfg(pcfgfile, pcmd, pfile, plen, NULL, GET_ENABLED_ONLY)) { + return strchr(pfile, '=') + 1; + } + + return NULL; +} + +int qsap_hostd_exec(int argc, char ** argv) { + +#define MAX_CMD_SIZE 256 + char qcCmdBuf[MAX_CMD_SIZE], *pCmdBuf; + u32 len = MAX_CMD_SIZE; + int i = 2, ret; + + if ( argc < 4 ) { + ALOGD("failure: invalid arguments"); + return -1; + } + + argc -= 2; + pCmdBuf = qcCmdBuf; + + while (argc--) { + ret = snprintf(pCmdBuf, len, " %s", argv[i]); + if ((ret < 0) || (ret >= (int)len)) { + /* Error case */ + /* TODO: Command too long send the error message */ + *pCmdBuf = '\0'; + break; + } + ALOGD("argv[%d] (%s)",i, argv[i]); + pCmdBuf += ret; + len -= ret; + i++; + } + + ALOGD("QCCMD data (%s)", pCmdBuf); + len = MAX_CMD_SIZE; + qsap_hostd_exec_cmd(qcCmdBuf, qcCmdBuf, (u32*)&len); + return 0; +} +/** Function to identify a valid MAC address */ +static int isValid_MAC_address(char *pMac) +{ + int i, len; + + len = strlen(pMac); + + if(len < MAC_ADDR_LEN) + return FALSE; + + for(i=0; i= MAX_ALLOWED_MAC) { + ALOGE("%s : File is full\n", __func__); + *plen = qsap_scnprintf(presp, *plen, "%s", ERR_UNKNOWN); + fclose(fp); + return; + } + + /** Update all the input MAC addresses into the MAC list file */ + len = strlen(pVal); + while(len > 0) { + int i = 0; + + /** Get a MAC address from the input string */ + while((*pVal != ' ' ) && (*pVal != '\0')) { + macbuf[i] = *pVal; + i++; + pVal++; + + if(i == MAC_ADDR_LEN) + break; + } + macbuf[i] = '\0'; + pVal++; + + /** Is valid MAC address input ? */ + if(TRUE == isValid_MAC_address(macbuf)) { + + /** Append the MAC address to the file */ + fprintf(fp, "%s\n", macbuf); + num_macs++; + + /** Evaluate with the allowed limit */ + if(num_macs == MAX_ALLOWED_MAC) { + ALOGE("MAC file is full now.... \n"); + break; + } + + } + len -= strlen(macbuf); + if(*pVal != '\0') + len--; + } + + fclose(fp); + + *plen = qsap_scnprintf(presp, *plen, "%s", SUCCESS); + + return; +} + +/** + * @brief + * Remove one or more MAC addresses from the allow or deny MAC list file. + * @param pfile [IN] path of the allow or deny list file. + * @param pVal [IN] a list of MAC addresses to be removed from the MAC list file. + * @param presp [OUT] the buffer to store the response + * @param plen [IN-OUT] The length of the 'presp' buffer is provided as input. + * The lenght of the response, stored in 'presp', is + * provided as output + * @return void +*/ +static void qsap_remove_from_file(s8 *pfile, s8 *pVal, s8 *presp, u32 *plen) +{ + FILE *fp; + FILE *ftmp; + s8 buf[MAX_CONF_LINE_LEN]; + int status; + + /** Open the allow or deny MAC list file */ + fp = fopen(pfile, "r+"); + + if(NULL == fp) { + ALOGE("%s : unable to open the file \n", __func__); + *plen = qsap_scnprintf(presp, *plen, "%s", ERR_RES_UNAVAILABLE); + return; + } + + qsap_scnprintf(buf, sizeof(buf), "%s~", pfile); + + /** Open a temporary file */ + ftmp = fopen(buf, "w"); + + if(ftmp == NULL) { + ALOGE("%s : unable to open the file \n", __func__); + *plen = qsap_scnprintf(presp, *plen, "%s", ERR_RES_UNAVAILABLE); + fclose(fp); + return; + } + + /** Read all the MAC addresses from the file */ + while(NULL != fgets(buf, MAX_CONF_LINE_LEN, fp)) { + s8 *plist; + s32 slen; + int write_back = 1; + + plist = pVal; + slen = strlen(pVal); + + /** Compare each MAC address in the file with all the + * input MAC addresses */ + write_back = 1; + while(slen > 0) { + + if(0 == strncmp(buf, plist, MAC_ADDR_LEN)) { + write_back = 0; + break; + } + + while((*plist != ' ') && (*plist != '\0')) { + plist++; + slen--; + } + + while(((*plist == ' ') || (*plist == '\t')) && (*plist != '\0')) { + plist++; slen--; + } + } + + /** Update the file */ + if(write_back) { + fprintf(ftmp, "%s", buf); + } + } + + fclose(fp); + fclose(ftmp); + + qsap_scnprintf(buf, sizeof(buf), "%s~", pfile); + + /** Restore the configuration file */ + status = rename(buf, pfile); + + qsap_scnprintf(presp, *plen, "%s", (status == eERR_UNKNOWN) ? ERR_FEATURE_NOT_ENABLED : SUCCESS); + + unlink(buf); + + return; +} + +/** + * @brief + * Identify the MAC list file and the type of updation on the file. + * The MAC list file can be : Allow file or Deny file. + * The type of operation is : Add to file or Delete from file + * + * @param file [IN] path of the allow or deny MAC list file. + * @param cNum [IN] command number to 'type of file' and the 'type of updation' + * to be done. + * @param pVal [IN] A list of one or more MAC addresses. Multiple MAC addresses + * are separated by a SPACE character + * @param presp [OUT] Buffer to store the command response + * @param plen [IN-OUT] The length of the 'presp' buffer is provided as input + * The length of the response, stored in the 'presp' is provided + * as the output + * @return void +*/ +static void qsap_update_mac_list(s8 *pfile, esap_cmd_t cNum, s8 *pVal, s8 *presp, u32 *plen) +{ + ALOGD("%s : Updating file %s \n", __func__, pfile); + + switch(cNum) { + case eCMD_ADD_TO_ALLOW: + case eCMD_ADD_TO_DENY: + qsap_add_mac_to_file(pfile, pVal, presp, plen); + break; + + case eCMD_REMOVE_FROM_ALLOW: + case eCMD_REMOVE_FROM_DENY: + qsap_remove_from_file(pfile, pVal, presp, plen); + break; + + default: + *plen = qsap_scnprintf(presp, *plen, "%s", ERR_UNKNOWN); + return; + } + + return; +} + +/** + * @brief + * @param fconfig [INPUT] configuration file name + * @param cNum [INPUT] command number. The valid command numbers supported by + * this function are : + * eCMD_ALLOW_LIST - Get the MAC address list from the allow list + * eCMD_DENY_LIST - Get the MAC address list from the deny list + * @param presp [OUTPUT] presp The command output format : + * On success, + * success = + * On failure, + * failure + * @param plen [IN-OUT] plen + * [IN] The length of the buffer, presp + * [OUT] The length of the response in the buffer, presp + * @return void +**/ +static void qsap_get_mac_list(s8 *fconfile, esap_cmd_t cNum, s8 *presp, u32 *plen) +{ + s8 buf[MAX_CONF_LINE_LEN]; + FILE *fp; + u32 len_remain; + s8 *pfile, *pOut; + esap_cmd_t sNum; + int cnt = 0; + + /** Identify the allow or deny file */ + if(eCMD_ALLOW_LIST == cNum) { + sNum = STR_ACCEPT_MAC_FILE; + } + else if(eCMD_DENY_LIST == cNum) { + sNum = STR_DENY_MAC_FILE; + } + else { + *plen = qsap_scnprintf(presp, *plen, "%s", ERR_UNKNOWN); + return; + } + + /** Get the MAC allow or MAC deny file path */ + len_remain = MAX_CONF_LINE_LEN; + if(NULL == (pfile = qsap_get_allow_deny_file_name(fconfile, &qsap_str[sNum], buf, &len_remain))) { + ALOGE("%s:Unknown error\n", __func__); + *plen = qsap_scnprintf(presp, *plen, "%s", ERR_RES_UNAVAILABLE); + return; + } + + /** Open allow / deny file, and read the MAC addresses */ + fp = fopen(pfile, "r"); + if(NULL == fp) { + ALOGE("%s: file open error\n",__func__); + *plen = qsap_scnprintf(presp, *plen, "%s", ERR_RES_UNAVAILABLE); + return; + } + + *plen -= qsap_scnprintf(presp, *plen, "%s %s=", SUCCESS, cmd_list[cNum].name); + + pOut = presp + strlen(presp); + + /** Read the MAC address from the MAC allow or deny file */ + while(NULL != (fgets(buf, MAX_CONF_LINE_LEN, fp))) { + u32 len; + + /** Avoid the commented lines */ + if(buf[0] == '#') + continue; + + if(FALSE == isValid_MAC_address(buf)) + continue; + + buf[strlen(buf)-1] = '\0'; + + if(*plen < strlen(buf)) { + *pOut = '\0'; + break; + } + + len = qsap_scnprintf(pOut, *plen, "%s ", buf); + cnt++; + + if (cnt >= MAX_ALLOWED_MAC) { + break; + } + + pOut += len; + *plen -= len; + } + + *plen = strlen(presp); + + fclose(fp); + + return; +} + +static int qsap_read_mac_address(s8 *presp, u32 *plen) +{ + char *ptr; + char mac[MAC_ADDR_LEN]; + u32 len, i; + int nRet = eERR_INVALID_MAC_ADDR; + + len = *plen; + + if(eSUCCESS != qsap_read_cfg(fIni, &qsap_str[STR_MAC_IN_INI], presp, plen, cmd_list[eCMD_MAC_ADDR].name, GET_ENABLED_ONLY)) { + ALOGE("%s :MAC addr read failure \n",__func__); + goto end; + } + + ptr = strchr(presp, '='); + if(NULL == ptr) + goto end; + + strlcpy(mac, ptr+1, MAC_ADDR_LEN); + *plen = qsap_scnprintf(presp, len, "%s %s=", SUCCESS, cmd_list[eCMD_MAC_ADDR].name); + ptr = presp + strlen(presp); + len -= strlen(presp); /* decrease the total available buf length */ + + for(i=0; iname); + } + } + + return ptr; +} + +static void qsap_read_wps_state(s8 *presp, u32 *plen) +{ + u32 tlen = *plen; + s32 status; + s8 *pstate; + + if(NULL == (pstate = qsap_get_config_value(pconffile, &cmd_list[eCMD_WPS_STATE], presp, &tlen))) { + /** unable to read the wps configuration, WPS is disabled !*/ + ALOGD("%s :wps_state not in cfg file \n", __func__); + status = DISABLE; + } + else { + status = (atoi(pstate) == WPS_STATE_ENABLE) ? ENABLE : DISABLE; + } + + *plen = qsap_scnprintf(presp, *plen, "success %s=%ld", cmd_list[eCMD_WPS_STATE].name, status); + + return; +} + +/** + * Get the channel being used in the soft AP. + */ +int qsap_get_operating_channel(s32 *pchan) +{ + int sock; + struct iwreq wrq; + s8 interface[MAX_CONF_LINE_LEN]; + u32 len = MAX_CONF_LINE_LEN; + s8 *pif; + int ret; + + if(ENABLE != is_softap_enabled()) { + goto error; + } + + if(NULL == (pif = qsap_get_config_value(pconffile, &qsap_str[STR_INTERFACE], interface, &len))) { + ALOGE("%s :interface error \n", __func__); + goto error; + } + + interface[len] = '\0'; + + sock = socket(AF_INET, SOCK_DGRAM, 0); + if(sock < 0) { + ALOGE("%s :socket error \n", __func__); + goto error; + } + + *pchan = 0; + + strlcpy(wrq.ifr_name, pif, sizeof(wrq.ifr_name)); + wrq.u.data.length = sizeof(s32); + wrq.u.data.pointer = pchan; + wrq.u.data.flags = 0; + + ret = ioctl(sock, QCSAP_IOCTL_GET_CHANNEL, &wrq); + if(ret < 0) { + ALOGE("%s: ioctl failure \n",__func__); + close(sock); + goto error; + } + + ALOGE("Recv len :%d \n", wrq.u.data.length); + *pchan = *(int *)(&wrq.u.name[0]); + ALOGE("Operating channel :%ld \n", *pchan); + close(sock); + return eSUCCESS; + +error: + *pchan = 0; + ALOGE("%s: Failed to read channel \n", __func__); + return eERR_CHAN_READ; +} + +/** + * Get the sap auto channel selection for soft AP. + */ +int qsap_get_sap_auto_channel_selection(s32 *pautochan) +{ + int sock; + struct iwreq wrq; + s8 interface[MAX_CONF_LINE_LEN]; + u32 len = MAX_CONF_LINE_LEN; + s8 *pif; + int ret; + sap_auto_channel_info sap_autochan_info; + s32 *pchan; + + if(ENABLE != is_softap_enabled()) { + ALOGE("%s :is_softap_enabled() goto error \n", __func__); + goto error; + } + + if(NULL == (pif = qsap_get_config_value(pconffile, + &qsap_str[STR_INTERFACE], interface, &len))) { + ALOGD("%s :interface error \n", __func__); + goto error; + } + + interface[len] = '\0'; + + sock = socket(AF_INET, SOCK_DGRAM, 0); + if(sock < 0) { + ALOGD("%s :socket error \n", __func__); + goto error; + } + + *pautochan = 0; + + memset(&sap_autochan_info, 0, sizeof(sap_autochan_info)); + memset(&wrq, 0, sizeof(wrq)); + + strlcpy(wrq.ifr_name, pif, sizeof(wrq.ifr_name)); + wrq.u.data.length = sizeof(s32); + sap_autochan_info.subioctl = QCSAP_PARAM_GET_AUTO_CHANNEL; + wrq.u.data.pointer = pautochan; + memcpy(wrq.u.name, (char *)(&sap_autochan_info), sizeof(sap_autochan_info)); + wrq.u.data.flags = 0; + + ret = ioctl(sock, QCSAP_IOCTL_GETPARAM, &wrq); + if(ret < 0) { + ALOGE("%s: ioctl failure \n",__func__); + close(sock); + goto error; + } + + ALOGD("Recv len :%d \n", wrq.u.data.length); + *pautochan = *(int *)(&wrq.u.name[0]); + ALOGD("Sap auto channel selection pautochan=%ld \n", *pautochan); + close(sock); + return eSUCCESS; + +error: + *pautochan = 0; + ALOGE("%s: Failed to read sap auto channel selection\n", __func__); + return eERR_GET_AUTO_CHAN; +} + + +static int iftypeCallback(struct nl_msg* msg, void* arg) +{ + struct nlmsghdr* ret_hdr = nlmsg_hdr(msg); + struct nlattr *tb_msg[NL80211_ATTR_MAX + 1]; + int* type = arg; + + struct genlmsghdr *gnlh = (struct genlmsghdr*) nlmsg_data(ret_hdr); + + nla_parse(tb_msg, NL80211_ATTR_MAX, genlmsg_attrdata(gnlh, 0), + genlmsg_attrlen(gnlh, 0), NULL); + + if (tb_msg[NL80211_ATTR_IFTYPE]) { + *type = nla_get_u32(tb_msg[NL80211_ATTR_IFTYPE]); + + } + return NL_SKIP; +} + +/** + * Get the mode of operation. + */ +int qsap_get_mode(s32 *pmode) +{ + int ret = eERR_UNKNOWN; + struct nl_sock* sk = NULL; + int nl80211_id = -1; + int if_type = -1; + s8 interface[MAX_CONF_LINE_LEN]; + u32 len = MAX_CONF_LINE_LEN; + s8 *pif; + struct nl_msg* msg = NULL; + + //get interface name + if(NULL == (pif = qsap_get_config_value(pconffile, + &qsap_str[STR_INTERFACE], interface, &len))) { + ALOGD("%s :interface error \n", __func__); + goto nla_put_failure; + } + + interface[len] = '\0'; + + //allocate socket + sk = nl_socket_alloc(); + + //return if socket allocation fails + if(sk == NULL){ + ALOGE( "socket allocation failure"); + return ret; + } + + //connect to generic netlink + if (genl_connect(sk)) { + ALOGE( "Netlink socket Connection failure"); + ret = eERR_UNKNOWN; + goto nla_put_failure; + } + + //find the nl80211 driver ID + nl80211_id = genl_ctrl_resolve(sk, "nl80211"); + + //attach a callback + nl_socket_modify_cb(sk, NL_CB_VALID, NL_CB_CUSTOM, + iftypeCallback, &if_type); + + //allocate a message + msg = nlmsg_alloc(); + + //return if message allocation fails + if(msg == NULL){ + ALOGE( "message allocation failure"); + goto nla_put_failure; + } + + // setup the message + genlmsg_put(msg, 0, 0, nl80211_id, 0, 0, NL80211_CMD_GET_INTERFACE, 0); + + //add message attributes + NLA_PUT_U32(msg, NL80211_ATTR_IFINDEX, if_nametoindex(pif)); + + // Send the message + ret = nl_send_auto_complete(sk, msg); + if (ret < 0 ) { + ALOGE( "nl_send_auto_complete failure"); + ret = eERR_UNKNOWN; + goto nla_put_failure; + } + + //block for message to return + nl_recvmsgs_default(sk); + *pmode = if_type; + ALOGI("%s: (%s) NL80211 Get Mode = %d \n",__func__, pif, (int)*pmode); + ret = eSUCCESS; + +nla_put_failure: + if (sk) + nl_socket_free(sk); + if (msg) + nlmsg_free(msg); + return ret; +} + +/** + * Set the channel Range for soft AP. + */ +int qsap_set_channel_range(s8 *buf) +{ + int sock; + struct iwreq wrq; + s8 interface[MAX_CONF_LINE_LEN]; + u32 len = MAX_CONF_LINE_LEN; + s8 *pif; + s8 *temp; + int ret, i; + sap_channel_info sap_chan_range; + sta_channel_info sta_chan_range; + + ALOGE("buf :%s\n", buf); + + temp = buf; + temp = strchr(buf, '='); + if (NULL == temp) { + goto error; + } + temp++; + + if (NULL == (pif = qsap_get_config_value(pconffile, + &qsap_str[STR_INTERFACE], interface, &len))) { + ALOGE("%s :interface error\n", __func__); + goto error; + } + + interface[len] = '\0'; + + sock = socket(AF_INET, SOCK_DGRAM, 0); + if (sock < 0) { + ALOGE("%s :socket error\n", __func__); + goto error; + } + + memset(&sap_chan_range, 0, sizeof(sap_chan_range)); + memset(&sta_chan_range, 0, sizeof(sta_chan_range)); + memset(&wrq, 0, sizeof(wrq)); + + if (ENABLE != is_softap_enabled()) { + strlcpy(wrq.ifr_name, "wlan0", sizeof(wrq.ifr_name)); + sta_chan_range.subioctl = WE_SET_SAP_CHANNELS; + ret = sscanf(temp, "%d %d %d", &(sta_chan_range.stastartchan), + &(sta_chan_range.staendchan), &(sta_chan_range.staband)); + if (3 != ret) { + ALOGE("%s : sscanf is not successful\n", __func__); + close(sock); + goto error; + } + memcpy(wrq.u.name, (char *)(&sta_chan_range), sizeof(sta_chan_range)); + + ALOGE("%s :Softap is off,Send SET_CHANNEL_RANGE over sta interface\n", + __func__); + ret = ioctl(sock, WLAN_PRIV_SET_THREE_INT_GET_NONE, &wrq); + } else { + strlcpy(wrq.ifr_name, pif, sizeof(wrq.ifr_name)); + ret = sscanf(temp, "%d %d %d", &(sap_chan_range.startchan), + &(sap_chan_range.endchan), &(sap_chan_range.band)); + if (3 != ret) { + ALOGE("%s : sscanf is not successful\n", __func__); + close(sock); + goto error; + } + memcpy(wrq.u.name, (char *)(&sap_chan_range), sizeof(sap_chan_range)); + + ALOGE("%s :SAP is on,Send SET_CHANNEL_RANGE over softap interface\n", + __func__); + ret = ioctl(sock, QCSAP_IOCTL_SET_CHANNEL_RANGE, &wrq); + } + + if (ret < 0) { + ALOGE("%s: ioctl failure\n", __func__); + close(sock); + goto error; + } + + ALOGE("Recv len :%d\n", wrq.u.data.length); + + close(sock); + return eSUCCESS; + +error: + ALOGE("%s: Failed to set channel range\n", __func__); + return eERR_SET_CHAN_RANGE; +} + +int qsap_read_channel(s8 *pfile, struct Command *pcmd, s8 *presp, u32 *plen, s8 *pvar) +{ + s8 *pval; + s32 chan; + u32 len = *plen; + + if(eSUCCESS == qsap_get_operating_channel(&chan)) { + *plen = qsap_scnprintf(presp, len, "%s %s=%lu", SUCCESS, pcmd->name, chan); + ALOGD("presp :%s\n", presp); + } else { + *plen = qsap_scnprintf(presp, len, "%s", ERR_UNKNOWN); + } + + return eSUCCESS; +} + +int qsap_read_auto_channel(struct Command *pcmd, s8 *presp, u32 *plen) +{ + s8 *pval, *pautoval; + s32 pautochan; + u32 len = *plen; + int autochan; + + ALOGE("%s :\n", __func__); + + if (eSUCCESS == qsap_get_sap_auto_channel_selection(&pautochan)) { + *plen = qsap_scnprintf(presp, len, "%s autochannel=%lu", SUCCESS, pautochan); + ALOGE("presp :%s\n", presp); + } else { + *plen = qsap_scnprintf(presp, len, "%s", ERR_UNKNOWN); + } + + return eSUCCESS; +} + +static int qsap_mac_to_macstr(s8 *pmac, u32 slen, s8 *pmstr, u32 *plen) +{ + int len; + int totlen = 0; + + while((slen > 0) && (*plen > 0)) { + len = qsap_scnprintf(pmstr, *plen, "%.2X:%.2X:%.2X:%.2X:%.2X:%.2X ", (int)pmac[0], (int)pmac[1], (int)pmac[2], + (int)pmac[3], (int)pmac[4], (int)pmac[5]); + pmac += 6; + slen -= 6; + *plen -= len; + pmstr += len; + totlen += len; + } + + if(totlen > 0) { + *pmstr--; + totlen--; + } + *pmstr = '\0'; + *plen = totlen; + + return 0; +} + +#define MAX_STA_ALLOWED 8 +void qsap_get_associated_sta_mac(s8 *presp, u32 *plen) +{ + int sock, ret; + struct iwreq wrq; + s8 interface[MAX_CONF_LINE_LEN]; + u32 len = MAX_CONF_LINE_LEN; + s8 *pif; + s8 *pbuf, *pout; + u32 buflen; + u32 recvLen; + u32 tlen; + + if(ENABLE != is_softap_enabled()) { + goto error; + } + + if(NULL == (pif = qsap_get_config_value(pconffile, &qsap_str[STR_INTERFACE], interface, &len))) { + ALOGE("%s :interface error \n", __func__); + goto error; + } + interface[len] = '\0'; + + sock = socket(AF_INET, SOCK_DGRAM, 0); + if(sock < 0) { + ALOGE("%s :socket failure \n", __func__); + goto error; + } + + /* response has length field + 6 bytes per STA */ + buflen = sizeof(u32) + (MAX_STA_ALLOWED * 6); + pbuf = (s8 *)malloc(buflen); + if(NULL == pbuf) { + ALOGE("%s :No memory \n", __func__); + close(sock); + goto error; + } + + +#define SIZE_OF_MAC_INT (6) + strlcpy(wrq.ifr_name, pif, sizeof(wrq.ifr_name)); + wrq.u.data.length = buflen; + wrq.u.data.pointer = (void *)pbuf; + wrq.u.data.flags = 0; + + ret = ioctl(sock, QCSAP_IOCTL_ASSOC_STA_MACADDR, &wrq); + if(ret < 0) { + ALOGE("%s :ioctl failure \n", __func__); + free(pbuf); + close(sock); + goto error; + } + + recvLen = *(u32 *)(wrq.u.data.pointer); + recvLen -= sizeof(u32); + + len = qsap_scnprintf(presp, *plen, "%s %s=", SUCCESS, cmd_list[eCMD_ASSOC_STA_MACS].name); + pout = presp + len; + tlen = *plen - len; + + qsap_mac_to_macstr(pbuf+sizeof(u32), recvLen, pout, &tlen); + + *plen = len + tlen; + + free(pbuf); + close(sock); + + return; +error: + *plen = qsap_scnprintf(presp, *plen, "%s", ERR_UNKNOWN); + + return; +} + +static void qsap_read_wep_key(s8 *pfile, struct Command *pcmd, s8 *presp, u32 *plen, s8 *var) +{ + s8 *pwep; + s8 *pkey; + + if(eSUCCESS != qsap_read_cfg(pfile, pcmd, presp, plen, var, GET_COMMENTED_VALUE)) + return; + + pwep = strchr(presp, '='); + if(NULL == pwep) + return; + pwep++; + + if(pwep[0] == '"') { + pkey = pwep; + pwep++; + + while(*pwep != '\0') { + *pkey = *pwep; + pkey++; + pwep++; + } + *pkey--; + *pkey = '\0'; + *plen -= 2; + } + + return; +} + +void qsap_read_ap_stats(s8 *presp, u32 *plen) +{ + int sock, ret; + struct iwreq wrq; + s8 interface[MAX_CONF_LINE_LEN]; + u32 len = MAX_CONF_LINE_LEN; + s8 *pif; + s8 *pbuf, *pout; + u32 tlen; + + if(ENABLE != is_softap_enabled()) { + *plen = qsap_scnprintf(presp, *plen, "%s", ERR_SOFTAP_NOT_STARTED); + return; + } + + if(NULL == (pif = qsap_get_config_value(pconffile, &qsap_str[STR_INTERFACE], interface, &len))) { + ALOGE("%s :interface error \n", __func__); + goto error; + } + interface[len] = '\0'; + + sock = socket(AF_INET, SOCK_DGRAM, 0); + if(sock < 0) { + ALOGE("%s :socket failure \n", __func__); + goto error; + } + + pbuf = (s8 *)malloc(MAX_RESP_LEN); + if(NULL == pbuf) { + ALOGE("%s :No memory \n", __func__); + close(sock); + goto error; + } + + strlcpy(wrq.ifr_name, pif, sizeof(wrq.ifr_name)); + wrq.u.data.length = MAX_RESP_LEN; + wrq.u.data.pointer = (void *)pbuf; + wrq.u.data.flags = 0; + + ret = ioctl(sock, QCSAP_IOCTL_AP_STATS, &wrq); + if(ret < 0) { + ALOGE("%s :ioctl failure \n", __func__); + free(pbuf); + close(sock); + goto error; + } + + *plen = qsap_scnprintf(presp, *plen, "%s %s=%s", SUCCESS, cmd_list[eCMD_AP_STATISTICS].name, pbuf); + + free(pbuf); + close(sock); + return; + +error: + *plen = qsap_scnprintf(presp, *plen, "%s", ERR_UNKNOWN); + + return; +} + +void qsap_read_autoshutoff(s8 *presp, u32 *plen) +{ + u32 tlen, time = 0; + s8 *ptime; + + tlen = *plen; + + if(NULL == (ptime = qsap_get_config_value(fIni, &qsap_str[STR_AP_AUTOSHUTOFF], presp, &tlen))) { + /** unable to read the AP shutoff time */ + ALOGE("%s :Failed to read AP shutoff time\n", __func__); + } + else { + time = atoi(ptime); + time = time / 60; /** Convert seconds to minutes */ + } + + *plen = qsap_scnprintf(presp, *plen, "success %s=%ld", cmd_list[eCMD_AP_AUTOSHUTOFF].name, time); + + return; +} + + +/** + * @brief + * Get the configuration information from the softAP configuration + * files + * @param cNum [INPUT] + * @param presp [OUTPUT] presp The command output format : + * On success, + * success = + * On failure, + * failure + * @param plen [IN-OUT] plen + * [IN] The length of the buffer, presp + * [OUT] The length of the response in the buffer, presp + * @return void +**/ +static void qsap_get_from_config(esap_cmd_t cNum, s8 *presp, u32 *plen) +{ + u32 len; + int status; + s8 * pval; + + switch(cNum) { + case eCMD_ENABLE_SOFTAP: + status = is_softap_enabled(); + *plen = qsap_scnprintf(presp, *plen, "%s %s=%d", SUCCESS, cmd_list[cNum].name, status); + break; + + case eCMD_WPA_PAIRWISE: + case eCMD_RSN_PAIRWISE: + case eCMD_DEFAULT_KEY: + case eCMD_PASSPHRASE: + case eCMD_GTK_TIMEOUT: + qsap_read_cfg(pconffile, &cmd_list[cNum], presp, plen, NULL, GET_COMMENTED_VALUE); + break; + + case eCMD_SSID: + case eCMD_BSSID: + case eCMD_BCN_INTERVAL: + case eCMD_DTIM_PERIOD: + case eCMD_HW_MODE: + case eCMD_AUTH_ALGS: + case eCMD_MAC_ACL: + case eCMD_WPS_CONFIG_METHOD: + case eCMD_UUID: + case eCMD_DEVICE_NAME: + case eCMD_MANUFACTURER: + case eCMD_MODEL_NAME: + case eCMD_MODEL_NUMBER: + case eCMD_SERIAL_NUMBER: + case eCMD_DEVICE_TYPE: + case eCMD_OS_VERSION: + case eCMD_FRIENDLY_NAME: + case eCMD_MANUFACTURER_URL: + case eCMD_MODEL_DESC: + case eCMD_MODEL_URL: + case eCMD_UPC: + case eCMD_SDK_VERSION: + case eCMD_COUNTRY_CODE: + qsap_read_cfg(pconffile, &cmd_list[cNum], presp, plen, NULL, GET_ENABLED_ONLY); + break; + + case eCMD_WEP_KEY0: + case eCMD_WEP_KEY1: + case eCMD_WEP_KEY2: + case eCMD_WEP_KEY3: + qsap_read_wep_key(pconffile, &cmd_list[cNum], presp, plen, NULL); + break; + + case eCMD_CHAN: + qsap_read_channel(pconffile, &cmd_list[cNum], presp, plen, NULL); + break; + + case eCMD_FRAG_THRESHOLD: + case eCMD_REGULATORY_DOMAIN: + case eCMD_RTS_THRESHOLD: + case eCMD_IEEE80211H: + qsap_read_cfg(pconffile, &cmd_list[cNum], presp, plen, NULL, GET_ENABLED_ONLY); + break; + + case eCMD_ALLOW_LIST: /* fall through */ + case eCMD_DENY_LIST: + qsap_get_mac_list(pconffile, cNum, presp, plen); + break; + + case eCMD_SEC_MODE: + qsap_read_security_mode(pconffile, presp, plen); + break; + + case eCMD_MAC_ADDR: + if(eSUCCESS != qsap_read_mac_address(presp, plen)) { + *plen = qsap_scnprintf(presp, *plen, "%s", ERR_NOT_SUPPORTED); + } + break; + + case eCMD_WMM_STATE: + qsap_read_cfg(pconffile, &cmd_list[cNum], presp, plen, NULL, GET_ENABLED_ONLY); + break; + + case eCMD_WPS_STATE: + qsap_read_wps_state(presp, plen); + break; + + case eCMD_PROTECTION_FLAG: + qsap_read_cfg(fIni, &qsap_str[STR_PROT_FLAG_IN_INI], presp, plen, cmd_list[eCMD_PROTECTION_FLAG].name, GET_ENABLED_ONLY); + break; + + case eCMD_DATA_RATES: + qsap_read_cfg(fIni, &qsap_str[STR_DATA_RATE_IN_INI], presp, plen, cmd_list[eCMD_DATA_RATES].name, GET_ENABLED_ONLY); + break; + + case eCMD_ASSOC_STA_MACS: + qsap_get_associated_sta_mac(presp, plen); + break; + + case eCMD_TX_POWER: + qsap_read_cfg(fIni, &qsap_str[STR_TX_POWER_IN_INI], presp, plen, cmd_list[eCMD_TX_POWER].name, GET_ENABLED_ONLY); + break; + + case eCMD_INTRA_BSS_FORWARD: + qsap_read_cfg(pconffile, &cmd_list[eCMD_INTRA_BSS_FORWARD], presp, plen, NULL, GET_ENABLED_ONLY); + break; + + case eCMD_AP_STATISTICS: + qsap_read_ap_stats(presp, plen); + break; + + case eCMD_AP_AUTOSHUTOFF: + qsap_read_autoshutoff(presp, plen); + break; + + case eCMD_AP_ENERGY_DETECT_TH: + qsap_read_cfg(fIni, &qsap_str[STR_AP_ENERGY_DETECT_TH], presp, plen, cmd_list[eCMD_AP_ENERGY_DETECT_TH].name, GET_ENABLED_ONLY); + break; + case eCMD_GET_AUTO_CHANNEL: + qsap_read_auto_channel(&cmd_list[cNum],presp, plen); + break; + default: + /** Error case */ + *plen = qsap_scnprintf(presp, *plen, "%s", ERR_INVALID_ARG); + } + + len = *plen-1; + + /** Remove the space or tabs in the end of response */ + while(len) { + if((presp[len] == ' ') || (presp[len] == '\t')) + len--; + else + break; + } + presp[len+1] = '\0'; + *plen = len+1; + + return; +} + +/** + * @brief + * Identify the command number corresponding to the input user command. + * @param cName [INPUT] command name + * @return + * On success, + * command number in the range 0 to (eCMD_INVALID-1) + * On failure, + * eCMD_INVALID +**/ +static esap_cmd_t qsap_get_cmd_num(s8 *cName) +{ + s16 i, len; + + for(i=0; i [ ...]" + * These commands are used to retreive the soft AP + * configuration information + * + * @param pcmd [IN] pointer to the structure, storing the command. + * @param presp [OUT] pointer to the buffer, to store the command response. + * The command output format : + * On success, + * success = + * On failure, + * failure + * @param plen [IN-OUT] + * [IN] : Maximum length of the reponse buffer + * [OUT]: Reponse length + * @return + * void +*/ +static void qsap_handle_get_request(s8 *pcmd, s8 *presp, u32 *plen) +{ + esap_cmd_t cNum; + + pcmd += strlen("get"); + + SKIP_BLANK_SPACE(pcmd); + + cNum = qsap_get_cmd_num(pcmd); + + if(cNum == eCMD_INVALID) { + *plen = qsap_scnprintf(presp, *plen, "%s", ERR_INVALID_PARAM); + return; + } + + qsap_get_from_config(cNum, presp, plen); + + return; +} + +static s16 is_valid_wep_key(s8 *pwep, s8 *pkey, s16 len) +{ + int weplen; + s16 ret = TRUE; + int ascii = FALSE; + + weplen = strlen(pwep); + + /** Remove the double quotes if any */ + if((pwep[0] == '"') && (pwep[weplen-1] == '"')) { + pwep[weplen-1] = '\0'; + pwep++; + weplen -= 2; + } + + /** The WEP key should be of length 5, 13 or 16 characters + * or 10, 26, or 32 digits */ + switch(weplen) { + case WEP_64_KEY_ASCII: + case WEP_128_KEY_ASCII: + case WEP_152_KEY_ASCII: + weplen--; + while(weplen--) { + if(0 == isascii(pwep[weplen])) { + ALOGD("%c not ascii \n", pwep[weplen]); + return FALSE; + } + } + ascii = TRUE; + break; + + case WEP_64_KEY_HEX: + case WEP_128_KEY_HEX: + case WEP_152_KEY_HEX: + while(weplen--) { + if(0 == isxdigit(pwep[weplen])) + return FALSE; + } + break; + + default: + ret = FALSE; + } + + qsap_scnprintf(pkey, len, (ascii == TRUE) ? "\"%s\"" : "%s", pwep); + + return ret; +} + +s16 wifi_qsap_reset_to_default(s8 *pcfgfile, s8 *pdefault) +{ + FILE *fcfg, *ftmp; + char buf[MAX_CONF_LINE_LEN]; + int status = eSUCCESS; + + fcfg = fopen(pdefault, "r"); + + if(NULL == fcfg) { + ALOGE("%s : unable to open file \n", __func__); + return eERR_FILE_OPEN; + } + + qsap_scnprintf(buf, sizeof(buf), "%s~", pcfgfile); + + ftmp = fopen(buf, "w+"); + if(NULL == ftmp) { + ALOGE("%s : unable to open file \n", __func__); + fclose(fcfg); + return eERR_FILE_OPEN; + } + + while(NULL != fgets(buf, MAX_CONF_LINE_LEN, fcfg)) { + fprintf(ftmp, "%s", buf); + } + + fclose(fcfg); + fclose(ftmp); + + qsap_scnprintf(buf, sizeof(buf), "%s~", pcfgfile); + + if(eERR_UNKNOWN == rename(buf, pcfgfile)) + status = eERR_CONF_FILE; + + /** Remove the temporary file. Dont care the return value */ + unlink(buf); + + return status; +} + +#define CTRL_IFACE_PATH_LEN (128) + +void qsap_del_ctrl_iface(void) +{ + u32 len; + s8 dst_path[CTRL_IFACE_PATH_LEN], *pcif, *pif; + s8 interface[64]; + s8 path[CTRL_IFACE_PATH_LEN + 64]; + + len = CTRL_IFACE_PATH_LEN; + + if(NULL == (pcif = qsap_get_config_value(pconffile, &qsap_str[STR_CTRL_INTERFACE], dst_path, &len))) { + ALOGE("%s :ctrl_iface path error \n", __func__); + goto error; + } + + len = 64; + + if(NULL == (pif = qsap_get_config_value(pconffile, &qsap_str[STR_INTERFACE], interface, &len))) { + ALOGE("%s :interface error \n", __func__); + goto error; + } + + if ((int)sizeof(path) <= snprintf(path, sizeof(path), "%s/%s", pcif, pif)) { + ALOGE("Iface path : truncating error, %s \n", path); + goto error; + } + + unlink(path); + +error: + return; +} + +static int qsap_send_cmd_to_hostapd(s8 *pcmd) +{ + int sock; + struct sockaddr_un cli; + struct sockaddr_un ser; + struct timeval timeout; + int ret = eERR_SEND_TO_HOSTAPD; + u32 len; + fd_set read; + s8 dst_path[CTRL_IFACE_PATH_LEN], *pcif, *pif; + s8 interface[64]; + s8 *ptr; + u32 retry_cnt = 3; + size_t ptr_size; + + len = CTRL_IFACE_PATH_LEN; + ptr_size = (sizeof(ser.sun_path) < CTRL_IFACE_PATH_LEN)? + CTRL_IFACE_PATH_LEN : sizeof(ser.sun_path); + ptr = malloc(ptr_size); + if(NULL == ptr) { + ALOGE("%s :No memory \n", __func__); + return ret; + } + + if(NULL == (pcif = qsap_get_config_value(pconffile, &qsap_str[STR_CTRL_INTERFACE], dst_path, &len))) { + ALOGE("%s :ctrl_iface path error \n", __func__); + goto error; + } + + len = 64; + + if(NULL == (pif = qsap_get_config_value(pconffile, &qsap_str[STR_INTERFACE], interface, &len))) { + ALOGE("%s :interface error \n", __func__); + goto error; + } + + if ((int)sizeof(ser.sun_path) <= snprintf(ptr, sizeof(ser.sun_path), "%s/%s", pcif, pif)) { + /* the sun_path is truncated. */ + ALOGE("Iface path : truncating error, %s \n", ptr); + goto error; + } + + ALOGD("Connect to :%s\n", ptr); + + sock = socket(PF_UNIX, SOCK_DGRAM, 0); + if(sock < 0) { + ALOGE("%s :Socket error \n", __func__); + goto error; + } + + cli.sun_family = AF_UNIX; + qsap_scnprintf(cli.sun_path, sizeof(cli.sun_path), SDK_CTRL_IF); + + ret = bind(sock, (struct sockaddr *)&cli, sizeof(cli)); + + if(ret < 0) { + ALOGE("Bind Failure\n"); + goto close_ret; + } + + ser.sun_family = AF_UNIX; + qsap_scnprintf(ser.sun_path, sizeof(ser.sun_path), "%s", ptr); + ALOGD("Connect to: %s,(%d)\n", ser.sun_path, sock); + + ret = connect(sock, (struct sockaddr *)&ser, sizeof(ser)); + if(ret < 0) { + ALOGE("Connect Failure...\n"); + goto close_ret; + } + + ret = send(sock, pcmd, strlen(pcmd), 0); + if(ret < 0) { + ALOGE("Unable to send cmd to hostapd \n"); + goto close_ret; + } + /* reset the ptr buffer size for recv */ + len = ptr_size; + +#define HOSTAPD_RECV_TIMEOUT (2) + while(1) { + timeout.tv_sec = HOSTAPD_RECV_TIMEOUT; + timeout.tv_usec = 0; + + FD_ZERO(&read); + FD_SET(sock, &read); + + ret = select(sock+1, &read, NULL, NULL, &timeout); + + if(FD_ISSET(sock, &read)) { + + ret = recv(sock, ptr, len, 0); + + if(ret < 0) { + ALOGE("%s: recv() failed \n", __func__); + goto close_ret; + } + + if ((u32)ret >= len) + ptr[len-1] = 0; + else + ptr[ret] = 0; + + if((ret > 0) && (ptr[0] == '<')) { + ALOGE("Not the expected response...\n: %s", ptr); + retry_cnt--; + if(retry_cnt) + continue; + break; + } + + if(!strncmp(ptr, "FAIL", 4)) { + ALOGE("Command failed in hostapd \n"); + goto close_ret; + } + else { + break; + } + } + else { + ALOGE("%s: Select failed \n", __func__); + goto close_ret; + } + } + + ret = eSUCCESS; + +close_ret: + close(sock); + +error: + free(ptr); + unlink(SDK_CTRL_IF); + return ret; +} + +static void qsap_update_wps_config(s8 *pVal, s8 *presp, u32 *plen) +{ + u32 tlen = *plen; + s32 status; + s8 pwps_state[MAX_INT_STR+1]; + s32 i; + + /* Enable/disable the following in hostapd.conf + * 1. Update the wps_state + * 2. Set eap_server=1 + * 3. Update UPnP related variables + */ + status = atoi(pVal); + + qsap_scnprintf(pwps_state, sizeof(pwps_state), "%d", (status == ENABLE) ? WPS_STATE_ENABLE : WPS_STATE_DISABLE); + + qsap_write_cfg(pconffile, &cmd_list[eCMD_WPS_STATE], pwps_state, presp, &tlen, HOSTAPD_CONF_QCOM_FILE); + + if(eERR_UNKNOWN == qsap_change_cfg(pconffile, &cmd_list[eCMD_WPS_STATE], status)) { + ALOGE("%s: Failed to enable %s\n", __func__, cmd_list[eCMD_WPS_STATE].name); + goto error; + } + + qsap_scnprintf(pwps_state, sizeof(pwps_state), "%d", ENABLE); + + /** update the eap_server=1 */ + qsap_write_cfg(pconffile, &qsap_str[STR_EAP_SERVER], pwps_state, presp, plen, HOSTAPD_CONF_QCOM_FILE); + + for(i=eCMD_UUID; i<=eCMD_UPC; i++) { + if(eERR_UNKNOWN == qsap_change_cfg(pconffile, &cmd_list[i], status)) { + ALOGE("%s: failed to set %s\n", __func__, cmd_list[i].name); + goto error; + } + } + + return; +error: + *plen = qsap_scnprintf(presp, *plen, "%s", ERR_UNKNOWN); + + return; +} + +static void qsap_config_wps_method(s8 *pVal, s8 *presp, u32 *plen) +{ + s8 buf[64]; + s8 *ptr; + int i; + s32 value; + + /** INPUT : <0/1> */ + /** PBC method : WPS_PBC */ + /** PIN method : WPS_PIN any */ + ptr = pVal; + i = 0; + + while((*ptr != '\0') && (*ptr != ' ')) { + buf[i] = *ptr; + ptr++; + i++; + } + + buf[i] = '\0'; + + /** Identify the WPS method */ + value = atoi(buf); + if(TRUE != IS_VALID_WPS_CONFIG(value)) { + *plen = qsap_scnprintf(presp, *plen, "%s", ERR_INVALID_PARAM); + return; + } + + SKIP_BLANK_SPACE(ptr); + + if( (value == WPS_CONFIG_PIN) && (*ptr == '\0') ){ + ALOGE("%s :Invalid command \n", __func__); + *plen = qsap_scnprintf(presp, *plen, "%s", ERR_INVALID_PARAM); + return; + } + + if(value == WPS_CONFIG_PBC) + qsap_scnprintf(buf, sizeof(buf), "WPS_PBC"); + else { + if(strlen(ptr) < WPS_KEY_LEN) { + ALOGD("%s :Invalid WPS key length\n", __func__); + *plen = qsap_scnprintf(presp, *plen, "%s", ERR_INVALID_PARAM); + return; + } + qsap_scnprintf(buf, sizeof(buf), "WPS_PIN any %s", ptr); + } + + value = qsap_send_cmd_to_hostapd(buf); + + *plen = qsap_scnprintf(presp, *plen, "%s", (value == eSUCCESS) ? SUCCESS: ERR_UNKNOWN); + + return; +} + + +s32 atoh(u8 *str) +{ + u32 val = 0; + u32 pos = 0; + s32 len = strlen((char *)str) - 1; + + while(len >= 0) { + switch(str[len]) { + + case '0' ... '9': + val += (str[len] - '0') << pos; + break; + + case 'a' ... 'f': + val += (str[len] - 'a' + 10) << pos; + break; + + case 'A'... 'F': + val += (str[len] - 'A' + 10) << pos; + break; + } + len--; + pos += 4; + } + + return val; +} + +int qsap_get_mac_in_bytes(char *psmac, char *pbmac) +{ + int val; + u8 str[3]; + u32 i; + + str[2] = '\0'; + + if(FALSE == isValid_MAC_address(psmac)) { + return FALSE; + } + + for(i=0; i 14) { + /** Change the operating mode to 'A' */ + ulen = *tlen; + if(eSUCCESS != qsap_write_cfg(pcfg, &cmd_list[eCMD_HW_MODE], hw_mode[HW_MODE_A], tbuf, &ulen, HOSTAPD_CONF_QCOM_FILE)) { + ALOGE("%s :Unable to update the operating mode \n", __func__); + return eERR_UNKNOWN; + } + } + +end: + qsap_scnprintf(schan, sizeof(schan), "%ld", channel); + + return qsap_write_cfg(pcfg, &cmd_list[eCMD_CHAN], schan, tbuf, tlen, HOSTAPD_CONF_QCOM_FILE); +} + +static int qsap_set_operating_mode(s32 mode, s8 *pmode, int pmode_len, s8 *tbuf, u32 *tlen) +{ + u32 ulen; + s8 *pcfgval; + s32 channel; + s8 sconf[MAX_INT_STR+1]; + s8 *pcfg = pconffile; + s32 rate_idx; + s8 ieee11n_enable[] = "1"; + s8 ieee11n_disable[] = "0"; + + ulen = *tlen; + + /** Update the operating mode */ + qsap_change_cfg(pcfg, &cmd_list[eCMD_BASIC_RATES],DISABLE); + qsap_change_cfg(pcfg, &cmd_list[eCMD_REQUIRE_HT],DISABLE); + qsap_write_cfg(pcfg, &cmd_list[eCMD_IEEE80211N],ieee11n_disable, tbuf, &ulen, HOSTAPD_CONF_QCOM_FILE); + switch(mode) + { + case HW_MODE_G_ONLY: + qsap_change_cfg(pcfg, &cmd_list[eCMD_BASIC_RATES],ENABLE); + break; + case HW_MODE_N_ONLY: + qsap_change_cfg(pcfg, &cmd_list[eCMD_REQUIRE_HT],ENABLE); + /* fall through */ + case HW_MODE_N: + case HW_MODE_G: + case HW_MODE_A: + case HW_MODE_ANY: + ulen = *tlen; + qsap_write_cfg(pcfg, &cmd_list[eCMD_IEEE80211N],ieee11n_enable, tbuf, &ulen, HOSTAPD_CONF_QCOM_FILE); + break; + case HW_MODE_B: + ulen = *tlen; + qsap_write_cfg(pcfg, &cmd_list[eCMD_IEEE80211N],ieee11n_disable, tbuf, &ulen, HOSTAPD_CONF_QCOM_FILE); + break; + case HW_MODE_AD: + /** For 802.11ad, disable the 802.11 HT */ + qsap_change_cfg(pcfg, &cmd_list[eCMD_HT_CAPAB], DISABLE); + break; + } + if(mode == HW_MODE_G_ONLY || mode == HW_MODE_N_ONLY || mode == HW_MODE_N ) { + qsap_scnprintf(pmode, pmode_len, "%s",hw_mode[HW_MODE_G]); + } + return qsap_write_cfg(pcfg, &cmd_list[eCMD_HW_MODE], pmode, tbuf, tlen, HOSTAPD_CONF_QCOM_FILE); +} + +static int qsap_set_data_rate(s32 drate_idx, s8 *presp, u32 *plen) +{ + u32 ulen; + s8 *pmode; + s8 sconf[MAX_INT_STR+1]; + int ret = eERR_UNKNOWN; + + if(TRUE != IS_VALID_DATA_RATE_IDX(drate_idx)) { + ALOGE("%s :Invalid rate index \n", __func__); + goto end; + } + + ulen = *plen; + /** Read the current operating mode */ + if(NULL == (pmode = qsap_get_config_value(pconffile, &cmd_list[eCMD_HW_MODE], presp, &ulen))) { + ALOGE("%s :Unable to read mode \n", __func__); + goto end; + } + + /** Validate the rate index against the current operating mode */ + if(((!strcmp(pmode, hw_mode[HW_MODE_B])) && (drate_idx > B_MODE_MAX_DATA_RATE_IDX)) || + ((!strcmp(pmode, hw_mode[HW_MODE_G]) || (!strcmp(pmode, hw_mode[HW_MODE_G_ONLY]))) && + (drate_idx > G_ONLY_MODE_MAX_DATA_RATE_IDX))) { + ALOGE("%s :Invalid rate index \n", __func__); + goto end; + } + + qsap_scnprintf(sconf, sizeof(sconf), "%ld", drate_idx); + + /** Update the rate index in the configuration */ + return qsap_write_cfg(fIni, &qsap_str[STR_DATA_RATE_IN_INI], sconf, presp, plen, INI_CONF_FILE); + +end: + *plen = qsap_scnprintf(presp, *plen, "%s", ERR_UNKNOWN); + + return ret; +} + +/** + * @brief + * Handle the user requests of the form, + * "set ..." + * These commands are used to update the soft AP + * configuration information + * + * @param pcmd [IN] pointer to the string, storing the command. + * @param presp [OUT] pointer to the buffer, to store the command response. + * The command output format : + * On success, + * success + * On failure, + * failure + * @param plen [IN-OUT] + * [IN]: Maximum length of the reponse buffer + * [OUT]: Reponse length + * @return + * void +*/ +static void qsap_handle_set_request(s8 *pcmd, s8 *presp, u32 *plen) +{ + esap_cmd_t cNum; + esap_str_t sNum = STR_DENY_MAC_FILE; + s8 *pVal, *pfile; + s8 filename[MAX_FILE_PATH_LEN]; + u32 ulen; + s32 status; + s32 value; + s16 ini = HOSTAPD_CONF_QCOM_FILE; + s8 *pcfg = pconffile; + + pcmd += strlen("set"); + + SKIP_BLANK_SPACE(pcmd); + + if(!(strncmp(pcmd, Conf_req[CONF_2g], strlen(Conf_req[CONF_2g])))) { + pcmd += strlen(Conf_req[CONF_2g]); + SKIP_BLANK_SPACE(pcmd); + } else if (!(strncmp(pcmd, Conf_req[CONF_5g], strlen(Conf_req[CONF_5g])))) { + pcmd += strlen(Conf_req[CONF_5g]); + SKIP_BLANK_SPACE(pcmd); + } else if (!(strncmp(pcmd, Conf_req[CONF_owe], strlen(Conf_req[CONF_owe])))) { + pcmd += strlen(Conf_req[CONF_owe]); + SKIP_BLANK_SPACE(pcmd); + } else if (!(strncmp(pcmd, Conf_req[CONF_60g], strlen(Conf_req[CONF_60g])))) { + pcmd += strlen(Conf_req[CONF_60g]); + SKIP_BLANK_SPACE(pcmd); + } else { + // DO NOTHING + } + cNum = qsap_get_cmd_num(pcmd); + if(cNum == eCMD_INVALID) { + *plen = qsap_scnprintf(presp, *plen, "%s", ERR_INVALID_ARG); + ALOGE("Invalid command number :%d\n", cNum); + return; + } + pVal = pcmd + strlen(cmd_list[cNum].name); + if( (cNum != eCMD_COMMIT) && + (cNum != eCMD_RESET_TO_DEFAULT) && + ((*pVal != '=') || (((eCMD_PASSPHRASE != cNum)) && (strlen(pVal) < 2)))) { + *plen = qsap_scnprintf(presp, *plen, "%s", ERR_INVALID_ARG); + return; + } + + pVal++; + + if((cNum != eCMD_COMMIT) && (cNum != eCMD_RESET_TO_DEFAULT)) { + ALOGE("Cmd: %s Argument :%s \n", cmd_list[cNum].name, pVal); + } + switch(cNum) { + case eCMD_ADD_TO_ALLOW: + case eCMD_REMOVE_FROM_ALLOW: + sNum = STR_ACCEPT_MAC_FILE; + /* fall through */ + + case eCMD_ADD_TO_DENY: + case eCMD_REMOVE_FROM_DENY: + ulen = MAX_FILE_PATH_LEN; + if(NULL != (pfile = qsap_get_allow_deny_file_name(pconffile, &qsap_str[sNum], filename, &ulen))) { + qsap_update_mac_list(pfile, cNum, pVal, presp, plen); + } + else { + *plen = qsap_scnprintf(presp, *plen, "%s", ERR_RES_UNAVAILABLE); + } + return; + + case eCMD_SEC_MODE: + value = atoi(pVal); + if(FALSE == IS_VALID_SEC_MODE(value)) + goto error; + /** Write back the integer value. This is to avoid values like 01, 001, 0001 + * being written to the configuration. + */ + qsap_scnprintf(pVal, strlen(pVal)+1, "%ld", value); + qsap_set_security_mode(pconffile, value, presp, plen); + return; + + case eCMD_MAC_ACL: + value = atoi(pVal); + if(FALSE == IS_VALID_MAC_ACL(value)) + goto error; + + /** Write back the integer value. This is to avoid values like 01, 001, 0001 + * being written to the configuration + */ + qsap_scnprintf(pVal, strlen(pVal)+1, "%ld", value); + + if(ACL_ALLOW_LIST == value) { + value = ENABLE; + status = DISABLE; + } + else if(ACL_DENY_LIST == value){ + value = DISABLE; + status = ENABLE; + } + else { + // must be ACL_ALLOW_AND_DENY_LIST + value = ENABLE; + status = ENABLE; + } + + if(eERR_UNKNOWN != qsap_change_cfg(pconffile, &qsap_str[STR_ACCEPT_MAC_FILE], value)) { + if(eERR_UNKNOWN != qsap_change_cfg(pconffile, &qsap_str[STR_DENY_MAC_FILE], status)) + { + qsap_write_cfg(pconffile, &cmd_list[cNum], pVal, presp, plen, HOSTAPD_CONF_QCOM_FILE); + } + else { + goto error; + } + } + else { + goto error; + } + return; + + case eCMD_COMMIT: +#if 0 // COMMIT is not required currently for ICS framework + if ( gIniUpdated ) { + status = wifi_qsap_reload_softap(); + gIniUpdated = 0; + } + else { + status = commit(); + } + *plen = qsap_scnprintf(presp, *plen, "%s", (status == eSUCCESS)? SUCCESS : ERR_UNKNOWN); +#endif + *plen = qsap_scnprintf(presp, *plen, "%s", SUCCESS); + return; + + case eCMD_ENABLE_SOFTAP: + value = atoi(pVal); + + if(TRUE != IS_VALID_SOFTAP_ENABLE(value)) + goto error; + + if ( *pVal == '0' ) { + status = wifi_qsap_unload_driver(); + } + else { + status = wifi_qsap_load_driver(); + } + *plen = qsap_scnprintf(presp, *plen, "%s", (status==eSUCCESS) ? SUCCESS : "failure Could not enable softap"); + return; + + case eCMD_ENABLE_WIGIG_SOFTAP: + value = atoi(pVal); + + if (TRUE != IS_VALID_SOFTAP_ENABLE(value)) + goto error; + + if ( *pVal == '0' ) { + status = wifi_qsap_stop_wigig_softap(); + } + else { + status = wifi_qsap_start_wigig_softap(); + } + *plen = qsap_scnprintf(presp, *plen, "%s", (status==eSUCCESS) ? SUCCESS : "failure Could not enable Wigig softap"); + return; + case eCMD_SSID: + value = strlen(pVal); + if(SSD_MAX_LEN < value) + goto error; + /* Disable ssid2 while setting ssid */ + qsap_change_cfg(pcfg, &cmd_list[eCMD_SSID2], DISABLE); + break; + + case eCMD_SET_MAX_CLIENTS: + value = strlen(pVal); + break; + case eCMD_BSSID: + value = atoi(pVal); + if(FALSE == IS_VALID_BSSID(value)) + goto error; + /** Write back the integer value. This is to avoid values like 01, 001, 0001 + * being written to the configuration + */ + qsap_scnprintf(pVal, strlen(pVal)+1, "%ld", value); + break; + case eCMD_PASSPHRASE: + value = strlen(pVal); + if(FALSE == IS_VALID_PASSPHRASE_LEN(value)) + goto error; + break; + + case eCMD_CHAN: + value = atoi(pVal); + + ulen = MAX_FILE_PATH_LEN; + value = qsap_set_channel(value, filename, &ulen); + + *plen = qsap_scnprintf(presp, *plen, "%s", (value == eSUCCESS) ? SUCCESS : ERR_UNKNOWN); + return; + + case eCMD_BCN_INTERVAL: + value = atoi(pVal); + if(FALSE == IS_VALID_BEACON(value)) + goto error; + /** Write back the integer value. This is to avoid values like 01, 001, 0001 + * being written to the configuration + */ + qsap_scnprintf(pVal, strlen(pVal)+1, "%ld", value); + break; + + case eCMD_DTIM_PERIOD: + value = atoi(pVal); + if(FALSE == IS_VALID_DTIM_PERIOD(value)) + goto error; + /** Write back the integer value. This is to avoid values like 01, 001, 0001 + * being written to the configuration + */ + qsap_scnprintf(pVal, strlen(pVal)+1, "%ld", value); + break; + + case eCMD_HW_MODE: + status = FALSE; + for(value=HW_MODE_B; value CTRY_MAX_LEN ) + goto error; + break; + + case eCMD_AP_AUTOSHUTOFF: + value = atoi(pVal); + if(TRUE != IS_VALID_APSHUTOFFTIME(value)) + goto error; + /* copy a larger value back to pVal. Please pay special care + * in caller to make sure that the buffer has sufficient size. */ + qsap_scnprintf(pVal, MAX_INT_STR, "%ld", value*60); + cNum = STR_AP_AUTOSHUTOFF; + ini = INI_CONF_FILE; + break; + + case eCMD_AP_ENERGY_DETECT_TH: + value = atoi(pVal); + if(TRUE != IS_VALID_ENERGY_DETECT_TH(value)) + goto error; + + qsap_scnprintf(pVal, strlen(pVal)+1, "%ld", value); + cNum = STR_AP_ENERGY_DETECT_TH; + ini = INI_CONF_FILE; + break; + + case eCMD_IEEE80211H: + value = atoi(pVal); + if(TRUE != IS_VALID_DFS_STATE(value)) + goto error; + + qsap_scnprintf(pVal, strlen(pVal)+1, "%ld", value); + break; + + case eCMD_SET_CHANNEL_RANGE: + ALOGE("eCMD_SET_CHANNEL_RANGE pcmd :%s\n", pcmd); + value = qsap_set_channel_range(pcmd); + *plen = qsap_scnprintf(presp, *plen, "%s", (value == eSUCCESS) ? SUCCESS : + ERR_UNKNOWN); + return; + case eCMD_SSID2: + /* Disable ssid while setting ssid2 */ + qsap_change_cfg(pcfg, &cmd_list[eCMD_SSID], DISABLE); + break; + + default: ; + /** Do not goto error, in default case */ + } + + if(ini == INI_CONF_FILE) { + ALOGD("WRITE TO INI FILE :%s\n", qsap_str[cNum].name); + qsap_write_cfg(fIni, &qsap_str[cNum], pVal, presp, plen, ini); + } + else { + qsap_write_cfg(pcfg, &cmd_list[cNum], pVal, presp, plen, ini); + } + + return; + +error: + *plen = qsap_scnprintf(presp, *plen, "%s", ERR_INVALID_PARAM); + return; +} + +/** + * @brief + * Initiate the command and return response + * @param pcmd string containing the command request + * The format of the command is + * get param=value + * or + * set param=value + * @param presp buffer to store the command response + * @param plen length of the respone buffer + * @return + * void +*/ +void qsap_hostd_exec_cmd(s8 *pcmd, s8 *presp, u32 *plen) +{ + ALOGD("CMD INPUT [%s][%lu]\n", pcmd, *plen); + /* Skip any blank spaces */ + SKIP_BLANK_SPACE(pcmd); + + if(!(strncmp(pcmd, Cmd_req[eCMD_SET], strlen(Cmd_req[eCMD_SET])))) { + if(!(strncmp(pcmd+4, Conf_req[CONF_2g], strlen(Conf_req[CONF_2g])))) { + pconffile = CONFIG_FILE_2G; + } else if (!(strncmp(pcmd+4, Conf_req[CONF_5g], strlen(Conf_req[CONF_5g])))) { + pconffile = CONFIG_FILE_5G; + } else if (!(strncmp(pcmd+4, Conf_req[CONF_owe], strlen(Conf_req[CONF_owe])))) { + pconffile = CONFIG_FILE_OWE; + } else if (!(strncmp(pcmd+4, Conf_req[CONF_60g], strlen(Conf_req[CONF_60g])))) { + pconffile = CONFIG_FILE_60G; + } else { + pconffile = CONFIG_FILE; + } + } + + check_for_configuration_files(); + + if(!strncmp(pcmd, Cmd_req[eCMD_GET], strlen(Cmd_req[eCMD_GET])) && isblank(pcmd[strlen(Cmd_req[eCMD_GET])])) { + qsap_handle_get_request(pcmd, presp, plen); + } + + else if(!(strncmp(pcmd, Cmd_req[eCMD_SET], strlen(Cmd_req[eCMD_SET]))) && isblank(pcmd[strlen(Cmd_req[eCMD_SET])]) ) { + qsap_handle_set_request(pcmd, presp, plen); + } + + else { + *plen = qsap_scnprintf(presp, *plen, "%s", ERR_INVALIDREQ); + } + + ALOGD("CMD OUTPUT [%s]\nlen :%lu\n\n", presp, *plen); + + return; +} + +/* netd and Froyo Native UI specific API */ +#define DEFAULT_INTFERACE "wlan0" +#define DEFAULT_SSID "SOFTAP_SSID" +#define DEFAULT_CHANNEL 4 +#define DEFAULT_PASSPHRASE "12345678" +#define DEFAULT_AUTH_ALG 1 +#define RECV_BUF_LEN 255 +#define CMD_BUF_LEN 255 +#define SET_BUF_LEN 15 + +/** Command input + argv[3] = SSID, + argv[4] = BROADCAST/HIDDEN, + argv[5] = CHANNEL + argv[6] = SECURITY, + argv[7] = KEY, +*/ +int qsapsetSoftap(int argc, char *argv[]) +{ + char cmdbuf[CMD_BUF_LEN]; + char respbuf[RECV_BUF_LEN]; + u32 rlen = RECV_BUF_LEN; + int i; + int hidden = 0; + int sec = SEC_MODE_NONE; + char setCmd[SET_BUF_LEN] = "set"; + int offset = 0; + + ALOGD("%s, %s, %s, %d\n", __FUNCTION__, argv[0], argv[1], argc); + + for ( i=0; i 2 + && (strncmp(argv[2], Conf_req[CONF_2g], 4) == 0 + || strncmp(argv[2], Conf_req[CONF_owe], 3) == 0 + || strncmp(argv[2], Conf_req[CONF_60g], 3) == 0)) { + snprintf(setCmd, SET_BUF_LEN, "set %s", argv[2]); + offset = 1; + argc--; + } + + /* set interface */ + if (argc > 2) { + snprintf(cmdbuf, CMD_BUF_LEN, "%s interface=%s", setCmd, argv[2 + offset]); + } + else { + snprintf(cmdbuf, CMD_BUF_LEN, "%s interface=%s", setCmd, DEFAULT_INTFERACE); + } + (void) qsap_hostd_exec_cmd(cmdbuf, respbuf, &rlen); + + + /** set SSID */ + if(argc > 3) { + // In case of dual2g/5g, Set ssid2 with hex values to accomodate sapce and special characters. + if (offset) + qsap_scnprintf(cmdbuf, sizeof(cmdbuf), "%s ssid2=%s", setCmd, argv[3 + offset]); + else + qsap_scnprintf(cmdbuf, sizeof(cmdbuf), "%s ssid=%s",setCmd, argv[3]); + } + else { + qsap_scnprintf(cmdbuf, sizeof(cmdbuf), "%s ssid=%s_%d", setCmd, DEFAULT_SSID, rand()); + } + (void) qsap_hostd_exec_cmd(cmdbuf, respbuf, &rlen); + + if(strncmp("success", respbuf, rlen) != 0) { + ALOGE("Failed to set ssid\n"); + return eERR_UNKNOWN; + } + + rlen = RECV_BUF_LEN; + if (argc > 4) { + if (strcmp(argv[4 + offset], "hidden") == 0) { + hidden = 1; + } + snprintf(cmdbuf, CMD_BUF_LEN, "%s ignore_broadcast_ssid=%d", setCmd, hidden); + (void) qsap_hostd_exec_cmd(cmdbuf, respbuf, &rlen); + if(strncmp("success", respbuf, rlen) != 0) { + ALOGE("Failed to set ignore_broadcast_ssid \n"); + return -1; + } + } + /** channel */ + rlen = RECV_BUF_LEN; + if(argc > 5) { + snprintf(cmdbuf, CMD_BUF_LEN, "%s channel=%d", setCmd, atoi(argv[5 + offset])); + (void) qsap_hostd_exec_cmd(cmdbuf, respbuf, &rlen); + + if(strncmp("success", respbuf, rlen) != 0) { + ALOGE("Failed to set channel \n"); + return -1; + } + } + + /** Security */ + rlen = RECV_BUF_LEN; + if(argc > 6) { + + /**TODO : need to identify the SEC strings for "wep", "wpa", "wpa2" */ + if(!strcmp(argv[6 + offset], "open")) + sec = SEC_MODE_NONE; + + else if(!strcmp(argv[6 + offset], "wep")) + sec = SEC_MODE_WEP; + + else if(!strcmp(argv[6 + offset], "wpa-psk")) + sec = SEC_MODE_WPA_PSK; + + else if(!strcmp(argv[6 + offset], "wpa2-psk")) + sec = SEC_MODE_WPA2_PSK; + + qsap_scnprintf(cmdbuf, sizeof(cmdbuf), "%s security_mode=%d",setCmd, sec); + } + else { + qsap_scnprintf(cmdbuf, sizeof(cmdbuf) , "%s security_mode=%d", setCmd, DEFAULT_AUTH_ALG); + } + + (void) qsap_hostd_exec_cmd(cmdbuf, respbuf, &rlen); + + if(strncmp("success", respbuf, rlen) != 0) { + ALOGE("Failed to set security mode\n"); + return -1; + } + + /** Key -- passphrase */ + rlen = RECV_BUF_LEN; + if ( (sec == SEC_MODE_WPA_PSK) || (sec == SEC_MODE_WPA2_PSK) ) { + if(argc > 7) { + /* If the input passphrase is more than 63 characters, consider first 63 characters only*/ + if ( strlen(argv[7 + offset]) > 63 ) argv[7 + offset][63] = '\0'; + qsap_scnprintf(cmdbuf, CMD_BUF_LEN, "%s wpa_passphrase=%s",setCmd, argv[7 + offset]); + } + else { + qsap_scnprintf(cmdbuf, sizeof(cmdbuf), "%s wpa_passphrase=%s", setCmd, DEFAULT_PASSPHRASE); + } + } + + (void) qsap_hostd_exec_cmd(cmdbuf, respbuf, &rlen); + if(strncmp("success", respbuf, rlen) != 0) { + ALOGE("Failed to set passphrase \n"); + return -1; + } + + rlen = RECV_BUF_LEN; + if(argc > 8) { + qsap_scnprintf(cmdbuf, sizeof(cmdbuf), "%s max_num_sta=%d",setCmd, atoi(argv[8 + offset])); + } + (void) qsap_hostd_exec_cmd(cmdbuf, respbuf, &rlen); + + if(strncmp("success", respbuf, rlen) != 0) { + ALOGE("Failed to set maximun client connections number \n"); + return -1; + } + rlen = RECV_BUF_LEN; + + qsap_scnprintf(cmdbuf, sizeof(cmdbuf), "%s commit", setCmd); + + (void) qsap_hostd_exec_cmd(cmdbuf, respbuf, &rlen); + + if(strncmp("success", respbuf, rlen) != 0) { + ALOGE("Failed to COMMIT \n"); + return -1; + } + + return 0; +} + + +static int check_for_config_file_size(FILE *fp) +{ + int length = 0; + + if( NULL != fp ) + { + fseek(fp, 0L, SEEK_END); + length = ftell(fp); + } + + return length; +} + +void check_for_configuration_files(void) +{ + FILE * fp; + char *pfile; + + /* Check if configuration files are present, if not create the default files */ + + /* If configuration file does not exist copy the default file */ + if ( NULL == (fp = fopen(pconffile, "r")) ) { + wifi_qsap_reset_to_default(pconffile, DEFAULT_CONFIG_FILE_PATH); + } + else { + + /* The configuration file could be of 0 byte size, replace with default */ + if (check_for_config_file_size(fp) <= 0) + wifi_qsap_reset_to_default(pconffile, DEFAULT_CONFIG_FILE_PATH); + + fclose(fp); + } + + /* If Accept MAC list file does not exist, copy the default file */ + if ( NULL == (fp = fopen(ACCEPT_LIST_FILE, "r")) ) { + wifi_qsap_reset_to_default(ACCEPT_LIST_FILE, DEFAULT_ACCEPT_LIST_FILE_PATH); + } + else { + + /* The configuration file could be of 0 byte size, replace with default */ + if (check_for_config_file_size(fp) <= 0) + wifi_qsap_reset_to_default(ACCEPT_LIST_FILE, DEFAULT_ACCEPT_LIST_FILE_PATH); + + fclose(fp); + } + + /* Provide read and write permissions to the owner */ + pfile = ACCEPT_LIST_FILE; + if (chmod(pfile, 0660) < 0) { + ALOGE("Error changing permissions of %s to 0660: %s", + pfile, strerror(errno)); + } + /* If deny MAC list file does not exist, copy the default file */ + if ( NULL == (fp = fopen(DENY_LIST_FILE, "r")) ) { + wifi_qsap_reset_to_default(DENY_LIST_FILE, DEFAULT_DENY_LIST_FILE_PATH); + } + else { + + /* The configuration file could be of 0 byte size, replace with default */ + if (check_for_config_file_size(fp) <= 0) + wifi_qsap_reset_to_default(DENY_LIST_FILE, DEFAULT_DENY_LIST_FILE_PATH); + + fclose(fp); + } + + /* Provide read and write permissions to the owner */ + pfile = DENY_LIST_FILE; + if (chmod(pfile, 0660) < 0) { + ALOGE("Error changing permissions of %s to 0660: %s", + pfile, strerror(errno)); + } + return; +} + +void qsap_set_ini_filename(void) +{ + if (property_get("wlan.driver.config", ini_file, NULL)) { + fIni = ini_file; + ALOGE("INI FILE PROP PRESENT %s\n", fIni); + } else + ALOGE("INI FILE PROP NOT PRESENT: Use default path %s\n", fIni); + return; +} + +// IOCTL command to create and delete bridge interface // +#ifndef SIOCBRADDBR +#define SIOCBRADDBR 0x89a0 +#endif +#ifndef SIOCBRDELBR +#define SIOCBRDELBR 0x89a1 +#endif + +static int linux_set_iface_flags(int sock, const char *ifname, int dev_up) +{ + struct ifreq ifr; + int ret; + + if (sock < 0) + return -1; + + memset(&ifr, 0, sizeof(ifr)); + strlcpy(ifr.ifr_name, ifname, IFNAMSIZ); + + if (ioctl(sock, SIOCGIFFLAGS, &ifr) != 0) { + ret = errno ? -errno : -999; + ALOGE("Could not read interface %s flags: %s", + ifname, strerror(errno)); + return ret; + } + + if (dev_up) { + if (ifr.ifr_flags & IFF_UP) + return 0; + ifr.ifr_flags |= IFF_UP; + } else { + if (!(ifr.ifr_flags & IFF_UP)) + return 0; + ifr.ifr_flags &= ~IFF_UP; + } + + if (ioctl(sock, SIOCSIFFLAGS, &ifr) != 0) { + ret = errno ? -errno : -999; + ALOGE("Could not set interface %s flags (%s): %s", + ifname, dev_up ? "UP" : "DOWN", strerror(errno)); + return ret; + } + return 0; +} + +int qsap_control_bridge(int argc, char ** argv) +{ + int br_socket; + + if (argc < 4) { + ALOGE("Command not supported"); + return -1; + } + + br_socket = socket(PF_INET, SOCK_DGRAM, 0); + if (br_socket < 0) { + ALOGE("socket(PF_INET,SOCK_DGRAM): %s",strerror(errno)); + return -1; + } + if (!strncmp(argv[2],"create", 6)) { + if (ioctl(br_socket, SIOCBRADDBR, argv[3]) < 0) { + ALOGE("Could not add bridge %s: %s", argv[3], strerror(errno)); + return -1; + } + } else if (!strncmp(argv[2],"remove", 6)) { + if (ioctl(br_socket, SIOCBRDELBR, argv[3]) < 0) { + ALOGE("Could not add remove %s: %s", argv[3], strerror(errno)); + return -1; + } + } else if (!strncmp(argv[2],"up", 2)) { + return linux_set_iface_flags(br_socket, argv[3], 1); + } else if (!strncmp(argv[2],"down", 4)) { + return linux_set_iface_flags(br_socket, argv[3], 0); + } else { + ALOGE("Command %s not handled.", argv[2]); + return -1; + } + + return 0; +} + + +int linux_get_ifhwaddr(const char *ifname, char *addr) +{ + struct ifreq ifr; + int sock = socket(AF_INET, SOCK_DGRAM, 0); + +#ifndef MAC2STR +#define MAC2STR(a) (a)[0], (a)[1], (a)[2], (a)[3], (a)[4], (a)[5] +#define MACSTR "%02x:%02x:%02x:%02x:%02x:%02x" +#endif + memset(&ifr, 0, sizeof(ifr)); + strlcpy(ifr.ifr_name, ifname, IFNAMSIZ); + if (ioctl(sock, SIOCGIFHWADDR, &ifr)) { + ALOGE("Could not get interface %s hwaddr: %s", ifname, strerror(errno)); + return -1; + } + + if (ifr.ifr_hwaddr.sa_family != ARPHRD_ETHER) { + ALOGE("%s: Invalid HW-addr family 0x%04x", ifname, ifr.ifr_hwaddr.sa_family); + return -1; + } + memcpy(addr, ifr.ifr_hwaddr.sa_data, ETH_ALEN); + ALOGE("%s: " MACSTR, ifname, MAC2STR(addr)); + + return 0; +} + + +int qsap_add_or_remove_interface(const char *newIface , int createIface) +{ + const char *wlanIface = "wlan0"; + int retVal = 0; + struct nl_msg *msg = NULL; + struct nl_cb *cb = NULL; + struct nl_cb *s_cb = NULL; + struct nl_sock *nl_sock = NULL; + int nl80211_id; + enum nl80211_iftype type = NL80211_IFTYPE_AP; + + /* Allocate a netlink socket */ + s_cb = nl_cb_alloc(NL_CB_DEFAULT); + if (!s_cb) { + ALOGE( "Failed to allocate Netlink Socket"); + retVal = -ENOMEM; + goto nla_put_failure; + } + + nl_sock = nl_socket_alloc_cb(s_cb); + if (!nl_sock) { + ALOGE( "Netlink socket Allocation failure"); + retVal = -ENOMEM; + goto nla_put_failure; + } + + /* connect to generic netlink socket */ + if (genl_connect(nl_sock)) { + ALOGE( "Netlink socket Connection failure"); + retVal = -ENOLINK; + goto nla_put_failure; + } + + nl80211_id = genl_ctrl_resolve(nl_sock, "nl80211"); + if (nl80211_id < 0) { + ALOGE( "nl80211 generic netlink not found"); + retVal = -ENOENT; + goto nla_put_failure; + } + + msg = nlmsg_alloc(); + if(!msg) { + ALOGE( "Failed to allocate netlink message"); + retVal = -ENOMEM; + goto nla_put_failure; + } + + cb = nl_cb_alloc(NL_CB_DEFAULT); + if (!cb) { + ALOGE( "Failed to allocate netlink callback"); + retVal = -ENOMEM; + goto nla_put_failure; + } + + if (createIface == 1) { + /* Issue NL80211_CMD_NEW_INTERFACE */ + genlmsg_put( msg, 0, 0, nl80211_id, 0, 0, NL80211_CMD_NEW_INTERFACE, 0); + nla_put_u32( msg, NL80211_ATTR_IFINDEX, if_nametoindex( wlanIface )); + NLA_PUT_STRING( msg, NL80211_ATTR_IFNAME, newIface); + nla_put_u32( msg, NL80211_ATTR_IFTYPE, type); + } else { + genlmsg_put( msg, 0, 0, nl80211_id, 0, 0, NL80211_CMD_DEL_INTERFACE, 0); + nla_put_u32( msg, NL80211_ATTR_IFINDEX, if_nametoindex( newIface )); + } + + retVal = nl_send_auto_complete(nl_sock, msg ); + if (retVal < 0 ) { + goto nla_put_failure; + } + else { + ALOGD("Interface %s is %s - Ok", (createIface == 1 ? "created":"removed") ,newIface); + } +nla_put_failure: + if (nl_sock) + nl_socket_free(nl_sock); + if (s_cb) + nl_cb_put(s_cb); + if (msg) + nlmsg_free(msg); + if (cb) + nl_cb_put(cb); + return retVal; +} diff --git a/qsap/qsap_api.h b/qsap/qsap_api.h new file mode 100644 index 0000000..4ba55ec --- /dev/null +++ b/qsap/qsap_api.h @@ -0,0 +1,650 @@ +/* + * Copyright (c) 2010, The Linux Foundation. All rights reserved. + + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials provided + * with the distribution. + * * Neither the name of The Linux Foundation nor the names of its + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + + * THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS + * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR + * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, + * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE + * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN + * IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + + +#ifndef _QSAP_API_H_ +#define _QSAP_API_H_ + +#if __cplusplus +extern "C" { +#endif +#include +typedef unsigned char u8; +typedef char s8; +typedef unsigned short int u16; +typedef signed short int s16; +typedef unsigned int u32; +typedef signed int s32; + +/** Success and error messages */ +#define SUCCESS "success" +#define ERR_INVALID_ARG "failure invalid arguments" +#define ERR_INVALID_PARAM "failure invalid parameter" +#define ERR_UNKNOWN "failure unknown error" +#define ERR_INVALIDCMD "failure invalid command" +#define ERR_INVALIDREQ "failure invalid request" +#define ERR_FEATURE_NOT_ENABLED "failure feature not enabled" +#define ERR_NOT_SUPPORTED "failure not supported" +#define ERR_NOT_READY "failure not ready" +#define ERR_RES_UNAVAILABLE "failure resource unavailable" +#define ERR_SOFTAP_NOT_STARTED "failure softap not started" + +/** Error numbers used with the SDK */ +enum error_val { + eERR_UNKNOWN = -1, + eSUCCESS = 0, + eERR_STOP_BSS, + eERR_BSS_NOT_STARTED, + eERR_COMMIT, + eERR_START_SAP, + eERR_STOP_SAP, + eERR_RELOAD_SAP, + eERR_FILE_OPEN, + eERR_CONF_FILE, + eERR_INVALID_MAC_ADDR, + eERR_SEND_TO_HOSTAPD, + eERR_CONFIG_PARAM_MISSING, + eERR_CHAN_READ, + eERR_FEATURE_NOT_ENABLED, + eERR_UNLOAD_FAILED_SDIO, + eERR_UNLOAD_FAILED_SOFTAP, + eERR_LOAD_FAILED_SDIOIF, + eERR_LOAD_FAILED_SOFTAP, + eERR_SET_CHAN_RANGE, + eERR_GET_AUTO_CHAN +}; + +#ifndef WIFI_DRIVER_CONF_FILE +#define WIFI_DRIVER_CONF_FILE NULL +#endif + +#ifndef WIFI_DRIVER_DEF_CONF_FILE +#define WIFI_DRIVER_DEF_CONF_FILE NULL +#endif + +/** Configuration file name for SAP+SAP*/ +#define CONFIG_FILE_2G "/data/vendor/wifi/hostapd/hostapd_dual2g.conf" +#define CONFIG_FILE_5G "/data/vendor/wifi/hostapd/hostapd_dual5g.conf" +#define CONFIG_FILE_60G "/data/vendor/wifi/hostapd/hostapd_60g.conf" + +/** Configuration file name for OWE-transition */ +#define CONFIG_FILE_OWE "/data/vendor/wifi/hostapd/hostapd_owe.conf" + +/** Configuration file name */ +#define CONFIG_FILE "/data/vendor/wifi/hostapd/hostapd.conf" + +/** Default configuration file path */ +#define DEFAULT_CONFIG_FILE_PATH "/vendor/etc/hostapd/hostapd_default.conf" + +/** Default Accept list file name */ +#define DEFAULT_ACCEPT_LIST_FILE_PATH "/vendor/etc/hostapd/hostapd.accept" + +/** Accept list file name */ +#define ACCEPT_LIST_FILE "/data/vendor/wifi/hostapd/hostapd.accept" + +/** Default Deny list file name */ +#define DEFAULT_DENY_LIST_FILE_PATH "/vendor/etc/hostapd/hostapd.deny" + +/** Deny list file name */ +#define DENY_LIST_FILE "/data/vendor/wifi/hostapd/hostapd.deny" + +/** Default Ini file */ +#define DEFAULT_INI_FILE "/persist/qcom/softap/qcom_cfg_default.ini" + +/** SDK control interface path */ +#define SDK_CTRL_IF "/data/vendor/wifi/hostapd/ctrl/softap_sdk_ctrl" + +/** Maximum length of the line in the configuration file */ +#define MAX_CONF_LINE_LEN (156) + +/** MAC address length in acsii string format*/ +#define MAC_ADDR_LEN (17) + +/** MAC address length, as integer */ +#define MAC_ADDR_LEN_INT (6) +/** Maximum number of MAC address in the allow / deny MAC list */ +#define MAX_ALLOWED_MAC (15) + +/** Maximum length of the file path */ +#define MAX_FILE_PATH_LEN (128) + +/** WPS key length - 8 digit key, usually*/ +#define WPS_KEY_LEN (8) + +/** Maximum length of the SSID */ +#define SSD_MAX_LEN (32) +#define CTRY_MAX_LEN (3) + +/** Beacon interval 50 to 65535 */ +#define BCN_INTERVAL_MIN (1) +#define BCN_INTERVAL_MAX (65535) + +/** Passphrase max length 63 bytes, Minumum lenght is 8. + * NOTE: If Passphrase length is 64, then phassphrase is treated as PSK. + */ +#define PASSPHRASE_MIN (8) +#define PASSPHRASE_MAX (63) + +/** DTIM period 1 to 255 -- Qualcomm 10 */ +#define DTIM_PERIOD_MIN (1) +#define DTIM_PERIOD_MAX (255) + +/** WEP key lengths in ASCII and hex */ +#define WEP_64_KEY_ASCII (5) +#define WEP_64_KEY_HEX (10) + +#define WEP_128_KEY_ASCII (13) +#define WEP_128_KEY_HEX (26) + +#define WEP_152_KEY_ASCII (16) +#define WEP_152_KEY_HEX (32) + +#define WPS_PIN_LEN (8) + +#define CHANNEL_MIN (0) +#define CHANNEL_MAX (14) +#define AUTO_CHANNEL (0) +#define BG_MAX_CHANNEL (11) + +/** Fragmentation threshold 256 to 2346 */ +#define FRAG_THRESHOLD_MIN (256) +#define FRAG_THRESHOLD_MAX (2346) + +/** RTS threshold 1 to 2347 */ +#define RTS_THRESHOLD_MIN (1) +#define RTS_THRESHOLD_MAX (2347) + +#define MIN_UUID_LEN (1) +#define MAX_UUID_LEN (36) + +#define MIN_DEVICENAME_LEN (1) +#define MAX_DEVICENAME_LEN (32) + +#define MIN_MANUFACTURER_LEN (1) +#define MAX_MANUFACTURER_LEN (64) + +#define MIN_MODELNAME_LEN (1) +#define MAX_MODELNAME_LEN (32) + +#define MIN_MODELNUM_LEN (1) +#define MAX_MODELNUM_LEN (32) + +#define MIN_SERIALNUM_LEN (1) +#define MAX_SERIALNUM_LEN (32) + +#define MIN_DEV_TYPE_LEN (1) +#define MAX_DEV_TYPE_LEN (20) + +#define MIN_OS_VERSION_LEN (1) +#define MAX_OS_VERSION_LEN (12) + +#define MIN_FRIENDLY_NAME_LEN (1) +#define MAX_FRIENDLY_NAME_LEN (64) + +#define MAX_URL_LEN (128) + +#define MIN_MODEL_DESC_LEN (1) +#define MAX_MODEL_DESC_LEN (128) + +#define MIN_UPC_LEN (1) +#define MAX_UPC_LEN (128) + +#define GTK_MIN (30) + +#define MAX_INT_STR (8) + +/** Tx Power range 2dBm to 18 dBm */ +#define MIN_TX_POWER (2) +#define MAX_TX_POWER (30) + +/** Data rate index */ +#define MIN_DATA_RATE_IDX (0) +#define MAX_DATA_RATE_IDX (28) +#define AUTO_DATA_RATE (0) +#define B_MODE_MAX_DATA_RATE_IDX (4) +#define G_ONLY_MODE_MAX_DATA_RATE_IDX (12) + +/** parameters for read config */ +#define GET_COMMENTED_VALUE 1 +#define GET_ENABLED_ONLY 0 + +#define MAX_RESP_LEN 255 + +/** AP shutoff time */ +#define AP_SHUTOFF_MIN (0) +#define AP_SHUTOFF_MAX (120) + +/** AP shutoff time */ +#define AP_ENERGY_DETECT_TH_MIN (0) +#define AP_ENERGY_DETECT_TH_MAX (9) + +/** command request index - in the array Cmd_req[] */ +enum eCmd_req { + eCMD_GET = 0, + eCMD_SET = 1, + + eCMD_REQ_LAST +}; + +/** config request index - in the array Conf_req[] */ +enum eConf_req { + CONF_2g = 0, + CONF_5g = 1, + CONF_owe = 2, + CONF_60g = 3, + + CONF_REQ_LAST +}; + +/** + * Command numbers, these numbers form the index into the array of + * command names stored in the 'cmd_list'. + * + * Warning: An addtion of an entry in 'esap_cmd', should be followed + * by an addition of a command name string in the 'cmd_list' array + */ +typedef enum esap_cmd { + eCMD_INVALID = -1, + eCMD_SSID = 0, + eCMD_BSSID = 1, + eCMD_CHAN = 2, + eCMD_BCN_INTERVAL = 3, + eCMD_DTIM_PERIOD = 4, + eCMD_HW_MODE = 5, + eCMD_AUTH_ALGS = 6, + eCMD_SEC_MODE = 7, + eCMD_WEP_KEY0 = 8, + eCMD_WEP_KEY1 = 9, + eCMD_WEP_KEY2 = 10, + eCMD_WEP_KEY3 = 11, + eCMD_DEFAULT_KEY = 12, + eCMD_PASSPHRASE = 13, + eCMD_WPA_PAIRWISE = 14, + eCMD_RSN_PAIRWISE = 15, + eCMD_MAC_ADDR = 16, + eCMD_RESET_AP = 17, + eCMD_MAC_ACL = 18, + eCMD_ADD_TO_ALLOW = 19, + eCMD_ADD_TO_DENY = 20, + eCMD_REMOVE_FROM_ALLOW = 21, + eCMD_REMOVE_FROM_DENY = 22, + eCMD_ALLOW_LIST = 23, + eCMD_DENY_LIST = 24, + eCMD_COMMIT = 25, + eCMD_ENABLE_SOFTAP = 26, + eCMD_DISASSOC_STA = 27, + eCMD_RESET_TO_DEFAULT = 28, + eCMD_PROTECTION_FLAG = 29, + eCMD_DATA_RATES = 30, + eCMD_ASSOC_STA_MACS = 31, + eCMD_TX_POWER = 32, + eCMD_SDK_VERSION = 33, + eCMD_WMM_STATE = 34, + + /** WARNING: The order of WPS commands should not be altered. + New commands SHOULD be added above or below this */ + eCMD_WPS_STATE = 35, + eCMD_WPS_CONFIG_METHOD = 36, + eCMD_UUID = 37, + eCMD_DEVICE_NAME = 38, + eCMD_MANUFACTURER = 39, + eCMD_MODEL_NAME = 40, + eCMD_MODEL_NUMBER = 41, + eCMD_SERIAL_NUMBER = 42, + eCMD_DEVICE_TYPE = 43, + eCMD_OS_VERSION = 44, + eCMD_FRIENDLY_NAME = 45, + eCMD_MANUFACTURER_URL = 46, + eCMD_MODEL_DESC = 47, + eCMD_MODEL_URL = 48, + eCMD_UPC = 49, + /******************************************************/ + + eCMD_FRAG_THRESHOLD = 50, + eCMD_RTS_THRESHOLD = 51, + eCMD_GTK_TIMEOUT = 52, + eCMD_COUNTRY_CODE = 53, + eCMD_INTRA_BSS_FORWARD = 54, + eCMD_REGULATORY_DOMAIN = 55, + eCMD_AP_STATISTICS = 56, + eCMD_AP_AUTOSHUTOFF = 57, + eCMD_AP_ENERGY_DETECT_TH = 58, + eCMD_BASIC_RATES = 59, + eCMD_REQUIRE_HT = 60, + eCMD_IEEE80211N = 61, + eCMD_SET_CHANNEL_RANGE = 62, + eCMD_GET_AUTO_CHANNEL = 63, + eCMD_IEEE80211W = 64, + eCMD_WPA_KEY_MGMT = 65, + eCMD_SET_MAX_CLIENTS = 66, + eCMD_IEEE80211AC = 67, + eCMD_VHT_OPER_CH_WIDTH = 68, + eCMD_ACS_CHAN_LIST = 69, + eCMD_HT_CAPAB = 70, + eCMD_IEEE80211H = 71, + + eCMD_ENABLE_WIGIG_SOFTAP = 72, + eCMD_INTERFACE = 73, + eCMD_SSID2 = 74, + eCMD_BRIDGE = 75, + eCMD_CTRL_INTERFACE = 76, + eCMD_VENDOR_ELEMENT = 77, + eCMD_ASSOCRESP_ELEMENT = 78, + eCMD_ACS_EXCLUDE_DFS = 79, + eCMD_WOWLAN_TRIGGERS = 80, + eCMD_ACCEPT_MAC_FILE = 81, + eCMD_DENY_MAC_FILE = 82, + eCMD_OWE_TRANS_IFNAME = 83, + eCMD_SAE_REQUIRE_MPF = 84, + + eCMD_IEEE80211AX = 85, + + eCMD_ENABLE_EDMG = 86, + eCMD_EDMG_CHANNEL = 87, + + eCMD_LAST /** New command numbers should be added above this */ +} esap_cmd_t; + +/** non-commands */ +typedef enum esap_str { + STR_WPA = 0, + STR_ACCEPT_MAC_FILE = 1, + STR_DENY_MAC_FILE = 2, + STR_MAC_IN_INI = 3, + STR_PROT_FLAG_IN_INI = 4, + STR_DATA_RATE_IN_INI = 5, + STR_TX_POWER_IN_INI = 6, + STR_FRAG_THRESHOLD_IN_INI = 7, + STR_RTS_THRESHOLD_IN_INI = 8, + STR_COUNTRY_CODE_IN_INI = 9, + STR_INTRA_BSS_FORWARD_IN_INI = 10, + STR_WMM_IN_INI = 11, + STR_802DOT11D_IN_INI = 12, + STR_HT_80211N = 13, + STR_CTRL_INTERFACE = 14, + STR_INTERFACE = 15, + STR_EAP_SERVER = 16, + STR_AP_AUTOSHUTOFF = 17, + STR_AP_ENERGY_DETECT_TH = 18, + eSTR_LAST +} esap_str_t; + +/** Supported security mode */ +typedef enum sec_mode { + SEC_MODE_NONE = 0, + SEC_MODE_WEP = 1, + SEC_MODE_WPA_PSK = 2, + SEC_MODE_WPA2_PSK = 3, + SEC_MODE_WPA_WPA2_PSK = 4, + + SEC_MODE_INVALID +} sec_mode_t; + +/** security mode in the configuration file */ +enum wpa_in_conf_file { + WPA_IN_CONF_FILE = 1, + WPA2_IN_CONF_FILE = 2, + WPA_WPA2_IN_CONF_FILE = 3 +}; + +enum { + DISABLE = 0, + ENABLE = 1 +}; + +enum { + FALSE = 0, + TRUE = 1 +}; + +/** IEEE 802.11 operating mode */ +enum oper_mode { + HW_MODE_B = 0, + HW_MODE_G = 1, + HW_MODE_N = 2, + HW_MODE_G_ONLY = 3, + HW_MODE_N_ONLY = 4, + HW_MODE_A = 5, + HW_MODE_ANY = 6, + HW_MODE_AD = 7, + + HW_MODE_UNKNOWN +}; + +/** Authentication algorithm */ +enum auth_alg { + AHTH_ALG_OPEN = 1, + AUTH_ALG_SHARED = 2, + AUTH_ALG_OPEN_SHARED = 3, + + AUTH_ALG_INVALID +}; + +/** Allow or Deny MAC address list selection */ +enum macaddr_acl { + ACL_DENY_LIST = 0, + ACL_ALLOW_LIST = 1, + ACL_ALLOW_AND_DENY_LIST = 2 +}; + +enum ap_reset { + SAP_RESET_BSS = 0, + SAP_RESET_DRIVER_BSS = 1, + SAP_STOP_BSS = 2, + SAP_STOP_DRIVER_BSS = 3, +#ifdef QCOM_WLAN_CONCURRENCY + SAP_INITAP = 4, + SAP_EXITAP = 5, +#endif + SAP_RESET_INVALID +}; + +enum wmm_state { + WMM_AUTO_IN_INI = 0, + WMM_ENABLED_IN_INI = 1, + WMM_DISABLED_IN_INI = 2 +}; + +enum wps_state { + WPS_STATE_DISABLE = 0, + WPS_STATE_ENABLE = 2 +}; + + +enum wps_config { + WPS_CONFIG_PBC = 0, + WPS_CONFIG_PIN = 1, +}; + +/** Choose the configuration file */ +enum eChoose_conf_file { + HOSTAPD_CONF_QCOM_FILE = 0, + INI_CONF_FILE = 1 +}; + +struct Command +{ + s8 * name; + s8 * default_value; +}; + +/** STA Channel information*/ +typedef struct sta_channel_info { + int subioctl; + int stastartchan; + int staendchan; + int staband; +} sta_channel_info; + +/**SAP Channel information*/ +typedef struct sap_channel_info { + int startchan; + int endchan; + int band; +} sap_channel_info; + +/**SAP auto Channel information*/ +typedef struct sap_auto_channel_info { + int subioctl; +} sap_auto_channel_info; + +/** Validate enable / disable softap */ +#define IS_VALID_SOFTAP_ENABLE(x) (((value == ENABLE) || (value == DISABLE)) ? TRUE: FALSE) + +/** Validate the channel */ +#define IS_VALID_CHANNEL(x) ((value >= CHANNEL_MIN) && (value <= CHANNEL_MAX) ? TRUE : FALSE) + +/** Validate the security mode */ +#define IS_VALID_SEC_MODE(x) (((x >= SEC_MODE_NONE) && (x < SEC_MODE_INVALID)) ? TRUE : FALSE) + +/** Validate the selection of access or deny MAC address list */ +#define IS_VALID_MAC_ACL(x) (((x==ACL_DENY_LIST) || (x==ACL_ALLOW_LIST) || (x==ACL_ALLOW_AND_DENY_LIST)) ? TRUE : FALSE) + +/** Validate the broadcast SSID status */ +#define IS_VALID_BSSID(x) (((value == ENABLE) || (value == DISABLE)) ? TRUE: FALSE) + +/** Validate the length of the passphrase */ +#define IS_VALID_PASSPHRASE_LEN(x) ((((x >= PASSPHRASE_MIN) && (x <= PASSPHRASE_MAX)) || (x == 0)) ? TRUE: FALSE) + +/** Validate the beacon interval */ +#define IS_VALID_BEACON(x) (((x >= BCN_INTERVAL_MIN) && (x <= BCN_INTERVAL_MAX)) ? TRUE: FALSE) + +/** Validate the DTIM period */ +#define IS_VALID_DTIM_PERIOD(x) (((x >= DTIM_PERIOD_MIN) && (x <= DTIM_PERIOD_MAX)) ? TRUE: FALSE) + +/** Validate the WEP index */ +#define IS_VALID_WEP_KEY_IDX(x) ((x >= 0) && (x < 4) ? TRUE : FALSE) + +/** Validate the pairwise encryption */ +#define IS_VALID_PAIRWISE(x) (((!strcmp(x, "TKIP")) || (!strcmp(x, "CCMP")) || \ + (!strcmp(x, "TKIP CCMP")) || (!strcmp(x, "CCMP TKIP")) || (!strcmp(x, "GCMP"))) ? TRUE : FALSE) + +/** Validate the WMM status */ +#define IS_VALID_WMM_STATE(x) (((x >= WMM_AUTO_IN_INI) && (x <= WMM_DISABLED_IN_INI)) ? TRUE: FALSE) + +/** Validate the WPS status */ +#define IS_VALID_WPS_STATE(x) (((x == ENABLE) || (x == DISABLE)) ? TRUE: FALSE) + +/** Validate the fragmentation threshold */ +#define IS_VALID_FRAG_THRESHOLD(x) (((x >= FRAG_THRESHOLD_MIN) && (x <= FRAG_THRESHOLD_MAX)) ? TRUE: FALSE) + +/** Validate the RTS threshold value */ +#define IS_VALID_RTS_THRESHOLD(x) (((x >= RTS_THRESHOLD_MIN) && (x <= RTS_THRESHOLD_MAX)) ? TRUE: FALSE) + +/** Validate the GTK */ +#define IS_VALID_GTK(x) ((x >= GTK_MIN) ? TRUE: FALSE) + +/** Validate the intra-bss forwarding status */ +#define IS_VALID_INTRA_BSS_STATUS(x) (((x == ENABLE) || (x == DISABLE)) ? TRUE: FALSE) + +/** Validate the protection flag */ +#define IS_VALID_PROTECTION(x) (((x == ENABLE) || (x == DISABLE)) ? TRUE: FALSE) + +/** Validate the UUID length */ +#define IS_VALID_UUID_LEN(x) (((x >= MIN_UUID_LEN) && (x <= MAX_UUID_LEN)) ? TRUE : FALSE) + +/** Validate the device name length */ +#define IS_VALID_DEVICENAME_LEN(x) (((x >= MIN_DEVICENAME_LEN) && (x <= MAX_DEVICENAME_LEN)) ? TRUE : FALSE) + +/** Validate the Manufacturer length */ +#define IS_VALID_MANUFACTURER_LEN(x) (((x >= MIN_MANUFACTURER_LEN) && (x <= MAX_MANUFACTURER_LEN)) ? TRUE : FALSE) + +/** Validate the Model name length */ +#define IS_VALID_MODELNAME_LEN(x) (((x >= MIN_MODELNAME_LEN) && (x <= MAX_MODELNAME_LEN)) ? TRUE : FALSE) + +/** Validate the Model number length */ +#define IS_VALID_MODELNUM_LEN(x) (((x >= MIN_MODELNUM_LEN) && (x <= MAX_MODELNUM_LEN)) ? TRUE : FALSE) + +/** Validate the Model serial number length */ +#define IS_VALID_SERIALNUM_LEN(x) (((x >= MIN_SERIALNUM_LEN) && (x <= MAX_SERIALNUM_LEN)) ? TRUE : FALSE) + +/** Validate the Primary device type length */ +#define IS_VALID_DEV_TYPE_LEN(x) (((x >= MIN_DEV_TYPE_LEN) && (x <= MAX_DEV_TYPE_LEN)) ? TRUE : FALSE) + +/** Validate the OS version length */ +#define IS_VALID_OS_VERSION_LEN(x) (((x >= MIN_OS_VERSION_LEN) && (x <= MAX_OS_VERSION_LEN)) ? TRUE : FALSE) + +/** Validate the friendly name length */ +#define IS_VALID_FRIENDLY_NAME_LEN(x) (((x >= MIN_FRIENDLY_NAME_LEN) && (x <= MAX_FRIENDLY_NAME_LEN)) ? TRUE : FALSE) + +/** Validate the URL length */ +#define IS_VALID_URL_LEN(x) (((x > 0) && (x <= MAX_URL_LEN)) ? TRUE : FALSE) + +/** Validate the model description length */ +#define IS_VALID_MODEL_DESC_LEN(x) (((x > MIN_MODEL_DESC_LEN) && (x <= MAX_MODEL_DESC_LEN)) ? TRUE : FALSE) + +/** Validate the Universal Product Code (UPC) length */ +#define IS_VALID_UPC_LEN(x) (((x > MIN_UPC_LEN) && (x <= MAX_UPC_LEN)) ? TRUE : FALSE) + +/** Validate the Tx power index */ +#define IS_VALID_TX_POWER(x) (((x >= MIN_TX_POWER ) && (x <= MAX_TX_POWER)) ? TRUE : FALSE) + +/** Validate the Data rate */ +#define IS_VALID_DATA_RATE_IDX(x) (((x >= MIN_DATA_RATE_IDX) && (x <= MAX_DATA_RATE_IDX)) ? TRUE : FALSE ) + +/** Validate WPS config */ +#define IS_VALID_WPS_CONFIG(x) (((x == WPS_CONFIG_PBC) || (x == WPS_CONFIG_PIN)) ? TRUE : FALSE) + +/** Validate the 802dot11d state */ +#define IS_VALID_802DOT11D_STATE(x) (((x == ENABLE) || (x == DISABLE)) ? TRUE: FALSE) + +/** Validate the AP shutoff time */ +#define IS_VALID_APSHUTOFFTIME(x) (((x >= AP_SHUTOFF_MIN) && (x <= AP_SHUTOFF_MAX)) ? TRUE : FALSE) + +/** Validate the AP shutoff time */ +#define IS_VALID_ENERGY_DETECT_TH(x) ((((x >= AP_ENERGY_DETECT_TH_MIN) && (x <= AP_ENERGY_DETECT_TH_MAX)) ||( x == 128)) ? TRUE : FALSE) + +/** Validate the 802dot11h state */ +#define IS_VALID_DFS_STATE(x) (((x == ENABLE) || (x == DISABLE)) ? TRUE: FALSE) + +/** Function declartion */ +int qsap_hostd_exec(int argc, char ** argv); +void qsap_hostd_exec_cmd(s8 *pcmd, s8 *presp, u32 *plen); +s8 *qsap_get_config_value(s8 *pfile, struct Command *pcmd, s8 *pbuf, u32 *plen); +int qsapsetSoftap(int argc, char *argv[]); +int qsap_add_or_remove_interface(const char *iface_name, int create_iface); +void qsap_del_ctrl_iface(void); +s16 wifi_qsap_reset_to_default(s8 *pcfgfile, s8 *pdefault); +void check_for_configuration_files(void); +void qsap_set_ini_filename(void); +int qsap_set_channel_range(s8 * cmd); +int qsap_get_sap_auto_channel_slection(s32 *pautochan); +int qsap_get_mode(s32 *pmode); +int qsap_prepare_softap(void); +int qsap_unprepare_softap(void); +int qsap_is_fst_enabled(void); +int qsap_control_bridge(int argc, char ** argv); +int linux_get_ifhwaddr(const char *ifname, char *addr); + +#if __cplusplus +}; // extern "C" +#endif + +#endif + diff --git a/sm8250.mk b/sm8250.mk index c6fe8c8..e237a37 100644 --- a/sm8250.mk +++ b/sm8250.mk @@ -426,6 +426,7 @@ PRODUCT_COPY_FILES += \ PRODUCT_PACKAGES += \ android.hardware.wifi@1.0-service \ hostapd \ + libqsap_sdk \ libwpa_client \ libwifi-hal-ctrl \ libwifi-hal-qcom \