nexus: Initial support for manipulating wifi networks + change wifi scan notification msgs

Signed-off-by: San Mehat <san@google.com>
diff --git a/nexus/Android.mk b/nexus/Android.mk
index 7cf4a1f..42176cf 100644
--- a/nexus/Android.mk
+++ b/nexus/Android.mk
@@ -20,6 +20,7 @@
                   VpnController.cpp        \
                   ScanResult.cpp           \
                   WifiScanner.cpp          \
+                  WifiNetwork.cpp          \
 
 LOCAL_MODULE:= nexus
 
diff --git a/nexus/CommandListener.cpp b/nexus/CommandListener.cpp
index 5967550..d9ee971 100644
--- a/nexus/CommandListener.cpp
+++ b/nexus/CommandListener.cpp
@@ -33,6 +33,11 @@
     registerCmd(new WifiDisableCmd());
     registerCmd(new WifiScanCmd());
     registerCmd(new WifiScanResultsCmd());
+    registerCmd(new WifiListNetworksCmd());
+    registerCmd(new WifiAddNetworkCmd());
+    registerCmd(new WifiRemoveNetworkCmd());
+    registerCmd(new WifiSetVarCmd());
+    registerCmd(new WifiGetVarCmd());
 
     registerCmd(new VpnEnableCmd());
     registerCmd(new VpnDisableCmd());
@@ -70,13 +75,46 @@
     return 0;
 }
 
+CommandListener::WifiAddNetworkCmd::WifiAddNetworkCmd() :
+                 NexusCommand("wifi_add_network") {
+} 
+               
+int CommandListener::WifiAddNetworkCmd::runCommand(SocketClient *cli, char *data) {
+    NetworkManager *nm = NetworkManager::Instance();
+    WifiController *wc = (WifiController *) nm->findController("WIFI");
+    int networkId;
+
+    if ((networkId = wc->addNetwork()) < 0)
+        cli->sendMsg(ErrorCode::OperationFailed, "Failed to add network", true);
+    else {
+        char tmp[128];
+        sprintf(tmp, "Added network id %d.", networkId);
+        cli->sendMsg(ErrorCode::CommandOkay, tmp, false);
+    }
+    return 0;
+}
+
+CommandListener::WifiRemoveNetworkCmd::WifiRemoveNetworkCmd() :
+                 NexusCommand("wifi_remove_network") {
+} 
+               
+int CommandListener::WifiRemoveNetworkCmd::runCommand(SocketClient *cli, char *data) {
+    NetworkManager *nm = NetworkManager::Instance();
+    WifiController *wc = (WifiController *) nm->findController("WIFI");
+
+    if (wc->removeNetwork(atoi(data)))
+        cli->sendMsg(ErrorCode::OperationFailed, "Failed to remove network", true);
+    else {
+        cli->sendMsg(ErrorCode::CommandOkay, "Network removed.", false);
+    }
+    return 0;
+}
+
 CommandListener::WifiScanCmd::WifiScanCmd() :
                  NexusCommand("wifi_scan") {
 } 
 
 int CommandListener::WifiScanCmd::runCommand(SocketClient *cli, char *data) {
-    LOGD("WifiScanCmd(%s)", data);
-
     WifiController *wc = (WifiController *) NetworkManager::Instance()->findController("WIFI");
 
     if (wc->setScanMode(atoi(data)))
@@ -93,7 +131,6 @@
 
 int CommandListener::WifiScanResultsCmd::runCommand(SocketClient *cli, char *data) {
     NetworkManager *nm = NetworkManager::Instance();
-
     WifiController *wc = (WifiController *) nm->findController("WIFI");
 
     ScanResultCollection *src = wc->createScanResults();
@@ -104,7 +141,7 @@
         sprintf(buffer, "%s:%u:%d:%s:%s",
                 (*it)->getBssid(), (*it)->getFreq(), (*it)->getLevel(),
                 (*it)->getFlags(), (*it)->getSsid());
-        cli->sendMsg(125, buffer, false);
+        cli->sendMsg(ErrorCode::WifiScanResult, buffer, false);
         delete (*it);
         it = src->erase(it);
     }
@@ -114,6 +151,99 @@
     return 0;
 }
 
