Changes to forwarding for wifi calling.

1. Support multiple forwarding requests. Keep track of all
   requests inside TetherController, and enable system
   forwarding any time there is more than one active request.
2. Enable both IPv4 and IPv6 forwarding.

Bug: 19500693
Change-Id: Ic81bae7b399bc6ebf6a63de4bcd341885638dfa4
diff --git a/server/CommandListener.cpp b/server/CommandListener.cpp
index b8bcf1a..76281fd 100644
--- a/server/CommandListener.cpp
+++ b/server/CommandListener.cpp
@@ -502,32 +502,34 @@
                  NetdCommand("ipfwd") {
 }
 
-int CommandListener::IpFwdCmd::runCommand(SocketClient *cli,
-                                                      int argc, char **argv) {
-    int rc = 0;
+int CommandListener::IpFwdCmd::runCommand(SocketClient *cli, int argc, char **argv) {
+    bool success;
 
-    if (argc < 2) {
+    if (argc == 2 && !strcmp(argv[1], "status")) {
+        char *tmp = NULL;
+
+        asprintf(&tmp, "Forwarding %s",
+                 ((sTetherCtrl->forwardingRequestCount() > 0) ? "enabled" : "disabled"));
+        cli->sendMsg(ResponseCode::IpFwdStatusResult, tmp, false);
+        free(tmp);
+        return 0;
+    }
+
+    if (argc < 3) {
         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);
+    if (!strcmp(argv[1], "enable")) {
+        success = sTetherCtrl->enableForwarding(argv[2]);
     } else if (!strcmp(argv[1], "disable")) {
-        rc = sTetherCtrl->setIpFwdEnabled(false);
+        success = sTetherCtrl->disableForwarding(argv[2]);
     } else {
         cli->sendMsg(ResponseCode::CommandSyntaxError, "Unknown ipfwd cmd", false);
         return 0;
     }
 
-    if (!rc) {
+    if (success) {
         cli->sendMsg(ResponseCode::CommandOkay, "ipfwd operation succeeded", false);
     } else {
         cli->sendMsg(ResponseCode::OperationFailed, "ipfwd operation failed", true);
diff --git a/server/TetherController.cpp b/server/TetherController.cpp
index fb51c06..dad03b4 100644
--- a/server/TetherController.cpp
+++ b/server/TetherController.cpp
@@ -36,12 +36,50 @@
 #include "Permission.h"
 #include "TetherController.h"
 
+namespace {
+
+static const char BP_TOOLS_MODE[] = "bp-tools";
+static const char IPV4_FORWARDING_PROC_FILE[] = "/proc/sys/net/ipv4/ip_forward";
+static const char IPV6_FORWARDING_PROC_FILE[] = "/proc/sys/net/ipv6/conf/all/forwarding";
+
+bool writeToFile(const char* filename, const char* value) {
+    int fd = open(filename, O_WRONLY);
+    if (fd < 0) {
+        ALOGE("Failed to open %s: %s", filename, strerror(errno));
+        return false;
+    }
+
+    const ssize_t len = strlen(value);
+    if (write(fd, value, len) != len) {
+        ALOGE("Failed to write %s to %s: %s", value, filename, strerror(errno));
+        close(fd);
+        return false;
+    }
+    close(fd);
+    return true;
+}
+
+bool inBpToolsMode() {
+    // In BP tools mode, do not disable IP forwarding
+    char bootmode[PROPERTY_VALUE_MAX] = {0};
+    property_get("ro.bootmode", bootmode, "unknown");
+    return !strcmp(BP_TOOLS_MODE, bootmode);
+}
+
+}  // namespace
+
+
 TetherController::TetherController() {
     mInterfaces = new InterfaceCollection();
     mDnsNetId = 0;
     mDnsForwarders = new NetAddressCollection();
     mDaemonFd = -1;
     mDaemonPid = 0;
+    if (inBpToolsMode()) {
+        enableForwarding(BP_TOOLS_MODE);
+    } else {
+        setIpFwdEnabled();
+    }
 }
 
 TetherController::~TetherController() {
@@ -53,51 +91,33 @@
     mInterfaces->clear();
 
     mDnsForwarders->clear();
+    mForwardingRequests.clear();
 }
 
-int TetherController::setIpFwdEnabled(bool enable) {
-
-    ALOGD("Setting IP forward enable = %d", enable);
-
-    // In BP tools mode, do not disable IP forwarding
-    char bootmode[PROPERTY_VALUE_MAX] = {0};
-    property_get("ro.bootmode", bootmode, "unknown");
-    if ((enable == false) && (0 == strcmp("bp-tools", bootmode))) {
-        return 0;
-    }
-
-    int fd = open("/proc/sys/net/ipv4/ip_forward", O_WRONLY);
-    if (fd < 0) {
-        ALOGE("Failed to open ip_forward (%s)", strerror(errno));
-        return -1;
-    }
-
-    if (write(fd, (enable ? "1" : "0"), 1) != 1) {
-        ALOGE("Failed to write ip_forward (%s)", strerror(errno));
-        close(fd);
-        return -1;
-    }
-    close(fd);
-    return 0;
+bool TetherController::setIpFwdEnabled() {
+    bool success = true;
+    const char* value = mForwardingRequests.empty() ? "0" : "1";
+    ALOGD("Setting IP forward enable = %s", value);
+    success &= writeToFile(IPV4_FORWARDING_PROC_FILE, value);
+    success &= writeToFile(IPV6_FORWARDING_PROC_FILE, value);
+    return success;
 }
 
-bool TetherController::getIpFwdEnabled() {
-    int fd = open("/proc/sys/net/ipv4/ip_forward", O_RDONLY);
+bool TetherController::enableForwarding(const char* requester) {
+    // Don't return an error if this requester already requested forwarding. Only return errors for
+    // things that the caller caller needs to care about, such as "couldn't write to the file to
+    // enable forwarding".
+    mForwardingRequests.insert(requester);
+    return setIpFwdEnabled();
+}
 
-    if (fd < 0) {
-        ALOGE("Failed to open ip_forward (%s)", strerror(errno));
-        return false;
-    }
+bool TetherController::disableForwarding(const char* requester) {
+    mForwardingRequests.erase(requester);
+    return setIpFwdEnabled();
+}
 
-    char enabled;
-    if (read(fd, &enabled, 1) != 1) {
-        ALOGE("Failed to read ip_forward (%s)", strerror(errno));
-        close(fd);
-        return -1;
-    }
-
-    close(fd);
-    return (enabled  == '1' ? true : false);
+size_t TetherController::forwardingRequestCount() {
+    return mForwardingRequests.size();
 }
 
 #define TETHER_START_CONST_ARG        8
diff --git a/server/TetherController.h b/server/TetherController.h
index 1c32627..91ffb9c 100644
--- a/server/TetherController.h
+++ b/server/TetherController.h
@@ -18,6 +18,8 @@
 #define _TETHER_CONTROLLER_H
 
 #include <netinet/in.h>
+#include <set>
+#include <string>
 
 #include "List.h"
 
@@ -32,16 +34,17 @@
     NetAddressCollection *mDnsForwarders;
     pid_t                 mDaemonPid;
     int                   mDaemonFd;
+    std::set<std::string> mForwardingRequests;
 
 public:
     TetherController();
     virtual ~TetherController();
 
-    int setIpFwdEnabled(bool enable);
-    bool getIpFwdEnabled();
+    bool enableForwarding(const char* requester);
+    bool disableForwarding(const char* requester);
+    size_t forwardingRequestCount();
 
     int startTethering(int num_addrs, struct in_addr* addrs);
-
     int stopTethering();
     bool isTetheringStarted();
 
@@ -55,6 +58,7 @@
 
 private:
     int applyDnsInterfaces();
+    bool setIpFwdEnabled();
 };
 
 #endif