diff --git a/EMPTY b/EMPTY deleted file mode 100644 index e69de29..0000000 diff --git a/softap/jni/Android.mk b/softap/jni/Android.mk new file mode 100644 index 0000000..ced8320 --- /dev/null +++ b/softap/jni/Android.mk @@ -0,0 +1,18 @@ + +LOCAL_PATH:= $(call my-dir) + +include $(CLEAR_VARS) + +LOCAL_PRELINK_MODULE := false + +LOCAL_SRC_FILES := QWiFiSoftApCfg.c + +LOCAL_MODULE := libQWiFiSoftApCfg + +LOCAL_C_INCLUDES := $(KERNEL_HEADERS) \ + $(JNI_H_INCLUDE) + +LOCAL_SHARED_LIBRARIES := libsysutils libcutils libnetutils libcrypto + +include $(BUILD_SHARED_LIBRARY) + diff --git a/softap/jni/QWiFiSoftApCfg.c b/softap/jni/QWiFiSoftApCfg.c new file mode 100644 index 0000000..34e2e8c --- /dev/null +++ b/softap/jni/QWiFiSoftApCfg.c @@ -0,0 +1,393 @@ +/* + * Copyright (c) 2010, Code Aurora Forum. 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 Code Aurora Forum, 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 "QWiFiSoftApCfg.h" + +#define UPDATE_ERROR_CODE(msg, code) \ + { \ + int rc; \ + rc = snprintf(resp, sizeof(resp), "failure %s:%s",msg, code); \ + if ( rc == sizeof(resp)) resp[sizeof(resp)-1] = 0; \ + LOGE(resp); \ + } + +static struct sockaddr_nl rtnl_local; +static int rtnl_fd = -1; +static char evt_buf[MAX_EVT_BUF_SIZE]; +static int evt_len; + + +static void softap_handle_associated_event(char *mac_addr) +{ + snprintf(evt_buf, sizeof(evt_buf), "102 Station " HWA_FORM " Associated", + HWA_ARG(mac_addr)); +} + +static void softap_handle_disassociated_event(char *mac_addr) +{ + snprintf(evt_buf, sizeof(evt_buf), "103 Station " HWA_FORM " Disassociated", + HWA_ARG(mac_addr)); +} + +static void softap_handle_wireless_event(char *atr, int atrlen) +{ + int len = 0; + struct iw_event iwe; + char *buffer = atr + RTA_ALIGN(RTATTRLEN); + + atrlen -= RTA_ALIGN(RTATTRLEN); + + while ((len + (int)IW_EV_LCP_LEN) < atrlen) { + memcpy((char *)&iwe, buffer + len, sizeof(struct iw_event)); + + if (iwe.len <= IW_EV_LCP_LEN) + break; + + LOGD("Received Wireless Event: cmd=0x%x len=%d", + iwe.cmd, iwe.len); + + switch (iwe.cmd) { + case IWEVEXPIRED: + LOGD("EVENT: IWEVEXPIRED\n"); + softap_handle_disassociated_event(iwe.u.addr.sa_data); + break; + + case IWEVREGISTERED: + LOGD("EVENT: IWEVREGISTERED\n"); + softap_handle_associated_event(iwe.u.addr.sa_data); + break; + + default: + break; + } + + len += iwe.len; + } + + return; +} + +void softap_handle_rtm_link_event(struct nlmsghdr *hdr) +{ + char *ptr = (char *)NLMSG_DATA(hdr); + struct rtattr *atr; + int atr_len; + + if ((hdr->nlmsg_len - MSGHDRLEN) < IFINFOLEN) { + LOGD("Message Length Problem1"); + return; + } + + if ((atr_len = hdr->nlmsg_len - NLMSG_ALIGN(IFINFOLEN)) < 0) { + LOGD("Message Length Problem2"); + return; + } + + ptr += NLMSG_ALIGN(IFINFOLEN); + atr = (struct rtattr *)ptr; + + while (RTA_OK(atr, atr_len)) { + switch (atr->rta_type) { + case IFLA_WIRELESS: + softap_handle_wireless_event((char *)atr, + atr->rta_len); + break; + + default: + break; + } + + atr = RTA_NEXT(atr, atr_len); + } + + return; +} + +static void softap_handle_iface_event(void) +{ + int cnt, mlen = 0; + char *ptr, buffer[MAX_RECV_BUF_SIZE]; + socklen_t slen; + struct nlmsghdr * hdr; + + while (1) { + cnt = recvfrom(rtnl_fd, buffer, sizeof(buffer), + MSG_DONTWAIT, + (struct sockaddr *)&rtnl_local, &slen); + + if (cnt <= 0) { + buffer[0] = '\0'; + LOGD("recvfrom failed"); + return; + } + + ptr = buffer; + + while (cnt >= MSGHDRLEN) { + hdr = (struct nlmsghdr *)ptr; + + mlen = hdr->nlmsg_len; + + if ((mlen > cnt) || ((mlen - MSGHDRLEN) < 0)) { + break; + } + + switch (hdr->nlmsg_type) { + case RTM_NEWLINK: + case RTM_DELLINK: + softap_handle_rtm_link_event(hdr); + break; + } + + mlen = NLMSG_ALIGN(hdr->nlmsg_len); + cnt -= mlen; + ptr += mlen; + } + } + + return; +} + +static inline int softap_rtnl_wait(void) +{ + fd_set fds; + int oldfd, ret; + + if (rtnl_fd < 0) { + LOGD("Netlink Socket Not Available"); + return -1; + } + + /* Initialize fds */ + FD_ZERO(&fds); + FD_SET(rtnl_fd, &fds); + oldfd = rtnl_fd; + + /* Wait for some trigger event */ + ret = select(oldfd + 1, &fds, NULL, NULL, NULL); + + if (ret < 0) { + /* Error Occurred */ + LOGD("Select on Netlink Socket Failed"); + return ret; + } else if (!ret) { + LOGD("Select on Netlink Socket Timed Out"); + /* Timeout Occurred */ + return -1; + } + + /* Check if any event is available for us */ + if (FD_ISSET(rtnl_fd, &fds)) { + softap_handle_iface_event(); + } + + return 0; +} + +static void softap_rtnl_close(void) +{ + close(rtnl_fd); +} + +static int softap_rtnl_open(void) +{ + int addr_len; + + rtnl_fd = socket(PF_NETLINK, SOCK_RAW, NETLINK_ROUTE); + + if (rtnl_fd < 0) { + LOGE("open netlink socket failed"); + return -1; + } + + memset(&rtnl_local, 0, sizeof(rtnl_local)); + rtnl_local.nl_family = AF_NETLINK; + rtnl_local.nl_groups = RTMGRP_LINK; + + if (bind(rtnl_fd, (struct sockaddr*)&rtnl_local, + sizeof(rtnl_local)) < 0) { + LOGE("bind netlink socket failed"); + return -1; + } + + addr_len = sizeof(rtnl_local); + + if (getsockname(rtnl_fd, (struct sockaddr*)&rtnl_local, + (socklen_t *) &addr_len) < 0) { + LOGE("getsockname failed"); + return -1; + } + + if (addr_len != sizeof(rtnl_local)) { + LOGE("Wrong address length %d\n", addr_len); + return -1; + } + + if (rtnl_local.nl_family != AF_NETLINK) { + LOGE("Wrong address family %d\n", rtnl_local.nl_family); + return -1; + } + + return 0; +} + +JNIEXPORT void JNICALL + Java_com_qualcomm_wifi_softap_QWiFiSoftApCfg_SapCloseNetlink + (JNIEnv *env, jobject obj) +{ + softap_rtnl_close(); + return; +} + +JNIEXPORT jstring JNICALL + Java_com_qualcomm_wifi_softap_QWiFiSoftApCfg_SapWaitForEvent + (JNIEnv *env, jobject obj) +{ + int ret; + + do { + evt_len = 0; + memset(evt_buf, 0, sizeof(evt_buf)); + + ret = softap_rtnl_wait(); + } while (!strlen(evt_buf)); + + return (*env)->NewStringUTF(env, evt_buf); +} + +JNIEXPORT jboolean JNICALL + Java_com_qualcomm_wifi_softap_QWiFiSoftApCfg_SapOpenNetlink + (JNIEnv *env, jobject obj) +{ + if (softap_rtnl_open() != 0) { + LOGD("Netlink Open Fail"); + return JNI_FALSE; + } + + return JNI_TRUE; +} + +JNIEXPORT jstring JNICALL + Java_com_qualcomm_wifi_softap_QWiFiSoftApCfg_SapSendCommand + (JNIEnv *env, jobject obj, jstring jcmd) +{ + const char *pcmd; + char cmd[MAX_CMD_SIZE]; + char resp[MAX_RESP_SIZE]; + int sock, rc; + int done = 0; + char code[32] = {0}; + int connect_retry; + + strncpy(cmd, "softap qccmd ", sizeof(cmd)); + + pcmd = (char *) ((*env)->GetStringUTFChars(env, jcmd, NULL)); + + if ( pcmd == NULL ) { + UPDATE_ERROR_CODE("Command not handled",""); + goto end; + } + + LOGD("Received Command: %s\n", pcmd); + + if ((strlen(cmd) + strlen(pcmd)) > sizeof(cmd)) { + UPDATE_ERROR_CODE("Command length is larger than MAX_CMD_SIZE", ""); + goto end; + } + + strcat(cmd, pcmd); + + connect_retry = 0; + + while ( 1 ) { + if ((sock = socket_local_client("netd", + ANDROID_SOCKET_NAMESPACE_RESERVED, + SOCK_STREAM)) < 0) { + if (connect_retry > 3) { + UPDATE_ERROR_CODE("Error connecting", + strerror(errno)); + goto end; + } + + LOGW("netd might have crashed, wait for it to " + "start back\n"); + sleep(1); + } else { + break; + } + + connect_retry++; + } + + if (write(sock, cmd, strlen(cmd) + 1) < 0) { + UPDATE_ERROR_CODE("Error Writing to socket", strerror(errno)); + goto end; + } + + while (!done) { + int i; + + if ((rc = read(sock, resp, sizeof(resp))) <= 0) { + if (rc == 0) { + UPDATE_ERROR_CODE("Lost connection to Netd", + strerror(errno)); + } else { + UPDATE_ERROR_CODE("Error reading data", + strerror(errno)); + } + + done = 1; + } else { + /* skip broadcase messages */ + i = 0; + + while(resp[i] && (i<(int)(sizeof(code)-1)) && + (resp[i] != ' ') && (resp[i] != '\t')) { + code[i] = resp[i]; + i++; + } + + code[i] = '\0'; + + if ( (!strcmp(code, "success")) || + (!strcmp(code, "failure")) ) { + done=1; + } else { + LOGW("Code(%s)\n", code); + LOGW("Ignore messages : %s\n", resp); + } + } + } + +end: + (*env)->ReleaseStringUTFChars(env, jcmd, pcmd); + + return (*env)->NewStringUTF(env, resp); +} diff --git a/softap/jni/QWiFiSoftApCfg.h b/softap/jni/QWiFiSoftApCfg.h new file mode 100644 index 0000000..c7aaec3 --- /dev/null +++ b/softap/jni/QWiFiSoftApCfg.h @@ -0,0 +1,87 @@ +/* + * Copyright (c) 2010, Code Aurora Forum. 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 Code Aurora Forum, 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. + */ + + +#ifndef __QWIFISOFTAPCFG +#define __QWIFISOFTAPCFG + +#define LOG_TAG "QWIFIAPCFG" + +#include "jni.h" +#include + +#include +#include +#include +#include +#include +#include +#include + +#include + +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include + +#include +#include + +typedef unsigned char u8; + +#define HWA_FORM "%02X:%02X:%02X:%02X:%02X:%02X" +#define HWA_ARG(x) *(((u8 *)x + 0)), *(((u8 *)x + 1)), \ + *(((u8 *)x + 2)), *(((u8 *)x + 3)), \ + *(((u8 *)x + 4)), *(((u8 *)x + 5)) + +#define MAX_RESP_SIZE 256 +#define MAX_CMD_SIZE 256 +#define MAX_EVT_BUF_SIZE 256 +#define MAX_RECV_BUF_SIZE 256 + +#define MSGHDRLEN ((int)(sizeof(struct nlmsghdr))) +#define IFINFOLEN ((int)(sizeof(struct ifinfomsg))) +#define RTATTRLEN ((int)(sizeof(struct rtattr))) + +#ifndef IFLA_WIRELESS +#define IFLA_WIRELESS (IFLA_MASTER + 1) +#endif + +#endif diff --git a/softap/sdk/Android.mk b/softap/sdk/Android.mk new file mode 100644 index 0000000..7827a52 --- /dev/null +++ b/softap/sdk/Android.mk @@ -0,0 +1,19 @@ + + +LOCAL_PATH := $(call my-dir) + +include $(CLEAR_VARS) + +LOCAL_C_INCLUDES := + +LOCAL_MODULE:= libqsap_sdk + +LOCAL_SRC_FILES := qsap_api.c \ + qsap.c + +LOCAL_PRELINK_MODULE := false + +LOCAL_SHARED_LIBRARIES := libnetutils libutils libbinder libcutils + +include $(BUILD_SHARED_LIBRARY) + diff --git a/softap/sdk/qsap.c b/softap/sdk/qsap.c new file mode 100644 index 0000000..2d91a4f --- /dev/null +++ b/softap/sdk/qsap.c @@ -0,0 +1,414 @@ +/* + * Copyright (c) 2010, Code Aurora Forum. 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 Code Aurora Forum, 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 + +#define LOG_TAG "QCLDR-" + +#include "cutils/log.h" +#include "cutils/memory.h" +#include "cutils/misc.h" +#include "cutils/properties.h" +#include "private/android_filesystem_config.h" + +#include "qsap_api.h" +#include "qsap.h" +#include "libwpa_client/wpa_ctrl.h" + +#include + +extern int init_module(const char *name, u32, const s8 *); +extern int delete_module(const char *name, int); + +static s32 check_driver_loaded( const s8 * tag) +{ + FILE *proc; + s8 line[126]; + + if ((proc = fopen("/proc/modules", "r")) == NULL) { + LOGW("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) ) { + LOGE("Driver: %s already loaded\n", filename); + return ret; + } + + LOGD("Loading Driver: %s %s\n", filename, args); + + module = (void*)load_file(filename, (unsigned int*)&size); + + if (!module) { + LOGE("Cannot load file: %s\n", filename); + return -1; + } + + ret = init_module(module, size, args); + + if ( ret ) { + LOGE("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) { + LOGD("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"; + +s32 wifi_qsap_load_driver(void) +{ + s32 size; + s32 ret = 0; + s32 retry; + + /* Unload the station mode driver first */ + wifi_qsap_unload_wifi_sta_driver(); + + if (system(SDIO_POLLING_ON)) { + LOGE("Could not turn on the polling..."); + } + +#define SDIO_IF_DRV "/system/lib/modules/librasdioif.ko" +#define SDIO_IF_DRV_ARG "" +#define SDIO_IF_DRV_TAG "librasdioif" + +#define SOFTAP_DRV "/system/lib/modules/libra.ko" +#define SOFTAP_DRV_ARG "con_mode=1" +#define SOFTAP_DRV_TAG "libra" + + ret = insmod(SDIO_IF_DRV, SDIO_IF_DRV_ARG, SDIO_IF_DRV_TAG " "); + + if ( ret != 0 ) { + LOGE("init_module failed sdioif\n"); + goto end; + } + + sched_yield(); + + ret = insmod(SOFTAP_DRV, SOFTAP_DRV_ARG, SOFTAP_DRV_TAG " "); + + if ( ret != 0 ) { + LOGE("init_module failed libra_softap\n"); + goto end; + } + + sched_yield(); +end: + if(system(SDIO_POLLING_OFF)) { + LOGE("Could not turn off the polling..."); + } + + return ret; +} + +s32 wifi_qsap_unload_wifi_sta_driver(void) +{ + s32 ret = 0; + + if(system(SDIO_POLLING_ON)) { + LOGE("Could not turn on the polling..."); + } + + if ( check_driver_loaded(SOFTAP_DRV_TAG " ") ) { + if ( rmmod(SOFTAP_DRV_TAG) ) { + LOGE("Unable to unload the station mode wifi driver...\n"); + ret = 1; + goto end; + } + } + + sched_yield(); + + if ( check_driver_loaded(SDIO_IF_DRV_TAG " ") ) { + if ( rmmod(SDIO_IF_DRV_TAG) ) { + LOGE("Unable to unload the station mode librasdioif driver\n"); + ret = 1; + goto end; + } + } + +end: + if(system(SDIO_POLLING_OFF)) { + LOGE("Could not turn off the polling..."); + } + sched_yield(); + return 0; +} + +s32 wifi_qsap_unload_driver() +{ + s32 ret = 0; + + if(system(SDIO_POLLING_ON)) { + LOGE("Could not turn on the polling..."); + } + + if ( check_driver_loaded(SOFTAP_DRV_TAG " ") ) { + if ( rmmod(SOFTAP_DRV_TAG) ) { + LOGE("Unable to unload the libra_softap driver\n"); + ret = 1; + goto end; + } + } + + sched_yield(); + + if ( check_driver_loaded(SDIO_IF_DRV_TAG " ") ) { + if ( rmmod(SDIO_IF_DRV_TAG) ) { + LOGE("Unable to unload the librasdioif driver\n"); + ret = 1; + goto end; + } + } +end: + if(system(SDIO_POLLING_OFF)) { + LOGE("Could not turn off the polling..."); + } + + return 0; +} + +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(NULL == (iface = qsap_get_config_value(CONFIG_FILE, "interface", interface, (u32*)&len))) { + LOGE("%s :interface error \n", __func__); + return ret; + } + + /* Issue the stopbss command to driver */ + sock = socket(AF_INET, SOCK_DGRAM, 0); + + if (sock < 0) { + LOGE("Failed to open socket"); + return eERR_STOP_BSS; + } + + strncpy(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) { + LOGE("IOCTL stopbss failed: %ld", ret); + ret = eERR_STOP_BSS; + } else { + LOGD("STOP BSS ISSUED"); + ret = eSUCCESS; + } + + sched_yield(); + return ret; +} + +s32 is_softap_enabled(void) +{ + s8 stat[32] = {0}; + + if ( property_get("init.svc.hostapd", stat, NULL) && + (strcmp(stat, "running") == 0)) { + LOGD("HOSTAPD enabled \n"); + return ENABLE; + } + + LOGD("HOSTAPD disabled \n"); + return DISABLE; +} + +s32 commit(void) +{ +#ifndef SDK_TEST + s32 ret = eERR_COMMIT; + + if ( is_softap_enabled() ) { + /** Stop BSS */ + if(eSUCCESS != wifi_qsap_stop_bss()) { + LOGE("%s: stop bss failed \n", __func__); + return ret; + } + } + + sleep(1); + + return wifi_qsap_start_softap(); +#else + return eSUCCESS; +#endif +} + +s32 wifi_qsap_start_softap() +{ + s32 retry = 4; + + LOGD("Starting Soft AP...\n"); + + while(--retry ) { + /** Stop hostapd */ + if(0 != property_set("ctl.start", "hostapd")) { + LOGE("failed \n"); + continue; + } + + sleep(1); + + if ( is_softap_enabled() ) { + LOGD("success \n"); + return eSUCCESS; + } + } + + LOGE("Unable to start the SoftAP\n"); + return eERR_START_SAP; +} + +s32 wifi_qsap_stop_softap() +{ + if ( is_softap_enabled() ) { + LOGD("Stopping BSS ..... "); + + /** Stop the BSS */ + if (eSUCCESS != wifi_qsap_stop_bss()) { + LOGE("failed \n"); + return eERR_STOP_SAP; + } + sleep(1); + } + + return eSUCCESS; +} + +s32 wifi_qsap_reload_softap() +{ + s32 ret = eERR_RELOAD_SAP; + + /** SDK API to reload the firmware */ + if (eSUCCESS != wifi_qsap_stop_softap()) { + return ret; + } + + if (eSUCCESS != wifi_qsap_unload_driver()) { + return ret; + } + + usleep(500000); + + if (eSUCCESS != wifi_qsap_load_driver()) { + return ret; + } + + sleep(1); + + if (eSUCCESS != wifi_qsap_start_softap()) { + return ret; + } + + return eSUCCESS; +} diff --git a/softap/sdk/qsap.h b/softap/sdk/qsap.h new file mode 100644 index 0000000..9d2600d --- /dev/null +++ b/softap/sdk/qsap.h @@ -0,0 +1,54 @@ +/* + * Copyright (c) 2010, Code Aurora Forum. 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 Code Aurora Forum, 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. + */ + + +#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_reload_softap(void); +s32 wifi_qsap_unload_wifi_sta_driver(void); + +#if __cplusplus +}; // extern "C" +#endif + +#endif // _QSAP_H diff --git a/softap/sdk/qsap_api.c b/softap/sdk/qsap_api.c new file mode 100644 index 0000000..00dd782 --- /dev/null +++ b/softap/sdk/qsap_api.c @@ -0,0 +1,2627 @@ +/* + * Copyright (c) 2010, Code Aurora Forum. 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 Code Aurora Forum, 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 "qsap_api.h" +#include "qsap.h" + +#define QCSAP_IOCTL_GET_CHANNEL (SIOCIWFIRSTPRIV+9) +#define QCSAP_IOCTL_ASSOC_STA_MACADDR (SIOCIWFIRSTPRIV+10) +#define QCSAP_IOCTL_DISASSOC_STA (SIOCIWFIRSTPRIV+11) + +//#define LOG_TAG "QCSDK-" + +#include "cutils/properties.h" +#include "cutils/log.h" + + +#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" +}; + +/* + * WARNING: On updating the cmd_list, the enum esap_cmd in file + * qsap_api.h must be updates to reflect the changes + */ +static s8 *cmd_list[eCMD_LAST] = { + "ssid", + "ignore_broadcast_ssid", + "channel", + "beacon_int", + "dtim_period", + "hw_mode", + "auth_algs", + "security_mode", + "wep_key0", + "wep_key1", + "wep_key2", + "wep_key3", + "wep_default_key", + "wpa_passphrase", + "wpa_pairwise", + "rsn_pairwise", + "mac_address", + "reset_ap", + "macaddr_acl", + "add_to_allow_list", + "add_to_deny_list", + "remove_from_allow_list", + "remove_from_deny_list", + "allow_list", + "deny_list", + "commit", + "enable_softap", + "disassoc_sta", + "reset_to_default", + "protection_flag", + "data_rate", + "sta_mac_list", + "tx_power", + "sdk_version", + "wmm_enabled", + + /** Warning: Do not change the order of the WPS commands */ + "wps_state", + "config_methods", + "uuid", + "device_name", + "manufacturer", + "model_name", + "model_number", + "serial_number", + "device_type", + "os_version", + "friendly_name", + "manufacturer_url", + "model_description", + "model_url", + "upc", + /************ WPS commands end *********/ + + "fragm_threshold", + "rts_threshold", + "wpa_group_rekey", + "country_code", + "intra_bss_forward", + "regulatory_domain", +}; + +static s8 *qsap_str[eSTR_LAST] = { + "wpa", + "accept_mac_file", + "deny_mac_file", + "gAPMacAddr", /** AP MAC address */ + "gEnableApProt", /** protection flag in ini file */ + "gFixedRate", /** Fixed rate in ini */ + "gTxPowerCap", /** Tx power in ini */ + "gFragmentationThreshold", /** Fragmentation threshold in ini */ + "RTSThreshold", /** RTS threshold in ini */ + "gAPCntryCode", /** Country code in ini */ + "gDisableIntraBssFwd", /** Intra-bss forward in ini */ + "WmmIsEnabled", /** WMM */ + "g11dSupportEnabled", /** 802.11d support */ + "ieee80211n", + "ctrl_interface", + "interface", + "eap_server" +}; + +/** Supported operating mode */ +char *hw_mode[HW_MODE_UNKNOWN] = { + "b", "g", "n", "g_only", "n_only" +}; + +/** configuration file path */ +char *pconffile = CONFIG_FILE; +char *fIni = INI_FILE; + +/** + * @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 string + * @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_read_cfg(s8 *pfile, s8 *pcmd, s8 *presp, u32 *plen, s8 *var) +{ + FILE *fcfg; + s8 buf[MAX_CONF_LINE_LEN]; + u16 len; + s8 *val; + + /** Open the configuration file */ + fcfg = fopen(pfile, "r"); + + if(NULL == fcfg) { + LOGE("%s : unable to open file \n", __func__); + *plen = snprintf(presp, *plen, "%s", ERR_RES_UNAVAILABLE); + return eERR_FILE_OPEN; + } + + /** Read the line from the configuration file */ + len = strlen(pcmd); + while(NULL != fgets(buf, MAX_CONF_LINE_LEN, fcfg)) { + s8 *pline = buf; + + /** Skip the commented lines */ + if(buf[0] == '#') { + continue; + } + + /** Identify the configuration parameter in the configuration file */ + if(!strncmp(pline, pcmd, len) && (pline[len] == '=')) { + buf[strlen(buf)-1] = '\0'; + if ( NULL != var ) { + val = strchr(pline, '='); + if(NULL == val) + break; + *plen = snprintf(presp, *plen, "%s %s%s", SUCCESS, var, val); + } + else { + *plen = snprintf(presp, *plen, "%s %s", SUCCESS, pline); + } + fclose(fcfg); + return eSUCCESS; + } + } + + /** Configuration parameter is absent in the file */ + *plen = snprintf(presp, *plen, "%s", ERR_FEATURE_NOT_ENABLED); + + 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, s8 * pcmd, s8 *pVal, s8 *presp, u32 *plen, s32 inifile) +{ + FILE *fcfg, *ftmp; + s8 buf[MAX_CONF_LINE_LEN+1]; + s16 len, result = FALSE; + + LOGD("cmd=%s, Val:%s, INI:%ld \n", pcmd, pVal, inifile); + + /** Open the configuration file */ + fcfg = fopen(pfile, "r"); + if(NULL == fcfg) { + LOGE("%s : unable to open file \n", __func__); + *plen = snprintf(presp, *plen, "%s", ERR_RES_UNAVAILABLE); + return eERR_FILE_OPEN; + } + + /** Open a temporary file */ + ftmp = fopen(TMP_FILE, "w"); + if(NULL == ftmp) { + LOGE("%s : unable to open tmp file \n", __func__); + *plen = snprintf(presp, *plen, "%s", ERR_RES_UNAVAILABLE); + fclose(fcfg); + return eERR_FILE_OPEN; + } + + /** Read the values from the configuration file */ + len = strlen(pcmd); + 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, len)) && (result == FALSE)) { + if(pline[len] == '=') { + snprintf(buf, MAX_CONF_LINE_LEN, "%s=%s\n", pcmd, pVal); + result = TRUE; + LOGD("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 */ + snprintf(buf, MAX_CONF_LINE_LEN, "%s=%s\n", pcmd, pVal); + fprintf(ftmp, "%s", buf); + LOGD("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); + + /** Restore the updated configuration file */ + result = rename(TMP_FILE, pfile); + + *plen = snprintf(presp, *plen, "%s", (result == eERR_UNKNOWN) ? ERR_FEATURE_NOT_ENABLED : SUCCESS); + + /** Remove the temporary file. Dont care the return value */ + unlink(TMP_FILE); + + 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); + + 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); + 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); + if ( !strcmp(presp, ERR_FEATURE_NOT_ENABLED) ) { + /** WPA is disabled, hence WEP is enabled */ + mode = SEC_MODE_WEP; + } + else { + *plen = snprintf(presp, *plen, "%s", ERR_UNKNOWN); + return SEC_MODE_INVALID; + } + } + + if(mode != SEC_MODE_INVALID) { + *plen = snprintf(presp, temp,"%s %s=%d", SUCCESS, cmd_list[eCMD_SEC_MODE], mode); + } + else { + *plen = snprintf(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 parameter name + * @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, s8 *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) { + LOGE("%s : unable to open file \n", __func__); + return eERR_UNKNOWN; + } + + /** Open a temporary file */ + ftmp = fopen(TMP_FILE, "w"); + if(NULL == ftmp) { + LOGE("%s : unable to open tmp file \n", __func__); + fclose(fcfg); + return eERR_UNKNOWN; + } + + /** Read the configuration parameters from the configuration file */ + len = strlen(pcmd); + 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, 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); + + /** Restore the new configuration file */ + if(eERR_UNKNOWN == rename(TMP_FILE, pfile)) { + LOGE("unable to rename the file \n"); + return eERR_UNKNOWN; + } + + /** Delete the temporary file */ + unlink(TMP_FILE); + + 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 = snprintf(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; + } + + snprintf(sec, MAX_INT_STR, "%u", wpa_val); + qsap_write_cfg(pfile, qsap_str[STR_WPA], sec, presp, plen, HOSTAPD_CONF_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)) { + LOGE("%s: wep_default_key error\n", __func__); + goto end; + } + + if(eERR_UNKNOWN == qsap_change_cfg(pfile, cmd_list[eCMD_WEP_KEY0], wep)) { + LOGE("%s: CMD_WEP_KEY0 \n", __func__); + goto end; + } + + if(eERR_UNKNOWN == qsap_change_cfg(pfile, cmd_list[eCMD_WEP_KEY1], wep)) { + LOGE("%s: CMD_WEP_KEY1 \n", __func__); + goto end; + } + + if(eERR_UNKNOWN == qsap_change_cfg(pfile, cmd_list[eCMD_WEP_KEY2], wep)) { + LOGE("%s: CMD_WEP_KEY2 \n", __func__); + goto end; + } + + if(eERR_UNKNOWN == qsap_change_cfg(pfile, cmd_list[eCMD_WEP_KEY3], wep)) { + LOGE("%s: CMD_WEP_KEY3 \n", __func__); + goto end; + } + + if(eERR_UNKNOWN == qsap_change_cfg(pfile, cmd_list[eCMD_PASSPHRASE], wpa)) { + LOGE("%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)) { + LOGE("%s: WPA Pairwise\n", __func__); + goto end; + } + } + + if(eERR_UNKNOWN == qsap_change_cfg(pfile, cmd_list[eCMD_RSN_PAIRWISE], rsn_status)) { + LOGE("%s: WPA2 Pairwise\n", __func__); + goto end; + } + + if(eERR_UNKNOWN == qsap_change_cfg(pfile, qsap_str[STR_WPA], wpa)) { + LOGE("%s: WPA\n", __func__); + goto end; + } + + ret = eSUCCESS; + +end: + *plen = snprintf(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, s8 *pcmd, s8 *pfile, u32 *plen) +{ + if(eSUCCESS == qsap_read_cfg(pcfgfile, pcmd, pfile, plen, NULL)) { + pfile[*plen] = '\0'; + return strchr(pfile, '=') + 1; + } + + return NULL; +} + +/** 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) { + LOGE("%s : File is full\n", __func__); + *plen = snprintf(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) { + LOGE("MAC file is full now.... \n"); + break; + } + + } + len -= strlen(macbuf); + if(*pVal != '\0') + len--; + } + + fclose(fp); + + *plen = snprintf(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) { + LOGE("%s : unable to open the file \n", __func__); + *plen = snprintf(presp, *plen, "%s", ERR_RES_UNAVAILABLE); + return; + } + + /** Open a temporary file */ + ftmp = fopen(TMP_FILE, "w"); + + if(ftmp == NULL) { + LOGE("%s : unable to open the file \n", __func__); + *plen = snprintf(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); + + /** Restore the configuration file */ + status = rename(TMP_FILE, pfile); + + snprintf(presp, *plen, "%s", (status == eERR_UNKNOWN) ? ERR_FEATURE_NOT_ENABLED : SUCCESS); + + unlink(TMP_FILE); + + 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) +{ + LOGD("%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 = snprintf(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 = snprintf(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))) { + LOGE("%s:Unknown error\n", __func__); + *plen = snprintf(presp, *plen, "%s", ERR_RES_UNAVAILABLE); + return; + } + + /** Open allow / deny file, and read the MAC addresses */ + fp = fopen(pfile, "r"); + if(NULL == fp) { + LOGE("%s: file open error\n",__func__); + *plen = snprintf(presp, *plen, "%s", ERR_RES_UNAVAILABLE); + return; + } + + /* Keep the NULL at the end of the buffer */ + presp[*plen-1] = '\0'; + *plen -= snprintf(presp, *plen, "%s %s=", SUCCESS, cmd_list[cNum]); + + /* Reserving the space for last null character in case of over flow */ + (u32)(*plen)--; + + 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 = snprintf(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])) { + LOGE("%s :MAC addr read failure \n",__func__); + goto end; + } + + ptr = strchr(presp, '='); + if(NULL == ptr) + goto end; + + strncpy(mac, ptr+1, MAC_ADDR_LEN); + *plen = snprintf(presp, len, "%s %s=", SUCCESS, cmd_list[eCMD_MAC_ADDR]); + ptr = presp + strlen(presp); + + for(i=0; i= + * 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; + + switch(cNum) { + case eCMD_ENABLE_SOFTAP: + status = is_softap_enabled(); + *plen = snprintf(presp, *plen, "%s %s=%d", SUCCESS, cmd_list[cNum], status); + 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_WEP_KEY0: + case eCMD_WEP_KEY1: + case eCMD_WEP_KEY2: + case eCMD_WEP_KEY3: + case eCMD_DEFAULT_KEY: + case eCMD_PASSPHRASE: + case eCMD_WPA_PAIRWISE: + case eCMD_RSN_PAIRWISE: + case eCMD_MAC_ACL: + case eCMD_WPS_CONFIG_METHOD: + case eCMD_GTK_TIMEOUT: + 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: + qsap_read_cfg(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: + qsap_read_cfg(fIni, qsap_str[STR_FRAG_THRESHOLD_IN_INI], presp, plen, cmd_list[eCMD_FRAG_THRESHOLD]); + break; + + case eCMD_REGULATORY_DOMAIN: + qsap_read_cfg(fIni, qsap_str[STR_802DOT11D_IN_INI], presp, plen, cmd_list[eCMD_REGULATORY_DOMAIN]); + break; + + case eCMD_RTS_THRESHOLD: + qsap_read_cfg(fIni, qsap_str[STR_RTS_THRESHOLD_IN_INI], presp, plen, cmd_list[eCMD_RTS_THRESHOLD]); + 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 = snprintf(presp, *plen, "%s", ERR_NOT_SUPPORTED); + } + break; + + case eCMD_WMM_STATE: + qsap_read_wmm(presp, plen); + 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]); + break; + + case eCMD_DATA_RATES: + qsap_read_cfg(fIni, qsap_str[STR_DATA_RATE_IN_INI], presp, plen, cmd_list[eCMD_DATA_RATES]); + 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]); + break; + + case eCMD_SDK_VERSION: + *plen = snprintf(presp, *plen, "%s", QSAP_SDK_VERSION); + break; + + case eCMD_INTRA_BSS_FORWARD: + qsap_read_cfg(fIni, qsap_str[STR_INTRA_BSS_FORWARD_IN_INI], presp, plen, cmd_list[eCMD_INTRA_BSS_FORWARD]); + break; + + case eCMD_COUNTRY_CODE: + qsap_read_cfg(fIni, qsap_str[STR_COUNTRY_CODE_IN_INI], presp, plen, cmd_list[eCMD_COUNTRY_CODE]); + break; + + default: + /** Error case */ + *plen = snprintf(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 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_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 = snprintf(presp, *plen, "%s", ERR_INVALID_PARAM); + return; + } + + qsap_get_from_config(cNum, presp, plen); + + return; +} + +static s16 is_valid_wep_key(s8 *pwep) +{ + int weplen; + s16 ret = TRUE; + + /** The WEP key should be of length 5, 13 or 16 characters + * or 10, 26, or 32 digits */ + weplen = strlen(pwep); + switch(weplen) { + case WEP_64_KEY_ASCII: + case WEP_128_KEY_ASCII: + case WEP_152_KEY_ASCII: + while(weplen--) { + if(0 == isascii(pwep[weplen])) + return FALSE; + } + 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; + } + return ret; +} + +static s16 wifi_qsap_reset_to_default(void) +{ + FILE *fcfg, *ftmp; + char buf[MAX_CONF_LINE_LEN]; + int status = eSUCCESS; + + fcfg = fopen(DEFAULT_CONFIG_FILE_PATH, "r"); + + if(NULL == fcfg) { + LOGE("%s : unable to open file \n", __func__); + return eERR_FILE_OPEN; + } + + ftmp = fopen(TMP_FILE, "w"); + if(NULL == ftmp) { + LOGE("%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); + + if(eERR_UNKNOWN == rename(TMP_FILE, pconffile)) + status = eERR_CONF_FILE; + + /** Remove the temporary file. Dont care the return value */ + unlink(TMP_FILE); + + return status; +} + +#define CTRL_IFACE_PATH_LEN (128) +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; + + len = CTRL_IFACE_PATH_LEN; + +#define RESP_BUF_SIZE (80) + ptr = malloc(RESP_BUF_SIZE); + if(NULL == ptr) { + LOGE("%s :No memory \n", __func__); + return ret; + } + + if(NULL == (pcif = qsap_get_config_value(pconffile, qsap_str[STR_CTRL_INTERFACE], dst_path, &len))) { + LOGE("%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))) { + LOGE("%s :interface error \n", __func__); + goto error; + } + + if(CTRL_IFACE_PATH_LEN <= snprintf(ptr, CTRL_IFACE_PATH_LEN-1, "%s/%s", pcif, pif)) { + LOGE("Iface path : error, %s \n", ptr); + goto error; + } + + LOGD("Connect to :%s\n", ptr); + + sock = socket(PF_UNIX, SOCK_DGRAM, 0); + if(sock < 0) { + LOGE("%s :Socket error \n", __func__); + goto error; + } + + cli.sun_family = AF_UNIX; + snprintf(cli.sun_path, sizeof(cli.sun_path), SDK_CTRL_IF); + + ret = bind(sock, (struct sockaddr *)&cli, sizeof(cli)); + + if(ret < 0) { + LOGE("Bind Failure\n"); + goto close_ret; + } + + ser.sun_family = AF_UNIX; + snprintf(ser.sun_path, sizeof(ser.sun_path), "%s", ptr); + LOGD("Connect to: %s,(%d)\n", ser.sun_path, sock); + + ret = connect(sock, (struct sockaddr *)&ser, sizeof(ser)); + if(ret < 0) { + LOGE("Connect Failure...\n"); + goto close_ret; + } + + ret = send(sock, pcmd, strlen(pcmd), 0); + if(ret < 0) { + LOGE("Unable to send cmd to hostapd \n"); + goto close_ret; + } + + len = RESP_BUF_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) { + LOGE("%s: recv() failed \n", __func__); + goto close_ret; + } + + if((ret > 0) && (ptr[0] == '<')) { + ptr[ret] = 0; + LOGE("Not the expected response...\n: %s", ptr); + retry_cnt--; + if(retry_cnt) + continue; + break; + } + + ptr[len] = '\0'; + if(!strncmp(ptr, "FAIL", 4)) { + LOGE("Command failed in hostapd \n"); + goto close_ret; + } + } + else { + LOGE("%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[8]; + s32 cmd, i; + + /* Enable/disable the following in hostapd.conf + * 1. Change the security mode to WPA-WPA2 Mixed + * 2. Update wps_state + * 3. Update config_methods + * 4. Update UPnP related variables + */ + status = atoi(pVal); + + if(status == ENABLE) { + snprintf(pwps_state, 8, "%d", WPS_STATE_ENABLE); + cmd = SEC_MODE_WPA_WPA2_PSK; + } + else { + snprintf(pwps_state, 8, "%d", WPS_STATE_DISABLE); + cmd = SEC_MODE_NONE; + } + + qsap_write_cfg(pconffile, cmd_list[eCMD_WPS_STATE], pwps_state, presp, &tlen, HOSTAPD_CONF_FILE); + + snprintf(pwps_state, 8, "%d", ENABLE); + + /** update the eap_server=1 */ + qsap_write_cfg(pconffile, qsap_str[STR_EAP_SERVER], pwps_state, presp, plen, HOSTAPD_CONF_FILE); + + for(i=eCMD_UUID; i<=eCMD_UPC; i++) { + if(eERR_UNKNOWN == qsap_change_cfg(pconffile, cmd_list[i], status)) { + LOGE("%s: failed to set %s\n", __func__, cmd_list[i]); + goto error; + } + } + + return; +error: + *plen = snprintf(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 = snprintf(presp, *plen, "%s", ERR_INVALID_PARAM); + return; + } + + SKIP_BLANK_SPACE(ptr); + + if( (value == WPS_CONFIG_PIN) && (*ptr == '\0') ){ + LOGE("%s :Invalid command \n", __func__); + *plen = snprintf(presp, *plen, "%s", ERR_INVALID_PARAM); + return; + } + + if(value == WPS_CONFIG_PBC) + snprintf(buf, 64, "WPS_PBC"); + else { + if(strlen(ptr) < WPS_KEY_LEN) { + LOGD("%s :Invalid WPS key length\n", __func__); + *plen = snprintf(presp, *plen, "%s", ERR_INVALID_PARAM); + return; + } + snprintf(buf, 64, "WPS_PIN any %s", ptr); + } + + value = qsap_send_cmd_to_hostapd(buf); + + *plen = snprintf(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 11)) { + /** Change the operating mode to 'B' */ + ulen = *tlen; + if(eSUCCESS != qsap_write_cfg(pcfg, cmd_list[eCMD_HW_MODE], hw_mode[HW_MODE_B], tbuf, &ulen, HOSTAPD_CONF_FILE)) { + LOGE("%s :Unable to update the operating mode \n", __func__); + return eERR_UNKNOWN; + } + + ulen = *tlen; + snprintf(schan, MAX_INT_STR, "%d", AUTO_DATA_RATE); + if(eSUCCESS != qsap_write_cfg(fIni, qsap_str[STR_DATA_RATE_IN_INI], schan, tbuf, &ulen, HOSTAPD_CONF_FILE)) { + LOGE("%s :Unable to set to auto data rate \n", __func__); + return eERR_UNKNOWN; + } + } + + snprintf(schan, MAX_INT_STR, "%ld", channel); + + return qsap_write_cfg(pcfg, cmd_list[eCMD_CHAN], schan, tbuf, tlen, HOSTAPD_CONF_FILE); +} + +static int qsap_set_operating_mode(s32 mode, s8 *pmode, s8 *tbuf, u32 *tlen) +{ + u32 ulen; + s8 *pcfgval; + s32 channel; + s8 sconf[MAX_INT_STR+1]; + s8 *pcfg = pconffile; + s32 rate_idx; + + ulen = *tlen; + + /** Read the current operating channel */ + if(NULL == (pcfgval = qsap_get_config_value(pconffile, cmd_list[eCMD_CHAN], tbuf, &ulen))) { + LOGE("%s :Read mode error \n", __func__); + return eERR_UNKNOWN; + } + + /** If the operating channel is 12, 13 or 14 and the mode to be set is not + 'B' mode, then change the channel to auto channel */ + channel = atoi(pcfgval); + + if((channel > BG_MAX_CHANNEL) && (mode != HW_MODE_B)) { + /** change to AUTO channel */ + ulen = *tlen; + snprintf(sconf, MAX_INT_STR, "%d", AUTO_CHANNEL); + if(eSUCCESS != qsap_write_cfg(pcfg, cmd_list[eCMD_CHAN], sconf, tbuf, &ulen, HOSTAPD_CONF_FILE)) { + LOGE("%s :Unable to update the channel \n", __func__); + return eERR_UNKNOWN; + } + } + + ulen = *tlen; + if(NULL == (pcfgval = qsap_get_config_value(fIni, qsap_str[STR_DATA_RATE_IN_INI], tbuf, &ulen))) { + LOGE("%s :Read mode error \n", __func__); + return eERR_UNKNOWN; + } + + /** Update the data rate, depending on the mode to be set */ + rate_idx = atoi(pcfgval); + if(((mode == HW_MODE_B) && (rate_idx > B_MODE_MAX_DATA_RATE_IDX)) || + (((mode == HW_MODE_G) || (mode == HW_MODE_G_ONLY)) && (rate_idx > G_ONLY_MODE_MAX_DATA_RATE_IDX))) { + snprintf(sconf, MAX_INT_STR, "%d", AUTO_DATA_RATE); + ulen = *tlen; + qsap_write_cfg(fIni, qsap_str[STR_DATA_RATE_IN_INI], sconf, tbuf, &ulen, INI_CONF_FILE); + } + + /** Update the operating mode */ + return qsap_write_cfg(pcfg, cmd_list[eCMD_HW_MODE], pmode, tbuf, tlen, HOSTAPD_CONF_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)) { + LOGE("%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))) { + LOGE("%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))) { + LOGE("%s :Invalid rate index \n", __func__); + goto end; + } + + snprintf(sconf, MAX_INT_STR, "%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 = snprintf(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_FILE; + s8 *pcfg = pconffile; + + pcmd += strlen("set"); + + SKIP_BLANK_SPACE(pcmd); + + cNum = qsap_get_cmd_num(pcmd); + if(cNum == eCMD_INVALID) { + *plen = snprintf(presp, *plen, "%s", ERR_INVALID_ARG); + LOGE("Invalid command number :%d\n", cNum); + return; + } + + pVal = pcmd + strlen(cmd_list[cNum]); + if( (cNum != eCMD_COMMIT) && + (cNum != eCMD_RESET_TO_DEFAULT) && + ((*pVal != '=') || (strlen(pVal) < 2)) ) { + *plen = snprintf(presp, *plen, "%s", ERR_INVALID_ARG); + return; + } + pVal++; + + if((cNum != eCMD_COMMIT) && (cNum != eCMD_RESET_TO_DEFAULT)) { + LOGE("Cmd: %s Argument :%s \n", cmd_list[cNum], 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 = snprintf(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 + */ + snprintf(pVal, sizeof(u32), "%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 + */ + snprintf(pVal, sizeof(u32), "%ld", value); + + if(ACL_ALLOW_LIST == value) { + value = ENABLE; + status = DISABLE; + } + else { + value = DISABLE; + 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_FILE); + } + else { + goto error; + } + } + else { + goto error; + } + return; + + case eCMD_COMMIT: + if ( gIniUpdated ) { + status = wifi_qsap_reload_softap(); + gIniUpdated = 0; + } + else { + status = commit(); + } + *plen = snprintf(presp, *plen, "%s", (status == eSUCCESS)? SUCCESS : ERR_UNKNOWN); + return; + + case eCMD_ENABLE_SOFTAP: + value = atoi(pVal); + + if(TRUE != IS_VALID_SOFTAP_ENABLE(value)) + goto error; + + if ( *pVal == '0' ) { + status = wifi_qsap_stop_softap(); + if(status == eSUCCESS) + status = wifi_qsap_unload_driver(); + } + else { + status = wifi_qsap_load_driver(); + if(status == eSUCCESS) + status = wifi_qsap_start_softap(); + } + *plen = snprintf(presp, *plen, "%s", (status==eSUCCESS) ? SUCCESS : "failure Could not enable softap"); + return; + + case eCMD_SSID: + value = strlen(pVal); + if(SSD_MAX_LEN < value) + goto error; + 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 + */ + snprintf(pVal, MAX_INT_STR, "%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); + if(FALSE == IS_VALID_CHANNEL(value)) + goto error; + + ulen = MAX_FILE_PATH_LEN; + value = qsap_set_channel(value, filename, &ulen); + + *plen = snprintf(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 + */ + snprintf(pVal, MAX_INT_STR, "%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 + */ + snprintf(pVal, MAX_INT_STR, "%ld", value); + break; + + case eCMD_HW_MODE: + status = FALSE; + for(value=HW_MODE_B; value 4) { + snprintf(cmdbuf, CMD_BUF_LEN, "set ssid=%s",argv[4]); + } + else { + snprintf(cmdbuf, CMD_BUF_LEN, "set ssid=%s_%d", DEFAULT_SSID, rand()); + } + (void) qsap_hostd_exec_cmd(cmdbuf, respbuf, &rlen); + + if(strncmp("success", respbuf, rlen) != 0) { + LOGE("Failed to set ssid\n"); + return eERR_UNKNOWN; + } + + /** Security */ + rlen = RECV_BUF_LEN; + if(argc > 5) { + int sec = SEC_MODE_NONE; + + /**TODO : need to identify the SEC strings for "wep", "wpa", "wpa2" */ + if(!strcmp(argv[5], "open")) + sec = SEC_MODE_NONE; + + else if(!strcmp(argv[5], "wep")) + sec = SEC_MODE_WEP; + + else if(!strcmp(argv[5], "wpa-psk")) + sec = SEC_MODE_WPA_PSK; + + else if(!strcmp(argv[5], "wpa2-psk")) + sec = SEC_MODE_WPA2_PSK; + + snprintf(cmdbuf, CMD_BUF_LEN, "set security_mode=%d",sec); + } + else { + snprintf(cmdbuf, CMD_BUF_LEN, "set security_mode=%d", DEFAULT_AUTH_ALG); + } + + (void) qsap_hostd_exec_cmd(cmdbuf, respbuf, &rlen); + + if(strncmp("success", respbuf, rlen) != 0) { + LOGE("Failed to set security mode\n"); + return -1; + } + + /** Key -- passphrase */ + rlen = RECV_BUF_LEN; + if(argc > 6) { + snprintf(cmdbuf, CMD_BUF_LEN, "set wpa_passphrase=%s",argv[6]); + } + else { + snprintf(cmdbuf, CMD_BUF_LEN, "set wpa_passphrase=%s", DEFAULT_PASSPHRASE); + } + + (void) qsap_hostd_exec_cmd(cmdbuf, respbuf, &rlen); + + /** channel */ + rlen = RECV_BUF_LEN; + if(argc > 7) { + snprintf(cmdbuf, CMD_BUF_LEN, "set channel=%d", atoi(argv[7])); + } + else { + snprintf(cmdbuf, CMD_BUF_LEN, "set channel=%d", DEFAULT_CHANNEL); + } + (void) qsap_hostd_exec_cmd(cmdbuf, respbuf, &rlen); + + if(strncmp("success", respbuf, rlen) != 0) { + LOGE("Failed to set channel \n"); + return -1; + } + + rlen = RECV_BUF_LEN; + + snprintf(cmdbuf, CMD_BUF_LEN, "set commit"); + + (void) qsap_hostd_exec_cmd(cmdbuf, respbuf, &rlen); + + if(strncmp("success", respbuf, rlen) != 0) { + LOGE("Failed to COMMIT \n"); + return -1; + } + + return 0; +} diff --git a/softap/sdk/qsap_api.h b/softap/sdk/qsap_api.h new file mode 100644 index 0000000..dd396af --- /dev/null +++ b/softap/sdk/qsap_api.h @@ -0,0 +1,504 @@ +/* + * Copyright (c) 2010, Code Aurora Forum. 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 Code Aurora Forum, 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. + */ + + +#ifndef _QSAP_API_H_ +#define _QSAP_API_H_ + +#if __cplusplus +extern "C" { +#endif + +typedef unsigned char u8; +typedef char s8; +typedef unsigned short int u16; +typedef signed short int s16; +typedef unsigned long int u32; +typedef signed long 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" + +/** Error numbers used with the SDK */ +enum error_val { + eERR_UNKNOWN = -1, + eSUCCESS = 0, + eERR_STOP_BSS, + 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 +}; + +/** Soft AP SDK version */ +#define QSAP_SDK_VERSION "1.0" + +/** Configuration file name */ +#define CONFIG_FILE "/system/lib/modules/hostapd.conf" + +/** Default configuration file path */ +#define DEFAULT_CONFIG_FILE_PATH "/system/lib/modules/hostapd_default.conf" + +/** Ini file */ +#define INI_FILE "/system/etc/firmware/wlan/qcom_cfg.ini" + +/** Temporary file name */ +#define TMP_FILE "/system/lib/modules/tmp.qcsoftap.conf" + +/** SDK control interface path */ +#define SDK_CTRL_IF "/system/lib/modules/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) + +/** 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) + +/** RTS threshold 1 to 2347 */ +#define RTS_THRESHOLD_MAX (2347) + +/** Fragmentation threshold 256 to 2346 */ +#define FRAG_THRESHOLD_MAX (2346) + +/** 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) + +#define FRAG_THRESHOLD_MIN (256) +#define FRAG_THRESHOLD_MAX (2346) + +#define RTS_THRESHOLD_MIN (0) +#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 (600) + +#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) + +/** command request index - in the array Cmd_req[] */ +enum eCmd_req { + eCMD_GET = 0, + eCMD_SET = 1, + + eCMD_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_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, + 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_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 +}; + +enum ap_reset { + SAP_RESET_BSS = 0, + SAP_RESET_DRIVER_BSS = 1, + SAP_STOP_BSS = 2, + SAP_STOP_DRIVER_BSS = 3, + SAP_RESET_INVALID +}; + +enum wmm_state { + 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_FILE = 0, + INI_CONF_FILE = 1 +}; + +/** 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)) ? 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)) ? 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"))) ? TRUE : FALSE) + +/** Validate the WMM status */ +#define IS_VALID_WMM_STATE(x) (((x == ENABLE) || (x == DISABLE)) ? 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) + +/** Function declartion */ +void qsap_hostd_exec_cmd(s8 *pcmd, s8 *presp, u32 *plen); +s8 *qsap_get_config_value(s8 *pfile, s8 *pcmd, s8 *pbuf, u32 *plen); +int qsapsetSoftap(int argc, char *argv[]); + +#if __cplusplus +}; // extern "C" +#endif + +#endif +