nexus: Refactor some of the create/remove network path and add code for
       retrieving network lists from supplicant
nexus: Rework properties
nexus: Implement wifi network enable/disable and add some error checking
nexus: Add some TODOs
nexus: Whitespace cleanup
nexus: Add bindings between controllers and network interfaces
nexus: Add properties for InterfaceConfig
nexus: Fix a few conversion bugs in InterfaceConfig

Signed-off-by: San Mehat <san@google.com>
diff --git a/nexus/Android.mk b/nexus/Android.mk
index 61240d5..1c4a394 100644
--- a/nexus/Android.mk
+++ b/nexus/Android.mk
@@ -23,10 +23,12 @@
                   WifiNetwork.cpp          \
                   OpenVpnController.cpp    \
                   InterfaceConfig.cpp      \
+                  PropertyManager.cpp      \
+                  SupplicantState.cpp 
 
 LOCAL_MODULE:= nexus
 
-LOCAL_C_INCLUDES := $(KERNEL_HEADERS)
+LOCAL_C_INCLUDES := $(KERNEL_HEADERS) -I../../../frameworks/base/include/
 
 LOCAL_CFLAGS := 
 
diff --git a/nexus/CommandListener.cpp b/nexus/CommandListener.cpp
index e2edc77..e8de7f5 100644
--- a/nexus/CommandListener.cpp
+++ b/nexus/CommandListener.cpp
@@ -1,5 +1,5 @@
 /*
- * Copyright (C) ErrorCode::CommandOkay8 The Android Open Source Project
+ * 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.
@@ -13,6 +13,7 @@
  * See the License for the specific language governing permissions and
  * limitations under the License.
  */
+
 #include <stdlib.h>
 #include <sys/socket.h>
 #include <netinet/in.h>
@@ -26,6 +27,7 @@
 
 #include "CommandListener.h"
 #include "Controller.h"
+#include "Property.h"
 #include "NetworkManager.h"
 #include "WifiController.h"
 #include "VpnController.h"
@@ -35,31 +37,32 @@
                  FrameworkListener("nexus") {
     registerCmd(new WifiScanResultsCmd());
     registerCmd(new WifiListNetworksCmd());
-    registerCmd(new WifiAddNetworkCmd());
+    registerCmd(new WifiCreateNetworkCmd());
     registerCmd(new WifiRemoveNetworkCmd());
 
     registerCmd(new GetCmd());
     registerCmd(new SetCmd());
+    registerCmd(new ListCmd());
 }
- 
+
 /* -------------
  * Wifi Commands
  * ------------ */
 
