Merge change 1365

* changes:
  Remove all gcc warnings.
diff --git a/adb/adb.h b/adb/adb.h
index a17c8dd..aebb81a 100644
--- a/adb/adb.h
+++ b/adb/adb.h
@@ -359,17 +359,10 @@
 
 // Google's USB Vendor ID
 #define VENDOR_ID_GOOGLE        0x18d1
+
 // HTC's USB Vendor ID
 #define VENDOR_ID_HTC           0x0bb4
 
-// products for VENDOR_ID_GOOGLE
-#define PRODUCT_ID_SOONER       0xd00d  // Sooner bootloader
-#define PRODUCT_ID_SOONER_COMP  0xdeed  // Sooner composite device
-
-// products for VENDOR_ID_HTC
-#define PRODUCT_ID_DREAM        0x0c01  // Dream bootloader
-#define PRODUCT_ID_DREAM_COMP   0x0c02  // Dream composite device
-
 void local_init();
 int  local_connect(int  port);
 
diff --git a/adb/usb_osx.c b/adb/usb_osx.c
index 49e1eef..2d4c1a9 100644
--- a/adb/usb_osx.c
+++ b/adb/usb_osx.c
@@ -31,21 +31,17 @@
 
 #define  DBG   D
 
-typedef struct {
-    int vid;
-    int pid;
-} VendorProduct;
+#define ADB_SUBCLASS           0x42
+#define ADB_PROTOCOL           0x1
 
