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;