+CommandListener::WifiListNetworksCmd::WifiListNetworksCmd() :
+                 NexusCommand("wifi_list_networks") {
+} 
+
+int CommandListener::WifiListNetworksCmd::runCommand(SocketClient *cli, char *data) {
+    NetworkManager *nm = NetworkManager::Instance();
+    WifiController *wc = (WifiController *) nm->findController("WIFI");
+
+    WifiNetworkCollection *src = wc->createNetworkList();
+    WifiNetworkCollection::iterator it;
+    char buffer[256];
+    
+    for(it = src->begin(); it != src->end(); ++it) {
+        sprintf(buffer, "%d:%s", (*it)->getNetworkId(), (*it)->getSsid());
+        cli->sendMsg(ErrorCode::WifiNetworkList, buffer, false);
+        delete (*it);
+        it = src->erase(it);
+    }
+
+    delete src;
+    cli->sendMsg(ErrorCode::CommandOkay, "Network listing complete.", false);
+    return 0;
+}
+
+CommandListener::WifiSetVarCmd::WifiSetVarCmd() :
+                 NexusCommand("wifi_setvar") {
+} 
+
+int CommandListener::WifiSetVarCmd::runCommand(SocketClient *cli, char *data) {
+    WifiController *wc = (WifiController *) NetworkManager::Instance()->findController("WIFI");
+
+    char *bword;
+    char *last;
+    char varname[32];
+    char val[250];
+    int networkId;
+
+    if (!(bword = strtok_r(data, ":", &last)))
+        goto out_inval;
+
+    networkId = atoi(bword);
+   
+    if (!(bword = strtok_r(NULL, ":", &last)))
+        goto out_inval;
+
+    strncpy(varname, bword, sizeof(varname));
+
+    if (!(bword = strtok_r(NULL, ":", &last)))
+        goto out_inval;
+
+    strncpy(val, bword, sizeof(val));
+
+    LOGD("Network id %d, varname '%s', value '%s'", networkId, varname, val);
+
+    return 0;
+
+out_inval:
+    errno = EINVAL;
+    cli->sendMsg(ErrorCode::CommandParameterError, "Failed to set variable.", true);
+    return 0;
+}
+
+CommandListener::WifiGetVarCmd::WifiGetVarCmd() :
+                 NexusCommand("wifi_getvar") {
+} 
+
+int CommandListener::WifiGetVarCmd::runCommand(SocketClient *cli, char *data) {
+    WifiController *wc = (WifiController *) NetworkManager::Instance()->findController("WIFI");
+
+    char *bword;
+    char *last;
+    char varname[32];
+    int networkId;
+
+    if (!(bword = strtok_r(data, ":", &last)))
+        goto out_inval;
+   
+    networkId = atoi(bword);
+
+    if (!(bword = strtok_r(NULL, ":", &last)))
+        goto out_inval;
+
+    strncpy(varname, bword, sizeof(varname));
+
+    LOGD("networkId = %d, varname '%s'", networkId, varname);
+
+    return 0;
+out_inval:
+    errno = EINVAL;
+    cli->sendMsg(ErrorCode::CommandParameterError, "Failed to get variable.", true);
+    return 0;
+}
+
 /* ------------
  * Vpn Commands
  * ------------ */
diff --git a/nexus/CommandListener.h b/nexus/CommandListener.h
index 064eab8..7bc89e3 100644
--- a/nexus/CommandListener.h
+++ b/nexus/CommandListener.h
@@ -53,6 +53,41 @@
         int runCommand(SocketClient *c, char *data);
     };
 
