summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorSubash Abhinov Kasiviswanathan <subashab@codeaurora.org>2014-07-15 00:08:40 -0600
committerLinux Build Service Account <lnxbuild@localhost>2014-11-04 08:44:58 -0700
commit0e217b53c619849dc3aa4d9f89932b1040b2f814 (patch)
tree12141b64a9e3a6992bbd8b467cb54930fe6ff314
parentc9e584f83bc95880f9fcce4711122d2f8c60d1bc (diff)
downloadandroid_system_netd-0e217b53c619849dc3aa4d9f89932b1040b2f814.tar.gz
android_system_netd-0e217b53c619849dc3aa4d9f89932b1040b2f814.tar.bz2
android_system_netd-0e217b53c619849dc3aa4d9f89932b1040b2f814.zip
netd: IPV6 tethering support
- Start NDP proxy daemon when tethering is enabled - Add new interface commands "add_upstream" and "remove_upstream". Used to provide the complete set of interfaces to be proxied to the NDP proxy daemon - Enable ipv6 forwarding - After repeatedly toggling tethering/Wifi hotspot on and off, hotspot may not turn on anymore. It appears untethering is unsuccessful and this eventually leads to a timeout and a framework reboot. The NDP proxy daemon appears to be started multiple times even though there is no ipv6 upstream interface present. There appears to be a signifcant number of calls to fork and exec this daemon even though this functionality is not needed in this case. Fix this overhead by invoking the daemon only if there are atleast 2 interfaces to establish a bridge and proxy the NDP messages. Conflicts: server/TetherController.cpp CRs-fixed: 665103 Change-Id: I89170f8acd60b949ede749f353acd27363ff5798
-rw-r--r--server/CommandListener.cpp74
-rw-r--r--server/CommandListener.h7
-rw-r--r--server/ResponseCode.h1
-rw-r--r--server/TetherController.cpp198
-rw-r--r--server/TetherController.h9
5 files changed, 287 insertions, 2 deletions
diff --git a/server/CommandListener.cpp b/server/CommandListener.cpp
index b57ec756..ededddb2 100644
--- a/server/CommandListener.cpp
+++ b/server/CommandListener.cpp
@@ -587,6 +587,7 @@ int CommandListener::TetherCmd::runCommand(SocketClient *cli,
int argc, char **argv) {
int rc = 0;
+ ALOGD("TetherCmd::runCommand. argc: %d. argv[0]: %s", argc, argv[0]);
if (argc < 2) {
cli->sendMsg(ResponseCode::CommandSyntaxError, "Missing argument", false);
return 0;
@@ -655,6 +656,11 @@ int CommandListener::TetherCmd::runCommand(SocketClient *cli,
} else if (!strcmp(argv[2], "remove")) {
rc = sTetherCtrl->untetherInterface(argv[3]);
/* else if (!strcmp(argv[2], "list")) handled above */
+ } else if (!strcmp(argv[2], "add_upstream")) {
+ ALOGD("command %s %s %s %s", argv[0], argv[1], argv[2], argv[3]);
+ rc = sTetherCtrl->addUpstreamInterface(argv[3]);
+ } else if (!strcmp(argv[2], "remove_upstream")) {
+ rc = sTetherCtrl->removeUpstreamInterface(argv[3]);
} else {
cli->sendMsg(ResponseCode::CommandParameterError,
"Unknown tether interface operation", false);
@@ -689,6 +695,74 @@ int CommandListener::TetherCmd::runCommand(SocketClient *cli,
return 0;
}
+CommandListener::V6RtrAdvCmd::V6RtrAdvCmd() :
+ NetdCommand("v6rtradv") {
+}
+
+int CommandListener::V6RtrAdvCmd::runCommand(SocketClient *cli,
+ int argc, char **argv) {
+ int rc = 0;
+
+ if (argc < 2) {
+ cli->sendMsg(ResponseCode::CommandSyntaxError, "Missing argument", false);
+ return 0;
+ }
+
+ if (!strcmp(argv[1], "stop")) {
+ rc = sTetherCtrl->stopV6RtrAdv();
+ } else if (!strcmp(argv[1], "status")) {
+ char *tmp = NULL;
+
+ asprintf(&tmp, "IPv6 Router Advertisement service %s",
+ (sTetherCtrl->isV6RtrAdvStarted() ? "started" : "stopped"));
+ cli->sendMsg(ResponseCode::V6RtrAdvResult, tmp, false);
+ free(tmp);
+ return 0;
+ } else {
+ /*
+ * These commands take a minimum of 4 arguments
+ */
+ if (argc < 4) {
+ cli->sendMsg(ResponseCode::CommandSyntaxError, "Missing argument", false);
+ return 0;
+ }
+
+ if (!strcmp(argv[1], "start")) {
+ int num_ifaces = argc - 2;
+ int arg_index = 2;
+ rc = sTetherCtrl->startV6RtrAdv(num_ifaces, &argv[arg_index]);
+ } else if (!strcmp(argv[1], "interface")) {
+ if (!strcmp(argv[2], "add")) {
+ rc = sTetherCtrl->tetherInterface(argv[3]);
+ } else if (!strcmp(argv[2], "remove")) {
+ rc = sTetherCtrl->untetherInterface(argv[3]);
+ } else if (!strcmp(argv[2], "list")) {
+ InterfaceCollection *ilist = sTetherCtrl->getTetheredInterfaceList();
+ InterfaceCollection::iterator it;
+
+ for (it = ilist->begin(); it != ilist->end(); ++it) {
+ cli->sendMsg(ResponseCode::TetherInterfaceListResult, *it, false);
+ }
+ } else {
+ cli->sendMsg(ResponseCode::CommandParameterError,
+ "Unknown tether interface operation", false);
+ return 0;
+ }
+ } else {
+ cli->sendMsg(ResponseCode::CommandSyntaxError, "Unknown v6rtradv cmd", false);
+ return 0;
+ }
+ }
+
+ if (!rc) {
+ cli->sendMsg(ResponseCode::CommandOkay, "V6RtrAdv operation succeeded", false);
+ } else {
+ cli->sendMsg(ResponseCode::OperationFailed, "V6RtrAdv operation failed", true);
+ }
+
+ return 0;
+}
+
CommandListener::NatCmd::NatCmd() :
NetdCommand("nat") {
}
diff --git a/server/CommandListener.h b/server/CommandListener.h
index 7819db60..c1f7867c 100644
--- a/server/CommandListener.h
+++ b/server/CommandListener.h
@@ -94,6 +94,13 @@ private:
int runCommand(SocketClient *c, int argc, char ** argv);
};
+ class V6RtrAdvCmd: public NetdCommand {
+ public:
+ V6RtrAdvCmd();
+ virtual ~V6RtrAdvCmd() {}
+ int runCommand(SocketClient *c, int argc, char ** argv);
+ };
+
class NatCmd : public NetdCommand {
public:
NatCmd();
diff --git a/server/ResponseCode.h b/server/ResponseCode.h
index 6a0c22c3..594d997b 100644
--- a/server/ResponseCode.h
+++ b/server/ResponseCode.h
@@ -46,6 +46,7 @@ public:
static const int TetheringStatsResult = 221;
static const int DnsProxyQueryResult = 222;
static const int ClatdStatusResult = 223;
+ static const int V6RtrAdvResult = 227;
// 400 series - The command was accepted but the requested action
// did not take place.
diff --git a/server/TetherController.cpp b/server/TetherController.cpp
index fb51c06c..f7108762 100644
--- a/server/TetherController.cpp
+++ b/server/TetherController.cpp
@@ -23,11 +23,15 @@
#include <sys/stat.h>
#include <sys/types.h>
#include <sys/wait.h>
+#include <linux/capability.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#define LOG_TAG "TetherController"
+#define LOG_NDEBUG 0
+#define LOG_NDDEBUG 0
+#define LOG_NIDEBUG 0
#include <cutils/log.h>
#include <cutils/properties.h>
@@ -36,9 +40,20 @@
#include "Permission.h"
#include "TetherController.h"
+#include <private/android_filesystem_config.h>
+#include <unistd.h>
+
+#define RTRADVDAEMON "/system/bin/radish"
+#define IP4_CFG_IP_FORWARD "/proc/sys/net/ipv4/ip_forward"
+#define IP6_CFG_ALL_PROXY_NDP "/proc/sys/net/ipv6/conf/all/proxy_ndp"
+#define IP6_CFG_ALL_FORWARDING "/proc/sys/net/ipv6/conf/all/forwarding"
+#define IP6_IFACE_CFG_ACCEPT_RA "/proc/sys/net/ipv6/conf/%s/accept_ra"
+#define PROC_PATH_SIZE 255
+
+
TetherController::TetherController() {
mInterfaces = new InterfaceCollection();
- mDnsNetId = 0;
+ mUpstreamInterfaces = new InterfaceCollection();
mDnsForwarders = new NetAddressCollection();
mDaemonFd = -1;
mDaemonPid = 0;
@@ -52,9 +67,32 @@ TetherController::~TetherController() {
}
mInterfaces->clear();
+ for (it = mUpstreamInterfaces->begin(); it != mUpstreamInterfaces->end(); ++it) {
+ free(*it);
+ }
+ mUpstreamInterfaces->clear();
+
mDnsForwarders->clear();
}
+static int config_write_setting(const char *path, const char *value)
+{
+ int fd = open(path, O_WRONLY);
+
+ ALOGD("config_write_setting(%s, %s)", path, value);
+ if (fd < 0) {
+ ALOGE("Failed to open %s (%s)", path, strerror(errno));
+ return -1;
+ }
+ if (write(fd, value, strlen(value)) != (int)strlen(value)) {
+ ALOGE("Failed to write to %s (%s)", path, strerror(errno));
+ close(fd);
+ return -1;
+ }
+ close(fd);
+ return 0;
+}
+
int TetherController::setIpFwdEnabled(bool enable) {
ALOGD("Setting IP forward enable = %d", enable);
@@ -78,6 +116,17 @@ int TetherController::setIpFwdEnabled(bool enable) {
return -1;
}
close(fd);
+ if (config_write_setting(
+ IP6_CFG_ALL_PROXY_NDP, enable ? "2" : "0")) {
+ ALOGE("Failed to write proxy_ndp (%s)", strerror(errno));
+ return -1;
+ }
+ if (config_write_setting(
+ IP6_CFG_ALL_FORWARDING, enable ? "2" : "0")) {
+ ALOGE("Failed to write ip6 forwarding (%s)", strerror(errno));
+ return -1;
+ }
+
return 0;
}
@@ -198,6 +247,107 @@ bool TetherController::isTetheringStarted() {
return (mDaemonPid == 0 ? false : true);
}
+int TetherController::startV6RtrAdv(int num_ifaces, char **ifaces) {
+ int pid;
+ int num_processed_args = 1;
+ gid_t groups [] = { AID_NET_ADMIN, AID_NET_RAW, AID_INET };
+
+ if (num_ifaces < 2) {
+ ALOGD("Need atleast two interfaces to start Router advertisement daemon");
+ return 0;
+ }
+
+ if ((pid = fork()) < 0) {
+ ALOGE("%s: fork failed (%s)", __func__, strerror(errno));
+ return -1;
+ }
+ if (!pid) {
+ char **args;
+ const char *cmd = RTRADVDAEMON;
+
+ args = (char **)calloc(num_ifaces * 3 + 2, sizeof(char *));
+
+ args[0] = strdup(RTRADVDAEMON);
+ for (int i=0; i < num_ifaces; i++) {
+ int aidx = 3 * i + num_processed_args;
+ args[aidx] = (char *)"-i";
+ args[aidx + 1] = ifaces[i];
+ args[aidx + 2] = (char *)"-x";
+ }
+
+
+ setgroups(sizeof(groups)/sizeof(groups[0]), groups);
+ setresgid(AID_RADIO, AID_RADIO, AID_RADIO);
+ setresuid(AID_RADIO, AID_RADIO, AID_RADIO);
+
+ if (execv(cmd, args)) {
+ ALOGE("Unable to exec %s: (%s)" , cmd, strerror(errno));
+ }
+ free(args[0]);
+ free(args);
+ exit(0);
+ } else {
+ mRtrAdvPid = pid;
+ ALOGD("Router advertisement daemon running");
+ }
+ return 0;
+}
+
+int TetherController::stopV6RtrAdv() {
+ if (!mRtrAdvPid) {
+ ALOGD("Router advertisement daemon already stopped");
+ return 0;
+ }
+
+ kill(mRtrAdvPid, SIGTERM);
+ waitpid(mRtrAdvPid, NULL, 0);
+ mRtrAdvPid = 0;
+ ALOGD("Router advertisement daemon stopped");
+ return 0;
+}
+
+int TetherController::addV6RtrAdvIface(const char *iface) {
+ char **args;
+ int i;
+ int len;
+ InterfaceCollection::iterator it;
+ /* For now, just stop and start the daemon with the new interface list */
+
+ len = mInterfaces->size() + mUpstreamInterfaces->size();
+ ALOGD("addV6RtrAdvIface: len = %d. Iface: %s\n", len, iface);
+ args = (char **)calloc(len, sizeof(char *));
+
+ if (!args) {
+ errno = ENOMEM;
+ return -1;
+ }
+
+ for (i = 0, it = mInterfaces->begin(); it != mInterfaces->end(); it++, i++) {
+ args[i] = *it;
+ }
+
+ for (it = mUpstreamInterfaces->begin(); i < len && it != mUpstreamInterfaces->end(); it++, i++) {
+ args[i] = *it;
+ }
+
+ stopV6RtrAdv();
+ startV6RtrAdv(i, args);
+
+ free(args);
+
+ return 0;
+}
+
+int TetherController::removeV6RtrAdvIface(const char *iface) {
+ /* For now, just call addV6RtrAdvIface, since that will stop and
+ * start the daemon with the updated interfaces
+ */
+ return addV6RtrAdvIface(iface);
+}
+bool TetherController::isV6RtrAdvStarted() {
+ return (mRtrAdvPid == 0 ? false : true);
+}
+
#define MAX_CMD_SIZE 1024
int TetherController::setDnsForwarders(unsigned netId, char **servers, int numServers) {
@@ -252,6 +402,48 @@ unsigned TetherController::getDnsNetId() {
return mDnsNetId;
}
+int TetherController::addUpstreamInterface(char *iface)
+{
+ InterfaceCollection::iterator it;
+
+ ALOGD("addUpstreamInterface(%s)\n", iface);
+
+ if (!iface) {
+ ALOGE("addUpstreamInterface: received null interface");
+ return 0;
+ }
+ for (it = mUpstreamInterfaces->begin(); it != mUpstreamInterfaces->end(); ++it) {
+ ALOGD(".");
+ if (*it && !strcmp(iface, *it)) {
+ ALOGD("addUpstreamInterface: interface %s already present", iface);
+ return 0;
+ }
+ }
+ mUpstreamInterfaces->push_back(strdup(iface));
+
+ return addV6RtrAdvIface(iface);
+}
+
+int TetherController::removeUpstreamInterface(char *iface)
+{
+ InterfaceCollection::iterator it;
+
+ if (!iface) {
+ ALOGE("removeUpstreamInterface: Null interface name received");
+ return 0;
+ }
+ for (it = mUpstreamInterfaces->begin(); it != mUpstreamInterfaces->end(); ++it) {
+ if (*it && !strcmp(iface, *it)) {
+ free(*it);
+ mUpstreamInterfaces->erase(it);
+ return removeV6RtrAdvIface(iface);
+ }
+ }
+
+ ALOGW("Couldn't find interface %s to remove", iface);
+ return 0;
+}
+
NetAddressCollection *TetherController::getDnsForwarders() {
return mDnsForwarders;
}
@@ -294,6 +486,8 @@ int TetherController::tetherInterface(const char *interface) {
}
mInterfaces->push_back(strdup(interface));
+ addV6RtrAdvIface(interface);
+
if (applyDnsInterfaces()) {
InterfaceCollection::iterator it;
for (it = mInterfaces->begin(); it != mInterfaces->end(); ++it) {
@@ -318,7 +512,7 @@ int TetherController::untetherInterface(const char *interface) {
if (!strcmp(interface, *it)) {
free(*it);
mInterfaces->erase(it);
-
+ removeV6RtrAdvIface(NULL);
return applyDnsInterfaces();
}
}
diff --git a/server/TetherController.h b/server/TetherController.h
index 1c326270..64c3e946 100644
--- a/server/TetherController.h
+++ b/server/TetherController.h
@@ -32,6 +32,8 @@ class TetherController {
NetAddressCollection *mDnsForwarders;
pid_t mDaemonPid;
int mDaemonFd;
+ pid_t mRtrAdvPid; // IPv6 support
+ InterfaceCollection *mUpstreamInterfaces;
public:
TetherController();
@@ -52,6 +54,13 @@ public:
int tetherInterface(const char *interface);
int untetherInterface(const char *interface);
InterfaceCollection *getTetheredInterfaceList();
+ int startV6RtrAdv(int num_ifaces, char **ifaces);
+ int stopV6RtrAdv();
+ bool isV6RtrAdvStarted();
+ int addV6RtrAdvIface(const char *iface);
+ int removeV6RtrAdvIface(const char *iface);
+ int addUpstreamInterface(char *iface);
+ int removeUpstreamInterface(char *iface);
private:
int applyDnsInterfaces();