Merge tag android-5.1.0_r1 into AOSP_5.1_MERGE

Change-Id: I0eca19ee2680183a7f393eac4bb7e109518cfe08
diff --git a/server/ClatdController.cpp b/server/ClatdController.cpp
index c19e299..348a0dd 100644
--- a/server/ClatdController.cpp
+++ b/server/ClatdController.cpp
@@ -13,6 +13,9 @@
  * See the License for the specific language governing permissions and
  * limitations under the License.
  */
+#include <map>
+#include <string>
+
 #include <unistd.h>
 #include <errno.h>
 #include <sys/types.h>
@@ -21,34 +24,63 @@
 #define LOG_TAG "ClatdController"
 #include <cutils/log.h>
 
+#include <resolv_netid.h>
+
 #include "NetdConstants.h"
 #include "ClatdController.h"
 #include "Fwmark.h"
 #include "NetdConstants.h"
 #include "NetworkController.h"
 
+static const char* kClatdPath = "/system/bin/clatd";
+
 ClatdController::ClatdController(NetworkController* controller)
-        : mNetCtrl(controller), mClatdPid(0) {
+        : mNetCtrl(controller) {
 }
 
 ClatdController::~ClatdController() {
 }
 
-int ClatdController::startClatd(char *interface) {
-    pid_t pid;
+// Returns the PID of the clatd running on interface |interface|, or 0 if clatd is not running on
+// |interface|.
+pid_t ClatdController::getClatdPid(char* interface) {
+    auto it = mClatdPids.find(interface);
+    return (it == mClatdPids.end() ? 0 : it->second);
+}
 
-    if(mClatdPid != 0) {
-        ALOGE("clatd already running");
+int ClatdController::startClatd(char* interface) {
+    pid_t pid = getClatdPid(interface);
+
+    if (pid != 0) {
+        ALOGE("clatd pid=%d already started on %s", pid, interface);
         errno = EBUSY;
         return -1;
     }
 
-    if (!isIfaceName(interface)) {
-        errno = ENOENT;
+    // Pass in the interface, a netid to use for DNS lookups, and a fwmark for outgoing packets.
+    unsigned netId = mNetCtrl->getNetworkForInterface(interface);
+    if (netId == NETID_UNSET) {
+        ALOGE("interface %s not assigned to any netId", interface);
+        errno = ENODEV;
         return -1;
     }
 
-    ALOGD("starting clatd");
+    char netIdString[UINT32_STRLEN];
+    snprintf(netIdString, sizeof(netIdString), "%u", netId);
+
+    Fwmark fwmark;
+    fwmark.netId = netId;
+    fwmark.explicitlySelected = true;
+    fwmark.protectedFromVpn = true;
+    fwmark.permission = PERMISSION_SYSTEM;
+
+    char fwmarkString[UINT32_HEX_STRLEN];
+    snprintf(fwmarkString, sizeof(fwmarkString), "0x%x", fwmark.intValue);
+
+    ALOGD("starting clatd on %s", interface);
+
+    std::string progname("clatd-");
+    progname += interface;
 
     if ((pid = fork()) < 0) {
         ALOGE("fork failed (%s)", strerror(errno));
@@ -56,23 +88,8 @@
     }
 
     if (!pid) {
-        // Pass in the interface, a netid to use for DNS lookups, and a fwmark for outgoing packets.
-        unsigned netId = mNetCtrl->getNetworkForInterface(interface);
-        char netIdString[UINT32_STRLEN];
-        snprintf(netIdString, sizeof(netIdString), "%u", netId);
-
-        Fwmark fwmark;
-
-        fwmark.netId = netId;
-        fwmark.explicitlySelected = true;
-        fwmark.protectedFromVpn = true;
-        fwmark.permission = PERMISSION_SYSTEM;
-
-        char fwmarkString[UINT32_HEX_STRLEN];
-        snprintf(fwmarkString, sizeof(fwmarkString), "0x%x", fwmark.intValue);
-
         char *args[] = {
-            (char *) "/system/bin/clatd",
+            (char *) progname.c_str(),
             (char *) "-i",
             interface,
             (char *) "-n",
@@ -82,44 +99,48 @@
             NULL
         };
 
-        if (execv(args[0], args)) {
+        if (execv(kClatdPath, args)) {
             ALOGE("execv failed (%s)", strerror(errno));
+            _exit(1);
         }
         ALOGE("Should never get here!");
-        _exit(0);
+        _exit(1);
     } else {
-        mClatdPid = pid;
-        ALOGD("clatd started");
+        mClatdPids[interface] = pid;
+        ALOGD("clatd started on %s", interface);
     }
 
     return 0;
 }
 
-int ClatdController::stopClatd() {
-    if (mClatdPid == 0) {
+int ClatdController::stopClatd(char* interface) {
+    pid_t pid = getClatdPid(interface);
+
+    if (pid == 0) {
         ALOGE("clatd already stopped");
         return -1;
     }
 
-    ALOGD("Stopping clatd");
+    ALOGD("Stopping clatd pid=%d on %s", pid, interface);
 
-    kill(mClatdPid, SIGTERM);
-    waitpid(mClatdPid, NULL, 0);
-    mClatdPid = 0;
+    kill(pid, SIGTERM);
+    waitpid(pid, NULL, 0);
+    mClatdPids.erase(interface);
 
-    ALOGD("clatd stopped");
+    ALOGD("clatd on %s stopped", interface);
 
     return 0;
 }
 
-bool ClatdController::isClatdStarted() {
+bool ClatdController::isClatdStarted(char* interface) {
     pid_t waitpid_status;
-    if(mClatdPid == 0) {
+    pid_t pid = getClatdPid(interface);
+    if (pid == 0) {
         return false;
     }
-    waitpid_status = waitpid(mClatdPid, NULL, WNOHANG);
-    if(waitpid_status != 0) {
-        mClatdPid = 0; // child exited, don't call waitpid on it again
+    waitpid_status = waitpid(pid, NULL, WNOHANG);
+    if (waitpid_status != 0) {
+        mClatdPids.erase(interface);  // child exited, don't call waitpid on it again
     }
     return waitpid_status == 0; // 0 while child is running
 }
diff --git a/server/ClatdController.h b/server/ClatdController.h
index 5bf48d9..1985836 100644
--- a/server/ClatdController.h
+++ b/server/ClatdController.h
@@ -17,6 +17,8 @@
 #ifndef _CLATD_CONTROLLER_H
 #define _CLATD_CONTROLLER_H
 
+#include <map>
+
 class NetworkController;
 
 class ClatdController {
@@ -25,12 +27,13 @@
     virtual ~ClatdController();
 
     int startClatd(char *interface);
-    int stopClatd();
-    bool isClatdStarted();
+    int stopClatd(char* interface);
+    bool isClatdStarted(char* interface);
 
 private:
     NetworkController* const mNetCtrl;
-    pid_t mClatdPid;
+    std::map<std::string, pid_t> mClatdPids;
+    pid_t getClatdPid(char* interface);
 };
 
 #endif
diff --git a/server/CommandListener.cpp b/server/CommandListener.cpp
index a0810e8..5b21c50 100644
--- a/server/CommandListener.cpp
+++ b/server/CommandListener.cpp
@@ -62,10 +62,10 @@
 const unsigned NUM_OEM_IDS = NetworkController::MAX_OEM_ID - NetworkController::MIN_OEM_ID + 1;
 
 Permission stringToPermission(const char* arg) {
-    if (!strcmp(arg, "android.permission.CHANGE_NETWORK_STATE")) {
+    if (!strcmp(arg, "NETWORK")) {
         return PERMISSION_NETWORK;
     }
-    if (!strcmp(arg, "android.permission.CONNECTIVITY_INTERNAL")) {
+    if (!strcmp(arg, "SYSTEM")) {
         return PERMISSION_SYSTEM;
     }
     return PERMISSION_NONE;
@@ -504,6 +504,21 @@
                         "Failed to change IPv6 state", true);
             }
             return 0;
+        } else if (!strcmp(argv[1], "ipv6ndoffload")) {
+            if (argc != 4) {
+                cli->sendMsg(ResponseCode::CommandSyntaxError,
+                        "Usage: interface ipv6ndoffload <interface> <enable|disable>",
+                        false);
+                return 0;
+            }
+            int enable = !strncmp(argv[3], "enable", 7);
+            if (sInterfaceCtrl->setIPv6NdOffload(argv[2], enable) == 0) {
+                cli->sendMsg(ResponseCode::CommandOkay, "IPv6 ND offload changed", false);
+            } else {
+                cli->sendMsg(ResponseCode::OperationFailed,
+                        "Failed to change IPv6 ND offload state", true);
+            }
+            return 0;
         } else if (!strcmp(argv[1], "setmtu")) {
             if (argc != 4) {
                 cli->sendMsg(ResponseCode::CommandSyntaxError,
@@ -937,6 +952,14 @@
                     "Wrong number of arguments to resolver setnetdns", false);
             return 0;
         }
+    } else if (!strcmp(argv[1], "clearnetdns")) { // "resolver clearnetdns <netId>"
+        if (argc == 3) {
+            rc = sResolverCtrl->clearDnsServers(strtoul(argv[2], NULL, 0));
+        } else {
+            cli->sendMsg(ResponseCode::CommandSyntaxError,
+                    "Wrong number of arguments to resolver clearnetdns", false);
+            return 0;
+        }
     } else if (!strcmp(argv[1], "flushnet")) { // "resolver flushnet <netId>"
         if (argc == 3) {
             rc = sResolverCtrl->flushDnsCache(strtoul(argv[2], NULL, 0));
@@ -1464,26 +1487,21 @@
 int CommandListener::ClatdCmd::runCommand(SocketClient *cli, int argc,
                                                             char **argv) {
     int rc = 0;
-    if (argc < 2) {
+    if (argc < 3) {
         cli->sendMsg(ResponseCode::CommandSyntaxError, "Missing argument", false);
         return 0;
     }
 
-    if(!strcmp(argv[1], "stop")) {
-        rc = sClatdCtrl->stopClatd();
+    if (!strcmp(argv[1], "stop")) {
+        rc = sClatdCtrl->stopClatd(argv[2]);
     } else if (!strcmp(argv[1], "status")) {
         char *tmp = NULL;
-
-        asprintf(&tmp, "Clatd status: %s", (sClatdCtrl->isClatdStarted() ?
-                                                        "started" : "stopped"));
+        asprintf(&tmp, "Clatd status: %s", (sClatdCtrl->isClatdStarted(argv[2]) ?
+                                            "started" : "stopped"));
         cli->sendMsg(ResponseCode::ClatdStatusResult, tmp, false);
         free(tmp);
         return 0;
-    } else if(!strcmp(argv[1], "start")) {
-        if (argc < 3) {
-            cli->sendMsg(ResponseCode::CommandSyntaxError, "Missing argument", false);
-            return 0;
-        }
+    } else if (!strcmp(argv[1], "start")) {
         rc = sClatdCtrl->startClatd(argv[2]);
     } else {
         cli->sendMsg(ResponseCode::CommandSyntaxError, "Unknown clatd cmd", false);
diff --git a/server/InterfaceController.cpp b/server/InterfaceController.cpp
index 061060f..b7a4d0b 100644
--- a/server/InterfaceController.cpp
+++ b/server/InterfaceController.cpp
@@ -18,6 +18,7 @@
 
 #define LOG_TAG "InterfaceController"
 #include <cutils/log.h>
+#include <logwrap/logwrap.h>
 
 #include "InterfaceController.h"
 #include "RouteController.h"
@@ -26,6 +27,8 @@
 
 const char sys_net_path[] = "/sys/class/net";
 
+const char wl_util_path[] = "/system/xbin/wlutil";
+
 InterfaceController::InterfaceController() {
 	// Initial IPv6 settings.
 	// By default, accept_ra is set to 1 (accept RAs unless forwarding is on) on all interfaces.
@@ -35,6 +38,9 @@
 	setAcceptRA("2");
 
 	setAcceptRARouteTable(-RouteController::ROUTE_TABLE_OFFSET_FROM_INDEX);
+
+	// Enable optimistic DAD for IPv6 addresses on all interfaces.
+	setIPv6OptimisticMode("1");
 }
 
 InterfaceController::~InterfaceController() {
@@ -66,6 +72,29 @@
 	return writeIPv6ProcPath(interface, "use_tempaddr", on ? "2" : "0");
 }
 
+// Enables or disables IPv6 ND offload. This is useful for 464xlat on wifi, IPv6 tethering, and
+// generally implementing IPv6 neighbour discovery and duplicate address detection properly.
+// TODO: This should be implemented in wpa_supplicant via driver commands instead.
+int InterfaceController::setIPv6NdOffload(char* interface, const int on) {
+    // Only supported on Broadcom chipsets via wlutil for now.
+    if (access(wl_util_path, X_OK) == 0) {
+        const char *argv[] = {
+            wl_util_path,
+            "-a",
+            interface,
+            "ndoe",
+            on ? "1" : "0"
+        };
+        int ret = android_fork_execvp(ARRAY_SIZE(argv), const_cast<char**>(argv), NULL,
+                                      false, false);
+        ALOGD("%s ND offload on %s: %d (%s)",
+              (on ? "enabling" : "disabling"), interface, ret, strerror(errno));
+        return ret;
+    } else {
+        return 0;
+    }
+}
+
 int InterfaceController::isInterfaceName(const char *name) {
 	return strcmp(name, ".") &&
 		strcmp(name, "..") &&
@@ -121,3 +150,8 @@
 	free(path);
 	return success;
 }
+
+void InterfaceController::setIPv6OptimisticMode(const char *value) {
+	setOnAllInterfaces("optimistic_dad", value);
+	setOnAllInterfaces("use_optimistic", value);
+}
diff --git a/server/InterfaceController.h b/server/InterfaceController.h
index f6e8cbd..60e2131 100644
--- a/server/InterfaceController.h
+++ b/server/InterfaceController.h
@@ -23,6 +23,7 @@
 	virtual ~InterfaceController();
 	int setEnableIPv6(const char *interface, const int on);
 	int setIPv6PrivacyExtensions(const char *interface, const int on);
+	int setIPv6NdOffload(char* interface, const int on);
 	int setMtu(const char *interface, const char *mtu);
 
  private:
@@ -31,6 +32,7 @@
 	void setOnAllInterfaces(const char* filename, const char* value);
 	void setAcceptRA(const char* value);
 	void setAcceptRARouteTable(int tableOrOffset);
+	void setIPv6OptimisticMode(const char *value);
 };
 
 #endif
diff --git a/server/ResolverController.cpp b/server/ResolverController.cpp
index a5d69ae..639423d 100644
--- a/server/ResolverController.cpp
+++ b/server/ResolverController.cpp
@@ -38,6 +38,14 @@
     return 0;
 }
 
+int ResolverController::clearDnsServers(unsigned netId) {
+    _resolv_set_nameservers_for_net(netId, NULL, 0, "");
+    if (DBG) {
+        ALOGD("clearDnsServers netId = %u\n", netId);
+    }
+    return 0;
+}
+
 int ResolverController::flushDnsCache(unsigned netId) {
     if (DBG) {
         ALOGD("flushDnsCache netId = %u\n", netId);
diff --git a/server/ResolverController.h b/server/ResolverController.h
index 0c245d7..39f002d 100644
--- a/server/ResolverController.h
+++ b/server/ResolverController.h
@@ -27,6 +27,7 @@
 
     int setDnsServers(unsigned netid, const char * domains, const char** servers,
             int numservers);
+    int clearDnsServers(unsigned netid);
     int flushDnsCache(unsigned netid);
     // TODO: Add deleteDnsCache(unsigned netId)
 };
diff --git a/server/RouteController.cpp b/server/RouteController.cpp
index 37f6f90..ba5da9d 100644
--- a/server/RouteController.cpp
+++ b/server/RouteController.cpp
@@ -813,11 +813,8 @@
     }
 
     int ret = modifyIpRoute(action, table, interface, destination, nexthop);
-    // We allow apps to call requestRouteToHost() multiple times with the same route, so ignore
-    // EEXIST failures when adding routes to legacy tables.
-    if (ret && !(action == RTM_NEWROUTE && ret == -EEXIST &&
-                 (tableType == RouteController::LEGACY_NETWORK ||
-                  tableType == RouteController::LEGACY_SYSTEM))) {
+    // Trying to add a route that already exists shouldn't cause an error.
+    if (ret && !(action == RTM_NEWROUTE && ret == -EEXIST)) {
         return ret;
     }
 
diff --git a/server/SoftapController.cpp b/server/SoftapController.cpp
index 07c77b0..270bd51 100644
--- a/server/SoftapController.cpp
+++ b/server/SoftapController.cpp
@@ -59,6 +59,10 @@
         return ResponseCode::SoftapStatusResult;
     }
 
+    if (ensure_entropy_file_exists() < 0) {
+        ALOGE("Wi-Fi entropy file was not created");
+    }
+
     if ((pid = fork()) < 0) {
         ALOGE("fork failed (%s)", strerror(errno));
         return ResponseCode::ServiceStartFailed;
diff --git a/server/main.cpp b/server/main.cpp
index 6af1e4e..5e189cc 100644
--- a/server/main.cpp
+++ b/server/main.cpp
@@ -37,6 +37,12 @@
 #include "FwmarkServer.h"
 
 static void blockSigpipe();
+static void remove_pid_file();
+static bool write_pid_file();
+
+const char* const PID_FILE_PATH = "/data/misc/net/netd_pid";
+const int PID_FILE_FLAGS = O_CREAT | O_TRUNC | O_WRONLY | O_NOFOLLOW | O_CLOEXEC;
+const mode_t PID_FILE_MODE = S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH;  // mode 0644, rw-r--r--
 
 int main() {
 
@@ -47,6 +53,7 @@
     FwmarkServer* fwmarkServer;
 
     ALOGI("Netd 1.0 starting");
+    remove_pid_file();
 
     blockSigpipe();
 
@@ -92,15 +99,52 @@
         exit(1);
     }
 
-    // Eventually we'll become the monitoring thread
+    bool wrote_pid = write_pid_file();
+
     while(1) {
-        sleep(1000);
+        sleep(30); // 30 sec
+        if (!wrote_pid) {
+            wrote_pid = write_pid_file();
+        }
     }
 
     ALOGI("Netd exiting");
+    remove_pid_file();
     exit(0);
 }
 
+static bool write_pid_file() {
+    char pid_buf[20];  // current pid_max is 32768, so plenty of room
+    snprintf(pid_buf, sizeof(pid_buf), "%ld\n", (long)getpid());
+
+    int fd = open(PID_FILE_PATH, PID_FILE_FLAGS, PID_FILE_MODE);
+    if (fd == -1) {
+        ALOGE("Unable to create pid file (%s)", strerror(errno));
+        return false;
+    }
+
+    // File creation is affected by umask, so make sure the right mode bits are set.
+    if (fchmod(fd, PID_FILE_MODE) == -1) {
+        ALOGE("failed to set mode 0%o on %s (%s)", PID_FILE_MODE, PID_FILE_PATH, strerror(errno));
+        close(fd);
+        remove_pid_file();
+        return false;
+    }
+
+    if (write(fd, pid_buf, strlen(pid_buf)) != (ssize_t)strlen(pid_buf)) {
+        ALOGE("Unable to write to pid file (%s)", strerror(errno));
+        close(fd);
+        remove_pid_file();
+        return false;
+    }
+    close(fd);
+    return true;
+}
+
+static void remove_pid_file() {
+    unlink(PID_FILE_PATH);
+}
+
 static void blockSigpipe()
 {
     sigset_t mask;