-#define kSupportedDeviceCount   4
-VendorProduct kSupportedDevices[kSupportedDeviceCount] = {
-    { VENDOR_ID_GOOGLE, PRODUCT_ID_SOONER },
-    { VENDOR_ID_GOOGLE, PRODUCT_ID_SOONER_COMP },
-    { VENDOR_ID_HTC, PRODUCT_ID_DREAM },
-    { VENDOR_ID_HTC, PRODUCT_ID_DREAM_COMP },
+int vendorIds[] = {
+    VENDOR_ID_GOOGLE,
+    VENDOR_ID_HTC,
 };
+#define NUM_VENDORS             (sizeof(vendorIds)/sizeof(vendorIds[0]))
 
 static IONotificationPortRef    notificationPort = 0;
-static io_iterator_t            notificationIterators[kSupportedDeviceCount];
+static io_iterator_t            notificationIterators[NUM_VENDORS];
 
 struct usb_handle
 {
@@ -61,17 +57,20 @@
 static pthread_cond_t start_cond;
 
 
-static void AndroidDeviceAdded(void *refCon, io_iterator_t iterator);
-static void AndroidDeviceNotify(void *refCon, io_iterator_t iterator, natural_t messageType, void *messageArgument);
-static usb_handle* FindDeviceInterface(IOUSBDeviceInterface **dev, UInt16 vendor, UInt16 product);
+static void AndroidInterfaceAdded(void *refCon, io_iterator_t iterator);
+static void AndroidInterfaceNotify(void *refCon, io_iterator_t iterator,
+                                   natural_t messageType,
+                                   void *messageArgument);
+static usb_handle* CheckInterface(IOUSBInterfaceInterface **iface,
+                                  UInt16 vendor, UInt16 product);
 
 static int
 InitUSB()
 {
     CFMutableDictionaryRef  matchingDict;
     CFRunLoopSourceRef      runLoopSource;
-    SInt32					vendor, product;
-    int                     i;
+    SInt32                  vendor, if_subclass, if_protocol;
+    unsigned                i;
 
     //* To set up asynchronous notifications, create a notification port and
     //* add its run loop event source to the program's run loop
@@ -81,51 +80,57 @@
 
     memset(notificationIterators, 0, sizeof(notificationIterators));
 
-    //* loop through all supported vendor/product pairs
-    for (i = 0; i < kSupportedDeviceCount; i++) {
-        //* Create our matching dictionary to find the Android device
-        //* IOServiceAddMatchingNotification consumes the reference, so we do not need to release this
-        matchingDict = IOServiceMatching(kIOUSBDeviceClassName);
+    //* loop through all supported vendors
+    for (i = 0; i < NUM_VENDORS; i++) {
+        //* Create our matching dictionary to find the Android device's
+        //* adb interface
+        //* IOServiceAddMatchingNotification consumes the reference, so we do
+        //* not need to release this
+        matchingDict = IOServiceMatching(kIOUSBInterfaceClassName);
 
         if (!matchingDict) {
             DBG("ERR: Couldn't create USB matching dictionary.\n");
             return -1;
         }
 
-        //* Set up two matching dictionaries, one for each product ID we support.
-        //* This will cause the kernel to notify us only if the vendor and product IDs match.
-        vendor = kSupportedDevices[i].vid;
-        product = kSupportedDevices[i].pid;
-        CFDictionarySetValue(matchingDict, CFSTR(kUSBVendorID), CFNumberCreate(kCFAllocatorDefault, kCFNumberSInt32Type, &vendor));
-        CFDictionarySetValue(matchingDict, CFSTR(kUSBProductID), CFNumberCreate(kCFAllocatorDefault, kCFNumberSInt32Type, &product));
-
-        //* Now set up two notifications: one to be called when a raw device
-        //* is first matched by the I/O Kit and another to be called when the
-        //* device is terminated.
-        //* we need to do this with each matching dictionary.
+        //* Match based on vendor id, interface subclass and protocol
+        vendor = vendorIds[i];
+        if_subclass = ADB_SUBCLASS;
+        if_protocol = ADB_PROTOCOL;
+        CFDictionarySetValue(matchingDict, CFSTR(kUSBVendorID),
+                             CFNumberCreate(kCFAllocatorDefault,
+                                            kCFNumberSInt32Type, &vendor));
+        CFDictionarySetValue(matchingDict, CFSTR(kUSBInterfaceSubClass),
+                             CFNumberCreate(kCFAllocatorDefault,
+                                            kCFNumberSInt32Type, &if_subclass));
+        CFDictionarySetValue(matchingDict, CFSTR(kUSBInterfaceProtocol),
+                             CFNumberCreate(kCFAllocatorDefault,
+                                            kCFNumberSInt32Type, &if_protocol));
         IOServiceAddMatchingNotification(
                 notificationPort,
                 kIOFirstMatchNotification,
                 matchingDict,
-                AndroidDeviceAdded,
+                AndroidInterfaceAdded,
                 NULL,
                 &notificationIterators[i]);
 
-        //* Iterate over set of matching devices to access already-present devices
-        //* and to arm the notification
-        AndroidDeviceAdded(NULL, notificationIterators[i]);
+        //* Iterate over set of matching interfaces to access already-present
+        //* devices and to arm the notification
+        AndroidInterfaceAdded(NULL, notificationIterators[i]);
     }
 
     return 0;
 }
 
 static void
-AndroidDeviceAdded(void *refCon, io_iterator_t iterator)
+AndroidInterfaceAdded(void *refCon, io_iterator_t iterator)
 {
     kern_return_t            kr;
     io_service_t             usbDevice;
+    io_service_t             usbInterface;
     IOCFPlugInInterface      **plugInInterface = NULL;
-    IOUSBDeviceInterface182  **dev = NULL;
+    IOUSBInterfaceInterface220  **iface = NULL;
+    IOUSBDeviceInterface197  **dev = NULL;
     HRESULT                  result;
     SInt32                   score;
     UInt16                   vendor;
@@ -133,28 +138,66 @@
     UInt8                    serialIndex;
     char                     serial[256];
 
-    while ((usbDevice = IOIteratorNext(iterator))) {
-        //* Create an intermediate plugin
+    while ((usbInterface = IOIteratorNext(iterator))) {
+        //* Create an intermediate interface plugin
+        kr = IOCreatePlugInInterfaceForService(usbInterface,
+                                               kIOUSBInterfaceUserClientTypeID,
+                                               kIOCFPlugInInterfaceID,
+                                               &plugInInterface, &score);
+        IOObjectRelease(usbInterface);
+        if ((kIOReturnSuccess != kr) || (!plugInInterface)) {
+            DBG("ERR: Unable to create an interface plug-in (%08x)\n", kr);
+            continue;
+        }
+
+        //* This gets us the interface object
+        result = (*plugInInterface)->QueryInterface(plugInInterface,
+                CFUUIDGetUUIDBytes(kIOUSBInterfaceInterfaceID), (LPVOID)
+                &iface);
+        //* We only needed the plugin to get the interface, so discard it
+        (*plugInInterface)->Release(plugInInterface);
+        if (result || !iface) {
+            DBG("ERR: Couldn't query the interface (%08x)\n", (int) result);
+            continue;
+        }
+
+        //* this gets us an ioservice, with which we will find the actual
+        //* device; after getting a plugin, and querying the interface, of
+        //* course.
+        //* Gotta love OS X
+        kr = (*iface)->GetDevice(iface, &usbDevice);
+        if (kIOReturnSuccess != kr || !usbDevice) {
+            DBG("ERR: Couldn't grab device from interface (%08x)\n", kr);
+            continue;
+        }
+
+        plugInInterface = NULL;
+        score = 0;
+        //* create an intermediate device plugin
         kr = IOCreatePlugInInterfaceForService(usbDevice,
                                                kIOUSBDeviceUserClientTypeID,
                                                kIOCFPlugInInterfaceID,
                                                &plugInInterface, &score);
-
+        //* only needed this to find the plugin
+        (void)IOObjectRelease(usbDevice);
         if ((kIOReturnSuccess != kr) || (!plugInInterface)) {
-            DBG("ERR: Unable to create a plug-in (%08x)\n", kr);
-            goto continue1;
+            DBG("ERR: Unable to create a device plug-in (%08x)\n", kr);
+            continue;
         }
 
-        //* Now create the device interface
         result = (*plugInInterface)->QueryInterface(plugInInterface,
                 CFUUIDGetUUIDBytes(kIOUSBDeviceInterfaceID), (LPVOID) &dev);
-
+        //* only needed this to query the plugin
+        (*plugInInterface)->Release(plugInInterface);
         if (result || !dev) {
-            DBG("ERR: Couldn't create a device interface (%08x)\n", (int) result);
-            goto continue2;
+            DBG("ERR: Couldn't create a device interface (%08x)\n",
+                (int) result);
+            continue;
         }
 
-        //* Check the device to see if it's ours
+        //* Now after all that, we actually have a ref to the device and
+        //* the interface that matched our criteria
+
         kr = (*dev)->GetDeviceVendor(dev, &vendor);
         kr = (*dev)->GetDeviceProduct(dev, &product);
         kr = (*dev)->USBGetSerialNumberStringIndex(dev, &serialIndex);
@@ -163,7 +206,8 @@
             IOUSBDevRequest req;
             UInt16          buffer[256];
 
-            req.bmRequestType = USBmakebmRequestType(kUSBIn, kUSBStandard, kUSBDevice);
+            req.bmRequestType =
+                USBmakebmRequestType(kUSBIn, kUSBStandard, kUSBDevice);
             req.bRequest = kUSBRqGetDescriptor;
             req.wValue = (kUSBStringDesc << 8) | serialIndex;
             req.wIndex = 0;
@@ -174,219 +218,149 @@
             if (kr == kIOReturnSuccess && req.wLenDone > 0) {
                 int i, count;
 
-                // skip first word, and copy the rest to the serial string, changing shorts to bytes.
+                // skip first word, and copy the rest to the serial string,
+                // changing shorts to bytes.
                 count = (req.wLenDone - 1) / 2;
                 for (i = 0; i < count; i++)
                   serial[i] = buffer[i + 1];
                 serial[i] = 0;
             }
         }
+        (*dev)->Release(dev);
 
-        usb_handle* handle = NULL;
+        DBG("INFO: Found vid=%04x pid=%04x serial=%s\n", vendor, product,
+            serial);
 
-        //* Open the device
-        kr = (*dev)->USBDeviceOpen(dev);
-
-        if (kr != kIOReturnSuccess) {
-            DBG("ERR: Could not open device: %08x\n", kr);
-            goto continue3;
-        } else {
-            //* Find an interface for the device
-            handle = FindDeviceInterface((IOUSBDeviceInterface**)dev, vendor, product);
-        }
-
+        usb_handle* handle = CheckInterface((IOUSBInterfaceInterface**)iface,
+                                            vendor, product);
         if (handle == NULL) {
             DBG("ERR: Could not find device interface: %08x\n", kr);
-            (*dev)->USBDeviceClose(dev);
-            goto continue3;
+            (*iface)->Release(iface);
+            continue;
         }
 
         DBG("AndroidDeviceAdded calling register_usb_transport\n");
         register_usb_transport(handle, (serial[0] ? serial : NULL));
 
-        // Register for an interest notification of this device being removed. Pass the reference to our
-        // private data as the refCon for the notification.
+        // Register for an interest notification of this device being removed.
+        // Pass the reference to our private data as the refCon for the
+        // notification.
         kr = IOServiceAddInterestNotification(notificationPort,
-                usbDevice,
+                usbInterface,
                 kIOGeneralInterest,
-                AndroidDeviceNotify,
+                AndroidInterfaceNotify,
                 handle,
                 &handle->usbNotification);
+
         if (kIOReturnSuccess != kr) {
             DBG("ERR: Unable to create interest notification (%08x)\n", kr);
         }
-
-continue3:
-        (void)(*dev)->Release(dev);
-continue2:
-        IODestroyPlugInInterface(plugInInterface);
-continue1:
-        IOObjectRelease(usbDevice);
     }
 }
 
 static void
-AndroidDeviceNotify(void *refCon, io_service_t service, natural_t messageType, void *messageArgument)
+AndroidInterfaceNotify(void *refCon, io_service_t service, natural_t messageType, void *messageArgument)
 {
     usb_handle *handle = (usb_handle *)refCon;
 
     if (messageType == kIOMessageServiceIsTerminated) {
-        DBG("AndroidDeviceNotify\n");
+        if (!handle) {
+            DBG("ERR: NULL handle\n");
+            return;
+        }
+        DBG("AndroidInterfaceNotify\n");
         IOObjectRelease(handle->usbNotification);
         usb_kick(handle);
     }
 }
 
+//* TODO: simplify this further since we only register to get ADB interface
+//* subclass+protocol events
 static usb_handle*
-FindDeviceInterface(IOUSBDeviceInterface **dev, UInt16 vendor, UInt16 product)
+CheckInterface(IOUSBInterfaceInterface **interface, UInt16 vendor, UInt16 product)
 {
     usb_handle*                 handle = NULL;
     IOReturn                    kr;
-    IOUSBFindInterfaceRequest   request;
-    io_iterator_t               iterator;
-    io_service_t                usbInterface;
-    IOCFPlugInInterface         **plugInInterface;
-    IOUSBInterfaceInterface     **interface = NULL;
-    HRESULT                     result;
-    SInt32                      score;
     UInt8  interfaceNumEndpoints, interfaceClass, interfaceSubClass, interfaceProtocol;
-    UInt8  endpoint, configuration;
+    UInt8  endpoint;
 
-    //* Placing the constant KIOUSBFindInterfaceDontCare into the following
-    //* fields of the IOUSBFindInterfaceRequest structure will allow us to
-    //* find all of the interfaces
-    request.bInterfaceClass = kIOUSBFindInterfaceDontCare;
-    request.bInterfaceSubClass = kIOUSBFindInterfaceDontCare;
-    request.bInterfaceProtocol = kIOUSBFindInterfaceDontCare;
-    request.bAlternateSetting = kIOUSBFindInterfaceDontCare;
 
-    //* SetConfiguration will kill an existing UMS connection, so let's not do this if not necessary.
-    configuration = 0;
-    (*dev)->GetConfiguration(dev, &configuration);
-    if (configuration != 1)
-        (*dev)->SetConfiguration(dev, 1);
-
-    //* Get an iterator for the interfaces on the device
-    kr = (*dev)->CreateInterfaceIterator(dev, &request, &iterator);
-
+    //* Now open the interface.  This will cause the pipes associated with
+    //* the endpoints in the interface descriptor to be instantiated
+    kr = (*interface)->USBInterfaceOpen(interface);
     if (kr != kIOReturnSuccess) {
-        DBG("ERR: Couldn't create a device interface iterator: (%08x)\n", kr);
+        DBG("ERR: Could not open interface: (%08x)\n", kr);
         return NULL;
     }
 
-    while ((usbInterface = IOIteratorNext(iterator))) {
-    //* Create an intermediate plugin
-        kr = IOCreatePlugInInterfaceForService(
-                usbInterface,
-                kIOUSBInterfaceUserClientTypeID,
-                kIOCFPlugInInterfaceID,
-                &plugInInterface,
-                &score);
-
-        //* No longer need the usbInterface object now that we have the plugin
-        (void) IOObjectRelease(usbInterface);
-
-        if ((kr != kIOReturnSuccess) || (!plugInInterface)) {
-            DBG("ERR: Unable to create plugin (%08x)\n", kr);
-            break;
-        }
-
-        //* Now create the interface interface for the interface
-        result = (*plugInInterface)->QueryInterface(
-                plugInInterface,
-                CFUUIDGetUUIDBytes(kIOUSBInterfaceInterfaceID),
-                (LPVOID) &interface);
-
-        //* No longer need the intermediate plugin
-        (*plugInInterface)->Release(plugInInterface);
-
-        if (result || !interface) {
-            DBG("ERR: Couldn't create interface interface: (%08x)\n",
-               (unsigned int) result);
-            break;
-        }
-
-        //* Now open the interface.  This will cause the pipes associated with
-        //* the endpoints in the interface descriptor to be instantiated
-        kr = (*interface)->USBInterfaceOpen(interface);
-
-        if (kr != kIOReturnSuccess)
-        {
-            DBG("ERR: Could not open interface: (%08x)\n", kr);
-            (void) (*interface)->Release(interface);
-            //* continue so we can try the next interface
-            continue;
-        }
-
-        //* Get the number of endpoints associated with this interface
-        kr = (*interface)->GetNumEndpoints(interface, &interfaceNumEndpoints);
-
-        if (kr != kIOReturnSuccess) {
-            DBG("ERR: Unable to get number of endpoints: (%08x)\n", kr);
-            goto next_interface;
-        }
-
-        //* Get interface class, subclass and protocol
-        if ((*interface)->GetInterfaceClass(interface, &interfaceClass) != kIOReturnSuccess ||
-            (*interface)->GetInterfaceSubClass(interface, &interfaceSubClass) != kIOReturnSuccess ||
-            (*interface)->GetInterfaceProtocol(interface, &interfaceProtocol) != kIOReturnSuccess)
-        {
-            DBG("ERR: Unable to get interface class, subclass and protocol\n");
-            goto next_interface;
-        }
-
-        //* check to make sure interface class, subclass and protocol match ADB
-        //* avoid opening mass storage endpoints
-        if (is_adb_interface(vendor, product, interfaceClass, interfaceSubClass, interfaceProtocol)) {
-            handle = calloc(1, sizeof(usb_handle));
-
-            //* Iterate over the endpoints for this interface and find the first
-            //* bulk in/out pipes available.  These will be our read/write pipes.
-            for (endpoint = 0; endpoint <= interfaceNumEndpoints; endpoint++) {
-                UInt8   transferType;
-                UInt16  maxPacketSize;
-                UInt8   interval;
-                UInt8   number;
-                UInt8   direction;
-
-                kr = (*interface)->GetPipeProperties(interface, endpoint, &direction,
-                        &number, &transferType, &maxPacketSize, &interval);
-
-                if (kIOReturnSuccess == kr) {
-                    if (kUSBBulk != transferType)
-                        continue;
-
-                    if (kUSBIn == direction)
-                        handle->bulkIn = endpoint;
-
-                    if (kUSBOut == direction)
-                        handle->bulkOut = endpoint;
-
-                    if (interfaceProtocol == 0x01) {
-                        handle->zero_mask = maxPacketSize - 1;
-                    }
-
-                } else {
-                    DBG("ERR: FindDeviceInterface - could not get pipe properties\n");
-                }
-            }
-
-            handle->interface = interface;
-            break;
-        }
-
-next_interface:
-        (*interface)->USBInterfaceClose(interface);
-        (*interface)->Release(interface);
+    //* Get the number of endpoints associated with this interface
+    kr = (*interface)->GetNumEndpoints(interface, &interfaceNumEndpoints);
+    if (kr != kIOReturnSuccess) {
+        DBG("ERR: Unable to get number of endpoints: (%08x)\n", kr);
+        goto err_get_num_ep;
     }
 
+    //* Get interface class, subclass and protocol
+    if ((*interface)->GetInterfaceClass(interface, &interfaceClass) != kIOReturnSuccess ||
+            (*interface)->GetInterfaceSubClass(interface, &interfaceSubClass) != kIOReturnSuccess ||
+            (*interface)->GetInterfaceProtocol(interface, &interfaceProtocol) != kIOReturnSuccess) {
+            DBG("ERR: Unable to get interface class, subclass and protocol\n");
+            goto err_get_interface_class;
+    }
+
+    //* check to make sure interface class, subclass and protocol match ADB
+    //* avoid opening mass storage endpoints
+    if (!is_adb_interface(vendor, product, interfaceClass,
+                interfaceSubClass, interfaceProtocol))
+        goto err_bad_adb_interface;
+
+    handle = calloc(1, sizeof(usb_handle));
+
+    //* Iterate over the endpoints for this interface and find the first
+    //* bulk in/out pipes available.  These will be our read/write pipes.
+    for (endpoint = 0; endpoint <= interfaceNumEndpoints; endpoint++) {
+        UInt8   transferType;
+        UInt16  maxPacketSize;
+        UInt8   interval;
+        UInt8   number;
+        UInt8   direction;
+
+        kr = (*interface)->GetPipeProperties(interface, endpoint, &direction,
+                &number, &transferType, &maxPacketSize, &interval);
+
+        if (kIOReturnSuccess == kr) {
+            if (kUSBBulk != transferType)
+                continue;
+
+            if (kUSBIn == direction)
+                handle->bulkIn = endpoint;
+
+            if (kUSBOut == direction)
+                handle->bulkOut = endpoint;
+
+            handle->zero_mask = maxPacketSize - 1;
+        } else {
+            DBG("ERR: FindDeviceInterface - could not get pipe properties\n");
+            goto err_get_pipe_props;
+        }
+    }
+
+    handle->interface = interface;
     return handle;
+
+err_get_pipe_props:
+    free(handle);
+err_bad_adb_interface:
+err_get_interface_class:
+err_get_num_ep:
+    (*interface)->USBInterfaceClose(interface);
+    return NULL;
 }
 
 
 void* RunLoopThread(void* unused)
 {
-    int i;
+    unsigned i;
 
     InitUSB();
 
@@ -400,7 +374,7 @@
     CFRunLoopRun();
     currentRunLoop = 0;
 
-    for (i = 0; i < kSupportedDeviceCount; i++) {
+    for (i = 0; i < NUM_VENDORS; i++) {
         IOObjectRelease(notificationIterators[i]);
     }
     IONotificationPortDestroy(notificationPort);
@@ -527,6 +501,9 @@
 void usb_kick(usb_handle *handle)
 {
     /* release the interface */
+    if (!handle)
+        return;
+
     if (handle->interface)
     {
         (*handle->interface)->USBInterfaceClose(handle->interface);
diff --git a/include/sysutils/FrameworkClient.h b/include/sysutils/FrameworkClient.h
new file mode 100644
index 0000000..1eb112a
--- /dev/null
+++ b/include/sysutils/FrameworkClient.h
@@ -0,0 +1,21 @@
+#ifndef _FRAMEWORK_CLIENT_H
+#define _FRAMEWORK_CLIENT_H
+
+#include "../../../frameworks/base/include/utils/List.h"
+
+#include <pthread.h>
+
+class FrameworkClient {
+    int             mSocket;
+    pthread_mutex_t mWriteMutex;
+
+public:
+    FrameworkClient(int sock);
+    virtual ~FrameworkClient() {}
+
+    int sendMsg(char *msg);
+    int sendMsg(char *msg, char *data);
+};
+
+typedef android::List<FrameworkClient *> FrameworkClientCollection;
+#endif
diff --git a/include/sysutils/FrameworkCommand.h b/include/sysutils/FrameworkCommand.h
index 952e99a..5b50247 100644
--- a/include/sysutils/FrameworkCommand.h
+++ b/include/sysutils/FrameworkCommand.h
@@ -18,6 +18,7 @@
 
 #include "../../../frameworks/base/include/utils/List.h"
 
+class SocketClient;
 
 class FrameworkCommand { 
 private:
@@ -28,7 +29,7 @@
     FrameworkCommand(const char *cmd);
     virtual ~FrameworkCommand() { }
 
-    virtual int runCommand(char *data);
+    virtual int runCommand(SocketClient *c, char *data) = 0;
 
     const char *getCommand() { return mCommand; }
 };
diff --git a/include/sysutils/FrameworkListener.h b/include/sysutils/FrameworkListener.h
index 1454a6f..8a83c33 100644
--- a/include/sysutils/FrameworkListener.h
+++ b/include/sysutils/FrameworkListener.h
@@ -19,6 +19,8 @@
 #include "SocketListener.h"
 #include "FrameworkCommand.h"
 
+class SocketClient;
+
 class FrameworkListener : public SocketListener {
 private:
     FrameworkCommandCollection *mCommands;
@@ -29,9 +31,9 @@
 
 protected:
     void registerCmd(FrameworkCommand *cmd);
-    virtual bool onDataAvailable(int socket);
+    virtual bool onDataAvailable(SocketClient *c);
 
 private:
-    void dispatchCommand(char *cmd);
+    void dispatchCommand(SocketClient *c, char *cmd);
 };
 #endif
diff --git a/include/sysutils/FrameworkManager.h b/include/sysutils/FrameworkManager.h
deleted file mode 100644
index 8a24d33..0000000
--- a/include/sysutils/FrameworkManager.h
+++ /dev/null
@@ -1,40 +0,0 @@
-/*
- * 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 _FRAMEWORKMANAGER_H
-#define _FRAMEWORKMANAGER_H
-
-#include <pthread.h>
-
-class FrameworkListener;
-
-class FrameworkManager {
-    int mDoorbell;        // Socket used to accept connections from framework
-    int mFwSock;          // Socket used to communicate with framework
-    const char *mSocketName;
-
-    FrameworkListener *mListener;
-    
-    pthread_mutex_t mWriteMutex;
-
-public:
-    FrameworkManager(FrameworkListener *Listener);
-    virtual ~FrameworkManager() {}
-
-    int run();
-    int sendMsg(char *msg);
-    int sendMsg(char *msg, char *data);
-};
-#endif
diff --git a/include/sysutils/NetlinkListener.h b/include/sysutils/NetlinkListener.h
index 8ac811c..6dcc005 100644
--- a/include/sysutils/NetlinkListener.h
+++ b/include/sysutils/NetlinkListener.h
@@ -27,6 +27,6 @@
     NetlinkListener(int socket);
     virtual ~NetlinkListener() {}
 protected:
-    virtual bool onDataAvailable(int socket);
+    virtual bool onDataAvailable(SocketClient *cli);
 };
 #endif
diff --git a/include/sysutils/SocketClient.h b/include/sysutils/SocketClient.h
new file mode 100644
index 0000000..39ec7ae
--- /dev/null
+++ b/include/sysutils/SocketClient.h
@@ -0,0 +1,23 @@
+#ifndef _SOCKET_CLIENT_H
+#define _SOCKET_CLIENT_H
+
+#include "../../../frameworks/base/include/utils/List.h"
+
+#include <pthread.h>
+
+class SocketClient {
+    int             mSocket;
+    pthread_mutex_t mWriteMutex;
+
+public:
+    SocketClient(int sock);
+    virtual ~SocketClient() {}
+
+    int getSocket() { return mSocket; }
+
+    int sendMsg(char *msg);
+    int sendMsg(char *msg, char *data);
+};
+
+typedef android::List<SocketClient *> SocketClientCollection;
+#endif
diff --git a/include/sysutils/SocketListener.h b/include/sysutils/SocketListener.h
index f079dba..be97421 100644
--- a/include/sysutils/SocketListener.h
+++ b/include/sysutils/SocketListener.h
@@ -16,20 +16,35 @@
 #ifndef _SOCKETLISTENER_H
 #define _SOCKETLISTENER_H
 
+#include <pthread.h>
+
+#include <sysutils/SocketClient.h>
+
 class SocketListener {
-    int mSock;
-    int mCsock;
-    int mAcceptClients;
-    const char *mSocketName;
+    int                     mSock;
+    const char              *mSocketName;
+    SocketClientCollection  *mClients;
+    pthread_mutex_t         mClientsLock;
+    bool                    mListen;
+    int                     mCtrlPipe[2];
+    pthread_t               mThread;
 
 public:
-    SocketListener(const char *socketName, bool acceptClients);
-    SocketListener(int socketFd, bool acceptClients);
+    SocketListener(const char *socketNames, bool listen);
+    SocketListener(int socketFd, bool listen);
 
     virtual ~SocketListener() {}
-    virtual int run();
+    int startListener();
+    int stopListener();
+
+    void sendBroadcast(char *msg);
+    void sendBroadcast(char *msg, char *data);
 
 protected:
-    virtual bool onDataAvailable(int socket);
+    virtual bool onDataAvailable(SocketClient *c) = 0;
+
+private:
+    static void *threadStart(void *obj);
+    void runListener();
 };
 #endif
diff --git a/libsysutils/Android.mk b/libsysutils/Android.mk
index 0b15c12..cbb1edf 100644
--- a/libsysutils/Android.mk
+++ b/libsysutils/Android.mk
@@ -3,12 +3,12 @@
 include $(CLEAR_VARS)
 
 LOCAL_SRC_FILES:=                             \
-                  src/FrameworkManager.cpp    \
                   src/SocketListener.cpp      \
                   src/FrameworkListener.cpp   \
                   src/NetlinkListener.cpp     \
                   src/NetlinkEvent.cpp        \
                   src/FrameworkCommand.cpp    \
+                  src/SocketClient.cpp        \
 
 LOCAL_MODULE:= libsysutils
 
diff --git a/libsysutils/src/FrameworkClient.cpp b/libsysutils/src/FrameworkClient.cpp
new file mode 100644
index 0000000..237bb60
--- /dev/null
+++ b/libsysutils/src/FrameworkClient.cpp
@@ -0,0 +1,41 @@
+#include <alloca.h>
+#include <errno.h>
+#include <sys/types.h>
+#include <pthread.h>
+
+#define LOG_TAG "FrameworkClient"
+#include <cutils/log.h>
+
+#include <sysutils/FrameworkClient.h>
+
+FrameworkClient::FrameworkClient(int socket) {
+    mSocket = socket;
+    pthread_mutex_init(&mWriteMutex, NULL);
+}
+
+int FrameworkClient::sendMsg(char *msg) {
+    LOGD("FrameworkClient::sendMsg(%s)", msg);
+    if (mSocket < 0) {
+        errno = EHOSTUNREACH;
+        return -1;
+    }
+
+    pthread_mutex_lock(&mWriteMutex);
+    if (write(mSocket, msg, strlen(msg) +1) < 0) {
+        LOGW("Unable to send msg '%s' (%s)", msg, strerror(errno));
+    }
+    pthread_mutex_unlock(&mWriteMutex);
+    return 0;
+}
+
+int FrameworkClient::sendMsg(char *msg, char *data) {
+    char *buffer = (char *) alloca(strlen(msg) + strlen(data) + 1);
+    if (!buffer) {
+        errno = -ENOMEM;
+        return -1;
+    }
+    strcpy(buffer, msg);
+    strcat(buffer, data);
+    return sendMsg(buffer);
+}
+
diff --git a/libsysutils/src/FrameworkCommand.cpp b/libsysutils/src/FrameworkCommand.cpp
index 0444de5..94e7426 100644
--- a/libsysutils/src/FrameworkCommand.cpp
+++ b/libsysutils/src/FrameworkCommand.cpp
@@ -25,7 +25,7 @@
     mCommand = cmd;
 }
 
-int FrameworkCommand::runCommand(char *data) {
+int FrameworkCommand::runCommand(SocketClient *c, char *data) {
     LOGW("Command %s has no run handler!", getCommand());
     errno = ENOSYS;
     return -1;
diff --git a/libsysutils/src/FrameworkListener.cpp b/libsysutils/src/FrameworkListener.cpp
index b920215..9210ca5 100644
--- a/libsysutils/src/FrameworkListener.cpp
+++ b/libsysutils/src/FrameworkListener.cpp
@@ -22,17 +22,18 @@
 
 #include <sysutils/FrameworkListener.h>
 #include <sysutils/FrameworkCommand.h>
+#include <sysutils/SocketClient.h>
 
 FrameworkListener::FrameworkListener(const char *socketName) :
                             SocketListener(socketName, true) {
     mCommands = new FrameworkCommandCollection();
 }
 
-bool FrameworkListener::onDataAvailable(int socket) {
+bool FrameworkListener::onDataAvailable(SocketClient *c) {
     char buffer[101];
     int len;
 
-    if ((len = read(socket, buffer, sizeof(buffer) -1)) < 0) {
+    if ((len = read(c->getSocket(), buffer, sizeof(buffer) -1)) < 0) {
         LOGE("read() failed (%s)", strerror(errno));
         return errno;
     } else if (!len) {
@@ -47,7 +48,7 @@
 
     for (i = 0; i < len; i++) {
         if (buffer[i] == '\0') {
-            dispatchCommand(buffer + start);
+            dispatchCommand(c, buffer + start);
             start = i + 1;
         }
     }
@@ -58,14 +59,22 @@
     mCommands->push_back(cmd);
 }
 
-void FrameworkListener::dispatchCommand(char *cmd) {
+void FrameworkListener::dispatchCommand(SocketClient *cli, char *cmd) {
+
+    char *cm, *last;
+
+    if (!(cm = strtok_r(cmd, ":", &last))) {
+        cli->sendMsg("BAD_MSG");
+        return;
+    }
+
     FrameworkCommandCollection::iterator i;
 
     for (i = mCommands->begin(); i != mCommands->end(); ++i) {
         FrameworkCommand *c = *i;
 
-        if (!strncmp(cmd, c->getCommand(), strlen(c->getCommand()))) {
-            if (c->runCommand(cmd)) {
+        if (!strcmp(cm, c->getCommand())) {
+            if (c->runCommand(cli, cmd)) {
                 LOGW("Handler '%s' error (%s)", c->getCommand(), strerror(errno));
             }
             return;
@@ -73,5 +82,6 @@
     }
 
     LOGE("No cmd handlers defined for '%s'", cmd);
+    cli->sendMsg("UNKNOWN_CMD");
+    return;
 }
-
diff --git a/libsysutils/src/FrameworkManager.cpp b/libsysutils/src/FrameworkManager.cpp
deleted file mode 100644
index 5dceb9f..0000000
--- a/libsysutils/src/FrameworkManager.cpp
+++ /dev/null
@@ -1,83 +0,0 @@
-/*
- * 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>
-#include <errno.h>
-#include <stdlib.h>
-#include <sys/socket.h>
-#include <sys/select.h>
-#include <sys/time.h>
-#include <sys/types.h>
-#include <sys/un.h>
-
-#include <cutils/config_utils.h>
-#include <cutils/cpu_info.h>
-#include <cutils/properties.h>
-#include <cutils/sockets.h>
-
-#define LOG_TAG "FrameworkManager"
-#include <cutils/log.h>
-
-#include <sysutils/FrameworkManager.h>
-#include <sysutils/FrameworkListener.h>
-
-FrameworkManager::FrameworkManager(FrameworkListener *Listener) {
-    mDoorbell = -1;
-    mFwSock = -1;
-    mListener = Listener;
-
-    pthread_mutex_init(&mWriteMutex, NULL);
-}
-
-int FrameworkManager::run() {
-
-    if (mListener->run()) {
-        LOGE("Error running listener (%s)", strerror(errno));
-        return -1;
-    }
-
-    return 0;
-}
-
-/* ========
- * Privates
- * ========
- */
-
-int FrameworkManager::sendMsg(char *msg) {
-    LOGD("FrameworkManager::sendMsg(%s)", msg);
-    if (mFwSock < 0) {
-        errno = EHOSTUNREACH;
-        return -1;
-    }
-
-    pthread_mutex_lock(&mWriteMutex);
-    if (write(mFwSock, msg, strlen(msg) +1) < 0) {
-        LOGW("Unable to send msg '%s' (%s)", msg, strerror(errno));
-    }
-    pthread_mutex_unlock(&mWriteMutex);
-    return 0;
-}
-
-int FrameworkManager::sendMsg(char *msg, char *data) {
-    char *buffer = (char *) alloca(strlen(msg) + strlen(data) + 1);
-    if (!buffer) {
-        errno = -ENOMEM;
-        return -1;
-    }
-    strcpy(buffer, msg);
-    strcat(buffer, data);
-    return sendMsg(buffer);
-}
diff --git a/libsysutils/src/NetlinkListener.cpp b/libsysutils/src/NetlinkListener.cpp
index 96a616d..3ec9d9d 100644
--- a/libsysutils/src/NetlinkListener.cpp
+++ b/libsysutils/src/NetlinkListener.cpp
@@ -29,8 +29,9 @@
                             SocketListener(socket, false) {
 }
 
-bool NetlinkListener::onDataAvailable(int socket)
+bool NetlinkListener::onDataAvailable(SocketClient *cli)
 {
+    int socket = cli->getSocket();
     LOGD("NetlinkListener::onDataAvailable()");
 
     int count;
diff --git a/libsysutils/src/SocketClient.cpp b/libsysutils/src/SocketClient.cpp
new file mode 100644
index 0000000..6db62b3
--- /dev/null
+++ b/libsysutils/src/SocketClient.cpp
@@ -0,0 +1,41 @@
+#include <alloca.h>
+#include <errno.h>
+#include <sys/types.h>
+#include <pthread.h>
+
+#define LOG_TAG "SocketClient"
+#include <cutils/log.h>
+
+#include <sysutils/SocketClient.h>
+
+SocketClient::SocketClient(int socket) {
+    mSocket = socket;
+    pthread_mutex_init(&mWriteMutex, NULL);
+}
+
+int SocketClient::sendMsg(char *msg) {
+    LOGD("SocketClient::sendMsg(%s)", msg);
+    if (mSocket < 0) {
+        errno = EHOSTUNREACH;
+        return -1;
+    }
+
+    pthread_mutex_lock(&mWriteMutex);
+    if (write(mSocket, msg, strlen(msg) +1) < 0) {
+        LOGW("Unable to send msg '%s' (%s)", msg, strerror(errno));
+    }
+    pthread_mutex_unlock(&mWriteMutex);
+    return 0;
+}
+
+int SocketClient::sendMsg(char *msg, char *data) {
+    char *buffer = (char *) alloca(strlen(msg) + strlen(data) + 1);
+    if (!buffer) {
+        errno = -ENOMEM;
+        return -1;
+    }
+    strcpy(buffer, msg);
+    strcat(buffer, data);
+    return sendMsg(buffer);
+}
+
diff --git a/libsysutils/src/SocketListener.cpp b/libsysutils/src/SocketListener.cpp
index f92e30d..cb69bfd 100644
--- a/libsysutils/src/SocketListener.cpp
+++ b/libsysutils/src/SocketListener.cpp
@@ -24,26 +24,28 @@
 
 #define LOG_TAG "SocketListener"
 #include <cutils/log.h>
-
 #include <cutils/sockets.h>
 
 #include <sysutils/SocketListener.h>
+#include <sysutils/SocketClient.h>
 
-SocketListener::SocketListener(const char *socketName, bool acceptClients) {
-    mAcceptClients = acceptClients;
-    mCsock = -1;
+SocketListener::SocketListener(const char *socketName, bool listen) {
+    mListen = listen;
     mSocketName = socketName;
     mSock = -1;
+    pthread_mutex_init(&mClientsLock, NULL);
+    mClients = new SocketClientCollection();
 }
 
-SocketListener::SocketListener(int socketFd, bool acceptClients) {
-    mAcceptClients = acceptClients;
-    mCsock = -1;
+SocketListener::SocketListener(int socketFd, bool listen) {
+    mListen = listen;
     mSocketName = NULL;
     mSock = socketFd;
+    pthread_mutex_init(&mClientsLock, NULL);
+    mClients = new SocketClientCollection();
 }
 
-int SocketListener::run() {
+int SocketListener::startListener() {
 
     if (!mSocketName && mSock == -1) {
         errno = EINVAL;
@@ -56,72 +58,155 @@
         }
     }
 
-    if (mAcceptClients) {
-        if (listen(mSock, 4) < 0) {
-            LOGE("Unable to listen on socket (%s)", strerror(errno));
-            return -1;
-        }
+    if (mListen && listen(mSock, 4) < 0) {
+        LOGE("Unable to listen on socket (%s)", strerror(errno));
+        return -1;
+    } else if (!mListen) {
+        mClients->push_back(new SocketClient(mSock));
+        LOGD("Created phantom client");
     }
 
+    if (pipe(mCtrlPipe))
+        return -1;
+
+    if (pthread_create(&mThread, NULL, SocketListener::threadStart, this))
+        return -1;
+
+    return 0;
+}
+
+int SocketListener::stopListener() {
+    char c = 0;
+
+    if (write(mCtrlPipe[1], &c, 1) != 1) {
+        LOGE("Error writing to control pipe (%s)", strerror(errno));
+        return -1;
+    }
+
+    LOGD("Signaled listener thread - waiting for it to die");
+    void *ret;
+    if (pthread_join(mThread, &ret)) {
+        LOGE("Error joining to listener thread (%s)", strerror(errno));
+        return -1;
+    }
+    LOGD("Listener stopped");
+    return 0;
+}
+
+void *SocketListener::threadStart(void *obj) {
+    SocketListener *me = reinterpret_cast<SocketListener *>(obj);
+
+    me->runListener();
+    LOGD("Listener thread shutting down");
+    pthread_exit(NULL);
+    return NULL;
+}
+
+void SocketListener::runListener() {
+
     while(1) {
+        SocketClientCollection::iterator it;
         fd_set read_fds;
         struct timeval to;
-        int max = 0;
         int rc = 0;
 
         to.tv_sec = 60 * 60;
         to.tv_usec = 0;
 
+        int max = 0;
+
         FD_ZERO(&read_fds);
 
-        if ((mAcceptClients == false) ||
-            (mAcceptClients == true && mCsock == -1)) {
-            FD_SET(mSock, &read_fds);
+        if (mListen) {
             max = mSock;
-        } else if (mCsock != -1) {
-            FD_SET(mCsock, &read_fds);
-            max = mCsock;
+            FD_SET(mSock, &read_fds);
         }
 
+        FD_SET(mCtrlPipe[0], &read_fds);
+        if (mCtrlPipe[0] > max)
+            max = mCtrlPipe[0];
+
+        pthread_mutex_lock(&mClientsLock);
+        for (it = mClients->begin(); it != mClients->end(); ++it) {
+            FD_SET((*it)->getSocket(), &read_fds);
+            if ((*it)->getSocket() > max)
+                max = (*it)->getSocket();
+        }
+        pthread_mutex_unlock(&mClientsLock);
+        
         if ((rc = select(max + 1, &read_fds, NULL, NULL, &to)) < 0) {
             LOGE("select failed (%s)", strerror(errno));
-            return -errno;
-        } else if (!rc)
+            sleep(1);
             continue;
-        else if (FD_ISSET(mSock, &read_fds)) {
-            /*
-             * If we're accepting client connections then 
-             * accept and gobble the event. Otherwise
-             * pass it on to the handlers.
-             */
-            if (mAcceptClients) {
-                struct sockaddr addr;
-                socklen_t alen = sizeof(addr);
+        } else if (!rc) {
+            LOGD("select timeout");
+            continue;
+        }
 
-                if ((mCsock = accept(mSock, &addr, &alen)) < 0) {
-                    LOGE("accept failed (%s)", strerror(errno));
-                    return -errno;
+        if (FD_ISSET(mCtrlPipe[0], &read_fds)) {
+            LOGD("Control message received");
+            break;
+        }
+        if (mListen && FD_ISSET(mSock, &read_fds)) {
+            struct sockaddr addr;
+            socklen_t alen = sizeof(addr);
+            int c;
+
+            if ((c = accept(mSock, &addr, &alen)) < 0) {
+                LOGE("accept failed (%s)", strerror(errno));
+                sleep(1);
+                continue;
+            }
+            LOGD("SocketListener client connection accepted");
+            pthread_mutex_lock(&mClientsLock);
+            mClients->push_back(new SocketClient(c));
+            pthread_mutex_unlock(&mClientsLock);
+        }
+
+        do {
+            pthread_mutex_lock(&mClientsLock);
+            for (it = mClients->begin(); it != mClients->end(); ++it) {
+                int fd = (*it)->getSocket();
+                if (FD_ISSET(fd, &read_fds)) {
+                    pthread_mutex_unlock(&mClientsLock);
+                    if (!onDataAvailable(*it)) {
+                        LOGD("SocketListener closing client socket");
+                        close(fd);
+                        pthread_mutex_lock(&mClientsLock);
+                        delete *it;
+                        it = mClients->erase(it);
+                        pthread_mutex_unlock(&mClientsLock);
+                    }
+                    FD_CLR(fd, &read_fds);
+                    continue;
                 }
-                LOGD("SocketListener client connection accepted");
-            } else if (!onDataAvailable(mSock)) {
-                LOGW("SocketListener closing listening socket (Will shut down)");
-                close(mSock);
-                return -ESHUTDOWN;
             }
-        } else if ((FD_ISSET(mCsock, &read_fds)) &&
-                   !onDataAvailable(mCsock)) {
-                /*
-                 * Once mCsock == -1, we'll start
-                 * accepting connections on mSock again.
-                 */
-                LOGD("SocketListener closing client socket");
-                close(mCsock);
-                mCsock = -1;
-            }
+            pthread_mutex_unlock(&mClientsLock);
+        } while (0);
     }
-    return 0;
 }
 
-bool SocketListener::onDataAvailable(int socket) {
-    return false;
+void SocketListener::sendBroadcast(char *msg) {
+    pthread_mutex_lock(&mClientsLock);
+    SocketClientCollection::iterator i;
+
+    for (i = mClients->begin(); i != mClients->end(); ++i) {
+        if ((*i)->sendMsg(msg)) {
+            LOGW("Error sending broadcast (%s)", strerror(errno));
+        }
+    }
+    pthread_mutex_unlock(&mClientsLock);
 }
+
+void SocketListener::sendBroadcast(char *msg, char *data) {
+    pthread_mutex_lock(&mClientsLock);
+    SocketClientCollection::iterator i;
+
+    for (i = mClients->begin(); i != mClients->end(); ++i) {
+        if ((*i)->sendMsg(msg, data)) {
+            LOGW("Error sending broadcast (%s)", strerror(errno));
+        }
+    }
+    pthread_mutex_unlock(&mClientsLock);
+}
+
diff --git a/nexus/Android.mk b/nexus/Android.mk
index e76cb27..7cf4a1f 100644
--- a/nexus/Android.mk
+++ b/nexus/Android.mk
@@ -19,6 +19,7 @@
                   SupplicantListener.cpp   \
                   VpnController.cpp        \
                   ScanResult.cpp           \
+                  WifiScanner.cpp          \
 
 LOCAL_MODULE:= nexus
 
diff --git a/nexus/CommandListener.cpp b/nexus/CommandListener.cpp
index cdb1db5..02ede15 100644
--- a/nexus/CommandListener.cpp
+++ b/nexus/CommandListener.cpp
@@ -19,60 +19,64 @@
 #define LOG_TAG "CommandListener"
 #include <cutils/log.h>
 
+#include <sysutils/SocketClient.h>
+
 #include "CommandListener.h"
 #include "Controller.h"
 #include "NetworkManager.h"
 #include "WifiController.h"
 
-CommandListener::CommandListener(NetworkManager *netman) :
+CommandListener::CommandListener() :
                  FrameworkListener("nexus") {
-    mNetman = netman;
+    registerCmd(new WifiEnableCmd());
+    registerCmd(new WifiDisableCmd());
+    registerCmd(new WifiScanCmd());
+    registerCmd(new WifiScanResultsCmd());
 
-    registerCmd(new WifiEnableCmd(netman));
-    registerCmd(new WifiDisableCmd(netman));
-    registerCmd(new WifiScanCmd(netman));
-
-    registerCmd(new VpnEnableCmd(netman));
-    registerCmd(new VpnDisableCmd(netman));
+    registerCmd(new VpnEnableCmd());
+    registerCmd(new VpnDisableCmd());
 }
  
 /* -------------
  * Wifi Commands
  * ------------ */
 
-CommandListener::WifiEnableCmd::WifiEnableCmd(NetworkManager *netman) :
-                 NexusCommand("wifi_enable", netman) {
+CommandListener::WifiEnableCmd::WifiEnableCmd() :
+                 NexusCommand("wifi_enable") {
 } 
                
-int CommandListener::WifiEnableCmd::runCommand(char *data) {
-    Controller *c = mNetman->findController("WIFI");
+int CommandListener::WifiEnableCmd::runCommand(SocketClient *cli, char *data) {
+    Controller *c = NetworkManager::Instance()->findController("WIFI");
     char buffer[32];
 
     sprintf(buffer, "WIFI_ENABLE:%d", (c->enable() ? errno : 0));
-    mNetman->getFrameworkManager()->sendMsg(buffer);
+
+    cli->sendMsg(buffer);
     return 0;
 }
 
-CommandListener::WifiDisableCmd::WifiDisableCmd(NetworkManager *netman) :
-                 NexusCommand("wifi_disable", netman) {
+CommandListener::WifiDisableCmd::WifiDisableCmd() :
+                 NexusCommand("wifi_disable") {
 } 
                
-int CommandListener::WifiDisableCmd::runCommand(char *data) {
-    Controller *c = mNetman->findController("WIFI");
+int CommandListener::WifiDisableCmd::runCommand(SocketClient *cli, char *data) {
+    Controller *c = NetworkManager::Instance()->findController("WIFI");
     char buffer[32];
 
     sprintf(buffer, "WIFI_DISABLE:%d", (c->disable() ? errno : 0));
-    mNetman->getFrameworkManager()->sendMsg(buffer);
+    cli->sendMsg(buffer);
     return 0;
 }
 
-CommandListener::WifiScanCmd::WifiScanCmd(NetworkManager *netman) :
-                 NexusCommand("wifi_scan", netman) {
+CommandListener::WifiScanCmd::WifiScanCmd() :
+                 NexusCommand("wifi_scan") {
 } 
 
-int CommandListener::WifiScanCmd::runCommand(char *data) {
+int CommandListener::WifiScanCmd::runCommand(SocketClient *cli, char *data) {
     LOGD("WifiScanCmd(%s)", data);
-    WifiController *wc = (WifiController *) mNetman->findController("WIFI");
+
+    WifiController *wc = (WifiController *) NetworkManager::Instance()->findController("WIFI");
+
     char buffer[32];
     int mode = 0;
     char *bword, *last;
@@ -90,35 +94,62 @@
     mode = atoi(bword);
 
     sprintf(buffer, "WIFI_SCAN:%d", (wc->setScanMode(mode) ? errno : 0));
-    mNetman->getFrameworkManager()->sendMsg(buffer);
+    cli->sendMsg(buffer);
+    return 0;
+}
+
+CommandListener::WifiScanResultsCmd::WifiScanResultsCmd() :
+                 NexusCommand("wifi_scan_results") {
+} 
+
+int CommandListener::WifiScanResultsCmd::runCommand(SocketClient *cli, char *data) {
+    NetworkManager *nm = NetworkManager::Instance();
+
+    WifiController *wc = (WifiController *) nm->findController("WIFI");
+
+    ScanResultCollection *src = wc->createScanResults();
+    ScanResultCollection::iterator it;
+    char buffer[256];
+    
+    for(it = src->begin(); it != src->end(); ++it) {
+        sprintf(buffer, "WIFI_SCAN_RESULT:%s:%u:%d:%s:%s",
+                (*it)->getBssid(), (*it)->getFreq(), (*it)->getLevel(),
+                (*it)->getFlags(), (*it)->getSsid());
+        cli->sendMsg(buffer);
+        delete (*it);
+        it = src->erase(it);
+    }
+
+    delete src;
+    cli->sendMsg("WIFI_SCAN_RESULT:0");
     return 0;
 }
 
 /* ------------
  * Vpn Commands
  * ------------ */
-CommandListener::VpnEnableCmd::VpnEnableCmd(NetworkManager *netman) :
-                 NexusCommand("vpn_enable", netman) {
+CommandListener::VpnEnableCmd::VpnEnableCmd() :
+                 NexusCommand("vpn_enable") {
 } 
                
-int CommandListener::VpnEnableCmd::runCommand(char *data) {
-    Controller *c = mNetman->findController("VPN");
+int CommandListener::VpnEnableCmd::runCommand(SocketClient *cli, char *data) {
+    Controller *c = NetworkManager::Instance()->findController("VPN");
     char buffer[32];
 
     sprintf(buffer, "VPN_ENABLE:%d", (c->enable() ? errno : 0));
-    mNetman->getFrameworkManager()->sendMsg(buffer);
+    cli->sendMsg(buffer);
     return 0;
 }
 
-CommandListener::VpnDisableCmd::VpnDisableCmd(NetworkManager *netman) :
-                 NexusCommand("vpn_disable", netman) {
+CommandListener::VpnDisableCmd::VpnDisableCmd() :
+                 NexusCommand("vpn_disable") {
 } 
                
-int CommandListener::VpnDisableCmd::runCommand(char *data) {
-    Controller *c = mNetman->findController("VPN");
+int CommandListener::VpnDisableCmd::runCommand(SocketClient *cli, char *data) {
+    Controller *c = NetworkManager::Instance()->findController("VPN");
     char buffer[32];
 
     sprintf(buffer, "VPN_DISABLE:%d", (c->disable() ? errno : 0));
-    mNetman->getFrameworkManager()->sendMsg(buffer);
+    cli->sendMsg(buffer);
     return 0;
 }
diff --git a/nexus/CommandListener.h b/nexus/CommandListener.h
index 261c093..064eab8 100644
--- a/nexus/CommandListener.h
+++ b/nexus/CommandListener.h
@@ -19,50 +19,52 @@
 #include <sysutils/FrameworkListener.h>
 #include "NexusCommand.h"
 
-class NetworkManager;
-
 class CommandListener : public FrameworkListener {
-protected:
-    NetworkManager *mNetman;
-
 public:
-    CommandListener(NetworkManager *netman);
+    CommandListener();
     virtual ~CommandListener() {}
 
 private:
     class WifiEnableCmd : public NexusCommand {
     public:
-        WifiEnableCmd(NetworkManager *);
+        WifiEnableCmd();
         virtual ~WifiEnableCmd() {}
-        int runCommand(char *data);
+        int runCommand(SocketClient *c, char *data);
     };
 
     class WifiDisableCmd : public NexusCommand {
     public:
-        WifiDisableCmd(NetworkManager *);
+        WifiDisableCmd();
         virtual ~WifiDisableCmd() {}
-        int runCommand(char *data);
+        int runCommand(SocketClient *c, char *data);
     };
 
     class WifiScanCmd : public NexusCommand {
     public:
-        WifiScanCmd(NetworkManager *);
+        WifiScanCmd();
         virtual ~WifiScanCmd() {}
-        int runCommand(char *data);
+        int runCommand(SocketClient *c, char *data);
+    };
+
+    class WifiScanResultsCmd : public NexusCommand {
+    public:
+        WifiScanResultsCmd();
+        virtual ~WifiScanResultsCmd() {}
+        int runCommand(SocketClient *c, char *data);
     };
 
     class VpnEnableCmd : public NexusCommand {
     public:
-        VpnEnableCmd(NetworkManager *);
+        VpnEnableCmd();
         virtual ~VpnEnableCmd() {}
-        int runCommand(char *data);
+        int runCommand(SocketClient *c, char *data);
     };
 
     class VpnDisableCmd : public NexusCommand {
     public:
-        VpnDisableCmd(NetworkManager *);
+        VpnDisableCmd();
         virtual ~VpnDisableCmd() {}
-        int runCommand(char *data);
+        int runCommand(SocketClient *c, char *data);
     };
 
 };
diff --git a/nexus/NetworkManager.cpp b/nexus/NetworkManager.cpp
index 9c64945..3b823d1 100644
--- a/nexus/NetworkManager.cpp
+++ b/nexus/NetworkManager.cpp
@@ -21,36 +21,30 @@
 #include <cutils/log.h>
 
 #include "NetworkManager.h"
-#include "CommandListener.h"
-#include "LoopController.h"
-#include "VpnController.h"
 
-#include "TiwlanWifiController.h"
+NetworkManager *NetworkManager::sInstance = NULL;
+
+NetworkManager *NetworkManager::Instance() {
+    if (!sInstance)
+        sInstance = new NetworkManager();
+    return sInstance;
+}
 
 NetworkManager::NetworkManager() {
-    mListener = new CommandListener(this);
-    mFm = new FrameworkManager(mListener);
+    mBroadcaster = NULL;
     mControllers = new ControllerCollection();
 }
 
 int NetworkManager::run() {
-    LOGD("NetworkManager::start()");
-
-    // XXX: Factory needed
-    addController(new LoopController());
-    addController(new TiwlanWifiController("/system/lib/modules/wlan.ko", "wlan", ""));
-    addController(new VpnController());
-    //addController(new GenericController("rmnet0"));
-
     if (startControllers()) {
         LOGW("Unable to start all controllers (%s)", strerror(errno));
     }
-    mFm->run();
     return 0;
 }
 
-void NetworkManager::addController(Controller *c) {
+int NetworkManager::attachController(Controller *c) {
     mControllers->push_back(c);
+    return 0;
 }
 
 int NetworkManager::startControllers() {
diff --git a/nexus/NetworkManager.h b/nexus/NetworkManager.h
index 8f362a9..0ac4a4d 100644
--- a/nexus/NetworkManager.h
+++ b/nexus/NetworkManager.h
@@ -16,31 +16,36 @@
 #ifndef _NETWORKMANAGER_H
 #define _NETWORKMANAGER_H
 
-#include "Controller.h"
+#include <sysutils/SocketListener.h>
 
-#include <sysutils/FrameworkManager.h>
+#include "Controller.h"
 
 class NetworkManager {
 private:
-    FrameworkListener    *mListener;
-    FrameworkManager     *mFm;
+    static NetworkManager *sInstance;
+
+private:
     ControllerCollection *mControllers;
+    SocketListener       *mBroadcaster;
 
 public:
-    NetworkManager();
     virtual ~NetworkManager() {}
 
     int run();
 
+    int attachController(Controller *controller);
+
+    Controller *findController(const char *name);
+
+    void setBroadcaster(SocketListener *sl) { mBroadcaster = sl; }
+    SocketListener *getBroadcaster() { return mBroadcaster; }
+
+    static NetworkManager *Instance();
+
 private:
-    void addController(Controller *c);
     int startControllers();
     int stopControllers();
-
-public:
-    Controller *findController(const char *name);
-    ControllerCollection *getControllers() { return mControllers; }
-    FrameworkManager *getFrameworkManager() { return mFm; }
+    NetworkManager();
 
 public:
 // XXX: Extract these into an interface
diff --git a/nexus/NexusCommand.cpp b/nexus/NexusCommand.cpp
index 090113c..92bb1c3 100644
--- a/nexus/NexusCommand.cpp
+++ b/nexus/NexusCommand.cpp
@@ -15,7 +15,6 @@
  */
 #include "NexusCommand.h"
 
-NexusCommand::NexusCommand(const char *cmd, NetworkManager *netman) :
+NexusCommand::NexusCommand(const char *cmd) :
               FrameworkCommand(cmd)  {
-    mNetman = netman;
 }
diff --git a/nexus/NexusCommand.h b/nexus/NexusCommand.h
index 204541c..1482998 100644
--- a/nexus/NexusCommand.h
+++ b/nexus/NexusCommand.h
@@ -18,14 +18,9 @@
 
 #include <sysutils/FrameworkCommand.h>
 
-class NetworkManager;
-
 class NexusCommand : public FrameworkCommand {
-protected:
-    NetworkManager *mNetman;
-
 public:
-    NexusCommand(const char *cmd, NetworkManager *netman);
+    NexusCommand(const char *cmd);
     virtual ~NexusCommand() {}
 };
 
diff --git a/nexus/ScanResult.h b/nexus/ScanResult.h
index 79b2b65..f70a1a9 100644
--- a/nexus/ScanResult.h
+++ b/nexus/ScanResult.h
@@ -38,6 +38,7 @@
 
     const char *getBssid() { return mBssid; }
     uint32_t getFreq() { return mFreq; }
+    int getLevel() { return mLevel; }
     const char *getFlags() { return mFlags; }
     const char *getSsid() { return mSsid; }
 };
diff --git a/nexus/Supplicant.cpp b/nexus/Supplicant.cpp
index 215a8b3..d809e6e 100644
--- a/nexus/Supplicant.cpp
+++ b/nexus/Supplicant.cpp
@@ -13,6 +13,8 @@
  * See the License for the specific language governing permissions and
  * limitations under the License.
  */
+
+#include <stdlib.h>
 #include <errno.h>
 
 #define LOG_TAG "Supplicant"
@@ -31,6 +33,7 @@
 #include "SupplicantState.h"
 #include "SupplicantEvent.h"
 #include "ScanResult.h"
+#include "NetworkManager.h"
 
 #include "libwpa_client/wpa_ctrl.h"
 
@@ -52,7 +55,6 @@
 }
 
 int Supplicant::start() {
-    LOGD("start():");
     // XXX: Validate supplicant config file
     
     char status[PROPERTY_VALUE_MAX] = {'\0'};
@@ -63,47 +65,47 @@
 #endif
 
     if (property_get(SUPP_PROP_NAME, status, NULL) &&
-        strcmp(status, "running") == 0) {
-        return 0;
+        !strcmp(status, "running")) {
+        LOGD("Supplicant already started");
+    } else {
+#ifdef HAVE_LIBC_SYSTEM_PROPERTIES
+        pi = __system_property_find(SUPP_PROP_NAME);
+        if (pi != NULL)
+            serial = pi->serial;
+#endif
+
+        LOGD("Starting Supplicant");
+        property_set("ctl.start", SUPPLICANT_NAME);
+        sched_yield();
+        while (count--) {
+#ifdef HAVE_LIBC_SYSTEM_PROPERTIES
+            if (!pi)
+                pi = __system_property_find(SUPP_PROP_NAME);
+            if (pi) {
+                __system_property_read(pi, NULL, status);
+                if (strcmp(status, "running") == 0)
+                    break;
+                else if (pi->serial != serial &&
+                        strcmp(status, "stopped") == 0) {
+                    errno = EIO;
+                    return -1;
+                }
+            }
+#else
+            if (property_get(SUPP_PROP_NAME, status, NULL)) {
+                if (strcmp(status, "running") == 0)
+                    break;
+            }
+#endif
+            usleep(100000);
+        }
+        if (!count) {
+            errno = ETIMEDOUT;
+            return -1;
+        }
     }
 
     wpa_ctrl_cleanup();
-#ifdef HAVE_LIBC_SYSTEM_PROPERTIES
-    pi = __system_property_find(SUPP_PROP_NAME);
-    if (pi != NULL)
-        serial = pi->serial;
-#endif
-
-    property_set("ctl.start", SUPPLICANT_NAME);
-    sched_yield();
-    while (count--) {
-#ifdef HAVE_LIBC_SYSTEM_PROPERTIES
-        if (!pi)
-            pi = __system_property_find(SUPP_PROP_NAME);
-        if (pi) {
-            __system_property_read(pi, NULL, status);
-            if (strcmp(status, "running") == 0)
-                return 0;
-            else if (pi->serial != serial &&
-                    strcmp(status, "stopped") == 0) {
-                errno = EIO;
-                return -1;
-            }
-        }
-#else
-        if (property_get(SUPP_PROP_NAME, status, NULL)) {
-            if (strcmp(status, "running") == 0)
-                break;
-        }
-#endif
-        usleep(100000);
-    }
-
-    if (!count) {
-        errno = ETIMEDOUT;
-        return -1;
-    }
-  
     if (connectToSupplicant()) {
         LOGE("Error connecting to supplicant (%s)\n", strerror(errno));
         return -1;
@@ -112,7 +114,6 @@
 }
 
 int Supplicant::stop() {
-    LOGD("stop()");
 
     char supp_status[PROPERTY_VALUE_MAX] = {'\0'};
     int count = 50; 
@@ -124,9 +125,11 @@
 
     if (property_get(SUPP_PROP_NAME, supp_status, NULL)
         && strcmp(supp_status, "stopped") == 0) {
+        LOGD("Supplicant already stopped");
         return 0;
     }
 
+    LOGD("Stopping Supplicant");
     property_set("ctl.stop", SUPPLICANT_NAME);
     sched_yield();
 
@@ -153,24 +156,29 @@
         return -1;
     }
 
-    LOGD("Stopped OK");
+    LOGD("Supplicant shutdown");
 
     return 0;
 }
 
 bool Supplicant::isStarted() {
     char supp_status[PROPERTY_VALUE_MAX] = {'\0'};
-    if (!property_get(SUPP_PROP_NAME, supp_status, NULL) ||
-        !strcmp(supp_status, "running")) {
-        return false;
-    }
-    return true;
+
+    int rc = property_get(SUPP_PROP_NAME, supp_status, NULL);
+
+    LOGD("rc = %d, property = '%s'", rc, supp_status);
+
+    if (!strcmp(supp_status, "running"))
+        return true;
+
+    return false;
 }
 
 int Supplicant::connectToSupplicant() {
     char ifname[256];
     char supp_status[PROPERTY_VALUE_MAX] = {'\0'};
 
+    LOGD("connectToSupplicant()");
     if (!property_get(SUPP_PROP_NAME, supp_status, NULL)
             || strcmp(supp_status, "running") != 0) {
         LOGE("Supplicant not running, cannot connect");
@@ -213,13 +221,14 @@
         return -1;
     }
 
-    LOGD("sendCommand(): -> '%s'", cmd);
+//    LOGD("sendCommand(): -> '%s'", cmd);
 
     int rc;
     if ((rc = wpa_ctrl_request(mCtrl, cmd, strlen(cmd), reply, reply_len, NULL)) == -2)  {
         errno = ETIMEDOUT;
         return -1;
     } else if (rc < 0 || !strncmp(reply, "FAIL", 4)) {
+        LOGW("sendCommand(): <- '%s'", reply);
         errno = EIO;
         return -1;
     }
@@ -228,7 +237,7 @@
         !strncmp(cmd, "SCAN_RESULTS", 12)) 
         reply[*reply_len] = '\0';
 
-    LOGD("sendCommand(): <- '%s'", reply);
+//    LOGD("sendCommand(): <- '%s'", reply);
     return 0;
 }
 
@@ -332,12 +341,16 @@
 
         if (!strtok_r(reply, "\n", &linep_next)) {
             free(reply);
-            return 0;;
+            pthread_mutex_unlock(&mLatestScanResultsLock);
+            return 0;
         }
 
         while((linep = strtok_r(NULL, "\n", &linep_next)))
             mLatestScanResults->push_back(new ScanResult(linep));
-
+    
+        char tmp[32];
+        sprintf(tmp, "WIFI_SCAN_RESULTS_READY:%d", mLatestScanResults->size());
+        NetworkManager::Instance()->getBroadcaster()->sendBroadcast(tmp);
         pthread_mutex_unlock(&mLatestScanResultsLock);
         free(reply);
     } else {
@@ -347,8 +360,24 @@
 }
 
 int Supplicant::onStateChangeEvent(SupplicantEvent *evt) {
-    LOGD("onStateChangeEvent(%s)", evt->getEvent());
-    // XXX: Update mState
+    char *bword, *last;
+    char *tmp = strdup(evt->getEvent());
+
+    if (!(bword = strtok_r(tmp, " ", &last))) {
+        LOGE("Malformatted state update (%s)", evt->getEvent());
+        free(tmp);
+        return 0;
+    }
+
+    if (!(bword = strtok_r(NULL, " ", &last))) {
+        LOGE("Malformatted state update (%s)", evt->getEvent());
+        free(tmp);
+        return 0;
+    }
+
+    mState = atoi(&bword[strlen("state=")]);
+    LOGD("State changed to %d", mState);
+    free(tmp);
     return 0;
 }
 
@@ -363,7 +392,7 @@
 }
 
 // XXX: Use a cursor + smartptr instead
-const ScanResultCollection *Supplicant::getLatestScanResults() {
+ScanResultCollection *Supplicant::createLatestScanResults() {
     ScanResultCollection *d = new ScanResultCollection();
     ScanResultCollection::iterator i;
 
diff --git a/nexus/Supplicant.h b/nexus/Supplicant.h
index 46a9e86..2a25ea2 100644
--- a/nexus/Supplicant.h
+++ b/nexus/Supplicant.h
@@ -46,7 +46,7 @@
 
     int getState() { return mState; }
 
-    const ScanResultCollection *getLatestScanResults();
+    ScanResultCollection *createLatestScanResults();
 
 // XXX: Extract these into an interface
 public:
diff --git a/nexus/SupplicantListener.cpp b/nexus/SupplicantListener.cpp
index 16306b5..76e9945 100644
--- a/nexus/SupplicantListener.cpp
+++ b/nexus/SupplicantListener.cpp
@@ -30,31 +30,9 @@
                     SocketListener(wpa_ctrl_get_fd(monitor), false) {
     mSupplicant = supplicant;
     mMonitor = monitor;
-    mThread = NULL;
 }
 
-int SupplicantListener::startListener() {
-    LOGD("startListener()");
-    pthread_attr_t attr;
-    pthread_attr_init(&attr);
-    pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED);
-
-    return pthread_create(&mThread, &attr, &SupplicantListener::threadStart, this);
-}
-
-int SupplicantListener::stopListener() {
-    errno = -ENOSYS;
-    return -1;
-}
-
-void *SupplicantListener::threadStart(void *obj) {
-    LOGD("threadStart(): Worker thread started");
-    reinterpret_cast<SupplicantListener *>(obj)->run();
-    LOGD("threadStart(): Worker thread exited");
-    return NULL;
-}
-
-bool SupplicantListener::onDataAvailable(int socket) {
+bool SupplicantListener::onDataAvailable(SocketClient *cli) {
     char buf[255];
     size_t buflen = sizeof(buf);
     int rc;
@@ -62,7 +40,7 @@
 
     if ((rc = wpa_ctrl_recv(mMonitor, buf, &nread))) {
         LOGE("wpa_ctrl_recv failed (%s)", strerror(errno));
-        return -errno;
+        return false;
     }
 
     buf[nread] = '\0';
@@ -108,7 +86,9 @@
 
     delete evt;
     
-    if (rc)
+    if (rc) {
+        LOGW("Handler %d (%s) error: %s", evt->getType(), evt->getEvent(), strerror(errno));
         return false;
+    }
     return true;
 }
diff --git a/nexus/SupplicantListener.h b/nexus/SupplicantListener.h
index 3d27a68..95bad9a 100644
--- a/nexus/SupplicantListener.h
+++ b/nexus/SupplicantListener.h
@@ -16,33 +16,27 @@
 #ifndef _SUPPLICANTLISTENER_H__
 #define _SUPPLICANTLISTENER_H__
 
-#include <pthread.h>
-
 #include <sysutils/SocketListener.h>
 
 struct wpa_ctrl;
 class Supplicant;
+class SocketClient;
 
 class SupplicantListener: public SocketListener {
 private:
     struct wpa_ctrl *mMonitor;
     Supplicant      *mSupplicant;
-    pthread_t       mThread;
 
 public:
     SupplicantListener(Supplicant *supplicant, struct wpa_ctrl *monitor);
     virtual ~SupplicantListener() {}
-    int startListener();
-    int stopListener();
 
     struct wpa_ctrl *getMonitor() { return mMonitor; }
     Supplicant *getSupplicant() { return mSupplicant; }
 
 protected:
-    virtual bool onDataAvailable(int socket);
+    virtual bool onDataAvailable(SocketClient *c);
 
-private:
-    static void *threadStart(void *obj);
 };
 
 #endif
diff --git a/nexus/SupplicantState.h b/nexus/SupplicantState.h
index f2cf603..e85dcb5 100644
--- a/nexus/SupplicantState.h
+++ b/nexus/SupplicantState.h
@@ -18,16 +18,16 @@
 
 class SupplicantState {
 public:
-    static const int UNKNOWN           = 0;
-    static const int DISCONNECTED      = 1;
-    static const int INACTIVE          = 2;
-    static const int SCANNING          = 3;
-    static const int ASSOCIATING       = 4;
-    static const int ASSOCIATED        = 5;
-    static const int FOURWAY_HANDSHAKE = 6;
-    static const int GROUP_HANDSHAKE   = 7;
-    static const int COMPLETED         = 8;
-    static const int IDLE              = 9;
+    static const int UNKNOWN           = -1;
+    static const int DISCONNECTED      = 0;
+    static const int INACTIVE          = 1;
+    static const int SCANNING          = 2;
+    static const int ASSOCIATING       = 3;
+    static const int ASSOCIATED        = 4;
+    static const int FOURWAY_HANDSHAKE = 5;
+    static const int GROUP_HANDSHAKE   = 6;
+    static const int COMPLETED         = 7;
+    static const int IDLE              = 8;
 };
 
 #endif
diff --git a/nexus/TiwlanWifiController.cpp b/nexus/TiwlanWifiController.cpp
index ec83825..10606a1 100644
--- a/nexus/TiwlanWifiController.cpp
+++ b/nexus/TiwlanWifiController.cpp
@@ -65,3 +65,17 @@
     property_set(DRIVER_PROP_NAME, "timeout");
     return -1;
 }
+
+bool TiwlanWifiController::isFirmwareLoaded() {
+    char driver_status[PROPERTY_VALUE_MAX];
+    if (property_get(DRIVER_PROP_NAME, driver_status, NULL)) {
+        if (!strcmp(driver_status, "ok"))
+            return true;
+        else {
+            LOGD("Driver status '%s'", driver_status);
+            return false;
+        }
+    }
+    LOGW("Unable to get property '%s'", DRIVER_PROP_NAME);
+    return false;
+}
diff --git a/nexus/TiwlanWifiController.h b/nexus/TiwlanWifiController.h
index a93d610..f17ef51 100644
--- a/nexus/TiwlanWifiController.h
+++ b/nexus/TiwlanWifiController.h
@@ -27,5 +27,6 @@
     virtual int powerDown();
     virtual bool isPoweredUp();
     virtual int loadFirmware();
+    virtual bool isFirmwareLoaded();
 };
 #endif
diff --git a/nexus/WifiController.cpp b/nexus/WifiController.cpp
index 8a7e33f..806141c 100644
--- a/nexus/WifiController.cpp
+++ b/nexus/WifiController.cpp
@@ -21,6 +21,8 @@
 
 #include "Supplicant.h"
 #include "WifiController.h"
+#include "WifiScanner.h"
+#include "NetworkManager.h"
 
 WifiController::WifiController(char *modpath, char *modname, char *modargs) :
                 Controller("WIFI") {
@@ -29,6 +31,7 @@
     strncpy(mModuleArgs, modargs, sizeof(mModuleArgs));
 
     mSupplicant = new Supplicant();
+    mScanner = new WifiScanner(mSupplicant, 10);
     mCurrentScanMode = 0;
 }
 
@@ -42,26 +45,36 @@
 }
 
 int WifiController::enable() {
-    if (!isPoweredUp() && powerUp()) {
-        LOGE("Powerup failed (%s)", strerror(errno));
-        return -1;
+    if (!isPoweredUp()) {
+        sendStatusBroadcast("POWERING_UP");
+        if (powerUp()) {
+            LOGE("Powerup failed (%s)", strerror(errno));
+            return -1;
+        }
     }
-   
+
     if (mModuleName[0] != '\0' && !isKernelModuleLoaded(mModuleName)) {
+        sendStatusBroadcast("LOADING_DRIVER");
         if (loadKernelModule(mModulePath, mModuleArgs)) {
             LOGE("Kernel module load failed (%s)", strerror(errno));
             goto out_powerdown;
         }
     }
 
-    if (loadFirmware()) {
-        LOGE("Firmware load failed (%s)", strerror(errno));
-        goto out_powerdown;
+    if (!isFirmwareLoaded()) {
+        sendStatusBroadcast("LOADING_FIRMWARE");
+        if (loadFirmware()) {
+            LOGE("Firmware load failed (%s)", strerror(errno));
+            goto out_powerdown;
+        }
     }
 
-    if (!mSupplicant->isStarted() && mSupplicant->start()) {
-        LOGE("Supplicant start failed (%s)", strerror(errno));
-        goto out_unloadmodule;
+    if (!mSupplicant->isStarted()) {
+        sendStatusBroadcast("STARTING_SUPPLICANT");
+        if (mSupplicant->start()) {
+            LOGE("Supplicant start failed (%s)", strerror(errno));
+            goto out_unloadmodule;
+        }
     }
 
     return 0;
@@ -80,24 +93,38 @@
     return -1;
 }
 
-int WifiController::disable() {
-    LOGD("disable()");
+void WifiController::sendStatusBroadcast(const char *msg) {
+    char tmp[255];
 
-    if (mSupplicant->isStarted() && mSupplicant->stop()) {
-        LOGE("Supplicant stop failed (%s)", strerror(errno));
-        return -1;
-    }
+    sprintf(tmp, "WIFI_STATUS:%s", msg);
+    NetworkManager::Instance()->getBroadcaster()->sendBroadcast(tmp);
+}
+
+int WifiController::disable() {
+
+    if (mSupplicant->isStarted()) {
+        sendStatusBroadcast("STOPPING_SUPPLICANT");
+        if (mSupplicant->stop()) {
+            LOGE("Supplicant stop failed (%s)", strerror(errno));
+            return -1;
+        }
+    } else 
+        LOGW("disable(): Supplicant not running?");
 
     if (mModuleName[0] != '\0' && isKernelModuleLoaded(mModuleName)) {
+        sendStatusBroadcast("UNLOADING_DRIVER");
         if (unloadKernelModule(mModuleName)) {
             LOGE("Unable to unload module (%s)", strerror(errno));
             return -1;
         }
     }
 
-    if (isPoweredUp() && powerDown()) {
-        LOGE("Powerdown failed (%s)", strerror(errno));
-        return -1;
+    if (isPoweredUp()) {
+        sendStatusBroadcast("POWERING_DOWN");
+        if (powerDown()) {
+            LOGE("Powerdown failed (%s)", strerror(errno));
+            return -1;
+        }
     }
     return 0;
 }
@@ -106,7 +133,7 @@
     return 0;
 }
 
-int WifiController::setScanMode(int mode) {
+int WifiController::setScanMode(uint32_t mode) {
     int rc = 0;
 
     if (mCurrentScanMode == mode)
@@ -114,21 +141,15 @@
 
     if (!(mode & SCAN_ENABLE_MASK)) {
         if (mCurrentScanMode & SCAN_REPEAT_MASK)
-            stopPeriodicScan();
+            mScanner->stopPeriodicScan();
     } else if (mode & SCAN_REPEAT_MASK)
-        rc = startPeriodicScan();
+        rc = mScanner->startPeriodicScan(mode & SCAN_ACTIVE_MASK);
     else
         rc = mSupplicant->triggerScan(mode & SCAN_ACTIVE_MASK);
     
     return rc;
 }
 
-int WifiController::startPeriodicScan() {
-    errno = -ENOSYS;
-    return -1;
-}
-
-int WifiController::stopPeriodicScan() {
-    errno = -ENOSYS;
-    return -1;
+ScanResultCollection *WifiController::createScanResults() {
+    return mSupplicant->createLatestScanResults();
 }
diff --git a/nexus/WifiController.h b/nexus/WifiController.h
index 6d00513..38aea81 100644
--- a/nexus/WifiController.h
+++ b/nexus/WifiController.h
@@ -22,6 +22,9 @@
 
 class NetInterface;
 class Supplicant;
+class WifiScanner;
+
+#include "ScanResult.h"
 
 class WifiController : public Controller {
 public:
@@ -40,8 +43,8 @@
     char        mModulePath[255];
     char        mModuleName[64];
     char        mModuleArgs[255];
-    int         mCurrentScanMode;
-
+    uint32_t    mCurrentScanMode;
+    WifiScanner *mScanner;
 
 public:
     WifiController(char *modpath, char *modname, char *modargs);
@@ -53,6 +56,8 @@
     int enable();
     int disable();
 
+    ScanResultCollection *createScanResults();
+
     int getType();
 
     char *getModulePath() { return mModulePath; }
@@ -62,17 +67,17 @@
     Supplicant *getSupplicant() { return mSupplicant; }
 
     int getScanMode() { return mCurrentScanMode; }
-    int setScanMode(int mode);
+    int setScanMode(uint32_t mode);
 
 protected:
     virtual int powerUp() = 0;
     virtual int powerDown() = 0;
     virtual int loadFirmware();
+
+    virtual bool isFirmwareLoaded() = 0;
     virtual bool isPoweredUp() = 0;
 
-private:
-    int startPeriodicScan();
-    int stopPeriodicScan();
+    void sendStatusBroadcast(const char *msg);
 };
 
 #endif
diff --git a/nexus/WifiScanner.cpp b/nexus/WifiScanner.cpp
new file mode 100644
index 0000000..590d895
--- /dev/null
+++ b/nexus/WifiScanner.cpp
@@ -0,0 +1,96 @@
+#include <errno.h>
+#include <pthread.h>
+
+#define LOG_TAG "WifiScanner"
+#include <cutils/log.h>
+
+#include "WifiScanner.h"
+#include "Supplicant.h"
+
+extern "C" int pthread_cancel(pthread_t thread);
+
+WifiScanner::WifiScanner(Supplicant *suppl, int period) {
+    mSuppl = suppl;
+    mPeriod = period;
+    mActive = false;
+    mWorkerRunning = false;
+    mAbortRequest = false;
+    pthread_mutex_init(&mAbortRequestLock, NULL);
+    pthread_mutex_init(&mWorkerLock, NULL);
+}
+
+int WifiScanner::startPeriodicScan(bool active) {
+    mActive = active;
+
+    pthread_mutex_lock(&mWorkerLock);
+    if (mWorkerRunning) {
+        errno = EBUSY;
+        return -1;
+    }
+
+    pthread_attr_t attr;
+    pthread_attr_init(&attr);
+    pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED);
+
+    if (pthread_create(&mWorker, &attr, WifiScanner::threadStart, this))
+        return -1;
+
+    return 0;
+}
+
+void *WifiScanner::threadStart(void *obj) {
+    WifiScanner *me = reinterpret_cast<WifiScanner *>(obj);
+    me->run();
+    pthread_exit(NULL);
+    return NULL;
+}
+
+void WifiScanner::threadCleanup(void *obj) {
+    WifiScanner *me = reinterpret_cast<WifiScanner *>(obj);
+
+    me->mWorkerRunning = false;
+    pthread_mutex_unlock(&me->mWorkerLock);
+
+    if (me->mAbortRequest) {
+        me->mAbortRequest = false;
+        pthread_mutex_unlock(&me->mAbortRequestLock);
+    }
+}
+
+int WifiScanner::stopPeriodicScan() {
+    pthread_mutex_lock(&mAbortRequestLock);
+    pthread_mutex_lock(&mWorkerLock);
+    if (mWorkerRunning)
+        mAbortRequest = true;
+    pthread_mutex_unlock(&mWorkerLock);
+    pthread_mutex_unlock(&mAbortRequestLock);
+
+    return 0;
+}
+
+void WifiScanner::run() {
+    LOGD("Thread started");
+
+    mWorkerRunning = true;
+    pthread_cleanup_push(WifiScanner::threadCleanup, this);
+    pthread_mutex_unlock(&mWorkerLock);
+
+    while(1) {
+        LOGD("Triggering periodic scan");
+        if (mSuppl->triggerScan(mActive)) {
+            LOGW("Error triggering scan (%s)", strerror(errno));
+        }
+
+        sleep(mPeriod);
+        pthread_mutex_lock(&mAbortRequestLock);
+        if (mAbortRequest) {
+            LOGD("Abort request!");
+            goto out;
+        }
+        pthread_mutex_unlock(&mAbortRequestLock);
+    }
+
+out:
+    pthread_cleanup_pop(1);
+    pthread_mutex_unlock(&mWorkerLock);
+}
diff --git a/nexus/WifiScanner.h b/nexus/WifiScanner.h
new file mode 100644
index 0000000..9ba1309
--- /dev/null
+++ b/nexus/WifiScanner.h
@@ -0,0 +1,36 @@
+#ifndef _WIFISCANNER_H
+#define _WIFISCANNER_H
+
+#include <pthread.h>
+
+class Supplicant;
+
+class WifiScanner {
+    pthread_t       mWorker;
+    pthread_mutex_t mWorkerLock;
+    bool            mWorkerRunning;
+    bool            mAbortRequest;
+    pthread_mutex_t mAbortRequestLock;
+
+    Supplicant *mSuppl;
+    int        mPeriod;
+    bool       mActive;
+    
+
+public:
+    WifiScanner(Supplicant *suppl, int period);
+    virtual ~WifiScanner() {}
+
+    int getPeriod() { return mPeriod; }
+
+    int startPeriodicScan(bool active);
+    int stopPeriodicScan();
+
+private:
+    static void *threadStart(void *obj);
+    static void threadCleanup(void *obj);
+
+    void run();
+};
+
+#endif
diff --git a/nexus/main.cpp b/nexus/main.cpp
index a26a14d..0a0b43f 100644
--- a/nexus/main.cpp
+++ b/nexus/main.cpp
@@ -20,22 +20,44 @@
 
 #include "cutils/log.h"
 #include "NetworkManager.h"
+#include "CommandListener.h"
+
+#include "LoopController.h"
+#include "VpnController.h"
+#include "TiwlanWifiController.h"
 
 int main() {
-    NetworkManager    *nm;
-
     LOGI("Nexus version 0.1 firing up");
 
-    if (!(nm = new NetworkManager())) {
+    CommandListener *cl = new CommandListener();
+
+    NetworkManager *nm;
+    if (!(nm = NetworkManager::Instance())) {
         LOGE("Unable to create NetworkManager");
         exit (-1);
     };
 
-    if (nm->run()) {
+    nm->setBroadcaster((SocketListener *) cl);
+
+    nm->attachController(new LoopController());
+    nm->attachController(new TiwlanWifiController("/system/lib/modules/wlan.ko", "wlan", ""));
+    nm->attachController(new VpnController());
+
+
+    if (NetworkManager::Instance()->run()) {
         LOGE("Unable to Run NetworkManager (%s)", strerror(errno));
         exit (1);
     }
 
+    if (cl->startListener()) {
+        LOGE("Unable to start  CommandListener (%s)", strerror(errno));
+        exit (1);
+    }
+
+    while(1) {
+        sleep(1000);
+    }
+
     LOGI("Nexus exiting");
     exit(0);
 }
diff --git a/nexus/nexctl.c b/nexus/nexctl.c
index 6d117c7..c326558 100644
--- a/nexus/nexctl.c
+++ b/nexus/nexctl.c
@@ -65,14 +65,13 @@
 
         buffer[strlen(buffer) -1] = 0;
 
-        printf("sending '%s'\n", buffer);
         if (write(sock, buffer, strlen(buffer) +1) < 0) {
             fprintf(stderr, "Error writing data (%s)\n", strerror(errno));
             exit(2);
         }
 
 wait:
-        to.tv_sec = 5;
+        to.tv_sec = 10;
         to.tv_usec = 0;
         FD_ZERO(&read_fds);
         FD_SET(sock, &read_fds);
@@ -88,12 +87,11 @@
             printf("{response timeout}\n");
             continue;
         } else if (FD_ISSET(sock, &read_fds)) {
-printf("got data!\n");
-             if ((rc = read(sock, buffer, sizeof(buffer)-1)) < 0) {
+             if ((rc = read(sock, buffer, sizeof(buffer)-1)) <= 0) {
                  fprintf(stderr, "Error reading response (%s)\n", strerror(errno));
                  exit(2);
              }
-            printf(" |%s|\n", buffer);
+            printf(" %s\n", buffer);
             goto wait;
         }
     }