+    class WifiAddNetworkCmd : public NexusCommand {
+    public:
+        WifiAddNetworkCmd();
+        virtual ~WifiAddNetworkCmd() {}
+        int runCommand(SocketClient *c, char *data);
+    };
+
+    class WifiRemoveNetworkCmd : public NexusCommand {
+    public:
+        WifiRemoveNetworkCmd();
+        virtual ~WifiRemoveNetworkCmd() {}
+        int runCommand(SocketClient *c, char *data);
+    };
+
+    class WifiListNetworksCmd : public NexusCommand {
+    public:
+        WifiListNetworksCmd();
+        virtual ~WifiListNetworksCmd() {}
+        int runCommand(SocketClient *c, char *data);
+    };
+
+    class WifiSetVarCmd : public NexusCommand {
+    public:
+        WifiSetVarCmd();
+        virtual ~WifiSetVarCmd() {}
+        int runCommand(SocketClient *c, char *data);
+    };
+
+    class WifiGetVarCmd : public NexusCommand {
+    public:
+        WifiGetVarCmd();
+        virtual ~WifiGetVarCmd() {}
+        int runCommand(SocketClient *c, char *data);
+    };
+
     class VpnEnableCmd : public NexusCommand {
     public:
         VpnEnableCmd();
diff --git a/nexus/ErrorCode.h b/nexus/ErrorCode.h
index dd2ea3b..8ca6cae 100644
--- a/nexus/ErrorCode.h
+++ b/nexus/ErrorCode.h
@@ -23,6 +23,9 @@
     // before proceeding with a new command.
     static const int ActionInitiated = 100;
 
+    static const int WifiScanResult = 125;
+    static const int WifiNetworkList = 126;
+
     // 200 series - Requested action has been successfully completed
     static const int CommandOkay = 200;
 
@@ -33,6 +36,7 @@
     // 500 series - The command was not accepted and the requested
     // action did not take place.
     static const int CommandSyntaxError = 500;
+    static const int CommandParameterError = 501;
 
     // 600 series - Unsolicited broadcasts
     static const int UnsolicitedInformational = 600;
diff --git a/nexus/Supplicant.cpp b/nexus/Supplicant.cpp
index 9443598..22964bb 100644
--- a/nexus/Supplicant.cpp
+++ b/nexus/Supplicant.cpp
@@ -229,7 +229,7 @@
         return -1;
     }
 
-//    LOGD("sendCommand(): -> '%s'", cmd);
+    LOGD("sendCommand(): -> '%s'", cmd);
 
     int rc;
     if ((rc = wpa_ctrl_request(mCtrl, cmd, strlen(cmd), reply, reply_len, NULL)) == -2)  {
@@ -245,7 +245,7 @@
         !strncmp(cmd, "SCAN_RESULTS", 12)) 
         reply[*reply_len] = '\0';
 
-//    LOGD("sendCommand(): <- '%s'", reply);
+    LOGD("sendCommand(): <- '%s'", reply);
     return 0;
 }
 
@@ -355,7 +355,7 @@
             mLatestScanResults->push_back(new ScanResult(linep));
     
         char tmp[128];
-        sprintf(tmp, "%d scan results ready", mLatestScanResults->size());
+        sprintf(tmp, "Scan results ready (%d)", mLatestScanResults->size());
         NetworkManager::Instance()->getBroadcaster()->
                                     sendBroadcast(ErrorCode::UnsolicitedInformational, tmp, false);
         pthread_mutex_unlock(&mLatestScanResultsLock);
@@ -412,6 +412,35 @@
     return d;
 }
 
