nexus: Rollup update for nexus

nexus: Change field separator from : to ' '

Signed-off-by: San Mehat <san@google.com>

nexus: Add some prototypes for stuff to come

Signed-off-by: San Mehat <san@google.com>

nexus: Add some TODOs

Signed-off-by: San Mehat <san@google.com>

libsysutils: Put a proper token parser into the FrameworkListener which
supports minimal \ escapes and quotes

Signed-off-by: San Mehat <san@google.com>

nexus: Fix a lot of bugs

Signed-off-by: San Mehat <san@google.com>

libsysutils: Remove some debugging
Signed-off-by: San Mehat <san@google.com>

nexus: Send broadcasts for supplicant state changes

Signed-off-by: San Mehat <san@google.com>

nexus: Plumb DHCP listener state changes to NetworkManager

Signed-off-by: San Mehat <san@google.com>

nexus: Make the SupplicantState strings more parsable

Signed-off-by: San Mehat <san@google.com>

nexus: Broadcast a message when dhcp state changes.

Signed-off-by: San Mehat <san@google.com>

nexus: Add a few new response codes

Signed-off-by: San Mehat <san@google.com>

nexus: Rename ErrorCode -> ResponseCode

Signed-off-by: San Mehat <san@google.com>

nexus: Add DHCP event broadcasting. Also adds the framework for
tracking supplicant 'searching-for-AP' state

Signed-off-by: San Mehat <san@google.com>

nexus: REmove WifiScanner

Signed-off-by: San Mehat <san@google.com>

nexus: Change the way scanning works. scanmode can now be selected
independantly of triggering a scan. Also adds rxfilter support

Signed-off-by: San Mehat <san@google.com>

nexus: Add support for configuring bluetooth coexistence scanning and modes

Signed-off-by: San Mehat <san@google.com>

nexus: use case insensitive match for property names

Signed-off-by: San Mehat <san@google.com>

nexus: Rollup of a bunch of stuff:
    - 'list' command now takes an argument to match against
    - InterfaceConfig has been moved into the Controller base (for now)
    - DhcpClient now has some rudimentry locking
    - process 'ADDRINFO' messages from dhcpcd
    - Drop tertiary dns

Signed-off-by: San Mehat <san@google.com>

nexus: Clean up some of the supplicant variable parsing and add 'wifi.current'

Signed-off-by: San Mehat <san@google.com>

nexus: Add driver-stop/start, initial suspend support

Signed-off-by: San Mehat <san@google.com>

nexus: Add Controller suspend/resume callbacks, as well as locking

Signed-off-by: San Mehat <san@google.com>

nexus: Make ARP probing configurable for DhcpClient

Signed-off-by: San Mehat <san@google.com>

nexus: Add linkspeed / rssi retrieval

Signed-off-by: San Mehat <san@google.com>

nexus: Add WifiStatusPoller to track RSSI/linkspeed when associated

Signed-off-by: San Mehat <san@google.com>

nexus: Disable some debugging and add 'wifi.netcount' property

Signed-off-by: San Mehat <san@google.com>

nexus: Replace the hackish property system with something more flexible with namespaces

Signed-off-by: San Mehat <san@google.com>

libsysutils: Fix a few bugs in SocketListener

Signed-off-by: San Mehat <san@google.com>

nexus: PropertyManager: Add array support

Signed-off-by: San Mehat <san@google.com>

nexus: Clean up properties
Signed-off-by: San Mehat <san@google.com>

nexus: WifiController: Change name of 'CurrentNetwork' property

Signed-off-by: San Mehat <san@google.com>
diff --git a/nexus/WifiController.cpp b/nexus/WifiController.cpp
index ef5ecae..c218c30 100644
--- a/nexus/WifiController.cpp
+++ b/nexus/WifiController.cpp
@@ -23,9 +23,8 @@
 
 #include "Supplicant.h"
 #include "WifiController.h"
-#include "WifiScanner.h"
 #include "NetworkManager.h"
