From 9d10b341a0ba46f108cb96e46691197d778cbc06 Mon Sep 17 00:00:00 2001 From: San Mehat Date: Mon, 18 Jan 2010 09:51:02 -0800 Subject: [PATCH] netd: Plumb in the tethering interfaces Signed-off-by: San Mehat --- Android.mk | 3 +- CommandListener.cpp | 139 ++++++++++++++++++++++++++++++-- CommandListener.h | 3 + ResponseCode.h | 22 ++--- TetherController.cpp | 224 +++++++++++++++++++++++++++++++++++++++++++++++++++ TetherController.h | 52 ++++++++++++ ndc.c | 4 +- 7 files changed, 422 insertions(+), 25 deletions(-) create mode 100644 TetherController.cpp create mode 100644 TetherController.h diff --git a/Android.mk b/Android.mk index c78d102..e4a640c 100644 --- a/Android.mk +++ b/Android.mk @@ -15,7 +15,8 @@ LOCAL_SRC_FILES:= \ NetdCommand.cpp \ NetlinkManager.cpp \ NetlinkHandler.cpp \ - logwrapper.c + logwrapper.c \ + TetherController.cpp LOCAL_MODULE:= netd diff --git a/CommandListener.cpp b/CommandListener.cpp index fa76f31..56f55fb 100644 --- a/CommandListener.cpp +++ b/CommandListener.cpp @@ -30,12 +30,17 @@ #include "CommandListener.h" #include "ResponseCode.h" +TetherController *CommandListener::sTetherCtrl = NULL; + CommandListener::CommandListener() : FrameworkListener("netd") { registerCmd(new ListInterfacesCmd()); registerCmd(new IpFwdCmd()); registerCmd(new TetherCmd()); registerCmd(new NatCmd()); + + if (!sTetherCtrl) + sTetherCtrl = new TetherController(); } CommandListener::ListInterfacesCmd::ListInterfacesCmd() : @@ -44,6 +49,7 @@ CommandListener::ListInterfacesCmd::ListInterfacesCmd() : int CommandListener::ListInterfacesCmd::runCommand(SocketClient *cli, int argc, char **argv) { + // XXX: Send a series of InterfaceListResults cli->sendMsg(ResponseCode::CommandOkay, "Interfaces listed.", false); return 0; } @@ -54,6 +60,34 @@ CommandListener::IpFwdCmd::IpFwdCmd() : int CommandListener::IpFwdCmd::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], "status")) { + char *tmp = NULL; + + asprintf(&tmp, "Forwarding %s", (sTetherCtrl->getIpFwdEnabled() ? "enabled" : "disabled")); + cli->sendMsg(ResponseCode::IpFwdStatusResult, tmp, false); + free(tmp); + return 0; + } else if (!strcmp(argv[1], "enable")) { + rc = sTetherCtrl->setIpFwdEnabled(true); + } else if (!strcmp(argv[1], "disable")) { + rc = sTetherCtrl->setIpFwdEnabled(false); + } else { + cli->sendMsg(ResponseCode::CommandSyntaxError, "Unknown ipfwd cmd", false); + return 0; + } + + if (!rc) { + cli->sendMsg(ResponseCode::CommandOkay, "ipfwd operation succeeded", false); + } else { + cli->sendMsg(ResponseCode::OperationFailed, "ipfwd operation failed", true); + } return 0; } @@ -64,19 +98,86 @@ CommandListener::TetherCmd::TetherCmd() : int CommandListener::TetherCmd::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], "start")) { - } else if (!strcmp(argv[1], "stop")) { + if (!strcmp(argv[1], "stop")) { + rc = sTetherCtrl->stopTethering(); } else if (!strcmp(argv[1], "status")) { - } else if (!strcmp(argv[1], "interface")) { - } else if (!strcmp(argv[1], "dns")) { - } else { - cli->sendMsg(ResponseCode::CommandSyntaxError, "Unknown tether cmd", false); + char *tmp = NULL; + + asprintf(&tmp, "Tethering services %s", + (sTetherCtrl->isTetheringStarted() ? "started" : "stopped")); + cli->sendMsg(ResponseCode::TetherStatusResult, 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")) { + struct in_addr s, e; + + if (!inet_aton(argv[2], &s)) { + cli->sendMsg(ResponseCode::CommandParameterError, "Invalid start address", false); + return 0; + } + if (!inet_aton(argv[3], &e)) { + cli->sendMsg(ResponseCode::CommandParameterError, "Invalid end address", false); + return 0; + } + rc = sTetherCtrl->startTethering(s, e); + } 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 if (!strcmp(argv[1], "dns")) { + if (!strcmp(argv[2], "set")) { + rc = sTetherCtrl->setDnsForwarders(&argv[3], argc - 3); + } else if (!strcmp(argv[2], "list")) { + NetAddressCollection *dlist = sTetherCtrl->getDnsForwarders(); + NetAddressCollection::iterator it; + + for (it = dlist->begin(); it != dlist->end(); ++it) { + cli->sendMsg(ResponseCode::TetherDnsFwdTgtListResult, inet_ntoa(*it), false); + } + } else { + cli->sendMsg(ResponseCode::CommandParameterError, + "Unknown tether interface operation", false); + return 0; + } + } else { + cli->sendMsg(ResponseCode::CommandSyntaxError, "Unknown tether cmd", false); + return 0; + } + } + + if (!rc) { + cli->sendMsg(ResponseCode::CommandOkay, "Tether operation succeeded", false); + } else { + cli->sendMsg(ResponseCode::OperationFailed, "Tether operation failed", true); } return 0; @@ -88,6 +189,32 @@ CommandListener::NatCmd::NatCmd() : int CommandListener::NatCmd::runCommand(SocketClient *cli, int argc, char **argv) { + int rc = 0; + + if (argc < 3) { + cli->sendMsg(ResponseCode::CommandSyntaxError, "Missing argument", false); + return 0; + } + + if (!strcmp(argv[1], "binding")) { + if (!strcmp(argv[2], "add")) { + rc = 0; + } else if (!strcmp(argv[2], "remove")) { + rc = 0; + } else { + cli->sendMsg(ResponseCode::CommandSyntaxError, "Unknown nat binding cmd", false); + return 0; + } + } else { + cli->sendMsg(ResponseCode::CommandSyntaxError, "Unknown nat cmd", false); + return 0; + } + + if (!rc) { + cli->sendMsg(ResponseCode::CommandOkay, "Nat operation succeeded", false); + } else { + cli->sendMsg(ResponseCode::OperationFailed, "Nat operation failed", true); + } return 0; } diff --git a/CommandListener.h b/CommandListener.h index c3fee39..1ec65ae 100644 --- a/CommandListener.h +++ b/CommandListener.h @@ -19,8 +19,11 @@ #include #include "NetdCommand.h" +#include "TetherController.h" class CommandListener : public FrameworkListener { + static TetherController *sTetherCtrl; + public: CommandListener(); virtual ~CommandListener() {} diff --git a/ResponseCode.h b/ResponseCode.h index bb27787..37f0008 100644 --- a/ResponseCode.h +++ b/ResponseCode.h @@ -21,15 +21,16 @@ class ResponseCode { public: // 100 series - Requestion action was initiated; expect another reply // before proceeding with a new command. - static const int ActionInitiated = 100; + static const int ActionInitiated = 100; + static const int InterfaceListResult = 110; + static const int TetherInterfaceListResult = 111; + static const int TetherDnsFwdTgtListResult = 112; - static const int VolumeListResult = 110; - static const int AsecListResult = 111; // 200 series - Requested action has been successfully completed static const int CommandOkay = 200; - static const int ShareAvailabilityResult = 210; - static const int AsecPathResult = 211; + static const int TetherStatusResult = 210; + static const int IpFwdStatusResult = 211; // 400 series - The command was accepted but the requested action // did not take place. @@ -41,16 +42,5 @@ public: static const int CommandParameterError = 501; // 600 series - Unsolicited broadcasts - static const int UnsolicitedInformational = 600; - static const int VolumeStateChange = 605; - static const int VolumeMountFailedBlank = 610; - static const int VolumeMountFailedDamaged = 611; - static const int VolumeMountFailedNoMedia = 612; - - static const int ShareAvailabilityChange = 620; - - static const int VolumeDiskInserted = 630; - static const int VolumeDiskRemoved = 631; - static const int VolumeBadRemoval = 632; }; #endif diff --git a/TetherController.cpp b/TetherController.cpp new file mode 100644 index 0000000..7a352a1 --- /dev/null +++ b/TetherController.cpp @@ -0,0 +1,224 @@ +/* + * 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 +#include +#include +#include +#include +#include +#include + +#define LOG_TAG "TetherController" +#include + + +#include "TetherController.h" + +TetherController::TetherController() { + mInterfaces = new InterfaceCollection(); + mDnsForwarders = new NetAddressCollection(); + mDaemonFd = -1; + mDaemonPid = 0; +} + +TetherController::~TetherController() { + InterfaceCollection::iterator it; + + for (it = mInterfaces->begin(); it != mInterfaces->end(); ++it) { + free(*it); + } + mInterfaces->clear(); + + mDnsForwarders->clear(); +} + +int TetherController::setIpFwdEnabled(bool enable) { + + LOGD("Setting IP forward enable = %d", enable); + int fd = open("/proc/sys/net/ipv4/ip_forward", O_WRONLY); + if (fd < 0) { + LOGE("Failed to open ip_forward (%s)", strerror(errno)); + return -1; + } + + if (write(fd, (enable ? "1" : "0"), 1) != 1) { + LOGE("Failed to write ip_forward (%s)", strerror(errno)); + return -1; + } + close(fd); + return 0; +} + +bool TetherController::getIpFwdEnabled() { + int fd = open("/proc/sys/net/ipv4/ip_forward", O_RDONLY); + + if (fd < 0) { + LOGE("Failed to open ip_forward (%s)", strerror(errno)); + return false; + } + + char enabled; + if (read(fd, &enabled, 1) != 1) { + LOGE("Failed to read ip_forward (%s)", strerror(errno)); + return -1; + } + + close(fd); + + return (enabled == '1' ? true : false); +} + +int TetherController::startTethering(struct in_addr dhcpStart, struct in_addr dhcpEnd) { + + if (mDaemonPid != 0) { + LOGE("Tethering already started"); + errno = EBUSY; + return -1; + } + + LOGD("Starting tethering services"); + + pid_t pid; + int pipefd[2]; + + if (pipe(pipefd) < 0) { + LOGE("pipe failed (%s)", strerror(errno)); + return -1; + } + + /* + * TODO: Create a monitoring thread to handle and restart + * the daemon if it exits prematurely + */ + if ((pid = fork()) < 0) { + LOGE("fork failed (%s)", strerror(errno)); + close(pipefd[0]); + close(pipefd[1]); + return -1; + } + + if (!pid) { + close(pipefd[1]); + if (pipefd[0] != STDIN_FILENO) { + if (dup2(pipefd[0], STDIN_FILENO) != STDIN_FILENO) { + LOGE("dup2 failed (%s)", strerror(errno)); + return -1; + } + close(pipefd[0]); + } + char *start = strdup(inet_ntoa(dhcpStart)); + char *end = strdup(inet_ntoa(dhcpEnd)); + char *range; + + asprintf(&range, "--dhcp-range=%s,%s,1h", start, end); + + if (execl("/system/bin/dnsmasq", "/system/bin/dnsmasq", "--no-daemon", "--no-resolv", + "--no-poll", "--no-hosts", range, (char *) NULL)) { + LOGE("execl failed (%s)", strerror(errno)); + } + LOGE("Should never get here!"); + return 0; + } else { + close(pipefd[0]); + mDaemonPid = pid; + mDaemonFd = pipefd[1]; + LOGD("Tethering services running"); + } + + return 0; +} + +int TetherController::stopTethering() { + + if (mDaemonPid == 0) { + LOGE("Tethering already stopped"); + return 0; + } + + LOGD("Stopping tethering services"); + + kill(mDaemonPid, SIGTERM); + mDaemonPid = 0; + close(mDaemonFd); + mDaemonFd = -1; + return 0; +} + +bool TetherController::isTetheringStarted() { + return (mDaemonPid == 0 ? false : true); +} + +int TetherController::setDnsForwarders(char **servers, int numServers) { + int i; + char daemonCmd[1024]; + + strcpy(daemonCmd, "update_dns"); + + mDnsForwarders->clear(); + for (i = 0; i < numServers; i++) { + LOGD("setDnsForwarders(%d = '%s')", i, servers[i]); + + struct in_addr a; + + if (!inet_aton(servers[i], &a)) { + LOGE("Failed to parse DNS server '%s'", servers[i]); + mDnsForwarders->clear(); + return -1; + } + strcat(daemonCmd, ":"); + strcat(daemonCmd, servers[i]); + mDnsForwarders->push_back(a); + } + + if (mDaemonFd != -1) { + LOGD("Sending update msg to dnsmasq [%s]", daemonCmd); + if (write(mDaemonFd, daemonCmd, strlen(daemonCmd) +1) < 0) { + LOGE("Failed to send update command to dnsmasq (%s)", strerror(errno)); + mDnsForwarders->clear(); + return -1; + } + } + return 0; +} + +NetAddressCollection *TetherController::getDnsForwarders() { + return mDnsForwarders; +} + +int TetherController::tetherInterface(const char *interface) { + mInterfaces->push_back(strdup(interface)); + return 0; +} + +int TetherController::untetherInterface(const char *interface) { + InterfaceCollection::iterator it; + + for (it = mInterfaces->begin(); it != mInterfaces->end(); ++it) { + if (!strcmp(interface, *it)) { + free(*it); + mInterfaces->erase(it); + return 0; + } + } + errno = ENOENT; + return -1; +} + +InterfaceCollection *TetherController::getTetheredInterfaceList() { + return mInterfaces; +} + diff --git a/TetherController.h b/TetherController.h new file mode 100644 index 0000000..208780a --- /dev/null +++ b/TetherController.h @@ -0,0 +1,52 @@ +/* + * 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 _TETHER_CONTROLLER_H +#define _TETHER_CONTROLLER_H + +#include + +#include + +typedef android::List InterfaceCollection; +typedef android::List NetAddressCollection; + +class TetherController { + InterfaceCollection *mInterfaces; + NetAddressCollection *mDnsForwarders; + pid_t mDaemonPid; + int mDaemonFd; + +public: + TetherController(); + virtual ~TetherController(); + + int setIpFwdEnabled(bool enable); + bool getIpFwdEnabled(); + + int startTethering(struct in_addr dhcpStart, struct in_addr dhcpEnd); + int stopTethering(); + bool isTetheringStarted(); + + int setDnsForwarders(char **servers, int numServers); + NetAddressCollection *getDnsForwarders(); + + int tetherInterface(const char *interface); + int untetherInterface(const char *interface); + InterfaceCollection *getTetheredInterfaceList(); +}; + +#endif diff --git a/ndc.c b/ndc.c index 8c6f146..a828f9b 100644 --- a/ndc.c +++ b/ndc.c @@ -41,7 +41,7 @@ int main(int argc, char **argv) { if (argc < 2) usage(argv[0]); - if ((sock = socket_local_client("vold", + if ((sock = socket_local_client("netd", ANDROID_SOCKET_NAMESPACE_RESERVED, SOCK_STREAM)) < 0) { fprintf(stderr, "Error connecting (%s)\n", strerror(errno)); @@ -106,7 +106,7 @@ static int do_monitor(int sock, int stop_after_cmd) { memset(buffer, 0, 4096); if ((rc = read(sock, buffer, 4096)) <= 0) { if (rc == 0) - fprintf(stderr, "Lost connection to Vold - did it crash?\n"); + fprintf(stderr, "Lost connection to Netd - did it crash?\n"); else fprintf(stderr, "Error reading data (%s)\n", strerror(errno)); free(buffer); -- 2.11.0