Merge commit 'goog/master' into merge_master
diff --git a/nexus/Android.mk b/nexus/Android.mk
index 865f58a..cd477ef 100644
--- a/nexus/Android.mk
+++ b/nexus/Android.mk
@@ -34,7 +34,8 @@
                   SupplicantConnectionTimeoutEvent.cpp \
                   SupplicantDisconnectedEvent.cpp      \
                   SupplicantStatus.cpp                 \
-                  TiwlanEventListener.cpp
+                  TiwlanEventListener.cpp              \
+                  DhcpClient.cpp DhcpListener.cpp      \
 
 LOCAL_MODULE:= nexus
 
diff --git a/nexus/DhcpClient.cpp b/nexus/DhcpClient.cpp
new file mode 100644
index 0000000..2bd9c68
--- /dev/null
+++ b/nexus/DhcpClient.cpp
@@ -0,0 +1,105 @@
+/*
+ * 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 <sys/types.h>
+#include <arpa/inet.h>
+
+#define LOG_TAG "DhcpClient"
+#include <cutils/log.h>
+#include <cutils/properties.h>
+
+#include <sysutils/ServiceManager.h>
+
+#include "DhcpClient.h"
+#include "DhcpState.h"
+#include "DhcpListener.h"
+#include "IDhcpEventHandlers.h"
+
+extern "C" {
+int ifc_disable(const char *ifname);
+int ifc_add_host_route(const char *ifname, uint32_t addr);
+int ifc_remove_host_routes(const char *ifname);
+int ifc_set_default_route(const char *ifname, uint32_t gateway);
+int ifc_get_default_route(const char *ifname);
+int ifc_remove_default_route(const char *ifname);
+int ifc_reset_connections(const char *ifname);
+int ifc_configure(const char *ifname, in_addr_t ipaddr, in_addr_t netmask, in_addr_t gateway, in_addr_t dns1, in_addr_t dns2);
+
+int dhcp_do_request(const char *ifname,
+                    in_addr_t *ipaddr,
+                    in_addr_t *gateway,
+                    in_addr_t *mask,
+                    in_addr_t *dns1,
+                    in_addr_t *dns2,
+                    in_addr_t *server,
+                    uint32_t  *lease);
+int dhcp_stop(const char *ifname);
+int dhcp_release_lease(const char *ifname);
+char *dhcp_get_errmsg();
+}
+
+DhcpClient::DhcpClient(IDhcpEventHandlers *handlers) :
+            mState(DhcpState::STOPPED), mHandlers(handlers) {
+    mServiceManager = new ServiceManager();
+    mListener = NULL;
+}
+
+DhcpClient::~DhcpClient() {
+    delete mServiceManager;
+    if (mListener)
+        delete mListener;
+}
+
+int DhcpClient::start(const char *interface) {
+
+    char svc[PROPERTY_VALUE_MAX];
+    snprintf(svc, sizeof(svc), "dhcpcd_ng:%s", interface);
+
+    if (mServiceManager->start(svc)) {
+        LOGE("Failed to start dhcp service");
+        return -1;
+    }
+
+    mListener = new DhcpListener(mHandlers);
+    if (mListener->startListener()) {
+        LOGE("Failed to start listener");
+#if 0
+        mServiceManager->stop("dhcpcd_ng");
+        return -1;
+#endif
+        delete mListener;
+        mListener = NULL;
+    }
+
+    mState = DhcpState::STARTED;
+
+    return 0;
+}
+
+int DhcpClient::stop() {
+    if (mListener) {
+        mListener->stopListener();
+        delete mListener;
+        mListener = NULL;
+    }
+
+    if (mServiceManager->stop("dhcpcd_ng")) 
+        LOGW("Failed to stop DHCP service (%s)", strerror(errno));
+    mState = DhcpState::STOPPED;
+    return 0;
+}
diff --git a/nexus/DhcpClient.h b/nexus/DhcpClient.h
new file mode 100644
index 0000000..e0a2784
--- /dev/null
+++ b/nexus/DhcpClient.h
@@ -0,0 +1,41 @@
+
+/*
+ * 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 _DhcpClient_H
+#define _DhcpClient_H
+
+class IDhcpEventHandlers;
+class ServiceManager;
+class DhcpListener;
+
+class DhcpClient {
+    int                mState;
+    IDhcpEventHandlers *mHandlers;
+    ServiceManager     *mServiceManager;
+    DhcpListener       *mListener;
+
+public:
+    DhcpClient(IDhcpEventHandlers *handlers);
+    virtual ~DhcpClient();
+
+    int getState() { return mState; }
+
+    int start(const char *interface);
+    int stop();
+};
+
+#endif
diff --git a/nexus/DhcpListener.cpp b/nexus/DhcpListener.cpp
new file mode 100644
index 0000000..2d07ee8
--- /dev/null
+++ b/nexus/DhcpListener.cpp
@@ -0,0 +1,34 @@
+/*
+ * Copyright (C) 2008 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#define LOG_TAG "DhcpListener"
+#include <cutils/log.h>
+
+#include <DhcpListener.h>
+#include "IDhcpEventHandlers.h"
+
+DhcpListener::DhcpListener(IDhcpEventHandlers *handlers) :
+              SocketListener("dhcp_ng", false) {
+    mHandlers = handlers;
+}
+
+DhcpListener::~DhcpListener() {
+}
+
+bool DhcpListener::onDataAvailable(SocketClient *cli) {
+    LOGD("onDataAvailable()");
+    return true;
+}
diff --git a/nexus/DhcpListener.h b/nexus/DhcpListener.h
new file mode 100644
index 0000000..bfc5a37
--- /dev/null
+++ b/nexus/DhcpListener.h
@@ -0,0 +1,36 @@
+/*
+ * 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 _DhcpListener_H
+#define _DhcpListener_H
+
+#include <sysutils/SocketListener.h>
+
+class IDhcpEventHandlers;
+
+class DhcpListener : public SocketListener {
+    IDhcpEventHandlers *mHandlers;
+
+public:
+
+    DhcpListener(IDhcpEventHandlers *handlers);
+    virtual ~DhcpListener();
+
+private:
+    bool onDataAvailable(SocketClient *cli);
+};
+
+#endif
diff --git a/nexus/DhcpState.h b/nexus/DhcpState.h
new file mode 100644
index 0000000..27d7c7e
--- /dev/null
+++ b/nexus/DhcpState.h
@@ -0,0 +1,27 @@
+/*
+ * 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 _DhcpState_H
+#define _DhcpState_H
+
+class DhcpState {
+public:
+    static const int UNKNOWN = 0;
+    static const int STOPPED = 1;
+    static const int STARTED = 2;
+};
+
+#endif
diff --git a/nexus/IControllerHandler.h b/nexus/IControllerHandler.h
index 92d015f..f7be39c 100644
--- a/nexus/IControllerHandler.h
+++ b/nexus/IControllerHandler.h
@@ -22,8 +22,8 @@
 
 class IControllerHandler {
 public:
-    virtual void onInterfaceStarted(Controller *c, const InterfaceConfig *cfg) = 0;
-    virtual void onInterfaceStopping(Controller *c, const char *name) = 0;
+    virtual void onInterfaceConnected(Controller *c, const InterfaceConfig *cfg) = 0;
+    virtual void onInterfaceDisconnected(Controller *c, const char *name) = 0;
 };
 
 #endif
diff --git a/nexus/IDhcpEventHandlers.h b/nexus/IDhcpEventHandlers.h
new file mode 100644
index 0000000..3f51f64
--- /dev/null
+++ b/nexus/IDhcpEventHandlers.h
@@ -0,0 +1,25 @@
+
+/*
+ * 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 _IDhcpEventHandlers_H
+#define _IDhcpEventHandlers_H
+
+class IDhcpEventHandlers {
+public:
+};
+
+#endif
diff --git a/nexus/NetworkManager.cpp b/nexus/NetworkManager.cpp
index 2f13a40..7450b95 100644
--- a/nexus/NetworkManager.cpp
+++ b/nexus/NetworkManager.cpp
@@ -23,6 +23,7 @@
 
 #include "NetworkManager.h"
 #include "InterfaceConfig.h"
+#include "DhcpClient.h"
 
 NetworkManager *NetworkManager::sInstance = NULL;
 
@@ -36,6 +37,7 @@
     mBroadcaster = NULL;
     mControllers = new ControllerCollection();
     mPropMngr = propMngr;
+    mDhcp = new DhcpClient(this);
 }
 
 NetworkManager::~NetworkManager() {
@@ -89,8 +91,8 @@
     return NULL;
 }
 
-void NetworkManager::onInterfaceStarted(Controller *c, const InterfaceConfig *cfg) {
-    LOGD("Interface %s started by controller %s", c->getBoundInterface(), c->getName());
+void NetworkManager::onInterfaceConnected(Controller *c, const InterfaceConfig *cfg) {
+    LOGD("Controller %s interface %s connected", c->getName(), c->getBoundInterface());
 
     // Look up the interface
 
@@ -98,9 +100,9 @@
     }
 
     if (cfg) {
-        if (cfg->getUseDhcp()) {
-            // Launch DHCP thread
-        } else {
+        if (cfg->getUseDhcp() && mDhcp->start(c->getBoundInterface())) {
+            LOGE("DHCP start failed");
+        } else if (!cfg->getUseDhcp()) {
             // Static configuration
         }
     } else {
@@ -109,6 +111,11 @@
     }
 }
 
-void NetworkManager::onInterfaceStopping(Controller *c, const char *name) {
-    LOGD("Interface %s stopped by controller %s", name, c->getName());
+void NetworkManager::onInterfaceDisconnected(Controller *c, const char *name) {
+    LOGD("Controller %s interface %s disconnected", c->getName(), name);
+
+    // If we have a DHCP request out on this interface then stop it
+    if (1) {
+        mDhcp->stop();
+    }
 }
diff --git a/nexus/NetworkManager.h b/nexus/NetworkManager.h
index edc80c9..44f3417 100644
--- a/nexus/NetworkManager.h
+++ b/nexus/NetworkManager.h
@@ -22,10 +22,12 @@
 #include "Controller.h"
 #include "PropertyManager.h"
 #include "IControllerHandler.h"
+#include "IDhcpEventHandlers.h"
 
 class InterfaceConfig;
+class DhcpClient;
 
-class NetworkManager : public IControllerHandler {
+class NetworkManager : public IControllerHandler, public IDhcpEventHandlers {
 private:
     static NetworkManager *sInstance;
 
@@ -33,6 +35,7 @@
     ControllerCollection *mControllers;
     SocketListener       *mBroadcaster;
     PropertyManager      *mPropMngr;
+    DhcpClient           *mDhcp;
 
 public:
     virtual ~NetworkManager();
@@ -55,7 +58,7 @@
 
     NetworkManager(PropertyManager *propMngr);
 
-    void onInterfaceStarted(Controller *c, const InterfaceConfig *cfg);
-    void onInterfaceStopping(Controller *c, const char *name);
+    void onInterfaceConnected(Controller *c, const InterfaceConfig *cfg);
+    void onInterfaceDisconnected(Controller *c, const char *name);
 };
 #endif
diff --git a/nexus/WifiController.cpp b/nexus/WifiController.cpp
index b7bd6ed..ef5ecae 100644
--- a/nexus/WifiController.cpp
+++ b/nexus/WifiController.cpp
@@ -279,33 +279,31 @@
 
 void WifiController::onConnectedEvent(SupplicantConnectedEvent *evt) {
     LOGD("onConnectedEvent(%s, %d)", evt->getBssid(), evt->getReassociated());
-    if (!evt->getReassociated()) {
-        SupplicantStatus *ss = mSupplicant->getStatus();
-        WifiNetwork *wn;
+    SupplicantStatus *ss = mSupplicant->getStatus();
+    WifiNetwork *wn;
 
-        if (ss->getWpaState() != SupplicantState::COMPLETED) {
-            char tmp[32];
+    if (ss->getWpaState() != SupplicantState::COMPLETED) {
+        char tmp[32];
 
-            LOGW("onConnected() with SupplicantState = %s!",
-                 SupplicantState::toString(ss->getWpaState(), tmp,
-                 sizeof(tmp)));
-            return;
-        }
-
-        if (ss->getId() == -1) {
-            LOGW("onConnected() with id = -1!");
-            return;
-        }
-        
-        if (!(wn = mSupplicant->lookupNetwork(ss->getId()))) {
-            LOGW("Error looking up connected network id %d (%s)",
-                 ss->getId(), strerror(errno));
-            return;
-        }
-      
-        delete ss;
-        mHandlers->onInterfaceStarted(this, wn->getIfaceCfg());
+        LOGW("onConnected() with SupplicantState = %s!",
+             SupplicantState::toString(ss->getWpaState(), tmp,
+             sizeof(tmp)));
+        return;
     }
+
+    if (ss->getId() == -1) {
+        LOGW("onConnected() with id = -1!");
+        return;
+    }
+    
+    if (!(wn = mSupplicant->lookupNetwork(ss->getId()))) {
+        LOGW("Error looking up connected network id %d (%s)",
+             ss->getId(), strerror(errno));
+        return;
+    }
+  
+    delete ss;
+    mHandlers->onInterfaceConnected(this, wn->getIfaceCfg());
 }
 
 void WifiController::onScanResultsEvent(SupplicantScanResultsEvent *evt) {
@@ -373,7 +371,7 @@
 }
 
 void WifiController::onDisconnectedEvent(SupplicantDisconnectedEvent *evt) {
-    LOGD("onDisconnectedEvent()");
+    mHandlers->onInterfaceDisconnected(this, getBoundInterface());
 }
 
 #if 0