-#include "ErrorCode.h"
+#include "ResponseCode.h"
 #include "WifiNetwork.h"
 #include "ISupplicantEventHandler.h"
 #include "SupplicantState.h"
@@ -37,11 +36,12 @@
 #include "SupplicantStateChangeEvent.h"
 #include "SupplicantConnectionTimeoutEvent.h"
 #include "SupplicantDisconnectedEvent.h"
+#include "WifiStatusPoller.h"
 
 WifiController::WifiController(PropertyManager *mPropMngr,
                                IControllerHandler *handlers,
                                char *modpath, char *modname, char *modargs) :
-                Controller("WIFI", mPropMngr, handlers) {
+                Controller("wifi", mPropMngr, handlers) {
     strncpy(mModulePath, modpath, sizeof(mModulePath));
     strncpy(mModuleName, modname, sizeof(mModuleName));
     strncpy(mModuleArgs, modargs, sizeof(mModuleArgs));
@@ -49,22 +49,59 @@
     mLatestScanResults = new ScanResultCollection();
     pthread_mutex_init(&mLatestScanResultsLock, NULL);
 
-    mSupplicant = new Supplicant(this, this);
-    mScanner = new WifiScanner(mSupplicant, 10);
-    mCurrentScanMode = 0;
+    pthread_mutex_init(&mLock, NULL);
 
+    mSupplicant = new Supplicant(this, this);
+    mActiveScan = false;
     mEnabled = false;
+    mScanOnly = false;
+    mPacketFilter = false;
+    mBluetoothCoexScan = false;
+    mBluetoothCoexMode = 0;
+    mCurrentlyConnectedNetworkId = -1;
+    mStatusPoller = new WifiStatusPoller(this);
+    mRssiEventThreshold = 5;
+    mLastLinkSpeed = 0;
 
     mSupplicantState = SupplicantState::UNKNOWN;
+
+    mStaticProperties.propEnabled = new WifiEnabledProperty(this);
+    mStaticProperties.propScanOnly = new WifiScanOnlyProperty(this);
+    mStaticProperties.propAllowedChannels = new WifiAllowedChannelsProperty(this);
+
+    mStaticProperties.propRssiEventThreshold =
+            new IntegerPropertyHelper("RssiEventThreshold", false, &mRssiEventThreshold);
+
+    mDynamicProperties.propSupplicantState = new WifiSupplicantStateProperty(this);
+    mDynamicProperties.propActiveScan = new WifiActiveScanProperty(this);
+    mDynamicProperties.propInterface = new WifiInterfaceProperty(this);
+    mDynamicProperties.propSearching = new WifiSearchingProperty(this);
+    mDynamicProperties.propPacketFilter = new WifiPacketFilterProperty(this);
+    mDynamicProperties.propBluetoothCoexScan = new WifiBluetoothCoexScanProperty(this);
+    mDynamicProperties.propBluetoothCoexMode = new WifiBluetoothCoexModeProperty(this);
+    mDynamicProperties.propCurrentNetwork = new WifiCurrentNetworkProperty(this);
+
+    mDynamicProperties.propRssi = new IntegerPropertyHelper("Rssi", true, &mLastRssi);
+    mDynamicProperties.propLinkSpeed = new IntegerPropertyHelper("LinkSpeed", true, &mLastLinkSpeed);
+
+    mDynamicProperties.propSuspended = new WifiSuspendedProperty(this);
+    mDynamicProperties.propNetCount = new WifiNetCountProperty(this);
+    mDynamicProperties.propTriggerScan = new WifiTriggerScanProperty(this);
 }
 
 int WifiController::start() {
-    mPropMngr->registerProperty("wifi.enabled", this);
+    mPropMngr->attachProperty("wifi", mStaticProperties.propEnabled);
+    mPropMngr->attachProperty("wifi", mStaticProperties.propScanOnly);
+    mPropMngr->attachProperty("wifi", mStaticProperties.propAllowedChannels);
+    mPropMngr->attachProperty("wifi", mStaticProperties.propRssiEventThreshold);
     return 0;
 }
 
 int WifiController::stop() {
-    mPropMngr->unregisterProperty("wifi.enabled");
+    mPropMngr->detachProperty("wifi", mStaticProperties.propEnabled);
+    mPropMngr->detachProperty("wifi", mStaticProperties.propScanOnly);
+    mPropMngr->detachProperty("wifi", mStaticProperties.propAllowedChannels);
+    mPropMngr->detachProperty("wifi", mStaticProperties.propRssiEventThreshold);
     return 0;
 }
 
@@ -114,9 +151,21 @@
     if (mSupplicant->refreshNetworkList())
         LOGW("Error getting list of networks (%s)", strerror(errno));
 
-    mPropMngr->registerProperty("wifi.supplicant.state", this);
-    mPropMngr->registerProperty("wifi.scanmode", this);
-    mPropMngr->registerProperty("wifi.interface", this);
+    LOGW("TODO: Set # of allowed regulatory channels!");
+
+    mPropMngr->attachProperty("wifi", mDynamicProperties.propSupplicantState);
+    mPropMngr->attachProperty("wifi", mDynamicProperties.propActiveScan);
+    mPropMngr->attachProperty("wifi", mDynamicProperties.propInterface);
+    mPropMngr->attachProperty("wifi", mDynamicProperties.propSearching);
+    mPropMngr->attachProperty("wifi", mDynamicProperties.propPacketFilter);
+    mPropMngr->attachProperty("wifi", mDynamicProperties.propBluetoothCoexScan);
+    mPropMngr->attachProperty("wifi", mDynamicProperties.propBluetoothCoexMode);
+    mPropMngr->attachProperty("wifi", mDynamicProperties.propCurrentNetwork);
+    mPropMngr->attachProperty("wifi", mDynamicProperties.propRssi);
+    mPropMngr->attachProperty("wifi", mDynamicProperties.propLinkSpeed);
+    mPropMngr->attachProperty("wifi", mDynamicProperties.propSuspended);
+    mPropMngr->attachProperty("wifi", mDynamicProperties.propNetCount);
+    mPropMngr->attachProperty("wifi", mDynamicProperties.propTriggerScan);
 
     LOGI("Enabled successfully");
     return 0;
@@ -135,17 +184,87 @@
     return -1;
 }
 