-CommandListener::WifiAddNetworkCmd::WifiAddNetworkCmd() :
-                 NexusCommand("wifi_add_network") {
-} 
-               
-int CommandListener::WifiAddNetworkCmd::runCommand(SocketClient *cli, char *data) {
+CommandListener::WifiCreateNetworkCmd::WifiCreateNetworkCmd() :
+                 NexusCommand("wifi_create_network") {
+}
+
+int CommandListener::WifiCreateNetworkCmd::runCommand(SocketClient *cli, char *data) {
     NetworkManager *nm = NetworkManager::Instance();
     WifiController *wc = (WifiController *) nm->findController("WIFI");
-    int networkId;
+    WifiNetwork *wn;
 
-    if ((networkId = wc->addNetwork()) < 0)
-        cli->sendMsg(ErrorCode::OperationFailed, "Failed to add network", true);
+    if (!(wn = wc->createNetwork()))
+        cli->sendMsg(ErrorCode::OperationFailed, "Failed to create network", true);
     else {
         char tmp[128];
-        sprintf(tmp, "Added network id %d.", networkId);
+        sprintf(tmp, "Created network id %d.", wn->getNetworkId());
         cli->sendMsg(ErrorCode::CommandOkay, tmp, false);
     }
     return 0;
@@ -67,8 +70,8 @@
 
 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");
@@ -83,7 +86,7 @@
 
 CommandListener::WifiScanResultsCmd::WifiScanResultsCmd() :
                  NexusCommand("wifi_scan_results") {
-} 
+}
 
 int CommandListener::WifiScanResultsCmd::runCommand(SocketClient *cli, char *data) {
     NetworkManager *nm = NetworkManager::Instance();
@@ -92,7 +95,7 @@
     ScanResultCollection *src = wc->createScanResults();
     ScanResultCollection::iterator it;
     char buffer[256];
-    
+
     for(it = src->begin(); it != src->end(); ++it) {
         sprintf(buffer, "%s:%u:%d:%s:%s",
                 (*it)->getBssid(), (*it)->getFreq(), (*it)->getLevel(),
@@ -103,13 +106,13 @@
     }
 
     delete src;
-    cli->sendMsg(ErrorCode::CommandOkay, "Scan results complete", false);
+    cli->sendMsg(ErrorCode::CommandOkay, "Scan results complete.", false);
     return 0;
 }
 
 CommandListener::WifiListNetworksCmd::WifiListNetworksCmd() :
                  NexusCommand("wifi_list_networks") {
-} 
+}
 
 int CommandListener::WifiListNetworksCmd::runCommand(SocketClient *cli, char *data) {
     NetworkManager *nm = NetworkManager::Instance();
@@ -118,12 +121,11 @@
     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;
@@ -140,34 +142,31 @@
  * ---------------- */
 CommandListener::GetCmd::GetCmd() :
                  NexusCommand("get") {
-} 
+}
 
 int CommandListener::GetCmd::runCommand(SocketClient *cli, char *data) {
-    char *bword;
-    char *last;
-    char propname[32];
+    char *next = data;
+    char *propname;
 
-    if (!(bword = strtok_r(data, ":", &last)))
+    if (!(propname = strsep(&next, ":")))
         goto out_inval;
-   
-    strncpy(propname, bword, sizeof(propname));
 
-    char pb[255];
+    char pb[Property::NameMaxSize + 6];
     snprintf(pb, sizeof(pb), "%s:", propname);
 
-    if (!NetworkManager::Instance()->getProperty(propname,
-                                                 &pb[strlen(pb)],
-                                                 sizeof(pb) - strlen(pb))) {
+    if (!NetworkManager::Instance()->getPropMngr()->get(propname,
+                                                        &pb[strlen(pb)],
+                                                        sizeof(pb) - strlen(pb))) {
         goto out_inval;
     }
 
-    cli->sendMsg(ErrorCode::VariableRead, pb, false);
+    cli->sendMsg(ErrorCode::PropertyRead, pb, false);
 
     cli->sendMsg(ErrorCode::CommandOkay, "Property read.", false);
     return 0;
 out_inval:
     errno = EINVAL;
-    cli->sendMsg(ErrorCode::CommandParameterError, "Failed to get variable.", true);
+    cli->sendMsg(ErrorCode::CommandParameterError, "Failed to read property.", true);
     return 0;
 }
 
@@ -178,8 +177,8 @@
 int CommandListener::SetCmd::runCommand(SocketClient *cli, char *data) {
     char *bword;
     char *last;
-    char propname[32];
-    char propval[250];
+    char propname[Property::NameMaxSize];
+    char propval[Property::ValueMaxSize];
 
     if (!(bword = strtok_r(data, ":", &last)))
         goto out_inval;
@@ -191,7 +190,7 @@
 
     strncpy(propval, bword, sizeof(propval));
 
-    if (NetworkManager::Instance()->setProperty(propname, propval))
+    if (NetworkManager::Instance()->getPropMngr()->set(propname, propval))
         goto out_inval;
 
     cli->sendMsg(ErrorCode::CommandOkay, "Property set.", false);
@@ -208,5 +207,39 @@
 }
 
 int CommandListener::ListCmd::runCommand(SocketClient *cli, char *data) {
+    android::List<char *> *pc;
+
+    if (!(pc = NetworkManager::Instance()->getPropMngr()->createPropertyList())) {
+        errno = ENODATA;
+        cli->sendMsg(ErrorCode::CommandParameterError, "Failed to list properties.", true);
+        return 0;
+    }
+
+    android::List<char *>::iterator it;
+
+    for (it = pc->begin(); it != pc->end(); ++it) {
+        char p_v[Property::ValueMaxSize];
+
+        if (!NetworkManager::Instance()->getPropMngr()->get((*it),
+                                                            p_v,
+                                                            sizeof(p_v))) {
+            LOGW("Failed to get %s (%s)", (*it), strerror(errno));
+        }
+
+        char *buf;
+        if (asprintf(&buf, "%s:%s", (*it), p_v) < 0) {
+            LOGE("Failed to allocate memory");
+            free((*it));
+            continue;
+        }
+        cli->sendMsg(ErrorCode::PropertyList, buf, false);
+        free(buf);
+
+        free((*it));
+    }
+
+    delete pc;
+
+    cli->sendMsg(ErrorCode::CommandOkay, "Properties list complete.", false);
     return 0;
 }
diff --git a/nexus/CommandListener.h b/nexus/CommandListener.h
index b44d3ec..b57c25f 100644
--- a/nexus/CommandListener.h
+++ b/nexus/CommandListener.h
@@ -13,6 +13,7 @@
  * See the License for the specific language governing permissions and
  * limitations under the License.
  */
+
 #ifndef _COMMANDLISTENER_H__
 #define _COMMANDLISTENER_H__
 
@@ -40,10 +41,10 @@
         int runCommand(SocketClient *c, char *data);
     };
 
-    class WifiAddNetworkCmd : public NexusCommand {
+    class WifiCreateNetworkCmd : public NexusCommand {
     public:
-        WifiAddNetworkCmd();
-        virtual ~WifiAddNetworkCmd() {}
+        WifiCreateNetworkCmd();
+        virtual ~WifiCreateNetworkCmd() {}
         int runCommand(SocketClient *c, char *data);
     };
 
diff --git a/nexus/Controller.cpp b/nexus/Controller.cpp
index 133e796..9d4ff3c 100644
--- a/nexus/Controller.cpp
+++ b/nexus/Controller.cpp
@@ -13,6 +13,7 @@
  * See the License for the specific language governing permissions and
  * limitations under the License.
  */
+
 #include <stdio.h>
 #include <stdlib.h>
 #include <string.h>
@@ -33,13 +34,17 @@
 extern "C" int init_module(void *, unsigned int, const char *);
 extern "C" int delete_module(const char *, unsigned int);
 
-Controller::Controller(const char *name, const char *prefix) {
-    mName = name;
-    mPropertyPrefix = prefix;
-    mProperties = new PropertyCollection();
+Controller::Controller(const char *name, PropertyManager *propMngr) {
+    mPropMngr = propMngr;
+    mName = strdup(name);
+    mBoundInterface = NULL;
+}
 
-    mEnabled = false;
-    registerProperty("enable");
+Controller::~Controller() {
+    if (mBoundInterface)
+        free(mBoundInterface);
+    if (mName)
+        free(mName);
 }
 
 int Controller::start() {
@@ -50,65 +55,16 @@
     return 0;
 }
 
-const PropertyCollection & Controller::getProperties() {
-    return *mProperties;
-}
-
-int Controller::setProperty(const char *name, char *value) {
-    if (!strcmp(name, "enable")) {
-        int en = atoi(value);
-        int rc;
-
-        rc = (en ? enable() : disable());
-
-        if (!rc)
-            mEnabled = en;
-
-        return rc;
-    }
-
+int Controller::set(const char *name, const char *value) {
     errno = ENOENT;
     return -1;
 }
 
-const char *Controller::getProperty(const char *name, char *buffer, size_t maxsize) {
-    if (!strcmp(name, "enable")) {
-        snprintf(buffer, maxsize, "%d", mEnabled);
-        return buffer;
-    }
-
+const char *Controller::get(const char *name, char *buffer, size_t maxsize) {
     errno = ENOENT;
     return NULL;
 }
 
-int Controller::registerProperty(const char *name) {
-    PropertyCollection::iterator it;
-
-    for (it = mProperties->begin(); it != mProperties->end(); ++it) {
-        if (!strcmp(name, (*it))) {
-            errno = EADDRINUSE;
-            LOGE("Failed to register property (%s)", strerror(errno));
-            return -1;
-        }
-    }
-
-    mProperties->push_back(name);
-    return 0;
-}
-
-int Controller::unregisterProperty(const char *name) {
-    PropertyCollection::iterator it;
-
-    for (it = mProperties->begin(); it != mProperties->end(); ++it) {
-        if (!strcmp(name, (*it))) {
-            mProperties->erase(it);
-            return 0;
-        }
-    }
-    errno = ENOENT;
-    return -1;
-}
-
 int Controller::loadKernelModule(char *modpath, const char *args) {
     void *module;
     unsigned int size;
@@ -137,7 +93,7 @@
     }
 
     if (rc != 0) {
-        LOGW("Unable to unload kernel driver '%s' (%s)", modtag, 
+        LOGW("Unable to unload kernel driver '%s' (%s)", modtag,
              strerror(errno));
     }
     return rc;
@@ -203,3 +159,16 @@
 	close(fd);
 	return buffer;
 }
+
+int Controller::bindInterface(const char *ifname) {
+    mBoundInterface = strdup(ifname);
+    LOGD("Controller %s bound to %s", mName, ifname);
+    return 0;
+}
+
+int Controller::unbindInterface(const char *ifname) {
+    free(mBoundInterface);
+    mBoundInterface = NULL;
+    LOGD("Controller %s unbound from %s", mName, ifname);
+    return 0;
+}
diff --git a/nexus/Controller.h b/nexus/Controller.h
index ae37426..9137f9a 100644
--- a/nexus/Controller.h
+++ b/nexus/Controller.h
@@ -13,51 +13,59 @@
  * See the License for the specific language governing permissions and
  * limitations under the License.
  */
+
 #ifndef _CONTROLLER_H
 #define _CONTROLLER_H
 
 #include <unistd.h>
 #include <sys/types.h>
 
-#include "../../../frameworks/base/include/utils/List.h"
+#include <utils/List.h>
 
-#include "PropertyCollection.h"
+class PropertyManager;
 
-class Controller {
+#include "PropertyManager.h"
+#include "IPropertyProvider.h"
+
+class Controller : public IPropertyProvider {
 private:
-    const char *mName;
-    const char *mPropertyPrefix;
-    PropertyCollection *mProperties;
-    bool mEnabled;
+    /*
+     * Name of this controller - WIFI/VPN/USBNET/BTNET/BTDUN/LOOP/etc
+     */
+    char *mName;
+
+    /*
+     * Name of the system ethernet interface which this controller is
+     * bound to.
+     */
+    char *mBoundInterface;
+
+protected:
+    PropertyManager *mPropMngr;
     
 public:
-    Controller(const char *name, const char *prefix);
-    virtual ~Controller() {}
+    Controller(const char *name, PropertyManager *propMngr);
+    virtual ~Controller();
 
     virtual int start();
     virtual int stop();
 
-    virtual const PropertyCollection &getProperties();
-    virtual int setProperty(const char *name, char *value);
-    virtual const char *getProperty(const char *name, char *buffer, size_t maxsize);
-
     const char *getName() { return mName; }
-    const char *getPropertyPrefix() { return mPropertyPrefix; }
+    const char *getBoundInterface() { return mBoundInterface; }
+
+    /* IPropertyProvider methods */
+    virtual int set(const char *name, const char *value);
+    virtual const char *get(const char *name, char *buffer, size_t maxsize);
 
 protected:
     int loadKernelModule(char *modpath, const char *args);
     bool isKernelModuleLoaded(const char *modtag);
     int unloadKernelModule(const char *modtag);
-
-    int registerProperty(const char *name);
-    int unregisterProperty(const char *name);
+    int bindInterface(const char *ifname);
+    int unbindInterface(const char *ifname);
 
 private:
     void *loadFile(char *filename, unsigned int *_size);
-
-    virtual int enable() = 0;
-    virtual int disable() = 0;
-
 };
 
 typedef android::List<Controller *> ControllerCollection;
diff --git a/nexus/ErrorCode.h b/nexus/ErrorCode.h
index 57c99c2..414dd2c 100644
--- a/nexus/ErrorCode.h
+++ b/nexus/ErrorCode.h
@@ -26,8 +26,9 @@
     static const int WifiScanResult = 125;
     static const int WifiNetworkList = 126;
 
-    static const int VariableRead = 127;
-    static const int VariableWrite = 128;
+    static const int PropertyRead = 127;
+    static const int PropertySet = 128;
+    static const int PropertyList = 129;
 
     // 200 series - Requested action has been successfully completed
     static const int CommandOkay = 200;
diff --git a/nexus/PropertyCollection.h b/nexus/IPropertyProvider.h
similarity index 62%
copy from nexus/PropertyCollection.h
copy to nexus/IPropertyProvider.h
index 4be1cf0..17ad5f8 100644
--- a/nexus/PropertyCollection.h
+++ b/nexus/IPropertyProvider.h
@@ -14,12 +14,20 @@
  * limitations under the License.
  */
 
-#ifndef _PROPERTY_COLLECTION_H
-#define _PROPERTY_COLLECTION_H
+#ifndef _IPROPERTY_PROVIDER_H
+#define _IPROPERTY_PROVIDER_H
 
-#include "../../../frameworks/base/include/utils/List.h"
+#include <unistd.h>
+#include <sys/types.h>
 
-typedef android::List<const char *> PropertyCollection;
+#include <utils/List.h>
+
+class IPropertyProvider {
+public:
+    virtual int set(const char *name, const char *value) = 0;
+    virtual const char *get(const char *name, char *buffer, size_t max) = 0;
+};
+
+typedef android::List<IPropertyProvider *> IPropertyProviderCollection;
 
 #endif
-
diff --git a/nexus/InterfaceConfig.cpp b/nexus/InterfaceConfig.cpp
index 89936f8..66861d0 100644
--- a/nexus/InterfaceConfig.cpp
+++ b/nexus/InterfaceConfig.cpp
@@ -14,47 +14,59 @@
  * limitations under the License.
  */
 
+#include <stdlib.h>
 #include <string.h>
 
 #define LOG_TAG "InterfaceConfig"
 #include <cutils/log.h>
 
 #include "InterfaceConfig.h"
+#include "NetworkManager.h"
 
-InterfaceConfig::InterfaceConfig(const char *name) {
-    mName = strdup(name);
+const char *InterfaceConfig::PropertyNames[] = { "dhcp", "ip",
+                                                 "netmask",
+                                                 "gateway", "dns1", "dns2",
+                                                 "dns3", '\0' };
+
+InterfaceConfig::InterfaceConfig(const char *prop_prefix) {
+    mPropPrefix = strdup(prop_prefix);
     mUseDhcp = true;
+    registerProperties();
 }
 
 InterfaceConfig::~InterfaceConfig() {
-    free(mName);
+    unregisterProperties();
+    free(mPropPrefix);
 }
 
-InterfaceConfig::InterfaceConfig(const char *name, const char *ip, const char *nm,
+InterfaceConfig::InterfaceConfig(const char *prop_prefix,
+                    const char *ip, const char *nm,
                     const char *gw, const char *dns1, const char *dns2,
                     const char *dns3) {
-    mName = strdup(name);
+    mPropPrefix = strdup(prop_prefix);
     mUseDhcp = false;
 
     if (!inet_aton(ip, &mIp))
         LOGW("Unable to parse ip (%s)", ip);
-    if (!inet_aton(nm, &mIp))
+    if (!inet_aton(nm, &mNetmask))
         LOGW("Unable to parse netmask (%s)", nm);
-    if (!inet_aton(gw, &mIp))
+    if (!inet_aton(gw, &mGateway))
         LOGW("Unable to parse gateway (%s)", gw);
-    if (!inet_aton(dns1, &mIp))
+    if (!inet_aton(dns1, &mDns1))
         LOGW("Unable to parse dns1 (%s)", dns1);
-    if (!inet_aton(dns2, &mIp))
+    if (!inet_aton(dns2, &mDns2))
         LOGW("Unable to parse dns2 (%s)", dns2);
-    if (!inet_aton(dns3, &mIp))
+    if (!inet_aton(dns3, &mDns3))
         LOGW("Unable to parse dns3 (%s)", dns3);
+    registerProperties();
 }
 
-InterfaceConfig::InterfaceConfig(const char *name, const struct in_addr *ip,
+InterfaceConfig::InterfaceConfig(const char *prop_prefix,
+                    const struct in_addr *ip,
                     const struct in_addr *nm, const struct in_addr *gw,
                     const struct in_addr *dns1, const struct in_addr *dns2,
                     const struct in_addr *dns3) {
-    mName = strdup(name);
+    mPropPrefix = strdup(prop_prefix);
     mUseDhcp = false;
 
     memcpy(&mIp, ip, sizeof(struct in_addr));
@@ -63,5 +75,95 @@
     memcpy(&mDns1, dns1, sizeof(struct in_addr));
     memcpy(&mDns2, dns2, sizeof(struct in_addr));
     memcpy(&mDns3, dns3, sizeof(struct in_addr));
+    registerProperties();
 }
 
+int InterfaceConfig::registerProperties() {
+    for (const char **p = InterfaceConfig::PropertyNames; *p != '\0'; p++) {
+        char *tmp;
+        asprintf(&tmp, "%s.if.%s", mPropPrefix, *p);
+
+        if (NetworkManager::Instance()->getPropMngr()->registerProperty(tmp,
+                                                                        this)) {
+            free(tmp);
+            return -1;
+        }
+        free(tmp);
+    }
+    return 0;
+}
+
+int InterfaceConfig::unregisterProperties() {
+    for (const char **p = InterfaceConfig::PropertyNames; *p != '\0'; p++) {
+        char *tmp;
+        asprintf(&tmp, "%s.if.%s", mPropPrefix, *p);
+
+        if (NetworkManager::Instance()->getPropMngr()->unregisterProperty(tmp))
+            LOGW("Unable to remove property '%s' (%s)", tmp, strerror(errno));
+        free(tmp);
+    }
+    return 0;
+}
+
+int InterfaceConfig::set(const char *name, const char *value) {
+    const char *n;
+
+    for (n = &name[strlen(name)]; *n != '.'; n--);
+    n++;
+
+    if (!strcasecmp(n, "name")) {
+        errno = EROFS;
+        return -1;
+    } else if (!strcasecmp(n, "ip") && !inet_aton(value, &mIp))
+        goto out_inval;
+    else if (!strcasecmp(n, "dhcp"))
+        mUseDhcp = (atoi(value) == 0 ? false : true);
+    else if (!strcasecmp(n, "netmask") && !inet_aton(value, &mNetmask))
+        goto out_inval;
+    else if (!strcasecmp(n, "gateway") && !inet_aton(value, &mGateway))
+        goto out_inval;
+    else if (!strcasecmp(n, "dns1") && !inet_aton(value, &mDns1))
+        goto out_inval;
+    else if (!strcasecmp(n, "dns2") && !inet_aton(value, &mDns2))
+        goto out_inval;
+    else if (!strcasecmp(n, "dns3") && !inet_aton(value, &mDns3))
+        goto out_inval;
+    else {
+        errno = ENOENT;
+        return -1;
+    }
+
+    return 0;
+
+out_inval:
+    errno = EINVAL;
+    return -1;
+}
+
+const char *InterfaceConfig::get(const char *name, char *buffer, size_t max) {
+    const char *n;
+
+    for (n = &name[strlen(name)]; *n != '.'; n--);
+    n++;
+
+    if (!strcasecmp(n, "ip"))
+        strncpy(buffer, inet_ntoa(mIp), max);
+    else if (!strcasecmp(n, "dhcp"))
+        snprintf(buffer, max, "%d", mUseDhcp);
+    else if (!strcasecmp(n, "netmask"))
+        strncpy(buffer, inet_ntoa(mNetmask), max);
+    else if (!strcasecmp(n, "gateway"))
+        strncpy(buffer, inet_ntoa(mGateway), max);
+    else if (!strcasecmp(n, "dns1"))
+        strncpy(buffer, inet_ntoa(mDns1), max);
+    else if (!strcasecmp(n, "dns2"))
+        strncpy(buffer, inet_ntoa(mDns2), max);
+    else if (!strcasecmp(n, "dns3"))
+        strncpy(buffer, inet_ntoa(mDns3), max);
+    else {
+        strncpy(buffer, "(internal error)", max);
+        errno = ENOENT;
+        return NULL;
+    }
+    return buffer;
+}
diff --git a/nexus/InterfaceConfig.h b/nexus/InterfaceConfig.h
index 1426e99..d97f20b 100644
--- a/nexus/InterfaceConfig.h
+++ b/nexus/InterfaceConfig.h
@@ -17,12 +17,21 @@
 #ifndef _INTERFACE_CONFIG_H
 #define _INTERFACE_CONFIG_H
 
+#include <unistd.h>
+#include <sys/types.h>
 #include <netinet/in.h>
 #include <arpa/inet.h>
 
-class InterfaceConfig {
+#include "IPropertyProvider.h"
+
+class PropertyManager;
+
+class InterfaceConfig : public IPropertyProvider {
+public:
+    static const char *PropertyNames[];
+
 private:
-    char *mName;
+    char *mPropPrefix;
     bool mUseDhcp;
     struct in_addr mIp;
     struct in_addr mNetmask;
@@ -32,19 +41,23 @@
     struct in_addr mDns3;
 
 public:
-    InterfaceConfig(const char *name);
-    InterfaceConfig(const char *name, const char *ip, const char *nm,
+    InterfaceConfig(const char *prop_prefix);
+    InterfaceConfig(const char *prop_prefix,
+                    const char *ip, const char *nm,
                     const char *gw, const char *dns1, const char *dns2,
                     const char *dns3);
 
-    InterfaceConfig(const char *name, const struct in_addr *ip,
+    InterfaceConfig(const char *prop_prefix,
+                    const struct in_addr *ip,
                     const struct in_addr *nm, const struct in_addr *gw,
                     const struct in_addr *dns1, const struct in_addr *dns2,
                     const struct in_addr *dns3);
 
     virtual ~InterfaceConfig();
+    
+    int set(const char *name, const char *value);
+    const char *get(const char *name, char *buffer, size_t maxsize);
 
-    const char     *getName() const { return mName; }
     bool            getUseDhcp() const { return mUseDhcp; }
     const struct in_addr &getIp() const { return mIp; }
     const struct in_addr &getNetmask() const { return mNetmask; }
@@ -52,6 +65,10 @@
     const struct in_addr &getDns1() const { return mDns1; }
     const struct in_addr &getDns2() const { return mDns2; }
     const struct in_addr &getDns3() const { return mDns3; }
+
+private:
+    int registerProperties();
+    int unregisterProperties();
 };
 
 
diff --git a/nexus/LoopController.cpp b/nexus/LoopController.cpp
index 400d279..a86202a 100644
--- a/nexus/LoopController.cpp
+++ b/nexus/LoopController.cpp
@@ -13,20 +13,21 @@
  * See the License for the specific language governing permissions and
  * limitations under the License.
  */
+
 #include <errno.h>
 
 #include "LoopController.h"
+#include "PropertyManager.h"
 
-LoopController::LoopController() :
-                Controller("LOOP", "loop") {
+LoopController::LoopController(PropertyManager *propmngr) :
+                Controller("LOOP", propmngr) {
 }
 
-int LoopController::enable() {
-    errno = ENOSYS;
-    return -1;
+int LoopController::set(const char *name, const char *value) {
+    return Controller::set(name, value);
 }
 
-int LoopController::disable() {
-    errno = ENOSYS;
-    return -1;
+const char *LoopController::get(const char *name, char *buffer, size_t maxsize) {
+    return Controller::get(name, buffer, maxsize);
 }
+
diff --git a/nexus/LoopController.h b/nexus/LoopController.h
index d047f87..bb8314f 100644
--- a/nexus/LoopController.h
+++ b/nexus/LoopController.h
@@ -13,19 +13,20 @@
  * See the License for the specific language governing permissions and
  * limitations under the License.
  */
+
 #ifndef _LOOP_CONTROLLER_H
 #define _LOOP_CONTROLLER_H
 
 #include "Controller.h"
 
+
 class LoopController : public Controller {
 public:
-    LoopController();
+    LoopController(PropertyManager *propmngr);
     virtual ~LoopController() {}
 
-private:
-    int enable();
-    int disable();
+    int set(const char *name, const char *value);
+    const char *get(const char *name, char *buffer, size_t maxsize);
 };
 
 #endif
diff --git a/nexus/NetworkManager.cpp b/nexus/NetworkManager.cpp
index 49b0210..f4ae88f 100644
--- a/nexus/NetworkManager.cpp
+++ b/nexus/NetworkManager.cpp
@@ -13,6 +13,7 @@
  * See the License for the specific language governing permissions and
  * limitations under the License.
  */
+
 #include <stdio.h>
 #include <errno.h>
 
@@ -27,13 +28,17 @@
 
 NetworkManager *NetworkManager::Instance() {
     if (!sInstance)
-        sInstance = new NetworkManager();
+        sInstance = new NetworkManager(new PropertyManager());
     return sInstance;
 }
 
-NetworkManager::NetworkManager() {
+NetworkManager::NetworkManager(PropertyManager *propMngr) {
     mBroadcaster = NULL;
     mControllers = new ControllerCollection();
+    mPropMngr = propMngr;
+}
+
+NetworkManager::~NetworkManager() {
 }
 
 int NetworkManager::run() {
@@ -55,7 +60,7 @@
     for (i = mControllers->begin(); i != mControllers->end(); ++i) {
         int irc = (*i)->start();
         LOGD("Controller '%s' start rc = %d", (*i)->getName(), irc);
-        if (irc && !rc) 
+        if (irc && !rc)
             rc = irc;
     }
     return rc;
@@ -68,7 +73,7 @@
     for (i = mControllers->begin(); i != mControllers->end(); ++i) {
         int irc = (*i)->stop();
         LOGD("Controller '%s' stop rc = %d", (*i)->getName(), irc);
-        if (irc && !rc) 
+        if (irc && !rc)
             rc = irc;
     }
     return rc;
@@ -84,75 +89,8 @@
     return NULL;
 }
 
-int NetworkManager::setProperty(const char *name, char *value) {
-    char *tmp = strdup(name);
-    char *next = tmp;
-    char *prefix;
-    char *rest;
-    ControllerCollection::iterator it;
-
-    if (!(prefix = strsep(&next, ".")))
-        goto out_inval;
-
-    rest = next;
-
-    if (!strncasecmp(prefix, "netman", 6)) {
-        errno = ENOSYS;
-        return -1;
-    }
-
-    for (it = mControllers->begin(); it != mControllers->end(); ++it) {
-        if (!strcasecmp(prefix, (*it)->getPropertyPrefix())) {
-            return (*it)->setProperty(rest, value);
-        }
-    }
-
-    errno = ENOENT;
-    return -1;
-
-out_inval:
-    errno = EINVAL;
-    return -1;
-}
-
-const char *NetworkManager::getProperty(const char *name, char *buffer,
-                                                          size_t maxsize) {
-    char *tmp = strdup(name);
-    char *next = tmp;
-    char *prefix;
-    char *rest;
-    ControllerCollection::iterator it;
-
-    if (!(prefix = strsep(&next, ".")))
-        goto out_inval;
-
-    rest = next;
-
-    if (!strncasecmp(prefix, "netman", 6)) {
-        errno = ENOSYS;
-        return NULL;
-    }
-
-    for (it = mControllers->begin(); it != mControllers->end(); ++it) {
-        if (!strcasecmp(prefix, (*it)->getPropertyPrefix())) {
-            return (*it)->getProperty(rest, buffer, maxsize);
-        }
-    }
-
-    errno = ENOENT;
-    return NULL;
-
-out_inval:
-    errno = EINVAL;
-    return NULL;
-}
-
-const PropertyCollection &NetworkManager::getProperties() {
-    return *mProperties;
-}
-
 int NetworkManager::onInterfaceStart(Controller *c, const InterfaceConfig *cfg) {
-    LOGD("Interface %s started by controller %s", cfg->getName(), c->getName());
+    LOGD("Interface %s started by controller %s", c->getBoundInterface(), c->getName());
 
     // Look up the interface
 
diff --git a/nexus/NetworkManager.h b/nexus/NetworkManager.h
index e8564ca..e75382d 100644
--- a/nexus/NetworkManager.h
+++ b/nexus/NetworkManager.h
@@ -13,13 +13,15 @@
  * See the License for the specific language governing permissions and
  * limitations under the License.
  */
+
 #ifndef _NETWORKMANAGER_H
 #define _NETWORKMANAGER_H
 
 #include <sysutils/SocketListener.h>
 
 #include "Controller.h"
-#include "PropertyCollection.h"
+
+#include "PropertyManager.h"
 
 class InterfaceConfig;
 
@@ -30,10 +32,10 @@
 private:
     ControllerCollection *mControllers;
     SocketListener       *mBroadcaster;
-    PropertyCollection   *mProperties;
+    PropertyManager      *mPropMngr;
 
 public:
-    virtual ~NetworkManager() {}
+    virtual ~NetworkManager();
 
     int run();
 
@@ -41,22 +43,17 @@
 
     Controller *findController(const char *name);
 
-    const PropertyCollection &getProperties();
-    int setProperty(const char *name, char *value);
-    const char *getProperty(const char *name, char *buffer, size_t maxsize);
-
     void setBroadcaster(SocketListener *sl) { mBroadcaster = sl; }
     SocketListener *getBroadcaster() { return mBroadcaster; }
+    PropertyManager *getPropMngr() { return mPropMngr; }
 
     static NetworkManager *Instance();
 
 private:
     int startControllers();
     int stopControllers();
-    int registerProperty(const char *name);
-    int unregisterProperty(const char *name);
 
-    NetworkManager();
+    NetworkManager(PropertyManager *propMngr);
 
 public:
     /*
diff --git a/nexus/NexusCommand.cpp b/nexus/NexusCommand.cpp
index 92bb1c3..541eeeb 100644
--- a/nexus/NexusCommand.cpp
+++ b/nexus/NexusCommand.cpp
@@ -13,6 +13,7 @@
  * See the License for the specific language governing permissions and
  * limitations under the License.
  */
+
 #include "NexusCommand.h"
 
 NexusCommand::NexusCommand(const char *cmd) :
diff --git a/nexus/NexusCommand.h b/nexus/NexusCommand.h
index 1482998..a7f944a 100644
--- a/nexus/NexusCommand.h
+++ b/nexus/NexusCommand.h
@@ -13,6 +13,7 @@
  * See the License for the specific language governing permissions and
  * limitations under the License.
  */
+
 #ifndef _NEXUS_COMMAND_H
 #define _NEXUS_COMMAND_H
 
diff --git a/nexus/OpenVpnController.cpp b/nexus/OpenVpnController.cpp
index 1934024..4c144a4 100644
--- a/nexus/OpenVpnController.cpp
+++ b/nexus/OpenVpnController.cpp
@@ -13,6 +13,7 @@
  * See the License for the specific language governing permissions and
  * limitations under the License.
  */
+
 #include <errno.h>
 #include <netinet/in.h>
 #include <arpa/inet.h>
@@ -24,13 +25,13 @@
 #include <sysutils/ServiceManager.h>
 
 #include "OpenVpnController.h"
+#include "PropertyManager.h"
 
 #define DAEMON_PROP_NAME "vpn.openvpn.status"
-
 #define DAEMON_CONFIG_FILE "/data/misc/openvpn/openvpn.conf"
 
-OpenVpnController::OpenVpnController() :
-                   VpnController() {
+OpenVpnController::OpenVpnController(PropertyManager *propmngr) :
+                   VpnController(propmngr) {
     mServiceManager = new ServiceManager();
 }
 
@@ -49,8 +50,8 @@
 int OpenVpnController::enable() {
     char svc[PROPERTY_VALUE_MAX];
     char tmp[64];
-    
-    if (!getProperty("vpn.gateway", tmp, sizeof(tmp))) {
+
+    if (!mPropMngr->get("vpn.gateway", tmp, sizeof(tmp))) {
         LOGE("Error reading property 'vpn.gateway' (%s)", strerror(errno));
         return -1;
     }
diff --git a/nexus/OpenVpnController.h b/nexus/OpenVpnController.h
index 439e18a..323c44c 100644
--- a/nexus/OpenVpnController.h
+++ b/nexus/OpenVpnController.h
@@ -17,6 +17,7 @@
 #ifndef _OPEN_VPN_CONTROLLER_H
 #define _OPEN_VPN_CONTROLLER_H
 
+#include "PropertyManager.h"
 #include "VpnController.h"
 
 class ServiceManager;
@@ -26,7 +27,7 @@
     ServiceManager *mServiceManager;
 
 public:
-    OpenVpnController();
+    OpenVpnController(PropertyManager *propmngr);
     virtual ~OpenVpnController();
 
     int start();
diff --git a/nexus/PropertyCollection.h b/nexus/Property.h
similarity index 76%
rename from nexus/PropertyCollection.h
rename to nexus/Property.h
index 4be1cf0..198f722 100644
--- a/nexus/PropertyCollection.h
+++ b/nexus/Property.h
@@ -14,12 +14,8 @@
  * limitations under the License.
  */
 
-#ifndef _PROPERTY_COLLECTION_H
-#define _PROPERTY_COLLECTION_H
-
-#include "../../../frameworks/base/include/utils/List.h"
-
-typedef android::List<const char *> PropertyCollection;
-
-#endif
-
+class Property {
+public:
+    static const int NameMaxSize = 128;
+    static const int ValueMaxSize  = 255;
+};
diff --git a/nexus/PropertyManager.cpp b/nexus/PropertyManager.cpp
new file mode 100644
index 0000000..3366bab
--- /dev/null
+++ b/nexus/PropertyManager.cpp
@@ -0,0 +1,122 @@
+/*
+ * 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.
+ */
+
+#define LOG_TAG "PropertyManager"
+
+#include <cutils/log.h>
+
+#include "PropertyManager.h"
+
+PropertyManager::PropertyManager() {
+    mPropertyPairs = new PropertyPairCollection();
+    pthread_mutex_init(&mLock, NULL);
+}
+
+PropertyManager::~PropertyManager() {
+    delete mPropertyPairs;
+}
+
+int PropertyManager::registerProperty(const char *name, IPropertyProvider *pp) {
+    PropertyPairCollection::iterator it;
+
+//    LOGD("registerProperty(%s)", name);
+    pthread_mutex_lock(&mLock);
+    for (it = mPropertyPairs->begin(); it != mPropertyPairs->end(); ++it) {
+        if (!strcmp(name, (*it)->getName())) {
+            errno = EADDRINUSE;
+            LOGE("Failed to register property (%s)", strerror(errno));
+            pthread_mutex_unlock(&mLock);
+            return -1;
+        }
+    }
+    mPropertyPairs->push_back(new PropertyPair(name, pp));
+    pthread_mutex_unlock(&mLock);
+    return 0;
+}
+
+int PropertyManager::unregisterProperty(const char *name) {
+    PropertyPairCollection::iterator it;
+
+//    LOGD("unregisterProperty(%s)", name);
+    pthread_mutex_lock(&mLock);
+    for (it = mPropertyPairs->begin(); it != mPropertyPairs->end(); ++it) {
+        if (!strcmp(name, (*it)->getName())) {
+            delete ((*it));
+            mPropertyPairs->erase(it);
+            pthread_mutex_unlock(&mLock);
+            return 0;
+        }
+    }
+    pthread_mutex_unlock(&mLock);
+    errno = ENOENT;
+    return -1;
+}
+
+/*
+ * IPropertyManager methods
+ */
+
+int PropertyManager::set(const char *name, const char *value) {
+    PropertyPairCollection::iterator it;
+
+    pthread_mutex_lock(&mLock);
+    for (it = mPropertyPairs->begin(); it != mPropertyPairs->end(); ++it) {
+        if (!strcmp(name, (*it)->getName())) {
+            pthread_mutex_unlock(&mLock);
+            return (*it)->getProvider()->set(name, value);
+        }
+    }
+    pthread_mutex_unlock(&mLock);
+    errno = ENOENT;
+    return -1;
+}
+
+const char *PropertyManager::get(const char *name, char *buffer, size_t max) {
+    PropertyPairCollection::iterator it;
+
+    memset(buffer, 0, max);
+    pthread_mutex_lock(&mLock);
+    for (it = mPropertyPairs->begin(); it != mPropertyPairs->end(); ++it) {
+        if (!strcmp(name, (*it)->getName())) {
+            pthread_mutex_unlock(&mLock);
+            return (*it)->getProvider()->get(name, buffer, max);
+            }
+    }
+    pthread_mutex_unlock(&mLock);
+    errno = ENOENT;
+    return NULL;
+}
+
+android::List<char *> *PropertyManager::createPropertyList() {
+    android::List<char *> *c = new android::List<char *>();
+
+    PropertyPairCollection::iterator it;
+
+    pthread_mutex_lock(&mLock);
+    for (it = mPropertyPairs->begin(); it != mPropertyPairs->end(); ++it)
+         c->push_back(strdup((*it)->getName()));
+    pthread_mutex_unlock(&mLock);
+    return c;
+}
+
+PropertyPair::PropertyPair(const char *name, IPropertyProvider *pp) {
+    mName = strdup(name);
+    mPp = pp;
+}
+
+PropertyPair::~PropertyPair() {
+    free(mName);
+}
diff --git a/nexus/PropertyManager.h b/nexus/PropertyManager.h
new file mode 100644
index 0000000..10d0b2a
--- /dev/null
+++ b/nexus/PropertyManager.h
@@ -0,0 +1,57 @@
+/*
+ * 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 _PROPERTY_MANAGER_H
+#define _PROPERTY_MANAGER_H
+
+#include <errno.h>
+#include <pthread.h>
+
+#include <utils/List.h>
+
+#include "IPropertyProvider.h"
+
+class PropertyPair {
+private:
+    char *mName;
+    IPropertyProvider *mPp;
+ 
+public:
+    PropertyPair(const char *name, IPropertyProvider *pp);
+    virtual ~PropertyPair();
+
+    const char *getName() { return mName; }
+    IPropertyProvider *getProvider() { return mPp; }
+};
+
+typedef android::List<PropertyPair *> PropertyPairCollection;
+
+class PropertyManager {
+    PropertyPairCollection *mPropertyPairs;
+    pthread_mutex_t         mLock;
+
+public:
+    PropertyManager();
+    virtual ~PropertyManager();   
+    int registerProperty(const char *name, IPropertyProvider *pp);
+    int unregisterProperty(const char *name);
+    android::List<char *> *createPropertyList();
+
+    int set(const char *name, const char *value);
+    const char *get(const char *name, char *buffer, size_t max);
+};
+
+#endif
diff --git a/nexus/ScanResult.cpp b/nexus/ScanResult.cpp
index dc7599a..e9a286c 100644
--- a/nexus/ScanResult.cpp
+++ b/nexus/ScanResult.cpp
@@ -13,6 +13,7 @@
  * See the License for the specific language governing permissions and
  * limitations under the License.
  */
+
 #include <stdlib.h>
 #include <ctype.h>
 
@@ -42,7 +43,7 @@
     mFreq = atoi(tmp);
     ++q;
 
-    // LEVEL 
+    // LEVEL
     for (p = q; *q != '\t'; ++q);
     strncpy(tmp, p, (q - p));
     tmp[q-p] = '\0';
@@ -60,7 +61,7 @@
     // haven't had time to dig into it ...
     if (*q == '\t')
         q++;
- 
+
     for (p = q; *q != '\t'; ++q) {
         if (*q == '\0')
             break;
diff --git a/nexus/ScanResult.h b/nexus/ScanResult.h
index f70a1a9..68ad0f0 100644
--- a/nexus/ScanResult.h
+++ b/nexus/ScanResult.h
@@ -13,12 +13,13 @@
  * See the License for the specific language governing permissions and
  * limitations under the License.
  */
+
 #ifndef _SCAN_RESULT_H
 #define _SCAN_RESULT_H
 
 #include <sys/types.h>
 
-#include "../../../frameworks/base/include/utils/List.h"
+#include <utils/List.h>
 
 class ScanResult {
     char     *mBssid;
diff --git a/nexus/Supplicant.cpp b/nexus/Supplicant.cpp
index 6737d91..e69f2c0 100644
--- a/nexus/Supplicant.cpp
+++ b/nexus/Supplicant.cpp
@@ -32,8 +32,10 @@
 #include "SupplicantState.h"
 #include "SupplicantEvent.h"
 #include "ScanResult.h"
+#include "PropertyManager.h"
 #include "NetworkManager.h"
 #include "ErrorCode.h"
+#include "WifiController.h"
 
 #include "libwpa_client/wpa_ctrl.h"
 
@@ -43,21 +45,29 @@
 #define SUPP_CONFIG_TEMPLATE "/system/etc/wifi/wpa_supplicant.conf"
 #define SUPP_CONFIG_FILE "/data/misc/wifi/wpa_supplicant.conf"
 
-Supplicant::Supplicant() {
+Supplicant::Supplicant(WifiController *wc, PropertyManager *propmngr) {
+    mController = wc;
+    mPropMngr = propmngr;
+    mInterfaceName = NULL;
     mCtrl = NULL;
     mMonitor = NULL;
     mListener = NULL;
-
+   
     mState = SupplicantState::UNKNOWN;
 
     mServiceManager = new ServiceManager();
 
     mLatestScanResults = new ScanResultCollection();
     pthread_mutex_init(&mLatestScanResultsLock, NULL);
+
+    mNetworks = new WifiNetworkCollection();
+    pthread_mutex_init(&mNetworksLock, NULL);
 }
 
 Supplicant::~Supplicant() {
     delete mServiceManager;
+    if (mInterfaceName)
+        free(mInterfaceName);
 }
 
 int Supplicant::start() {
@@ -65,7 +75,7 @@
     if (setupConfig()) {
         LOGW("Unable to setup supplicant.conf");
     }
- 
+
     if (mServiceManager->start(SUPPLICANT_SERVICE_NAME)) {
         LOGE("Error starting supplicant (%s)", strerror(errno));
         return -1;
@@ -76,11 +86,20 @@
         LOGE("Error connecting to supplicant (%s)\n", strerror(errno));
         return -1;
     }
+    
+    if (retrieveInterfaceName()) {
+        LOGE("Error retrieving interface name (%s)\n", strerror(errno));
+        return -1;
+    }
+
+    mPropMngr->registerProperty("wifi.supplicant.state", this);
     return 0;
 }
 
 int Supplicant::stop() {
 
+    mPropMngr->unregisterProperty("wifi.supplicant.state");
+
     if (mListener->stopListener()) {
         LOGW("Unable to stop supplicant listener (%s)", strerror(errno));
         return -1;
@@ -106,13 +125,55 @@
     return mServiceManager->isRunning(SUPPLICANT_SERVICE_NAME);
 }
 
-int Supplicant::connectToSupplicant() {
-    if (!isStarted()) {
-        LOGE("Supplicant not running, cannot connect");
+int Supplicant::refreshNetworkList() {
+    char *reply;
+    size_t len = 4096;
+
+    if (!(reply = (char *) malloc(len))) {
+        errno = ENOMEM;
         return -1;
     }
 
-    mCtrl = wpa_ctrl_open("tiwlan0");
+    if (sendCommand("LIST_NETWORKS", reply, &len)) {
+        free(reply);
+        return -1;
+    }
+
+    char *linep;
+    char *linep_next = NULL;
+
+    if (!strtok_r(reply, "\n", &linep_next)) {
+        LOGW("Malformatted network list\n");
+    } else {
+        pthread_mutex_lock(&mNetworksLock);
+        if (!mNetworks->empty()) {
+            WifiNetworkCollection::iterator i;
+
+            for (i = mNetworks->begin(); i !=mNetworks->end(); ++i)
+                delete *i;
+            mNetworks->clear();
+        }
+
+        while((linep = strtok_r(NULL, "\n", &linep_next))) {
+            WifiNetwork *wn = new WifiNetwork(mController, this, linep);
+            mNetworks->push_back(wn);
+            if (wn->refresh())
+                LOGW("Unable to refresh network id %d", wn->getNetworkId());
+        }
+
+        LOGD("Loaded %d networks\n", mNetworks->size());
+        pthread_mutex_unlock(&mNetworksLock);
+    }
+
+    free(reply);
+    return 0;
+}
+
+int Supplicant::connectToSupplicant() {
+    if (!isStarted())
+        LOGW("Supplicant service not running");
+
+    mCtrl = wpa_ctrl_open("tiwlan0"); // XXX:
     if (mCtrl == NULL) {
         LOGE("Unable to open connection to supplicant on \"%s\": %s",
              "tiwlan0", strerror(errno));
@@ -132,7 +193,7 @@
     }
 
     mListener = new SupplicantListener(this, mMonitor);
-    
+
     if (mListener->startListener()) {
         LOGE("Error - unable to start supplicant listener");
         stop();
@@ -151,20 +212,17 @@
 //    LOGD("sendCommand(): -> '%s'", cmd);
 
     int rc;
+    memset(reply, 0, *reply_len);
     if ((rc = wpa_ctrl_request(mCtrl, cmd, strlen(cmd), reply, reply_len, NULL)) == -2)  {
         errno = ETIMEDOUT;
         return -1;
     } else if (rc < 0 || !strncmp(reply, "FAIL", 4)) {
-        LOGW("sendCommand(): <- '%s'", reply);
+        strcpy(reply, "FAIL");
         errno = EIO;
         return -1;
     }
 
-    if (!strncmp(cmd, "PING", 4) ||
-        !strncmp(cmd, "SCAN_RESULTS", 12)) 
-        reply[*reply_len] = '\0';
-
-//    LOGD("sendCommand(): <- '%s'", reply);
+//   LOGD("sendCommand(): <- '%s'", reply);
     return 0;
 }
 
@@ -187,6 +245,22 @@
     return 0;
 }
 
+int Supplicant::set(const char *name, const char *value) {
+    const char *n = name + strlen("wifi.supplicant.");
+
+    errno = -EROFS;
+    return -1;
+}
+
+const char *Supplicant::get(const char *name, char *buffer, size_t max) {
+    const char *n = name + strlen("wifi.supplicant.");
+
+    if (!strcasecmp(n, "state"))
+        return SupplicantState::toString(mState, buffer, max);
+    errno = ENOENT;
+    return NULL;
+}
+
 int Supplicant::onConnectedEvent(SupplicantEvent *evt) {
     LOGD("onConnectedEvent(%s)", evt->getEvent());
     return 0;
@@ -237,12 +311,12 @@
         char *reply;
 
         if (!(reply = (char *) malloc(4096))) {
-            errno = -ENOMEM;
+            errno = ENOMEM;
             return -1;
         }
 
         size_t len = 4096;
- 
+
         if (sendCommand("SCAN_RESULTS", reply, &len)) {
             LOGW("onScanResultsEvent(%s): Error getting scan results (%s)",
                   evt->getEvent(), strerror(errno));
@@ -272,7 +346,7 @@
 
         while((linep = strtok_r(NULL, "\n", &linep_next)))
             mLatestScanResults->push_back(new ScanResult(linep));
-    
+
         char tmp[128];
         sprintf(tmp, "Scan results ready (%d)", mLatestScanResults->size());
         NetworkManager::Instance()->getBroadcaster()->
@@ -323,43 +397,78 @@
     ScanResultCollection::iterator i;
 
     pthread_mutex_lock(&mLatestScanResultsLock);
-    for (i = mLatestScanResults->begin(); i != mLatestScanResults->end(); ++i) {
+    for (i = mLatestScanResults->begin(); i != mLatestScanResults->end(); ++i)
         d->push_back((*i)->clone());
-    }
 
     pthread_mutex_unlock(&mLatestScanResultsLock);
     return d;
 }
 
-WifiNetworkCollection *Supplicant::createNetworkList() {
-    WifiNetworkCollection *d = new WifiNetworkCollection();
-    return d;
-}
-
-int Supplicant::addNetwork() {
-    char reply[32];
+WifiNetwork *Supplicant::createNetwork() {
+    char reply[255];
     size_t len = sizeof(reply) -1;
 
-    memset(reply, 0, sizeof(reply));
     if (sendCommand("ADD_NETWORK", reply, &len))
-        return -1;
+        return NULL;
 
-    return atoi(reply);
+    if (reply[strlen(reply) -1] == '\n')
+        reply[strlen(reply) -1] = '\0';
+
+    WifiNetwork *wn = new WifiNetwork(mController, this, atoi(reply));
+    pthread_mutex_lock(&mNetworksLock);
+    mNetworks->push_back(wn);
+    pthread_mutex_unlock(&mNetworksLock);
+    return wn;
 }
 
-int Supplicant::removeNetwork(int networkId) {
+int Supplicant::removeNetwork(WifiNetwork *wn) {
     char req[64];
 
-    sprintf(req, "REMOVE_NETWORK %d", networkId);
+    sprintf(req, "REMOVE_NETWORK %d", wn->getNetworkId());
     char reply[32];
     size_t len = sizeof(reply) -1;
-    memset(reply, 0, sizeof(reply));
-    
+
     if (sendCommand(req, reply, &len))
         return -1;
+
+    pthread_mutex_lock(&mNetworksLock);
+    WifiNetworkCollection::iterator it;
+    for (it = mNetworks->begin(); it != mNetworks->end(); ++it) {
+        if ((*it) == wn) {
+            mNetworks->erase(it);
+            break;
+        }
+    }
+    pthread_mutex_unlock(&mNetworksLock);
     return 0;
 }
 
+WifiNetwork *Supplicant::lookupNetwork(int networkId) {
+    pthread_mutex_lock(&mNetworksLock);
+    WifiNetworkCollection::iterator it;
+    for (it = mNetworks->begin(); it != mNetworks->end(); ++it) {
+        if ((*it)->getNetworkId() == networkId) {
+            pthread_mutex_unlock(&mNetworksLock);
+            return *it;
+        }
+    }
+    pthread_mutex_unlock(&mNetworksLock);
+    errno = ENOENT;
+    return NULL;
+}
+
+WifiNetworkCollection *Supplicant::createNetworkList() {
+    WifiNetworkCollection *d = new WifiNetworkCollection();
+    WifiNetworkCollection::iterator i;
+
+    pthread_mutex_lock(&mNetworksLock);
+    for (i = mNetworks->begin(); i != mNetworks->end(); ++i)
+        d->push_back((*i)->clone());
+
+    pthread_mutex_unlock(&mNetworksLock);
+    return d;
+}
+
 int Supplicant::setupConfig() {
     char buf[2048];
     int srcfd, destfd;
@@ -407,3 +516,60 @@
     }
     return 0;
 }
+
+int Supplicant::setNetworkVar(int networkId, const char *var, const char *val) {
+    char reply[255];
+    size_t len = sizeof(reply) -1;
+
+    char *tmp;
+    asprintf(&tmp, "SET_NETWORK %d %s \"%s\"", networkId, var, val);
+    if (sendCommand(tmp, reply, &len)) {
+        free(tmp);
+        return -1;
+    }
+    free(tmp);
+    return 0;
+}
+
+const char *Supplicant::getNetworkVar(int networkId, const char *var,
+                                      char *buffer, size_t max) {
+    size_t len = max - 1;
+    char *tmp;
+
+    asprintf(&tmp, "GET_NETWORK %d %s", networkId, var);
+    if (sendCommand(tmp, buffer, &len)) {
+        free(tmp);
+        return NULL;
+    }
+    free(tmp);
+    return buffer;
+}
+
+int Supplicant::enableNetwork(int networkId, bool enabled) {
+    char req[64];
+
+    if (enabled)
+        sprintf(req, "ENABLE_NETWORK %d", networkId);
+    else
+        sprintf(req, "DISABLE_NETWORK %d", networkId);
+
+    char reply[16];
+    size_t len = sizeof(reply) -1;
+
+    if (sendCommand(req, reply, &len))
+        return -1;
+    return 0;
+}
+
+
+int Supplicant::retrieveInterfaceName() {
+    char reply[255];
+    size_t len = sizeof(reply) -1;
+
+    if (sendCommand("INTERFACES", reply, &len))
+        return -1;
+
+    reply[strlen(reply)-1] = '\0';
+    mInterfaceName = strdup(reply);
+    return 0;
+}
diff --git a/nexus/Supplicant.h b/nexus/Supplicant.h
index 2ea0892..34ecdcf 100644
--- a/nexus/Supplicant.h
+++ b/nexus/Supplicant.h
@@ -13,6 +13,7 @@
  * See the License for the specific language governing permissions and
  * limitations under the License.
  */
+
 #ifndef _SUPPLICANT_H
 #define _SUPPLICANT_H
 
@@ -20,25 +21,35 @@
 class SupplicantListener;
 class SupplicantEvent;
 class ServiceManager;
+class PropertyManager;
+class Controller;
+class WifiController;
 
 #include <pthread.h>
 
 #include "ScanResult.h"
 #include "WifiNetwork.h"
+#include "IPropertyProvider.h"
 
-class Supplicant {
+class Supplicant : public IPropertyProvider {
 private:
     struct wpa_ctrl      *mCtrl;
     struct wpa_ctrl      *mMonitor;
     SupplicantListener   *mListener;
     int                  mState;
     ServiceManager       *mServiceManager;
+    PropertyManager      *mPropMngr;
+    WifiController       *mController;
+    char                 *mInterfaceName;
 
     ScanResultCollection *mLatestScanResults;
     pthread_mutex_t      mLatestScanResultsLock;
-  
+
+    WifiNetworkCollection *mNetworks;
+    pthread_mutex_t        mNetworksLock;
+ 
 public:
-    Supplicant();
+    Supplicant(WifiController *wc, PropertyManager *propmngr);
     virtual ~Supplicant();
 
     int start();
@@ -48,12 +59,23 @@
     int triggerScan(bool active);
     ScanResultCollection *createLatestScanResults();
 
-    int addNetwork();
-    int removeNetwork(int networkId);
+    WifiNetwork *createNetwork();
+    WifiNetwork *lookupNetwork(int networkId);
+    int removeNetwork(WifiNetwork *net);
     WifiNetworkCollection *createNetworkList();
+    int refreshNetworkList();
+
+    int setNetworkVar(int networkId, const char *var, const char *value);
+    const char *getNetworkVar(int networkid, const char *var, char *buffer,
+                              size_t max);
+    int enableNetwork(int networkId, bool enabled);
 
     int getState() { return mState; }
+    Controller *getController() { return (Controller *) mController; }
+    const char *getInterfaceName() { return mInterfaceName; }
 
+    int set(const char *name, const char *value);
+    const char *get(const char *name, char *buffer, size_t max);
 
 // XXX: Extract these into an interface
 // handlers for SupplicantListener
@@ -76,6 +98,7 @@
     int connectToSupplicant();
     int sendCommand(const char *cmd, char *reply, size_t *reply_len);
     int setupConfig();
+    int retrieveInterfaceName();
 };
 
 #endif
diff --git a/nexus/SupplicantEvent.cpp b/nexus/SupplicantEvent.cpp
index 5c0944a..2e6d665 100644
--- a/nexus/SupplicantEvent.cpp
+++ b/nexus/SupplicantEvent.cpp
@@ -13,6 +13,7 @@
  * See the License for the specific language governing permissions and
  * limitations under the License.
  */
+
 #include <stdlib.h>
 
 #define LOG_TAG "SupplicantEvent"
diff --git a/nexus/SupplicantEvent.h b/nexus/SupplicantEvent.h
index 86ce8cb..2dc6722 100644
--- a/nexus/SupplicantEvent.h
+++ b/nexus/SupplicantEvent.h
@@ -13,6 +13,7 @@
  * See the License for the specific language governing permissions and
  * limitations under the License.
  */
+
 #ifndef _SUPPLICANT_EVENT_H
 #define _SUPPLICANT_EVENT_H
 
diff --git a/nexus/SupplicantListener.cpp b/nexus/SupplicantListener.cpp
index 76e9945..852eeb2 100644
--- a/nexus/SupplicantListener.cpp
+++ b/nexus/SupplicantListener.cpp
@@ -13,6 +13,7 @@
  * See the License for the specific language governing permissions and
  * limitations under the License.
  */
+
 #include <errno.h>
 #include <sys/types.h>
 #include <pthread.h>
@@ -85,7 +86,7 @@
     }
 
     delete evt;
-    
+
     if (rc) {
         LOGW("Handler %d (%s) error: %s", evt->getType(), evt->getEvent(), strerror(errno));
         return false;
diff --git a/nexus/SupplicantListener.h b/nexus/SupplicantListener.h
index 95bad9a..680a523 100644
--- a/nexus/SupplicantListener.h
+++ b/nexus/SupplicantListener.h
@@ -13,6 +13,7 @@
  * See the License for the specific language governing permissions and
  * limitations under the License.
  */
+
 #ifndef _SUPPLICANTLISTENER_H__
 #define _SUPPLICANTLISTENER_H__
 
diff --git a/nexus/SupplicantState.cpp b/nexus/SupplicantState.cpp
new file mode 100644
index 0000000..a16d370
--- /dev/null
+++ b/nexus/SupplicantState.cpp
@@ -0,0 +1,49 @@
+/*
+ * 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 <stdio.h>
+
+#define LOG_TAG "SupplicantState"
+#include <cutils/log.h>
+
+#include "SupplicantState.h"
+
+char *SupplicantState::toString(int val, char *buffer, int max) {
+    if (val == SupplicantState::UNKNOWN)
+        strncpy(buffer, "Unknown", max);
+    else if (val == SupplicantState::DISCONNECTED)
+        strncpy(buffer, "Disconnected", max);
+    else if (val == SupplicantState::INACTIVE)
+        strncpy(buffer, "Inactive", max);
+    else if (val == SupplicantState::SCANNING)
+        strncpy(buffer, "Scanning", max);
+    else if (val == SupplicantState::ASSOCIATING)
+        strncpy(buffer, "Associating", max);
+    else if (val == SupplicantState::ASSOCIATED)
+        strncpy(buffer, "Associated", max);
+    else if (val == SupplicantState::FOURWAY_HANDSHAKE)
+        strncpy(buffer, "Fourway Handshake", max);
+    else if (val == SupplicantState::GROUP_HANDSHAKE)
+        strncpy(buffer, "Group Handshake", max);
+    else if (val == SupplicantState::COMPLETED)
+        strncpy(buffer, "Completed", max);
+    else if (val == SupplicantState::IDLE)
+        strncpy(buffer, "Idle", max);
+    else
+        strncpy(buffer, "(internal error)", max);
+
+    return buffer;
+}
diff --git a/nexus/SupplicantState.h b/nexus/SupplicantState.h
index e85dcb5..6882f0c 100644
--- a/nexus/SupplicantState.h
+++ b/nexus/SupplicantState.h
@@ -13,6 +13,7 @@
  * See the License for the specific language governing permissions and
  * limitations under the License.
  */
+
 #ifndef _SUPPLICANT_STATE_H
 #define _SUPPLICANT_STATE_H
 
@@ -28,6 +29,8 @@
     static const int GROUP_HANDSHAKE   = 6;
     static const int COMPLETED         = 7;
     static const int IDLE              = 8;
+
+    static char *toString(int val, char *buffer, int max);
 };
 
 #endif
diff --git a/nexus/TiwlanWifiController.cpp b/nexus/TiwlanWifiController.cpp
index 27c972b..307c48c 100644
--- a/nexus/TiwlanWifiController.cpp
+++ b/nexus/TiwlanWifiController.cpp
@@ -13,6 +13,7 @@
  * See the License for the specific language governing permissions and
  * limitations under the License.
  */
+
 #include <stdlib.h>
 #include <fcntl.h>
 #include <errno.h>
@@ -22,14 +23,15 @@
 #define LOG_TAG "TiwlanWifiController"
 #include <cutils/log.h>
 
+#include "PropertyManager.h"
 #include "TiwlanWifiController.h"
 
 #define DRIVER_PROP_NAME "wlan.driver.status"
 
 extern "C" int sched_yield(void);
 
-TiwlanWifiController::TiwlanWifiController(char *modpath, char *modname, char *modargs) :
-                      WifiController(modpath, modname, modargs) {
+TiwlanWifiController::TiwlanWifiController(PropertyManager *propmngr, char *modpath, char *modname, char *modargs) :
+                      WifiController(propmngr, modpath, modname, modargs) {
 }
 
 int TiwlanWifiController::powerUp() {
diff --git a/nexus/TiwlanWifiController.h b/nexus/TiwlanWifiController.h
index f17ef51..d3ebe88 100644
--- a/nexus/TiwlanWifiController.h
+++ b/nexus/TiwlanWifiController.h
@@ -13,14 +13,16 @@
  * See the License for the specific language governing permissions and
  * limitations under the License.
  */
+
 #ifndef _TIWLAN_WIFI_CONTROLLER_H
 #define _TIWLAN_WIFI_CONTROLLER_H
 
+#include "PropertyManager.h"
 #include "WifiController.h"
 
 class TiwlanWifiController : public WifiController {
 public:
-    TiwlanWifiController(char *modpath, char *modname, char *modargs);
+    TiwlanWifiController(PropertyManager *propmngr, char *modpath, char *modname, char *modargs);
     virtual ~TiwlanWifiController() {}
 
     virtual int powerUp();
diff --git a/nexus/VpnController.cpp b/nexus/VpnController.cpp
index d3bc216..1246703 100644
--- a/nexus/VpnController.cpp
+++ b/nexus/VpnController.cpp
@@ -16,55 +16,61 @@
 
 #include <stdio.h>
 #include <string.h>
+#include <stdlib.h>
 #include <errno.h>
 #include <sys/socket.h>
 #include <netinet/in.h>
 #include <arpa/inet.h>
 
+#include "PropertyManager.h"
 #include "VpnController.h"
 
-VpnController::VpnController() :
-               Controller("VPN", "vpn") {
-    registerProperty("gateway");
+VpnController::VpnController(PropertyManager *propmngr) :
+               Controller("VPN", propmngr) {
+    mEnabled = false;
+    propmngr->registerProperty("vpn.enabled", this);
+    propmngr->registerProperty("vpn.gateway", this);
 }
 
 int VpnController::start() {
-    errno = ENOSYS;
-    return -1;
+    return 0;
 }
 
 int VpnController::stop() {
-    errno = ENOSYS;
-    return -1;
+    return 0;
 }
 
-int VpnController::enable() {
-    errno = ENOSYS;
-    return -1;
-}
+int VpnController::set(const char *name, const char *value) {
+    if (!strcmp(name, "vpn.enabled")) {
+        int en = atoi(value);
+        int rc;
 
-int VpnController::disable() {
-    errno = ENOSYS;
-    return -1;
-}
+        if (en == mEnabled)
+            return 0;
+        rc = (en ? enable() : disable());
 
-int VpnController::setProperty(const char *name, char *value) {
-    if (!strcmp(name, "gateway")) {
+        if (!rc)
+            mEnabled = en;
+        return rc;
+    } if (!strcmp(name, "vpn.gateway")) {
         if (!inet_aton(value, &mVpnGateway)) {
             errno = EINVAL;
             return -1;
         }
         return 0;
-    } 
+    }
 
-    return Controller::setProperty(name, value);
+    return Controller::set(name, value);
 }
 
-const char *VpnController::getProperty(const char *name, char *buffer, size_t maxsize) {
-    if (!strcmp(name, "gateway")) {
+const char *VpnController::get(const char *name, char *buffer, size_t maxsize) {
+    if (!strcmp(name, "vpn.enabled")) {
+        snprintf(buffer, maxsize, "%d", mEnabled);
+        return buffer;
+    } if (!strcmp(name, "vpn.gateway")) {
         snprintf(buffer, maxsize, "%s", inet_ntoa(mVpnGateway));
         return buffer;
     }
 
-    return Controller::getProperty(name, buffer, maxsize);
+    return Controller::get(name, buffer, maxsize);
 }
diff --git a/nexus/VpnController.h b/nexus/VpnController.h
index 0a93990..b36856f 100644
--- a/nexus/VpnController.h
+++ b/nexus/VpnController.h
@@ -13,6 +13,7 @@
  * See the License for the specific language governing permissions and
  * limitations under the License.
  */
+
 #ifndef _VPN_CONTROLLER_H
 #define _VPN_CONTROLLER_H
 
@@ -21,25 +22,25 @@
 #include "Controller.h"
 
 class VpnController : public Controller {
+    bool           mEnabled;
     /*
      * Gateway of the VPN server to connect to
      */
     struct in_addr mVpnGateway;
 
 public:
-    VpnController();
+    VpnController(PropertyManager *propmngr);
     virtual ~VpnController() {}
 
     virtual int start();
     virtual int stop();
 
-    virtual int setProperty(const char *name, char *value);
-    virtual const char *getProperty(const char *name, char *buffer,
-                                    size_t maxlen);
+    virtual int set(const char *name, const char *value);
+    virtual const char *get(const char *name, char *buffer, size_t maxlen);
 
-private:
-    virtual int enable();
-    virtual int disable();
+protected:
+    virtual int enable() = 0;
+    virtual int disable() = 0;
 
 };
 
diff --git a/nexus/WifiController.cpp b/nexus/WifiController.cpp
index 72207ce..3d06806 100644
--- a/nexus/WifiController.cpp
+++ b/nexus/WifiController.cpp
@@ -26,18 +26,21 @@
 #include "WifiScanner.h"
 #include "NetworkManager.h"
 #include "ErrorCode.h"
+#include "WifiNetwork.h"
 
-WifiController::WifiController(char *modpath, char *modname, char *modargs) :
-                Controller("WIFI", "wifi") {
+WifiController::WifiController(PropertyManager *propmngr, char *modpath, char *modname, char *modargs) :
+                Controller("WIFI", propmngr) {
     strncpy(mModulePath, modpath, sizeof(mModulePath));
     strncpy(mModuleName, modname, sizeof(mModuleName));
     strncpy(mModuleArgs, modargs, sizeof(mModuleArgs));
 
-    mSupplicant = new Supplicant();
+    mSupplicant = new Supplicant(this, propmngr);
     mScanner = new WifiScanner(mSupplicant, 10);
     mCurrentScanMode = 0;
 
-    registerProperty("scanmode");
+    mEnabled = false;
+
+    propmngr->registerProperty("wifi.enabled", this);
 }
 
 int WifiController::start() {
@@ -82,6 +85,17 @@
         }
     }
 
+    if (Controller::bindInterface(mSupplicant->getInterfaceName())) {
+        LOGE("Error binding interface (%s)", strerror(errno));
+        goto out_unloadmodule;
+    }
+
+    if (mSupplicant->refreshNetworkList())
+        LOGW("Error getting list of networks (%s)", strerror(errno));
+
+    mPropMngr->registerProperty("wifi.scanmode", this);
+    mPropMngr->registerProperty("wifi.interface", this);
+
     return 0;
 
 out_unloadmodule:
@@ -106,13 +120,14 @@
 
 int WifiController::disable() {
 
+    mPropMngr->unregisterProperty("wifi.scanmode");
     if (mSupplicant->isStarted()) {
         sendStatusBroadcast("STOPPING_SUPPLICANT");
         if (mSupplicant->stop()) {
             LOGE("Supplicant stop failed (%s)", strerror(errno));
             return -1;
         }
-    } else 
+    } else
         LOGW("disable(): Supplicant not running?");
 
     if (mModuleName[0] != '\0' && isKernelModuleLoaded(mModuleName)) {
@@ -155,36 +170,60 @@
     return rc;
 }
 
-int WifiController::addNetwork() {
-    return mSupplicant->addNetwork();
+WifiNetwork *WifiController::createNetwork() {
+    WifiNetwork *wn = mSupplicant->createNetwork();
+    return wn;
 }
 
 int WifiController::removeNetwork(int networkId) {
-    return mSupplicant->removeNetwork(networkId);
+    WifiNetwork *wn = mSupplicant->lookupNetwork(networkId);
+
+    if (!wn)
+        return -1;
+    return mSupplicant->removeNetwork(wn);
 }
 
 ScanResultCollection *WifiController::createScanResults() {
     return mSupplicant->createLatestScanResults();
 }
 
-// XXX: This should be a const list
 WifiNetworkCollection *WifiController::createNetworkList() {
     return mSupplicant->createNetworkList();
 }
 
-int WifiController::setProperty(const char *name, char *value) {
-    if (!strcmp(name, "scanmode")) 
-        return setScanMode((uint32_t) strtoul(value, NULL, 0));
+int WifiController::set(const char *name, const char *value) {
+    int rc;
 
-    return Controller::setProperty(name, value);
+    if (!strcmp(name, "wifi.enabled")) {
+        int en = atoi(value);
+
+        if (en == mEnabled)
+            return 0;
+        rc = (en ? enable() : disable());
+        if (!rc)
+            mEnabled = en;
+    } else if (!strcmp(name, "wifi.interface")) {
+        errno = EROFS;
+        return -1;
+    } else if (!strcmp(name, "wifi.scanmode"))
+        return setScanMode((uint32_t) strtoul(value, NULL, 0));
+    else
+        return Controller::set(name, value);
+    return rc;
 }
 
-const char *WifiController::getProperty(const char *name, char *buffer, size_t maxsize) {
-    if (!strcmp(name, "scanmode")) {
-        snprintf(buffer, maxsize, "0x%.8x", mCurrentScanMode);
-        return buffer;
-    } 
+const char *WifiController::get(const char *name, char *buffer, size_t maxsize) {
 
-    return Controller::getProperty(name, buffer, maxsize);
+    if (!strcmp(name, "wifi.enabled"))
+        snprintf(buffer, maxsize, "%d", mEnabled);
+    else if (!strcmp(name, "wifi.interface")) {
+        snprintf(buffer, maxsize, "%s",
+                 (getBoundInterface() ? getBoundInterface() : "none"));
+    } else if (!strcmp(name, "wifi.scanmode"))
+        snprintf(buffer, maxsize, "0x%.8x", mCurrentScanMode);
+    else
+        return Controller::get(name, buffer, maxsize);
+
+    return buffer;
 }
 
diff --git a/nexus/WifiController.h b/nexus/WifiController.h
index a70fb5b..b2f4530 100644
--- a/nexus/WifiController.h
+++ b/nexus/WifiController.h
@@ -13,6 +13,7 @@
  * See the License for the specific language governing permissions and
  * limitations under the License.
  */
+
 #ifndef _WIFI_CONTROLLER_H
 #define _WIFI_CONTROLLER_H
 
@@ -46,21 +47,21 @@
     char        mModuleArgs[255];
     uint32_t    mCurrentScanMode;
     WifiScanner *mScanner;
+    bool        mEnabled;
 
 public:
-    WifiController(char *modpath, char *modname, char *modargs);
+    WifiController(PropertyManager *propmngr, char *modpath, char *modname, char *modargs);
     virtual ~WifiController() {}
 
     int start();
     int stop();
 
-    int addNetwork();
+    WifiNetwork *createNetwork();
     int removeNetwork(int networkId);
     WifiNetworkCollection *createNetworkList();
 
-    virtual int setProperty(const char *name, char *value);
-    virtual const char *getProperty(const char *name, char *buffer,
-                                    size_t maxlen);
+    virtual int set(const char *name, const char *value);
+    virtual const char *get(const char *name, char *buffer, size_t maxlen);
 
     ScanResultCollection *createScanResults();
 
@@ -71,6 +72,7 @@
     Supplicant *getSupplicant() { return mSupplicant; }
 
 protected:
+    // Move this crap into a 'driver'
     virtual int powerUp() = 0;
     virtual int powerDown() = 0;
     virtual int loadFirmware();
@@ -78,13 +80,11 @@
     virtual bool isFirmwareLoaded() = 0;
     virtual bool isPoweredUp() = 0;
 
-    void sendStatusBroadcast(const char *msg);
-
 private:
+    void sendStatusBroadcast(const char *msg);
     int setScanMode(uint32_t mode);
     int enable();
     int disable();
-
 };
 
 #endif
diff --git a/nexus/WifiNetwork.cpp b/nexus/WifiNetwork.cpp
index ef013c0..1f53a20 100644
--- a/nexus/WifiNetwork.cpp
+++ b/nexus/WifiNetwork.cpp
@@ -16,14 +16,93 @@
 
 #include <errno.h>
 #include <string.h>
+#include <stdlib.h>
 #include <sys/types.h>
 
+#define LOG_TAG "WifiNetwork"
+#include <cutils/log.h>
+
+#include "NetworkManager.h"
 #include "WifiNetwork.h"
 #include "Supplicant.h"
+#include "WifiController.h"
+#include "InterfaceConfig.h"
 
-WifiNetwork::WifiNetwork(Supplicant *suppl) {
+const char *WifiNetwork::PropertyNames[] = { "ssid", "bssid", "psk", "wepkey.1",
+                                             "wepkey.2", "wepkey.3", "wepkey.4",
+                                             "defkeyidx", "pri", "hiddenssid",
+                                             "AllowedKeyManagement",
+                                             "AllowedProtocols",
+                                             "AllowedAuthAlgorithms",
+                                             "AllowedPairwiseCiphers",
+                                             "AllowedGroupCiphers",
+                                             "enabled", '\0' };
+WifiNetwork::WifiNetwork() {
+   // This is private to restrict copy constructors
+}
+
+WifiNetwork::WifiNetwork(WifiController *c, Supplicant *suppl, const char *data) {
+    mController = c;
     mSuppl = suppl;
-    mNetid = -1;
+
+    char *tmp = strdup(data);
+    char *next = tmp;
+    char *id;
+    char *ssid;
+    char *bssid;
+    char *flags;
+
+    if (!(id = strsep(&next, "\t")))
+        LOGE("Failed to extract network id");
+    if (!(ssid = strsep(&next, "\t")))
+        LOGE("Failed to extract ssid");
+    if (!(bssid = strsep(&next, "\t")))
+        LOGE("Failed to extract bssid");
+    if (!(flags = strsep(&next, "\t")))
+        LOGE("Failed to extract flags");
+
+   // LOGD("id '%s', ssid '%s', bssid '%s', flags '%s'", id, ssid, bssid,
+   //      flags ? flags :"null");
+
+    if (id)
+        mNetid = atoi(id);
+    if (ssid)
+        mSsid = strdup(ssid);
+    if (bssid)
+        mBssid = strdup(bssid);
+
+    mPsk = NULL;
+    memset(mWepKeys, 0, sizeof(mWepKeys));
+    mDefaultKeyIndex = -1;
+    mPriority = -1;
+    mHiddenSsid = NULL;
+    mAllowedKeyManagement = 0;
+    mAllowedProtocols = 0;
+    mAllowedAuthAlgorithms = 0;
+    mAllowedPairwiseCiphers = 0;
+    mAllowedGroupCiphers = 0;
+    mEnabled = true;
+
+    if (flags && flags[0] != '\0') {
+        if (!strcmp(flags, "[DISABLED]"))
+            mEnabled = false;
+        else
+            LOGW("Unsupported flags '%s'", flags);
+    }
+
+    char *tmp2;
+    asprintf(&tmp2, "wifi.net.%d", mNetid);
+    mIfaceCfg = new InterfaceConfig(tmp2);
+    free(tmp2);
+
+    registerProperties();
+    free(tmp);
+}
+
+WifiNetwork::WifiNetwork(WifiController *c, Supplicant *suppl, int networkId) {
+    mController = c;
+    mSuppl = suppl;
+    mNetid = networkId;
     mSsid = NULL;
     mBssid = NULL;
     mPsk = NULL;
@@ -36,9 +115,45 @@
     mAllowedAuthAlgorithms = 0;
     mAllowedPairwiseCiphers = 0;
     mAllowedGroupCiphers = 0;
+    mEnabled = false;
+
+    char *tmp2;
+    asprintf(&tmp2, "wifi.net.%d", mNetid);
+    mIfaceCfg = new InterfaceConfig(tmp2);
+    free(tmp2);
+
+    registerProperties();
+}
+
+WifiNetwork *WifiNetwork::clone() {
+    WifiNetwork *r = new WifiNetwork();
+
+    r->mSuppl = mSuppl;
+    r->mNetid = mNetid;
+
+    if (mSsid)
+        r->mSsid = strdup(mSsid);
+    if (mBssid)
+        r->mBssid = strdup(mBssid);
+    if (mPsk)
+        r->mPsk = strdup(mPsk);
+
+    r->mController = mController;
+    memcpy(r->mWepKeys, mWepKeys, sizeof(mWepKeys));
+    r->mDefaultKeyIndex = mDefaultKeyIndex;
+    r->mPriority = mPriority;
+    if (mHiddenSsid)
+        r->mHiddenSsid = strdup(mHiddenSsid);
+    r->mAllowedKeyManagement = mAllowedKeyManagement;
+    r->mAllowedProtocols = mAllowedProtocols;
+    r->mAllowedAuthAlgorithms = mAllowedAuthAlgorithms;
+    r->mAllowedPairwiseCiphers = mAllowedPairwiseCiphers;
+    r->mAllowedGroupCiphers = mAllowedGroupCiphers;
+    return r;
 }
 
 WifiNetwork::~WifiNetwork() {
+    unregisterProperties();
     if (mSsid)
         free(mSsid);
     if (mBssid)
@@ -49,61 +164,423 @@
         if (mWepKeys[i])
             free(mWepKeys[i]);
     }
+
     if (mHiddenSsid)
         free(mHiddenSsid);
+    if (mIfaceCfg)
+        delete(mIfaceCfg);
 }
 
-int WifiNetwork::setSsid(char *ssid) {
-    errno = ENOSYS;
+int WifiNetwork::refresh() {
+    char buffer[255];
+    size_t len;
+
+    len = sizeof(buffer);
+    if (mSuppl->getNetworkVar(mNetid, "psk", buffer, len))
+        mPsk = strdup(buffer);
+
+    for (int i = 0; i < 4; i++) {
+        char *name;
+
+        asprintf(&name, "wep_key%d", i);
+        len = sizeof(buffer);
+        if (mSuppl->getNetworkVar(mNetid, name, buffer, len))
+            mWepKeys[i] = strdup(buffer);
+        free(name);
+    }
+
+    len = sizeof(buffer);
+    if (mSuppl->getNetworkVar(mNetid, "wep_tx_keyidx", buffer, len))
+        mDefaultKeyIndex = atoi(buffer);
+
+    len = sizeof(buffer);
+    if (mSuppl->getNetworkVar(mNetid, "priority", buffer, len))
+        mPriority = atoi(buffer);
+
+    len = sizeof(buffer);
+    if (mSuppl->getNetworkVar(mNetid, "scan_ssid", buffer, len))
+        mHiddenSsid = strdup(buffer);
+
+    len = sizeof(buffer);
+    if (mSuppl->getNetworkVar(mNetid, "key_mgmt", buffer, len)) {
+        // TODO
+    }
+
+    len = sizeof(buffer);
+    if (mSuppl->getNetworkVar(mNetid, "proto", buffer, len)) {
+        // TODO
+    }
+
+    len = sizeof(buffer);
+    if (mSuppl->getNetworkVar(mNetid, "auth_alg", buffer, len)) {
+        // TODO
+    }
+
+    len = sizeof(buffer);
+    if (mSuppl->getNetworkVar(mNetid, "pairwise", buffer, len)) {
+        // TODO
+    }
+
+    len = sizeof(buffer);
+    if (mSuppl->getNetworkVar(mNetid, "group", buffer, len)) {
+        // TODO
+    }
+
+    return 0;
+out_err:
+    LOGE("Refresh failed (%s)",strerror(errno));
     return -1;
 }
 
-int WifiNetwork::setBssid(char *bssid) {
-    errno = ENOSYS;
+int WifiNetwork::set(const char *name, const char *value) {
+    char *n_tmp = strdup(name + strlen("wifi.net."));
+    char *n_next = n_tmp;
+    char *n_local;
+    char *n_rest;
+    int rc = 0;
+
+    if (!strsep(&n_next, ".")) // skip net id
+        goto out_inval;
+
+    if (!(n_local = strsep(&n_next, ".")))
+        goto out_inval;
+
+    n_rest = n_next;
+
+//    LOGD("set(): var '%s'(%s / %s) = %s", name, n_local, n_rest, value);
+    if (!strcasecmp(n_local, "enabled"))
+        rc = setEnabled(atoi(value));
+    else if (!strcmp(n_local, "ssid"))
+        rc = setSsid(value);
+    else if (!strcasecmp(n_local, "bssid"))
+        rc = setBssid(value);
+    else if (!strcasecmp(n_local, "psk"))
+        rc = setPsk(value);
+    else if (!strcasecmp(n_local, "wepkey"))
+        rc = setWepKey(atoi(n_rest) -1, value);
+    else if (!strcasecmp(n_local, "defkeyidx"))
+        rc = setDefaultKeyIndex(atoi(value));
+    else if (!strcasecmp(n_local, "pri"))
+        rc = setPriority(atoi(value));
+    else if (!strcasecmp(n_local, "hiddenssid"))
+        rc = setHiddenSsid(value);
+    else if (!strcasecmp(n_local, "AllowedKeyManagement")) {
+        uint32_t mask = 0;
+        bool none = false;
+        char *v_tmp = strdup(value);
+        char *v_next = v_tmp;
+        char *v_token;
+
+        while((v_token = strsep(&v_next, " "))) {
+            if (!strcasecmp(v_token, "NONE")) {
+                mask = 0;
+                none = true;
+            } else if (!none) {
+                if (!strcasecmp(v_token, "WPA_PSK"))
+                    mask |= KeyManagementMask::WPA_PSK;
+                else if (!strcasecmp(v_token, "WPA_EAP"))
+                    mask |= KeyManagementMask::WPA_EAP;
+                else if (!strcasecmp(v_token, "IEEE8021X"))
+                    mask |= KeyManagementMask::IEEE8021X;
+                else {
+                    errno = EINVAL;
+                    rc = -1;
+                    free(v_tmp);
+                    goto out;
+                }
+            } else {
+                errno = EINVAL;
+                rc = -1;
+                free(v_tmp);
+                goto out;
+            }
+        }
+        free(v_tmp);
+    } else if (!strcasecmp(n_local, "AllowedProtocols")) {
+        // TODO
+    } else if (!strcasecmp(n_local, "AllowedPairwiseCiphers")) {
+        // TODO
+    } else if (!strcasecmp(n_local, "AllowedAuthAlgorithms")) {
+        // TODO
+    } else if (!strcasecmp(n_local, "AllowedGroupCiphers")) {
+        // TODO
+    } else {
+        errno = ENOENT;
+        free(n_tmp);
+        return -1;
+    }
+
+out:
+    free(n_tmp);
+    return rc;
+
+out_inval:
+    errno = EINVAL;
+    free(n_tmp);
     return -1;
 }
 
-int WifiNetwork::setPsk(char *psk) {
-    errno = ENOSYS;
-    return -1;
+const char *WifiNetwork::get(const char *name, char *buffer, size_t maxsize) {
+    char *n_tmp = strdup(name + strlen("wifi.net."));
+    char *n_next = n_tmp;
+    char *n_local;
+    char fc[64];
+    char rc[128];
+
+    if (!strsep(&n_next, ".")) // skip net id
+        goto out_inval;
+
+    if (!(n_local = strsep(&n_next, ".")))
+        goto out_inval;
+
+
+    strncpy(fc, n_local, sizeof(fc));
+    rc[0] = '\0';
+    if (n_next)
+        strncpy(rc, n_next, sizeof(rc));
+
+    free(n_tmp);
+
+    if (!strcasecmp(fc, "enabled"))
+        snprintf(buffer, maxsize, "%d", getEnabled());
+    else if (!strcasecmp(fc, "ssid")) {
+        strncpy(buffer,
+                getSsid() ? getSsid() : "none",
+                maxsize);
+    } else if (!strcasecmp(fc, "bssid")) {
+        strncpy(buffer,
+                getBssid() ? getBssid() : "none",
+                maxsize);
+    } else if (!strcasecmp(fc, "psk")) {
+        strncpy(buffer,
+                getPsk() ? getPsk() : "none",
+                maxsize);
+    } else if (!strcasecmp(fc, "wepkey")) {
+        strncpy(buffer,
+                getWepKey(atoi(rc)-1) ? getWepKey(atoi(rc)-1) : "none",
+                maxsize);
+    } else if (!strcasecmp(fc, "defkeyidx"))
+        snprintf(buffer, maxsize, "%d", getDefaultKeyIndex());
+    else if (!strcasecmp(fc, "pri"))
+        snprintf(buffer, maxsize, "%d", getPriority());
+    else if (!strcasecmp(fc, "hiddenssid")) {
+        strncpy(buffer,
+                getHiddenSsid() ? getHiddenSsid() : "none",
+                maxsize);
+    } else {
+        strncpy(buffer, "(internal error)", maxsize);
+        errno = ENOENT;
+        return NULL;
+    }
+
+    return buffer;
+
+out_inval:
+    errno = EINVAL;
+    free(n_tmp);
+    return NULL;
 }
 
-int WifiNetwork::setWepKey(int idx, char *key) {
-    errno = ENOSYS;
-    return -1;
+int WifiNetwork::setSsid(const char *ssid) {
+    if (mSuppl->setNetworkVar(mNetid, "ssid", ssid))
+        return -1;
+    if (mSsid)
+        free(mSsid);
+    mSsid = strdup(ssid);
+    return 0;
+}
+
+int WifiNetwork::setBssid(const char *bssid) {
+    if (mSuppl->setNetworkVar(mNetid, "bssid", bssid))
+        return -1;
+    if (mBssid)
+        free(mBssid);
+    mBssid = strdup(bssid);
+    return 0;
+}
+
+int WifiNetwork::setPsk(const char *psk) {
+    if (mSuppl->setNetworkVar(mNetid, "psk", psk))
+        return -1;
+
+    if (mPsk)
+        free(mPsk);
+    mPsk = strdup(psk);
+    return 0;
+}
+
+int WifiNetwork::setWepKey(int idx, const char *key) {
+    char *name;
+
+    asprintf(&name, "wep_key%d", idx);
+    int rc = mSuppl->setNetworkVar(mNetid, name, key);
+    free(name);
+
+    if (rc)
+        return -1;
+
+    if (mWepKeys[idx])
+        free(mWepKeys[idx]);
+    mWepKeys[idx] = strdup(key);
+    return 0;
 }
 
 int WifiNetwork::setDefaultKeyIndex(int idx) {
-    errno = ENOSYS;
-    return -1;
+    char val[16];
+    sprintf(val, "%d", idx);
+    if (mSuppl->setNetworkVar(mNetid, "wep_tx_keyidx", val))
+        return -1;
+
+    mDefaultKeyIndex = idx;
+    return 0;
 }
 
-int WifiNetwork::setPriority(int idx) {
-    errno = ENOSYS;
-    return -1;
+int WifiNetwork::setPriority(int priority) {
+    char val[16];
+    sprintf(val, "%d", priority);
+    if (mSuppl->setNetworkVar(mNetid, "priority", val))
+        return -1;
+
+    mPriority = priority;
+    return 0;
 }
 
-int WifiNetwork::setHiddenSsid(char *ssid) {
-    errno = ENOSYS;
-    return -1;
+int WifiNetwork::setHiddenSsid(const char *ssid) {
+    if (mSuppl->setNetworkVar(mNetid, "scan_ssid", ssid))
+        return -1;
+
+    if (mHiddenSsid)
+        free(mHiddenSsid);
+    mHiddenSsid = strdup(ssid);
+    return 0;
 }
 
 int WifiNetwork::setAllowedKeyManagement(uint32_t mask) {
-    errno = ENOSYS;
-    return -1;
+    char accum[255];
+
+    if (mask == KeyManagementMask::NONE)
+        strcpy(accum, "NONE");
+    else {
+        if (mask & KeyManagementMask::WPA_PSK)
+            strcat(accum, "WPA_PSK ");
+        if (mask & KeyManagementMask::WPA_EAP)
+            strcat(accum, "WPA_EAP ");
+        if (mask & KeyManagementMask::IEEE8021X)
+            strcat(accum, "IEEE8021X ");
+    }
+
+    if (mSuppl->setNetworkVar(mNetid, "key_mgmt", accum))
+        return -1;
+    mAllowedKeyManagement = mask;
+    return 0;
 }
 
 int WifiNetwork::setAllowedProtocols(uint32_t mask) {
-    errno = ENOSYS;
-    return -1;
+    char accum[255];
+
+    accum[0] = '\0';
+
+    if (mask & SecurityProtocolMask::WPA)
+        strcpy(accum, "WPA ");
+
+    if (mask & SecurityProtocolMask::RSN)
+        strcat(accum, "RSN");
+
+    if (mSuppl->setNetworkVar(mNetid, "proto", accum))
+        return -1;
+    mAllowedProtocols = mask;
+    return 0;
+}
+
+int WifiNetwork::setAllowedAuthAlgorithms(uint32_t mask) {
+    char accum[255];
+
+    accum[0] = '\0';
+
+    if (mask & AuthenticationAlgorithmMask::OPEN)
+        strcpy(accum, "OPEN ");
+
+    if (mask & AuthenticationAlgorithmMask::SHARED)
+        strcat(accum, "SHARED ");
+
+    if (mask & AuthenticationAlgorithmMask::LEAP)
+        strcat(accum, "LEAP ");
+
+    if (mSuppl->setNetworkVar(mNetid, "auth_alg", accum))
+        return -1;
+
+    mAllowedAuthAlgorithms = mask;
+    return 0;
 }
 
 int WifiNetwork::setAllowedPairwiseCiphers(uint32_t mask) {
-    errno = ENOSYS;
-    return -1;
+    char accum[255];
+
+    if (mask == PairwiseCiphersMask::NONE)
+        strcpy(accum, "NONE");
+    else {
+        if (mask & PairwiseCiphersMask::TKIP)
+            strcat(accum, "TKIP ");
+        if (mask & PairwiseCiphersMask::CCMP)
+            strcat(accum, "CCMP ");
+    }
+
+    if (mSuppl->setNetworkVar(mNetid, "pairwise", accum))
+        return -1;
+
+    mAllowedPairwiseCiphers = mask;
+    return 0;
 }
 
 int WifiNetwork::setAllowedGroupCiphers(uint32_t mask) {
-    errno = ENOSYS;
-    return -1;
+    char accum[255];
+
+    if (mask & GroupCiphersMask::WEP40)
+        strcat(accum, "WEP40 ");
+    if (mask & GroupCiphersMask::WEP104)
+        strcat(accum, "WEP104 ");
+    if (mask & GroupCiphersMask::TKIP)
+        strcat(accum, "TKIP ");
+    if (mask & GroupCiphersMask::CCMP)
+        strcat(accum, "CCMP ");
+
+    if (mSuppl->setNetworkVar(mNetid, "group", accum))
+        return -1;
+    mAllowedGroupCiphers = mask;
+    return 0;
+}
+
+int WifiNetwork::setEnabled(bool enabled) {
+    if (mSuppl->enableNetwork(mNetid, enabled))
+        return -1;
+
+    mEnabled = enabled;
+    return 0;
+}
+
+int WifiNetwork::registerProperties() {
+    for (const char **p = WifiNetwork::PropertyNames; *p != '\0'; p++) {
+        char *tmp;
+        asprintf(&tmp, "wifi.net.%d.%s", mNetid, *p);
+
+        if (NetworkManager::Instance()->getPropMngr()->registerProperty(tmp,
+                                                                        this)) {
+            free(tmp);
+            return -1;
+        }
+        free(tmp);
+    }
+    return 0;
+}
+
+int WifiNetwork::unregisterProperties() {
+    for (const char **p = WifiNetwork::PropertyNames; *p != '\0'; p++) {
+        char *tmp;
+        asprintf(&tmp, "wifi.net.%d.%s", mNetid, *p);
+
+        if (NetworkManager::Instance()->getPropMngr()->unregisterProperty(tmp))
+            LOGW("Unable to remove property '%s' (%s)", tmp, strerror(errno));
+        free(tmp);
+    }
+    return 0;
 }
diff --git a/nexus/WifiNetwork.h b/nexus/WifiNetwork.h
index 1354730..bdffa8b 100644
--- a/nexus/WifiNetwork.h
+++ b/nexus/WifiNetwork.h
@@ -19,7 +19,7 @@
 
 #include <sys/types.h>
 
-#include "../../../frameworks/base/include/utils/List.h"
+#include <utils/List.h>
 
 class KeyManagementMask {
 public:
@@ -43,14 +43,14 @@
     static const uint32_t LEAP   = 0x04;
 };
 
-class PairwiseCipherMask {
+class PairwiseCiphersMask {
 public:
     static const uint32_t NONE = 0x00;
     static const uint32_t TKIP = 0x01;
     static const uint32_t CCMP = 0x02;
 };
 
-class GroupCipherMask {
+class GroupCiphersMask {
 public:
     static const uint32_t WEP40  = 0x01;
     static const uint32_t WEP104 = 0x02;
@@ -59,9 +59,20 @@
 };
 
 class Supplicant;
+class InterfaceConfig;
+class Controller;
+class WifiController;
 
-class WifiNetwork {
+#include "IPropertyProvider.h"
+
+class WifiNetwork : public IPropertyProvider{
+public:
+    static const char *PropertyNames[];
+
+private:
     Supplicant *mSuppl;
+    InterfaceConfig *mIfaceCfg;
+    WifiController *mController;
 
     /*
      * Unique network id - normally provided by supplicant
@@ -138,10 +149,24 @@
      */
     uint32_t mAllowedGroupCiphers;
 
+    /*
+     * Set if this Network is enabled
+     */
+    bool mEnabled;
+
+private:
+    WifiNetwork();
+    int registerProperties();
+    int unregisterProperties();
+
 public:
-    WifiNetwork(Supplicant *suppl);
+    WifiNetwork(WifiController *c, Supplicant *suppl, int networkId);
+    WifiNetwork(WifiController *c, Supplicant *suppl, const char *data);
+
     virtual ~WifiNetwork();
 
+    WifiNetwork *clone();
+
     int getNetworkId() { return mNetid; }
     const char *getSsid() { return mSsid; }
     const char *getBssid() { return mBssid; }
@@ -155,18 +180,30 @@
     uint32_t getAllowedAuthAlgorithms() { return mAllowedAuthAlgorithms; }
     uint32_t getAllowedPairwiseCiphers() { return mAllowedPairwiseCiphers; }
     uint32_t getAllowedGroupCiphers() { return mAllowedGroupCiphers; }
+    bool getEnabled() { return mEnabled; }
+    Controller *getController() { return (Controller *) mController; }
 
-    int setSsid(char *ssid);
-    int setBssid(char *bssid);
-    int setPsk(char *psk);
-    int setWepKey(int idx, char *key);
+    int set(const char *name, const char *value);
+    const char *get(const char *name, char *buffer, size_t maxsize);
+
+//    InterfaceConfig *getIfaceCfg() { return mIfaceCfg; }
+
+    int setEnabled(bool enabled);
+    int setSsid(const char *ssid);
+    int setBssid(const char *bssid);
+    int setPsk(const char *psk);
+    int setWepKey(int idx, const char *key);
     int setDefaultKeyIndex(int idx);
     int setPriority(int pri);
-    int setHiddenSsid(char *ssid);
+    int setHiddenSsid(const char *ssid);
     int setAllowedKeyManagement(uint32_t mask);
     int setAllowedProtocols(uint32_t mask);
+    int setAllowedAuthAlgorithms(uint32_t mask);
     int setAllowedPairwiseCiphers(uint32_t mask);
     int setAllowedGroupCiphers(uint32_t mask);
+
+    // XXX:Should this really be exposed?.. meh
+    int refresh();
 };
 
 typedef android::List<WifiNetwork *> WifiNetworkCollection;
diff --git a/nexus/WifiScanner.cpp b/nexus/WifiScanner.cpp
index 048e784..bdfa497 100644
--- a/nexus/WifiScanner.cpp
+++ b/nexus/WifiScanner.cpp
@@ -1,3 +1,19 @@
+/*
+ * 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 <stdlib.h>
 #include <sys/socket.h>
 #include <sys/select.h>
diff --git a/nexus/WifiScanner.h b/nexus/WifiScanner.h
index 4406e9f..92822e9 100644
--- a/nexus/WifiScanner.h
+++ b/nexus/WifiScanner.h
@@ -1,3 +1,19 @@
+/*
+ * 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 _WIFISCANNER_H
 #define _WIFISCANNER_H
 
diff --git a/nexus/main.cpp b/nexus/main.cpp
index 0aec3e5..e460d42 100644
--- a/nexus/main.cpp
+++ b/nexus/main.cpp
@@ -13,6 +13,7 @@
  * See the License for the specific language governing permissions and
  * limitations under the License.
  */
+
 #include <stdlib.h>
 #include <errno.h>
 
@@ -39,10 +40,10 @@
 
     nm->setBroadcaster((SocketListener *) cl);
 
-    nm->attachController(new LoopController());
-    nm->attachController(new TiwlanWifiController("/system/lib/modules/wlan.ko", "wlan", ""));
+    nm->attachController(new LoopController(nm->getPropMngr()));
+    nm->attachController(new TiwlanWifiController(nm->getPropMngr(), "/system/lib/modules/wlan.ko", "wlan", ""));
 //    nm->attachController(new AndroidL2TPVpnController());
-    nm->attachController(new OpenVpnController());
+    nm->attachController(new OpenVpnController(nm->getPropMngr()));
 
 
     if (NetworkManager::Instance()->run()) {
@@ -56,7 +57,7 @@
     }
 
     // XXX: we'll use the main thread for the NetworkManager eventually
-    
+
     while(1) {
         sleep(1000);
     }
diff --git a/nexus/nexctl.c b/nexus/nexctl.c
index 4ad73c4..cfebbf0 100644
--- a/nexus/nexctl.c
+++ b/nexus/nexctl.c
@@ -13,6 +13,7 @@
  * See the License for the specific language governing permissions and
  * limitations under the License.
  */
+
 #include <stdio.h>
 #include <stdlib.h>
 #include <unistd.h>