softap: Add basic functionality directly through WEXT

Signed-off-by: Dmitry Shmidt <dimitrysh@google.com>
diff --git a/SoftapController.cpp b/SoftapController.cpp
index 88bae5c..66310b1 100644
--- a/SoftapController.cpp
+++ b/SoftapController.cpp
@@ -26,6 +26,8 @@
 #include <netinet/in.h>
 #include <arpa/inet.h>
 
+#include <linux/wireless.h>
+
 #define LOG_TAG "SoftapController"
 #include <cutils/log.h>
 
@@ -33,13 +35,47 @@
 
 SoftapController::SoftapController() {
     mPid = 0;
+    mSock = socket(AF_INET, SOCK_DGRAM, 0);
+    if (mSock < 0)
+        LOGE("Failed to open socket");
+    memset(mIface, 0, sizeof(mIface));
 }
 
 SoftapController::~SoftapController() {
+    if (mSock >= 0)
+        close(mSock);
+}
+
+int SoftapController::getPrivFuncNum(char *iface, const char *fname) {
+    struct iwreq wrq;
+    struct iw_priv_args *priv_ptr;
+    int i, ret;
+
+    strncpy(wrq.ifr_name, iface, sizeof(wrq.ifr_name));
+    wrq.u.data.pointer = mBuf;
+    wrq.u.data.length = sizeof(mBuf) / sizeof(struct iw_priv_args);
+    wrq.u.data.flags = 0;
+    if ((ret = ioctl(mSock, SIOCGIWPRIV, &wrq)) < 0) {
+        LOGE("SIOCGIPRIV failed: %d", ret);
+        return ret;
+    }
+    priv_ptr = (struct iw_priv_args *)wrq.u.data.pointer;
+#if 0
+    for(i=0;(i < wrq.u.data.length);i++) {
+        LOGE("%s: [%x] %s\n", __func__, priv_ptr[i].cmd, priv_ptr[i].name);
+    }
+#endif
+    for(i=0;(i < wrq.u.data.length);i++) {
+        if (strcmp(priv_ptr[i].name, fname) == 0)
+            return priv_ptr[i].cmd;
+    }
+    return -1;
 }
 
 int SoftapController::startSoftap() {
+    struct iwreq wrq;
     pid_t pid = 1;
+    int fnum, ret = 0;
 
     LOGD("Softap start");
     if (mPid) {
@@ -47,43 +83,123 @@
         errno = EBUSY;
         return -1;
     }
+    if (mSock < 0) {
+        LOGE("Failed to open socket");
+        return -1;
+    }
 #if 0
    if ((pid = fork()) < 0) {
         LOGE("fork failed (%s)", strerror(errno));
         return -1;
     }
 #endif
+    /* system("iwpriv wl0.1 AP_BSS_START"); */
     if (!pid) {
-        LOGE("Softap Started");
-        return 0;
+        /* start hostapd */
+        return ret;
     } else {
-        mPid = pid;
+        LOGD("Softap Started: %s", mIface);
+        fnum = getPrivFuncNum(mIface, "AP_BSS_START");
+        if (fnum < 0) {
+            LOGE("Softap start - function not supported");
+            return -1;
+        }
+        strncpy(wrq.ifr_name, mIface, sizeof(wrq.ifr_name));
+        wrq.u.data.length = 0;
+        wrq.u.data.pointer = mBuf;
+        wrq.u.data.flags = 0;
+        ret = ioctl(mSock, fnum, &wrq);
+        if (ret) {
+            LOGE("Softap start - failed: %d", ret);
+        }
+        else {
+           mPid = pid;
+           LOGD("Softap start - Ok");
+        }
     }
-    return 0;
+    return ret;
 
 }
 
 int SoftapController::stopSoftap() {
+    struct iwreq wrq;
+    int fnum, ret;
+
     LOGD("Softap stop");
     if (mPid == 0) {
         LOGE("Softap already stopped");
         return 0;
     }
+    if (mSock < 0) {
+        LOGE("Failed to open socket");
+        return -1;
+    }
+    fnum = getPrivFuncNum(mIface, "WL_AP_STOP");
+    if (fnum < 0) {
+        LOGE("Softap stop - function not supported");
+        return -1;
+    }
+    strncpy(wrq.ifr_name, mIface, sizeof(wrq.ifr_name));
+    wrq.u.data.length = 0;
+    wrq.u.data.pointer = mBuf;
+    wrq.u.data.flags = 0;
+    ret = ioctl(mSock, fnum, &wrq);
 #if 0
     LOGD("Stopping Softap service");
     kill(mPid, SIGTERM);
     waitpid(mPid, NULL, 0);
 #endif
     mPid = 0;
-    LOGD("Softap service stopped");
-    return 0;
+    LOGD("Softap service stopped: %d", ret);
+    return ret;
 }
 
 bool SoftapController::isSoftapStarted() {
     return (mPid != 0 ? true : false);
 }
 
+/*
+ * Arguments:
+ *      argv[2] - wlan interface
+ *      argv[3] - softap interface
+ *      argv[4] - command line
+ */
 int SoftapController::setSoftap(int argc, char *argv[]) {
+    struct iwreq wrq;
+    int fnum, ret;
+
     LOGD("Softap set");
-    return 0;
+    if (mSock < 0) {
+        LOGE("Failed to open socket");
+        return -1;
+    }
+    if (argc < 4) {
+        LOGE("Missing arguments");
+        return -1;
+    }
+
+    fnum = getPrivFuncNum(argv[2], "WL_AP_CFG");
+    if (fnum < 0) {
+        LOGE("Softap set - function not supported");
+        return -1;
+    }
+
+    strncpy(mIface, argv[3], sizeof(mIface));
+    strncpy(wrq.ifr_name, argv[2], sizeof(wrq.ifr_name));
+    if (argc >= 4) {
+        strncpy(mBuf, argv[4], sizeof(mBuf));
+    }
+
+    wrq.u.data.length = strlen(mBuf) + 1;
+    wrq.u.data.pointer = mBuf;
+    wrq.u.data.flags = 0;
+    /* system("iwpriv eth0 WL_AP_CFG ASCII_CMD=AP_CFG,SSID=\"AndroidAP\",SEC=\"open\",KEY=12345,CHANNEL=1,PREAMBLE=0,MAX_SCB=8,END"); */
+    ret = ioctl(mSock, fnum, &wrq);
+    if (ret) {
+        LOGE("Softap set - failed: %d", ret);
+    }
+    else {
+        LOGD("Softap set - Ok");
+    }
+    return ret;
 }