+WifiNetworkCollection *Supplicant::createNetworkList() {
+    WifiNetworkCollection *d = new WifiNetworkCollection();
+    return d;
+}
+
+int Supplicant::addNetwork() {
+    char reply[32];
+    size_t len = sizeof(reply) -1;
+
+    memset(reply, 0, sizeof(reply));
+    if (sendCommand("ADD_NETWORK", reply, &len))
+        return -1;
+
+    return atoi(reply);
+}
+
+int Supplicant::removeNetwork(int networkId) {
+    char req[64];
+
+    sprintf(req, "REMOVE_NETWORK %d", networkId);
+    char reply[32];
+    size_t len = sizeof(reply) -1;
+    memset(reply, 0, sizeof(reply));
+    
+    if (sendCommand(req, reply, &len))
+        return -1;
+    return 0;
+}
+
 int Supplicant::setupConfig() {
     char buf[2048];
     int srcfd, destfd;
diff --git a/nexus/Supplicant.h b/nexus/Supplicant.h
index 579bfd6..4a7ec3a 100644
--- a/nexus/Supplicant.h
+++ b/nexus/Supplicant.h
@@ -23,6 +23,7 @@
 #include <pthread.h>
 
 #include "ScanResult.h"
+#include "WifiNetwork.h"
 
 class Supplicant {
 private:
@@ -41,10 +42,13 @@
     int start();
     int stop();
     bool isStarted();
-    int triggerScan(bool active);
 
+    int triggerScan(bool active);
     ScanResultCollection *createLatestScanResults();
-    WifiNetworkCollection *createWifiNetworkList();
+
+    int addNetwork();
+    int removeNetwork(int networkId);
+    WifiNetworkCollection *createNetworkList();
 
 
     int getState() { return mState; }
diff --git a/nexus/WifiController.cpp b/nexus/WifiController.cpp
index f67761a..126db69 100644
--- a/nexus/WifiController.cpp
+++ b/nexus/WifiController.cpp
@@ -23,7 +23,7 @@
 #include "WifiController.h"
 #include "WifiScanner.h"
 #include "NetworkManager.h"
-#include "ErrorCode.h";
+#include "ErrorCode.h"
 
 WifiController::WifiController(char *modpath, char *modname, char *modargs) :
                 Controller("WIFI") {
@@ -151,6 +151,19 @@
     return rc;
 }
 
+int WifiController::addNetwork() {
+    return mSupplicant->addNetwork();
+}
+
+int WifiController::removeNetwork(int networkId) {
+    return mSupplicant->removeNetwork(networkId);
+}
+
 ScanResultCollection *WifiController::createScanResults() {
     return mSupplicant->createLatestScanResults();
 }
+
+// XXX: This should be a const list
+WifiNetworkCollection *WifiController::createNetworkList() {
+    return mSupplicant->createNetworkList();
+}
diff --git a/nexus/WifiController.h b/nexus/WifiController.h
index ba26cb8..b9c981c 100644
--- a/nexus/WifiController.h
+++ b/nexus/WifiController.h
@@ -25,6 +25,7 @@
 class WifiScanner;
 
 #include "ScanResult.h"
+#include "WifiNetwork.h"
 
 class WifiController : public Controller {
 public:
@@ -56,9 +57,13 @@
     int enable();
     int disable();
 
-    ScanResultCollection *createScanResults();
+    int addNetwork();
+    int removeNetwork(int networkId);
+    WifiNetworkCollection *createNetworkList();
 
-    int getType();
+    int getScanMode() { return mCurrentScanMode; }
+    int setScanMode(uint32_t mode);
+    ScanResultCollection *createScanResults();
 
     char *getModulePath() { return mModulePath; }
     char *getModuleName() { return mModuleName; }
@@ -66,9 +71,6 @@
 
     Supplicant *getSupplicant() { return mSupplicant; }
 
-    int getScanMode() { return mCurrentScanMode; }
-    int setScanMode(uint32_t mode);
-
 protected:
     virtual int powerUp() = 0;
     virtual int powerDown() = 0;
diff --git a/nexus/WifiNetwork.cpp b/nexus/WifiNetwork.cpp
new file mode 100644
index 0000000..ef013c0
--- /dev/null
+++ b/nexus/WifiNetwork.cpp
@@ -0,0 +1,109 @@
+/*
+ * Copyright (C) 2008 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <errno.h>
+#include <string.h>
+#include <sys/types.h>
+
+#include "WifiNetwork.h"
+#include "Supplicant.h"
+
+WifiNetwork::WifiNetwork(Supplicant *suppl) {
+    mSuppl = suppl;
+    mNetid = -1;
+    mSsid = NULL;
+    mBssid = NULL;
+    mPsk = NULL;
+    memset(mWepKeys, 0, sizeof(mWepKeys));
+    mDefaultKeyIndex = -1;
+    mPriority = -1;
+    mHiddenSsid = NULL;
+    mAllowedKeyManagement = 0;
+    mAllowedProtocols = 0;
+    mAllowedAuthAlgorithms = 0;
+    mAllowedPairwiseCiphers = 0;
+    mAllowedGroupCiphers = 0;
+}
+
+WifiNetwork::~WifiNetwork() {
+    if (mSsid)
+        free(mSsid);
+    if (mBssid)
+        free(mBssid);
+    if (mPsk)
+        free(mPsk);
+    for (int i = 0; i < 4; i++) {
+        if (mWepKeys[i])
+            free(mWepKeys[i]);
+    }
+    if (mHiddenSsid)
+        free(mHiddenSsid);
+}
+
+int WifiNetwork::setSsid(char *ssid) {
+    errno = ENOSYS;
+    return -1;
+}
+
+int WifiNetwork::setBssid(char *bssid) {
+    errno = ENOSYS;
+    return -1;
+}
+
+int WifiNetwork::setPsk(char *psk) {
+    errno = ENOSYS;
+    return -1;
+}
+
+int WifiNetwork::setWepKey(int idx, char *key) {
+    errno = ENOSYS;
+    return -1;
+}
+
+int WifiNetwork::setDefaultKeyIndex(int idx) {
+    errno = ENOSYS;
+    return -1;
+}
+
+int WifiNetwork::setPriority(int idx) {
+    errno = ENOSYS;
+    return -1;
+}
+
+int WifiNetwork::setHiddenSsid(char *ssid) {
+    errno = ENOSYS;
+    return -1;
+}
+
+int WifiNetwork::setAllowedKeyManagement(uint32_t mask) {
+    errno = ENOSYS;
+    return -1;
+}
+
+int WifiNetwork::setAllowedProtocols(uint32_t mask) {
+    errno = ENOSYS;
+    return -1;
+}
+
+int WifiNetwork::setAllowedPairwiseCiphers(uint32_t mask) {
+    errno = ENOSYS;
+    return -1;
+}
+
+int WifiNetwork::setAllowedGroupCiphers(uint32_t mask) {
+    errno = ENOSYS;
+    return -1;
+}
diff --git a/nexus/WifiNetwork.h b/nexus/WifiNetwork.h
new file mode 100644
index 0000000..1354730
--- /dev/null
+++ b/nexus/WifiNetwork.h
@@ -0,0 +1,174 @@
+/*
+ * Copyright (C) 2008 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef _WIFI_NETWORK_H
+#define _WIFI_NETWORK_H
+
+#include <sys/types.h>
+
+#include "../../../frameworks/base/include/utils/List.h"
+
+class KeyManagementMask {
+public:
+    static const uint32_t NONE      = 0;
+    static const uint32_t WPA_PSK   = 0x01;
+    static const uint32_t WPA_EAP   = 0x02;
+    static const uint32_t IEEE8021X = 0x04;
+    static const uint32_t ALL       = WPA_PSK | WPA_EAP | IEEE8021X;
+};
+
+class SecurityProtocolMask {
+public:
+    static const uint32_t WPA = 0x01;
+    static const uint32_t RSN = 0x02;
+};
+
+class AuthenticationAlgorithmMask {
+public:
+    static const uint32_t OPEN   = 0x01;
+    static const uint32_t SHARED = 0x02;
+    static const uint32_t LEAP   = 0x04;
+};
+
+class PairwiseCipherMask {
+public:
+    static const uint32_t NONE = 0x00;
+    static const uint32_t TKIP = 0x01;
+    static const uint32_t CCMP = 0x02;
+};
+
+class GroupCipherMask {
+public:
+    static const uint32_t WEP40  = 0x01;
+    static const uint32_t WEP104 = 0x02;
+    static const uint32_t TKIP   = 0x04;
+    static const uint32_t CCMP   = 0x08;
+};
+
+class Supplicant;
+
+class WifiNetwork {
+    Supplicant *mSuppl;
+
+    /*
+     * Unique network id - normally provided by supplicant
+     */
+    int mNetid;
+
+    /*
+     * The networks' SSID. Can either be an ASCII string,
+     * which must be enclosed in double quotation marks
+     * (ie: "MyNetwork"), or a string of hex digits which
+     * are not enclosed in quotes (ie: 01ab7893)
+     */
+    char *mSsid;
+
+    /*
+     * When set, this entry should only be used
+     * when associating with the AP having the specified
+     * BSSID. The value is a string in the format of an
+     * Ethernet MAC address
+     */
+    char *mBssid;
+
+    /*
+     *  Pre-shared key for use with WPA-PSK
+     */
+    char *mPsk;
+
+    /*
+     * Up to four WEP keys. Either in ASCII string enclosed in
+     * double quotes, or a string of hex digits
+     */
+    char *mWepKeys[4];
+
+    /*
+     * Default WEP key index, ranging from 0 -> NUM_WEP_KEYS -1
+     */
+    int mDefaultKeyIndex;
+
+    /*
+     * Priority determines the preference given to a network by 
+     * supplicant when choosing an access point with which
+     * to associate
+     */
+    int mPriority;
+
+    /*
+     * This is a network that does not broadcast it's SSID, so an
+     * SSID-specific probe request must be used for scans.
+     */
+    char *mHiddenSsid;
+
+    /*
+     * The set of key management protocols supported by this configuration.
+     */
+    uint32_t mAllowedKeyManagement;
+
+    /*
+     * The set of security protocols supported by this configuration.
+     */
+    uint32_t mAllowedProtocols;
+
+    /*
+     * The set of authentication protocols supported by this configuration.
+     */
+    uint32_t mAllowedAuthAlgorithms;
+
+    /*
+     * The set of pairwise ciphers for WPA supported by this configuration.
+     */
+    uint32_t mAllowedPairwiseCiphers;
+
+    /*
+     * The set of group ciphers for WPA supported by this configuration.
+     */
+    uint32_t mAllowedGroupCiphers;
+
+public:
+    WifiNetwork(Supplicant *suppl);
+    virtual ~WifiNetwork();
+
+    int getNetworkId() { return mNetid; }
+    const char *getSsid() { return mSsid; }
+    const char *getBssid() { return mBssid; }
+    const char *getPsk() { return mPsk; }
+    const char *getWepKey(int idx) { return mWepKeys[idx]; }
+    int getDefaultKeyIndex() { return mDefaultKeyIndex; }
+    int getPriority() { return mPriority; }
+    const char *getHiddenSsid() { return mHiddenSsid; }
+    uint32_t getAllowedKeyManagement() { return mAllowedKeyManagement; }
+    uint32_t getAllowedProtocols() { return mAllowedProtocols; }
+    uint32_t getAllowedAuthAlgorithms() { return mAllowedAuthAlgorithms; }
+    uint32_t getAllowedPairwiseCiphers() { return mAllowedPairwiseCiphers; }
+    uint32_t getAllowedGroupCiphers() { return mAllowedGroupCiphers; }
+
+    int setSsid(char *ssid);
+    int setBssid(char *bssid);
+    int setPsk(char *psk);
+    int setWepKey(int idx, char *key);
+    int setDefaultKeyIndex(int idx);
+    int setPriority(int pri);
+    int setHiddenSsid(char *ssid);
+    int setAllowedKeyManagement(uint32_t mask);
+    int setAllowedProtocols(uint32_t mask);
+    int setAllowedPairwiseCiphers(uint32_t mask);
+    int setAllowedGroupCiphers(uint32_t mask);
+};
+
+typedef android::List<WifiNetwork *> WifiNetworkCollection;
+
+#endif