+bool WifiController::getSuspended() {
+    pthread_mutex_lock(&mLock);
+    bool r = mSuspended;
+    pthread_mutex_unlock(&mLock);
+    return r;
+}
+
+int WifiController::setSuspend(bool suspend) {
+
+    pthread_mutex_lock(&mLock);
+    if (suspend == mSuspended) {
+        LOGW("Suspended state already = %d", suspend);
+        pthread_mutex_unlock(&mLock);
+        return 0;
+    }
+
+    if (suspend) {
+        mHandlers->onControllerSuspending(this);
+
+        char tmp[80];
+        LOGD("Suspending from supplicant state %s",
+             SupplicantState::toString(mSupplicantState,
+                                       tmp,
+                                       sizeof(tmp)));
+
+        if (mSupplicantState != SupplicantState::IDLE) {
+            LOGD("Forcing Supplicant disconnect");
+            if (mSupplicant->disconnect()) {
+                LOGW("Error disconnecting (%s)", strerror(errno));
+            }
+        }
+
+        LOGD("Stopping Supplicant driver");
+        if (mSupplicant->stopDriver()) {
+            LOGE("Error stopping driver (%s)", strerror(errno));
+            pthread_mutex_unlock(&mLock);
+            return -1;
+        }
+    } else {
+        LOGD("Resuming");
+
+        if (mSupplicant->startDriver()) {
+            LOGE("Error resuming driver (%s)", strerror(errno));
+            pthread_mutex_unlock(&mLock);
+            return -1;
+        }
+        // XXX: set regulatory max channels 
+        if (mScanOnly)
+            mSupplicant->triggerScan();
+        else
+            mSupplicant->reconnect();
+
+        mHandlers->onControllerResumed(this);
+    }
+
+    mSuspended = suspend;
+    pthread_mutex_unlock(&mLock);
+    LOGD("Suspend / Resume completed");
+    return 0;
+}
+
 void WifiController::sendStatusBroadcast(const char *msg) {
     NetworkManager::Instance()->
                     getBroadcaster()->
-                    sendBroadcast(ErrorCode::UnsolicitedInformational, msg, false);
+                    sendBroadcast(ResponseCode::UnsolicitedInformational, msg, false);
 }
 
 int WifiController::disable() {
 
-    mPropMngr->unregisterProperty("wifi.scanmode");
-    mPropMngr->unregisterProperty("wifi.supplicant.state");
-    mPropMngr->unregisterProperty("wifi.scanmode");
+    mPropMngr->detachProperty("wifi", mDynamicProperties.propSupplicantState);
+    mPropMngr->detachProperty("wifi", mDynamicProperties.propActiveScan);
+    mPropMngr->detachProperty("wifi", mDynamicProperties.propInterface);
+    mPropMngr->detachProperty("wifi", mDynamicProperties.propSearching);
+    mPropMngr->detachProperty("wifi", mDynamicProperties.propPacketFilter);
+    mPropMngr->detachProperty("wifi", mDynamicProperties.propBluetoothCoexScan);
+    mPropMngr->detachProperty("wifi", mDynamicProperties.propBluetoothCoexMode);
+    mPropMngr->detachProperty("wifi", mDynamicProperties.propCurrentNetwork);
+    mPropMngr->detachProperty("wifi", mDynamicProperties.propRssi);
+    mPropMngr->detachProperty("wifi", mDynamicProperties.propLinkSpeed);
+    mPropMngr->detachProperty("wifi", mDynamicProperties.propSuspended);
+    mPropMngr->detachProperty("wifi", mDynamicProperties.propNetCount);
 
     if (mSupplicant->isStarted()) {
         sendStatusBroadcast("Stopping WPA Supplicant");
@@ -178,35 +297,61 @@
     return 0;
 }
 
-int WifiController::setScanMode(uint32_t mode) {
-    int rc = 0;
+int WifiController::triggerScan() {
+    pthread_mutex_lock(&mLock);
+    if (verifyNotSuspended()) {
+        pthread_mutex_unlock(&mLock);
+        return -1;
+    }
 
-    if (mCurrentScanMode == mode)
+    switch (mSupplicantState) {
+        case SupplicantState::DISCONNECTED:
+        case SupplicantState::INACTIVE:
+        case SupplicantState::SCANNING:
+        case SupplicantState::IDLE:
+            break;
+        default:
+            // Switch to scan only mode
+            mSupplicant->setApScanMode(2);
+            break;
+    }
+
+    int rc = mSupplicant->triggerScan();
+    pthread_mutex_unlock(&mLock);
+    return rc;
+}
+
+int WifiController::setActiveScan(bool active) {
+    pthread_mutex_lock(&mLock);
+    if (mActiveScan == active) {
+        pthread_mutex_unlock(&mLock);
         return 0;
+    }
+    mActiveScan = active;
 
-    if (!(mode & SCAN_ENABLE_MASK)) {
-        if (mCurrentScanMode & SCAN_REPEAT_MASK)
-            mScanner->stop();
-    } else if (mode & SCAN_REPEAT_MASK)
-        rc = mScanner->start(mode & SCAN_ACTIVE_MASK);
-    else
-        rc = mSupplicant->triggerScan(mode & SCAN_ACTIVE_MASK);
-
-    mCurrentScanMode = mode;
+    int rc = mSupplicant->setScanMode(active);
+    pthread_mutex_unlock(&mLock);
     return rc;
 }
 
 WifiNetwork *WifiController::createNetwork() {
+    pthread_mutex_lock(&mLock);
     WifiNetwork *wn = mSupplicant->createNetwork();
+    pthread_mutex_unlock(&mLock);
     return wn;
 }
 
 int WifiController::removeNetwork(int networkId) {
+    pthread_mutex_lock(&mLock);
     WifiNetwork *wn = mSupplicant->lookupNetwork(networkId);
 
-    if (!wn)
+    if (!wn) {
+        pthread_mutex_unlock(&mLock);
         return -1;
-    return mSupplicant->removeNetwork(wn);
+    }
+    int rc = mSupplicant->removeNetwork(wn);
+    pthread_mutex_unlock(&mLock);
+    return rc;
 }
 
 ScanResultCollection *WifiController::createScanResults() {
@@ -225,45 +370,59 @@
     return mSupplicant->createNetworkList();
 }
 
-int WifiController::set(const char *name, const char *value) {
+int WifiController::setPacketFilter(bool enable) {
     int rc;
 
-    if (!strcmp(name, "wifi.enabled")) {
-        int en = atoi(value);
+    pthread_mutex_lock(&mLock);
+    if (enable)
+        rc = mSupplicant->enablePacketFilter();
+    else
+        rc = mSupplicant->disablePacketFilter();
 
-        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 if (!strcmp(name, "wifi.supplicant.state")) {
-        errno = EROFS;
-        return -1;
-    } else
-        return Controller::set(name, value);
+    if (!rc)
+        mPacketFilter = enable;
+    pthread_mutex_unlock(&mLock);
     return rc;
 }
 
-const char *WifiController::get(const char *name, char *buffer, size_t maxsize) {
+int WifiController::setBluetoothCoexistenceScan(bool enable) {
+    int rc;
 
-    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 if (!strcmp(name, "wifi.supplicant.state"))
-        return SupplicantState::toString(mSupplicantState, buffer, maxsize);
+    pthread_mutex_lock(&mLock);
+
+    if (enable)
+        rc = mSupplicant->enableBluetoothCoexistenceScan();
     else
-        return Controller::get(name, buffer, maxsize);
+        rc = mSupplicant->disableBluetoothCoexistenceScan();
 
-    return buffer;
+    if (!rc)
+        mBluetoothCoexScan = enable;
+    pthread_mutex_unlock(&mLock);
+    return rc;
+}
+
+int WifiController::setScanOnly(bool scanOnly) {
+    pthread_mutex_lock(&mLock);
+    int rc = mSupplicant->setApScanMode((scanOnly ? 2 : 1));
+    if (!rc)
+        mScanOnly = scanOnly;
+    if (!mSuspended) {
+        if (scanOnly)
+            mSupplicant->disconnect();
+        else
+            mSupplicant->reconnect();
+    }
+    pthread_mutex_unlock(&mLock);
+    return rc;
+}
+
+int WifiController::setBluetoothCoexistenceMode(int mode) {
+    pthread_mutex_lock(&mLock);
+    int rc = mSupplicant->setBluetoothCoexistenceMode(mode);
+    if (!rc)
+        mBluetoothCoexMode = mode;
+    pthread_mutex_unlock(&mLock);
+    return rc;
 }
 
 void WifiController::onAssociatingEvent(SupplicantAssociatingEvent *evt) {
@@ -296,6 +455,7 @@
         return;
     }
     
+    mCurrentlyConnectedNetworkId = ss->getId();
     if (!(wn = mSupplicant->lookupNetwork(ss->getId()))) {
         LOGW("Error looking up connected network id %d (%s)",
              ss->getId(), strerror(errno));
@@ -303,7 +463,7 @@
     }
   
     delete ss;
-    mHandlers->onInterfaceConnected(this, wn->getIfaceCfg());
+    mHandlers->onInterfaceConnected(this);
 }
 
 void WifiController::onScanResultsEvent(SupplicantScanResultsEvent *evt) {
@@ -314,6 +474,10 @@
         return;
     }
 
+    mNumScanResultsSinceLastStateChange++;
+    if (mNumScanResultsSinceLastStateChange >= 3)
+        mIsSupplicantSearching = false;
+
     size_t len = 4096;
 
     if (mSupplicant->sendCommand("SCAN_RESULTS", reply, &len)) {
@@ -346,10 +510,14 @@
     while((linep = strtok_r(NULL, "\n", &linep_next)))
         mLatestScanResults->push_back(new ScanResult(linep));
 
+    // Switch handling of scan results back to normal mode
+    mSupplicant->setApScanMode(1);
+
     char *tmp;
     asprintf(&tmp, "Scan results ready (%d)", mLatestScanResults->size());
     NetworkManager::Instance()->getBroadcaster()->
-                                sendBroadcast(ErrorCode::UnsolicitedInformational, tmp, false);
+                                sendBroadcast(ResponseCode::ScanResultsReady,
+                                              tmp, false);
     free(tmp);
     pthread_mutex_unlock(&mLatestScanResultsLock);
     free(reply);
@@ -359,11 +527,35 @@
     char tmp[32];
     char tmp2[32];
     
+    if (evt->getState() == mSupplicantState)
+        return;
+
     LOGD("onStateChangeEvent(%s -> %s)", 
          SupplicantState::toString(mSupplicantState, tmp, sizeof(tmp)),
          SupplicantState::toString(evt->getState(), tmp2, sizeof(tmp2)));
 
+    if (evt->getState() != SupplicantState::SCANNING) {
+        mIsSupplicantSearching = true;
+        mNumScanResultsSinceLastStateChange = 0;
+    }
+
+    char *tmp3;
+    asprintf(&tmp3,
+             "Supplicant state changed from %d (%s) -> %d (%s)",
+             mSupplicantState, tmp, evt->getState(), tmp2);
+
     mSupplicantState = evt->getState();
+
+    if (mSupplicantState == SupplicantState::COMPLETED) {
+        mStatusPoller->start();
+    } else if (mStatusPoller->isStarted()) {
+        mStatusPoller->stop();
+    }
+
+    NetworkManager::Instance()->getBroadcaster()->
+                                sendBroadcast(ResponseCode::SupplicantStateChange,
+                                              tmp3, false);
+    free(tmp3);
 }
 
 void WifiController::onConnectionTimeoutEvent(SupplicantConnectionTimeoutEvent *evt) {
@@ -371,7 +563,8 @@
 }
 
 void WifiController::onDisconnectedEvent(SupplicantDisconnectedEvent *evt) {
-    mHandlers->onInterfaceDisconnected(this, getBoundInterface());
+    mCurrentlyConnectedNetworkId = -1;
+    mHandlers->onInterfaceDisconnected(this);
 }
 
 #if 0
@@ -411,3 +604,216 @@
     LOGD("onDriverStateEvent(%s)", evt->getEvent());
 }
 #endif
+
+void WifiController::onStatusPollInterval() {
+    pthread_mutex_lock(&mLock);
+    int rssi;
+    if (mSupplicant->getRssi(&rssi)) {
+        LOGE("Failed to get rssi (%s)", strerror(errno));
+        pthread_mutex_unlock(&mLock);
+        return;
+    }
+
+    if (abs(mLastRssi - rssi) > mRssiEventThreshold) {
+        char *tmp3;
+        asprintf(&tmp3, "RSSI changed from %d -> %d",
+                 mLastRssi, rssi);
+        mLastRssi = rssi;
+        NetworkManager::Instance()->getBroadcaster()->
+                               sendBroadcast(ResponseCode::RssiChange,
+                                             tmp3, false);
+        free(tmp3);
+    }
+
+    int linkspeed = mSupplicant->getLinkSpeed();
+    if (linkspeed != mLastLinkSpeed) {
+        char *tmp3;
+        asprintf(&tmp3, "Link speed changed from %d -> %d",
+                 mLastLinkSpeed, linkspeed);
+        mLastLinkSpeed = linkspeed;
+        NetworkManager::Instance()->getBroadcaster()->
+                               sendBroadcast(ResponseCode::LinkSpeedChange,
+                                             tmp3, false);
+        free(tmp3);
+        
+    }
+    pthread_mutex_unlock(&mLock);
+}
+
+int WifiController::verifyNotSuspended() {
+    if (mSuspended) {
+        errno = ESHUTDOWN;
+        return -1;
+    }
+    return 0;
+}
+
+/*
+ * Property inner classes
+ */
+
+WifiController::WifiIntegerProperty::WifiIntegerProperty(WifiController *c, 
+                                                         const char *name,
+                                                         bool ro,
+                                                         int elements) :
+                IntegerProperty(name, ro, elements) {
+    mWc = c;
+}
+
+WifiController::WifiStringProperty::WifiStringProperty(WifiController *c, 
+                                                       const char *name,
+                                                       bool ro, int elements) :
+                StringProperty(name, ro, elements) {
+    mWc = c;
+}
+
+WifiController::WifiEnabledProperty::WifiEnabledProperty(WifiController *c) :
+                WifiIntegerProperty(c, "Enabled", false, 1) {
+}
+
+int WifiController::WifiEnabledProperty::get(int idx, int *buffer) {
+    *buffer = mWc->mEnabled;
+    return 0;
+}
+int WifiController::WifiEnabledProperty::set(int idx, int value) {
+    int rc = (value ? mWc->enable() : mWc->disable());
+    if (!rc)
+        mWc->mEnabled = value;
+    return rc;
+}
+
+WifiController::WifiScanOnlyProperty::WifiScanOnlyProperty(WifiController *c) :
+                WifiIntegerProperty(c, "ScanOnly", false, 1) {
+}
+int WifiController::WifiScanOnlyProperty::get(int idx, int *buffer) {
+    *buffer = mWc->mScanOnly;
+    return 0;
+}
+int WifiController::WifiScanOnlyProperty::set(int idx, int value) {
+    return mWc->setScanOnly(value == 1);
+}
+
+WifiController::WifiAllowedChannelsProperty::WifiAllowedChannelsProperty(WifiController *c) :
+                WifiIntegerProperty(c, "AllowedChannels", false, 1) {
+}
+int WifiController::WifiAllowedChannelsProperty::get(int idx, int *buffer) {
+    *buffer = mWc->mNumAllowedChannels;
+    return 0;
+}
+int WifiController::WifiAllowedChannelsProperty::set(int idx, int value) {
+    // XXX: IMPL
+    errno = ENOSYS;
+    return -1;
+}
+
+WifiController::WifiSupplicantStateProperty::WifiSupplicantStateProperty(WifiController *c) :
+                WifiStringProperty(c, "SupplicantState", true, 1) {
+}
+int WifiController::WifiSupplicantStateProperty::get(int idx, char *buffer, size_t max) {
+    if (!SupplicantState::toString(mWc->mSupplicantState, buffer, max))
+        return -1;
+    return 0;
+}
+
+WifiController::WifiActiveScanProperty::WifiActiveScanProperty(WifiController *c) :
+                WifiIntegerProperty(c, "ActiveScan", false, 1) {
+}
+int WifiController::WifiActiveScanProperty::get(int idx, int *buffer) {
+    *buffer = mWc->mActiveScan;
+    return 0;
+}
+int WifiController::WifiActiveScanProperty::set(int idx, int value) {
+    return mWc->setActiveScan(value);
+}
+
+WifiController::WifiInterfaceProperty::WifiInterfaceProperty(WifiController *c) :
+                WifiStringProperty(c, "Interface", true, 1) {
+}
+int WifiController::WifiInterfaceProperty::get(int idx, char *buffer, size_t max) {
+    strncpy(buffer, (mWc->getBoundInterface() ? mWc->getBoundInterface() : "none"), max);
+    return 0;
+}
+
+WifiController::WifiSearchingProperty::WifiSearchingProperty(WifiController *c) :
+                WifiIntegerProperty(c, "Searching", true, 1) {
+}
+int WifiController::WifiSearchingProperty::get(int idx, int *buffer) {
+    *buffer = mWc->mIsSupplicantSearching;
+    return 0;
+}
+
+WifiController::WifiPacketFilterProperty::WifiPacketFilterProperty(WifiController *c) :
+                WifiIntegerProperty(c, "PacketFilter", false, 1) {
+}
+int WifiController::WifiPacketFilterProperty::get(int idx, int *buffer) {
+    *buffer = mWc->mPacketFilter;
+    return 0;
+}
+int WifiController::WifiPacketFilterProperty::set(int idx, int value) {
+    return mWc->setPacketFilter(value);
+}
+
+WifiController::WifiBluetoothCoexScanProperty::WifiBluetoothCoexScanProperty(WifiController *c) :
+                WifiIntegerProperty(c, "BluetoothCoexScan", false, 1) {
+}
+int WifiController::WifiBluetoothCoexScanProperty::get(int idx, int *buffer) {
+    *buffer = mWc->mBluetoothCoexScan;
+    return 0;
+}
+int WifiController::WifiBluetoothCoexScanProperty::set(int idx, int value) {
+    return mWc->setBluetoothCoexistenceScan(value == 1);
+}
+
+WifiController::WifiBluetoothCoexModeProperty::WifiBluetoothCoexModeProperty(WifiController *c) :
+                WifiIntegerProperty(c, "BluetoothCoexMode", false, 1) {
+}
+int WifiController::WifiBluetoothCoexModeProperty::get(int idx, int *buffer) {
+    *buffer = mWc->mBluetoothCoexMode;
+    return 0;
+}
+int WifiController::WifiBluetoothCoexModeProperty::set(int idx, int value) {
+    return mWc->setBluetoothCoexistenceMode(value);
+}
+
+WifiController::WifiCurrentNetworkProperty::WifiCurrentNetworkProperty(WifiController *c) :
+                WifiIntegerProperty(c, "CurrentlyConnectedNetworkId", true, 1) {
+}
+int WifiController::WifiCurrentNetworkProperty::get(int idx, int *buffer) {
+    *buffer = mWc->mCurrentlyConnectedNetworkId;
+    return 0;
+}
+
+WifiController::WifiSuspendedProperty::WifiSuspendedProperty(WifiController *c) :
+                WifiIntegerProperty(c, "Suspended", false, 1) {
+}
+int WifiController::WifiSuspendedProperty::get(int idx, int *buffer) {
+    *buffer = mWc->getSuspended();
+    return 0;
+}
+int WifiController::WifiSuspendedProperty::set(int idx, int value) {
+    return mWc->setSuspend(value == 1);
+}
+
+WifiController::WifiNetCountProperty::WifiNetCountProperty(WifiController *c) :
+                WifiIntegerProperty(c, "NetCount", true, 1) {
+}
+int WifiController::WifiNetCountProperty::get(int idx, int *buffer) {
+    pthread_mutex_lock(&mWc->mLock);
+    *buffer = mWc->mSupplicant->getNetworkCount();
+    pthread_mutex_unlock(&mWc->mLock);
+    return 0;
+}
+
+WifiController::WifiTriggerScanProperty::WifiTriggerScanProperty(WifiController *c) :
+                WifiIntegerProperty(c, "TriggerScan", false, 1) {
+}
+int WifiController::WifiTriggerScanProperty::get(int idx, int *buffer) {
+    // XXX: Need action type
+    *buffer = 0;
+    return 0;
+}
+
+int WifiController::WifiTriggerScanProperty::set(int idx, int value) {
+    return mWc->triggerScan();
+}
+