Merge change 1628

* changes:
  Begin filling in ARM code generator.
diff --git a/libsysutils/Android.mk b/libsysutils/Android.mk
index cbb1edf..2f3e106 100644
--- a/libsysutils/Android.mk
+++ b/libsysutils/Android.mk
@@ -1,3 +1,10 @@
+BUILD_LIBSYSUTILS := false
+ifneq ($(TARGET_SIMULATOR),true)
+    BUILD_LIBSYSUTILS := true
+endif
+
+ifeq ($(BUILD_LIBSYSUTILS),true)
+
 LOCAL_PATH:= $(call my-dir)
 
 include $(CLEAR_VARS)
@@ -18,4 +25,10 @@
 
 LOCAL_SHARED_LIBRARIES := libcutils
 
+ifeq ($(TARGET_SIMULATOR),true)
+  LOCAL_LDLIBS += -lpthread
+endif
+
 include $(BUILD_SHARED_LIBRARY)
+
+endif
diff --git a/libsysutils/src/FrameworkListener.cpp b/libsysutils/src/FrameworkListener.cpp
index eb96c9a..71e0772 100644
--- a/libsysutils/src/FrameworkListener.cpp
+++ b/libsysutils/src/FrameworkListener.cpp
@@ -59,7 +59,6 @@
 }
 
 void FrameworkListener::dispatchCommand(SocketClient *cli, char *cmd) {
-    LOGD("Dispatching '%s'", cmd);
     char *cm, *last;
 
     if (!(cm = strtok_r(cmd, ":", &last))) {
diff --git a/libsysutils/src/SocketClient.cpp b/libsysutils/src/SocketClient.cpp
index 930fa4c..ab020ca 100644
--- a/libsysutils/src/SocketClient.cpp
+++ b/libsysutils/src/SocketClient.cpp
@@ -28,8 +28,6 @@
 }
 
 int SocketClient::sendMsg(char *msg) {
-    LOGD("SocketClient::sendMsg(%s)", msg);
-
     if (mSocket < 0) {
         errno = EHOSTUNREACH;
         return -1;
diff --git a/libsysutils/src/SocketListener.cpp b/libsysutils/src/SocketListener.cpp
index 7e38546..acc4a67 100644
--- a/libsysutils/src/SocketListener.cpp
+++ b/libsysutils/src/SocketListener.cpp
@@ -61,10 +61,8 @@
     if (mListen && listen(mSock, 4) < 0) {
         LOGE("Unable to listen on socket (%s)", strerror(errno));
         return -1;
-    } else if (!mListen) {
+    } else if (!mListen)
         mClients->push_back(new SocketClient(mSock));
-        LOGD("Created phantom client");
-    }
 
     if (pipe(mCtrlPipe))
         return -1;
@@ -106,12 +104,7 @@
     while(1) {
         SocketClientCollection::iterator it;
         fd_set read_fds;
-        struct timeval to;
         int rc = 0;
-
-        to.tv_sec = 60 * 60;
-        to.tv_usec = 0;
-
         int max = 0;
 
         FD_ZERO(&read_fds);
@@ -133,14 +126,12 @@
         }
         pthread_mutex_unlock(&mClientsLock);
         
-        if ((rc = select(max + 1, &read_fds, NULL, NULL, &to)) < 0) {
+        if ((rc = select(max + 1, &read_fds, NULL, NULL, NULL)) < 0) {
             LOGE("select failed (%s)", strerror(errno));
             sleep(1);
             continue;
-        } else if (!rc) {
-            LOGD("select timeout");
+        } else if (!rc)
             continue;
-        }
 
         if (FD_ISSET(mCtrlPipe[0], &read_fds))
             break;
diff --git a/nexus/Android.mk b/nexus/Android.mk
index 7cf4a1f..df170b8 100644
--- a/nexus/Android.mk
+++ b/nexus/Android.mk
@@ -20,6 +20,8 @@
                   VpnController.cpp        \
                   ScanResult.cpp           \
                   WifiScanner.cpp          \
+                  WifiNetwork.cpp          \
+                  OpenVpnController.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/OpenVpnController.cpp b/nexus/OpenVpnController.cpp
new file mode 100644
index 0000000..eff653a
--- /dev/null
+++ b/nexus/OpenVpnController.cpp
@@ -0,0 +1,104 @@
+/*
+ * 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>
+
+#define LOG_TAG "OpenVpnController"
+#include <cutils/log.h>
+#include <cutils/properties.h>
+
+#include "OpenVpnController.h"
+
+#define DAEMON_PROP_NAME "vpn.openvpn.status"
+
+OpenVpnController::OpenVpnController() :
+                   VpnController() {
+}
+
+int OpenVpnController::start() {
+    return 0;
+}
+
+int OpenVpnController::stop() {
+    return 0;
+}
+
+int OpenVpnController::enable() {
+
+    // Validate configuration file
+   
+    // Validate key file
+
+    if (startServiceDaemon())
+        return -1;
+
+    errno = -ENOSYS;
+    return -1;
+}
+
+int OpenVpnController::startServiceDaemon() {
+    char status[PROPERTY_VALUE_MAX];
+    int count = 100;
+
+    property_set("ctl.start", "openvpn");
+    sched_yield();
+
+    while (count-- > 0) {
+        if (property_get(DAEMON_PROP_NAME, status, NULL)) {
+            if (strcmp(status, "ok") == 0)
+                return 0;
+            else if (strcmp(DAEMON_PROP_NAME, "failed") == 0)
+                return -1;
+        }
+        usleep(200000);
+    }
+    property_set(DAEMON_PROP_NAME, "timeout");
+    return -1;
+}
+
+int OpenVpnController::stopServiceDaemon() {
+    char status[PROPERTY_VALUE_MAX] = {'\0'};
+    int count = 50;
+
+    if (property_get(DAEMON_PROP_NAME, status, NULL) &&
+        !strcmp(status, "stopped")) {
+        LOGD("Service already stopped");
+        return 0;
+    }
+
+    property_set("ctl.stop", "openvpn");
+    sched_yield();
+
+    while (count-- > 0) {
+        if (property_get(DAEMON_PROP_NAME, status, NULL)) {
+            if (!strcmp(status, "stopped"))
+                break;
+        }
+        usleep(100000);
+    }
+
+    if (!count) {
+        LOGD("Timed out waiting for openvpn to stop");
+        errno = ETIMEDOUT;
+        return -1;
+    }
+
+    return 0;
+}
+
+int OpenVpnController::disable() {
+    errno = -ENOSYS;
+    return -1;
+}
diff --git a/nexus/OpenVpnController.h b/nexus/OpenVpnController.h
new file mode 100644
index 0000000..1ecc3fb
--- /dev/null
+++ b/nexus/OpenVpnController.h
@@ -0,0 +1,40 @@
+/*
+ * 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 _OPEN_VPN_CONTROLLER_H
+#define _OPEN_VPN_CONTROLLER_H
+
+#include "VpnController.h"
+
+class OpenVpnController : public VpnController {
+
+public:
+    OpenVpnController();
+    virtual ~OpenVpnController() {}
+
+    int start();
+    int stop();
+    int enable();
+    int disable();
+
+protected:
+
+private:
+    int startServiceDaemon();
+    int stopServiceDaemon();
+};
+
+#endif
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/TiwlanWifiController.cpp b/nexus/TiwlanWifiController.cpp
index 2dc1eb3..27c972b 100644
--- a/nexus/TiwlanWifiController.cpp
+++ b/nexus/TiwlanWifiController.cpp
@@ -48,7 +48,6 @@
     char driver_status[PROPERTY_VALUE_MAX];
     int count = 100;
 
-    LOGD("loadFirmware()");
     property_set("ctl.start", "wlan_loader");
     sched_yield();
 
diff --git a/nexus/VpnController.cpp b/nexus/VpnController.cpp
index 2d3db85..17bfe41 100644
--- a/nexus/VpnController.cpp
+++ b/nexus/VpnController.cpp
@@ -31,9 +31,6 @@
 }
 
 int VpnController::enable() {
-
-    // Load modules
-    // Start daemons
     errno = -ENOSYS;
     return -1;
 }
diff --git a/nexus/VpnController.h b/nexus/VpnController.h
index f792ce3..049fe6e 100644
--- a/nexus/VpnController.h
+++ b/nexus/VpnController.h
@@ -31,8 +31,6 @@
     virtual int disable();
 
 protected:
-
-private:
 };
 
 #endif
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
diff --git a/nexus/main.cpp b/nexus/main.cpp
index 9945034..0aec3e5 100644
--- a/nexus/main.cpp
+++ b/nexus/main.cpp
@@ -23,7 +23,7 @@
 #include "CommandListener.h"
 
 #include "LoopController.h"
-#include "VpnController.h"
+#include "OpenVpnController.h"
 #include "TiwlanWifiController.h"
 
 int main() {
@@ -41,7 +41,8 @@
 
     nm->attachController(new LoopController());
     nm->attachController(new TiwlanWifiController("/system/lib/modules/wlan.ko", "wlan", ""));
-    nm->attachController(new VpnController());
+//    nm->attachController(new AndroidL2TPVpnController());
+    nm->attachController(new OpenVpnController());
 
 
     if (NetworkManager::Instance()->run()) {
@@ -50,11 +51,11 @@
     }
 
     if (cl->startListener()) {
-        LOGE("Unable to start  CommandListener (%s)", strerror(errno));
+        LOGE("Unable to start CommandListener (%s)", strerror(errno));
         exit (1);
     }
 
-    // XXX: we'll use the main thread for the NetworkManager eventuall
+    // XXX: we'll use the main thread for the NetworkManager eventually
     
     while(1) {
         sleep(1000);
diff --git a/toolbox/ifconfig.c b/toolbox/ifconfig.c
index e83cd8b..dff183e 100644
--- a/toolbox/ifconfig.c
+++ b/toolbox/ifconfig.c
@@ -33,6 +33,12 @@
 	sin->sin_addr.s_addr = inet_addr(addr);
 }
 
+static void setdstaddr(int s, struct ifreq *ifr, const char *addr)
+{
+	init_sockaddr_in((struct sockaddr_in *) &ifr->ifr_dstaddr, addr);
+    if(ioctl(s, SIOCSIFDSTADDR, ifr) < 0) die("SIOCSIFDSTADDR");
+}
+
 static void setnetmask(int s, struct ifreq *ifr, const char *addr)
 {
 	init_sockaddr_in((struct sockaddr_in *) &ifr->ifr_netmask, addr);
@@ -120,6 +126,16 @@
     while(argc > 0){
         if(!strcmp(argv[0], "up")) {
             setflags(s, &ifr, IFF_UP, 0);
+        } else if(!strcmp(argv[0], "-pointopoint")) {
+            setflags(s, &ifr, IFF_POINTOPOINT, 1);
+        } else if(!strcmp(argv[0], "pointopoint")) {
+		argc--, argv++;
+		if (0 == argc) { 
+			errno = EINVAL;
+			die("expecting an IP address for parameter \"pointtopoint\"");
+		}
+		setdstaddr(s, &ifr, argv[0]);
+                setflags(s, &ifr, IFF_POINTOPOINT, 0);
         } else if(!strcmp(argv[0], "down")) {
             setflags(s, &ifr, 0, IFF_UP);
 		} else if(!strcmp(argv[0], "netmask")) {