Fix tethering in the case of a regular upstream connection.

Fixes tethering via Ethernet, Bluetooth and WiFi (hotspot).

Tethering when the upstream has a DUN-specific APN is likely still broken
(untested).

For now, assign a fixed NetId (a hack) until we can change the framework to
create a valid NetworkAgent and all that jazz.

Bug: 15968336
Bug: 14988803
Change-Id: Idcf4d492d9329a9c87913e27be6dd835a792bea2
diff --git a/server/Android.mk b/server/Android.mk
index 28defba..475d817 100644
--- a/server/Android.mk
+++ b/server/Android.mk
@@ -48,6 +48,7 @@
         FwmarkServer.cpp \
         IdletimerController.cpp \
         InterfaceController.cpp \
+        LocalNetwork.cpp \
         MDnsSdListener.cpp \
         NatController.cpp \
         NetdCommand.cpp \
diff --git a/server/CommandListener.cpp b/server/CommandListener.cpp
index b7723d4..f2a8745 100644
--- a/server/CommandListener.cpp
+++ b/server/CommandListener.cpp
@@ -174,9 +174,9 @@
     if (!sSecondaryTableCtrl)
         sSecondaryTableCtrl = new SecondaryTableController(sNetCtrl);
     if (!sTetherCtrl)
-        sTetherCtrl = new TetherController();
+        sTetherCtrl = new TetherController(sNetCtrl);
     if (!sNatCtrl)
-        sNatCtrl = new NatController(sSecondaryTableCtrl, sNetCtrl);
+        sNatCtrl = new NatController(sNetCtrl);
     if (!sPppCtrl)
         sPppCtrl = new PppController();
     if (!sSoftapCtrl)
diff --git a/server/LocalNetwork.cpp b/server/LocalNetwork.cpp
new file mode 100644
index 0000000..ba0b21e
--- /dev/null
+++ b/server/LocalNetwork.cpp
@@ -0,0 +1,56 @@
+/*
+ * Copyright (C) 2014 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 "LocalNetwork.h"
+
+#include "RouteController.h"
+
+#define LOG_TAG "Netd"
+#include "log/log.h"
+
+LocalNetwork::LocalNetwork(unsigned netId) : Network(netId) {
+}
+
+LocalNetwork::~LocalNetwork() {
+}
+
+Network::Type LocalNetwork::getType() const {
+    return LOCAL;
+}
+
+int LocalNetwork::addInterface(const std::string& interface) {
+    if (hasInterface(interface)) {
+        return 0;
+    }
+    if (int ret = RouteController::addInterfaceToLocalNetwork(mNetId, interface.c_str())) {
+        ALOGE("failed to add interface %s to local netId %u", interface.c_str(), mNetId);
+        return ret;
+    }
+    mInterfaces.insert(interface);
+    return 0;
+}
+
+int LocalNetwork::removeInterface(const std::string& interface) {
+    if (!hasInterface(interface)) {
+        return 0;
+    }
+    if (int ret = RouteController::removeInterfaceFromLocalNetwork(mNetId, interface.c_str())) {
+        ALOGE("failed to remove interface %s from local netId %u", interface.c_str(), mNetId);
+        return ret;
+    }
+    mInterfaces.erase(interface);
+    return 0;
+}
diff --git a/server/LocalNetwork.h b/server/LocalNetwork.h
new file mode 100644
index 0000000..89a67f4
--- /dev/null
+++ b/server/LocalNetwork.h
@@ -0,0 +1,33 @@
+/*
+ * Copyright (C) 2014 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 NETD_SERVER_LOCAL_NETWORK_H
+#define NETD_SERVER_LOCAL_NETWORK_H
+
+#include "Network.h"
+
+class LocalNetwork : public Network {
+public:
+    explicit LocalNetwork(unsigned netId);
+    virtual ~LocalNetwork();
+
+private:
+    Type getType() const override;
+    int addInterface(const std::string& interface) override WARN_UNUSED_RESULT;
+    int removeInterface(const std::string& interface) override WARN_UNUSED_RESULT;
+};
+
+#endif  // NETD_SERVER_LOCAL_NETWORK_H
diff --git a/server/NatController.cpp b/server/NatController.cpp
index 6c066f8..8340b73 100644
--- a/server/NatController.cpp
+++ b/server/NatController.cpp
@@ -33,15 +33,13 @@
 
 #include "NatController.h"
 #include "NetworkController.h"
-#include "SecondaryTableController.h"
 #include "NetdConstants.h"
 
 const char* NatController::LOCAL_FORWARD = "natctrl_FORWARD";
 const char* NatController::LOCAL_NAT_POSTROUTING = "natctrl_nat_POSTROUTING";
 const char* NatController::LOCAL_TETHER_COUNTERS_CHAIN = "natctrl_tether_counters";
 
-NatController::NatController(SecondaryTableController *table_ctrl, NetworkController* net_ctrl) :
-        mSecondaryTableCtrl(table_ctrl), mNetCtrl(net_ctrl) {
+NatController::NatController(NetworkController* net_ctrl) : mNetCtrl(net_ctrl) {
 }
 
 NatController::~NatController() {
@@ -114,12 +112,6 @@
         {{IPTABLES_PATH, "-F", LOCAL_FORWARD,}, 1},
         {{IPTABLES_PATH, "-A", LOCAL_FORWARD, "-j", "DROP"}, 1},
         {{IPTABLES_PATH, "-t", "nat", "-F", LOCAL_NAT_POSTROUTING}, 1},
-        {{IP_PATH, "rule", "flush"}, 0},
-        {{IP_PATH, "-6", "rule", "flush"}, 0},
-        {{IP_PATH, "rule", "add", "from", "all", "lookup", "default", "prio", "32767"}, 0},
-        {{IP_PATH, "rule", "add", "from", "all", "lookup", "main", "prio", "32766"}, 0},
-        {{IP_PATH, "-6", "rule", "add", "from", "all", "lookup", "default", "prio", "32767"}, 0},
-        {{IP_PATH, "-6", "rule", "add", "from", "all", "lookup", "main", "prio", "32766"}, 0},
         {{IP_PATH, "route", "flush", "cache"}, 0},
     };
     for (unsigned int cmdNum = 0; cmdNum < ARRAY_SIZE(defaultCommands); cmdNum++) {
@@ -134,17 +126,15 @@
     return 0;
 }
 
-int NatController::routesOp(bool add, const char *intIface, const char *extIface, char **argv, int addrCount) {
-    unsigned netId = mNetCtrl->getNetworkForInterface(extIface);
+int NatController::routesOp(bool add, const char *intIface, char **argv, int addrCount) {
+    unsigned netId = mNetCtrl->getNetworkForInterface(intIface);
     int ret = 0;
 
     for (int i = 0; i < addrCount; i++) {
         if (add) {
-            ret |= mSecondaryTableCtrl->modifyFromRule(netId, ADD, argv[5+i]);
-            ret |= mSecondaryTableCtrl->modifyLocalRoute(netId, ADD, intIface, argv[5+i]);
+            ret |= mNetCtrl->addRoute(netId, intIface, argv[5+i], NULL, false, INVALID_UID);
         } else {
-            ret |= mSecondaryTableCtrl->modifyLocalRoute(netId, DEL, intIface, argv[5+i]);
-            ret |= mSecondaryTableCtrl->modifyFromRule(netId, DEL, argv[5+i]);
+            ret |= mNetCtrl->addRoute(netId, intIface, argv[5+i], NULL, false, INVALID_UID);
         }
     }
     const char *cmd[] = {
@@ -183,9 +173,9 @@
         errno = EINVAL;
         return -1;
     }
-    if (routesOp(true, intIface, extIface, argv, addrCount)) {
+    if (routesOp(true, intIface, argv, addrCount)) {
         ALOGE("Error setting route rules");
-        routesOp(false, intIface, extIface, argv, addrCount);
+        routesOp(false, intIface, argv, addrCount);
         errno = ENODEV;
         return -1;
     }
@@ -206,7 +196,7 @@
         if (runCmd(ARRAY_SIZE(cmd), cmd)) {
             ALOGE("Error seting postroute rule: iface=%s", extIface);
             // unwind what's been done, but don't care about success - what more could we do?
-            routesOp(false, intIface, extIface, argv, addrCount);
+            routesOp(false, intIface, argv, addrCount);
             setDefaults();
             return -1;
         }
@@ -215,7 +205,7 @@
 
     if (setForwardRules(true, intIface, extIface) != 0) {
         ALOGE("Error setting forward rules");
-        routesOp(false, intIface, extIface, argv, addrCount);
+        routesOp(false, intIface, argv, addrCount);
         if (natCount == 0) {
             setDefaults();
         }
@@ -415,7 +405,7 @@
     }
 
     setForwardRules(false, intIface, extIface);
-    routesOp(false, intIface, extIface, argv, addrCount);
+    routesOp(false, intIface, argv, addrCount);
     if (--natCount <= 0) {
         // handle decrement to 0 case (do reset to defaults) and erroneous dec below 0
         setDefaults();
diff --git a/server/NatController.h b/server/NatController.h
index afddb27..e3cc394 100644
--- a/server/NatController.h
+++ b/server/NatController.h
@@ -22,12 +22,11 @@
 #include <string>
 
 class NetworkController;
-class SecondaryTableController;
 
 class NatController {
 
 public:
-    NatController(SecondaryTableController *table_ctrl, NetworkController* net_ctrl);
+    explicit NatController(NetworkController* net_ctrl);
     virtual ~NatController();
 
     int enableNat(const int argc, char **argv);
@@ -43,7 +42,6 @@
 
 private:
     int natCount;
-    SecondaryTableController *mSecondaryTableCtrl;
     NetworkController *mNetCtrl;
 
     bool checkTetherCountingRuleExist(const char *pair_name);
@@ -52,7 +50,7 @@
     int runCmd(int argc, const char **argv);
     int setForwardRules(bool set, const char *intIface, const char *extIface);
     int setTetherCountingRules(bool add, const char *intIface, const char *extIface);
-    int routesOp(bool add, const char *intIface, const char *extIface, char **argv, int addrCount);
+    int routesOp(bool add, const char *intIface, char **argv, int addrCount);
 };
 
 #endif
diff --git a/server/Network.h b/server/Network.h
index f72cebb..39c81aa 100644
--- a/server/Network.h
+++ b/server/Network.h
@@ -26,6 +26,7 @@
 class Network {
 public:
     enum Type {
+        LOCAL,
         PHYSICAL,
         VIRTUAL,
     };
diff --git a/server/NetworkController.cpp b/server/NetworkController.cpp
index 1487b72..3bc0e70 100644
--- a/server/NetworkController.cpp
+++ b/server/NetworkController.cpp
@@ -32,6 +32,7 @@
 
 #include "NetworkController.h"
 
+#include "LocalNetwork.h"
 #include "PhysicalNetwork.h"
 #include "RouteController.h"
 #include "VirtualNetwork.h"
@@ -110,6 +111,29 @@
     return NETID_UNSET;
 }
 
+unsigned NetworkController::getNetIdForLocalNetwork() const {
+    return MIN_NET_ID - 1;
+}
+
+int NetworkController::createLocalNetwork(unsigned netId) {
+    // TODO: Enable this check after removing the getNetIdForLocalNetwork() hack.
+    if (false) {
+        if (netId < MIN_NET_ID || netId > MAX_NET_ID) {
+            ALOGE("invalid netId %u", netId);
+            return -EINVAL;
+        }
+    }
+
+    if (isValidNetwork(netId)) {
+        ALOGE("duplicate netId %u", netId);
+        return -EEXIST;
+    }
+
+    android::RWLock::AutoWLock lock(mRWLock);
+    mNetworks[netId] = new LocalNetwork(netId);
+    return 0;
+}
+
 int NetworkController::createPhysicalNetwork(unsigned netId, Permission permission) {
     if (netId < MIN_NET_ID || netId > MAX_NET_ID) {
         ALOGE("invalid netId %u", netId);
diff --git a/server/NetworkController.h b/server/NetworkController.h
index 217dfbc..f0a5ea7 100644
--- a/server/NetworkController.h
+++ b/server/NetworkController.h
@@ -52,6 +52,10 @@
     unsigned getNetworkForUser(uid_t uid, unsigned requestedNetId, bool forDns) const;
     unsigned getNetworkForInterface(const char* interface) const;
 
+    // TODO: Remove this hack.
+    unsigned getNetIdForLocalNetwork() const;
+
+    int createLocalNetwork(unsigned netId) WARN_UNUSED_RESULT;
     int createPhysicalNetwork(unsigned netId, Permission permission) WARN_UNUSED_RESULT;
     int createVirtualNetwork(unsigned netId, bool hasDns) WARN_UNUSED_RESULT;
     int destroyNetwork(unsigned netId) WARN_UNUSED_RESULT;
diff --git a/server/RouteController.cpp b/server/RouteController.cpp
index d33c47c..8efbda4 100644
--- a/server/RouteController.cpp
+++ b/server/RouteController.cpp
@@ -42,7 +42,7 @@
 const uint32_t RULE_PRIORITY_OUTPUT_INTERFACE    = 14000;
 const uint32_t RULE_PRIORITY_LEGACY_SYSTEM       = 15000;
 const uint32_t RULE_PRIORITY_LEGACY_NETWORK      = 16000;
-// const uint32_t RULE_PRIORITY_LOCAL_NETWORK       = 17000;
+const uint32_t RULE_PRIORITY_LOCAL_NETWORK       = 17000;
 // const uint32_t RULE_PRIORITY_TETHERING           = 18000;
 const uint32_t RULE_PRIORITY_IMPLICIT_NETWORK    = 19000;
 // const uint32_t RULE_PRIORITY_BYPASSABLE_VPN      = 20000;
@@ -542,6 +542,38 @@
                         fwmark.intValue, mask.intValue, OIF_NONE, INVALID_UID, INVALID_UID);
 }
 
+// A rule to allow local network routes to override the default network.
+WARN_UNUSED_RESULT int modifyLocalOverrideRule(uint32_t table, bool add) {
+    Fwmark fwmark;
+    Fwmark mask;
+
+    fwmark.explicitlySelected = false;
+    mask.explicitlySelected = true;
+
+    return modifyIpRule(add ? RTM_NEWRULE : RTM_DELRULE, RULE_PRIORITY_LOCAL_NETWORK, table,
+                        fwmark.intValue, mask.intValue, OIF_NONE, INVALID_UID, INVALID_UID);
+}
+
+WARN_UNUSED_RESULT int modifyLocalNetwork(unsigned netId, const char* interface, bool add) {
+    uint32_t table = getRouteTableForInterface(interface);
+    if (table == RT_TABLE_UNSPEC) {
+        return -ESRCH;
+    }
+
+    if (int ret = modifyIncomingPacketMark(netId, interface, PERMISSION_NONE, add)) {
+        return ret;
+    }
+    if (int ret = modifyExplicitNetworkRule(netId, table, PERMISSION_NONE, INVALID_UID, INVALID_UID,
+                                            add)) {
+        return ret;
+    }
+    if (int ret = modifyOutputInterfaceRule(interface, table, PERMISSION_NONE, INVALID_UID,
+                                            INVALID_UID, add)) {
+        return ret;
+    }
+    return modifyLocalOverrideRule(table, add);
+}
+
 WARN_UNUSED_RESULT int modifyPhysicalNetwork(unsigned netId, const char* interface,
                                              Permission permission, bool add) {
     uint32_t table = getRouteTableForInterface(interface);
@@ -714,6 +746,25 @@
     return 0;
 }
 
+int RouteController::addInterfaceToLocalNetwork(unsigned netId, const char* interface) {
+    if (int ret = modifyLocalNetwork(netId, interface, ACTION_ADD)) {
+        return ret;
+    }
+    updateTableNamesFile();
+    return 0;
+}
+
+int RouteController::removeInterfaceFromLocalNetwork(unsigned netId, const char* interface) {
+    if (int ret = modifyLocalNetwork(netId, interface, ACTION_DEL)) {
+        return ret;
+    }
+    if (int ret = flushRoutes(interface)) {
+        return ret;
+    }
+    updateTableNamesFile();
+    return 0;
+}
+
 int RouteController::addInterfaceToPhysicalNetwork(unsigned netId, const char* interface,
                                                    Permission permission) {
     if (int ret = modifyPhysicalNetwork(netId, interface, permission, ACTION_ADD)) {
diff --git a/server/RouteController.h b/server/RouteController.h
index 86ac089..a3010de 100644
--- a/server/RouteController.h
+++ b/server/RouteController.h
@@ -37,6 +37,10 @@
 
     static int Init() WARN_UNUSED_RESULT;
 
+    static int addInterfaceToLocalNetwork(unsigned netId, const char* interface) WARN_UNUSED_RESULT;
+    static int removeInterfaceFromLocalNetwork(unsigned netId,
+                                               const char* interface) WARN_UNUSED_RESULT;
+
     static int addInterfaceToPhysicalNetwork(unsigned netId, const char* interface,
                                              Permission permission) WARN_UNUSED_RESULT;
     static int removeInterfaceFromPhysicalNetwork(unsigned netId, const char* interface,
diff --git a/server/TetherController.cpp b/server/TetherController.cpp
index fbee5a2..47b620d 100644
--- a/server/TetherController.cpp
+++ b/server/TetherController.cpp
@@ -33,8 +33,10 @@
 
 #include "NetdConstants.h"
 #include "TetherController.h"
+#include "NetworkController.h"
 
-TetherController::TetherController() {
+TetherController::TetherController(NetworkController* networkController) :
+        mNetworkController(networkController) {
     mInterfaces = new InterfaceCollection();
     mDnsForwarders = new NetAddressCollection();
     mDaemonFd = -1;
@@ -170,6 +172,17 @@
         ALOGD("Tethering services running");
     }
 
+    unsigned netId = mNetworkController->getNetIdForLocalNetwork();
+    if (int ret = mNetworkController->createLocalNetwork(netId)) {
+        return ret;
+    }
+    // If any interfaces have already been configured, add them to the local network now.
+    for (InterfaceCollection::iterator it = mInterfaces->begin(); it != mInterfaces->end(); ++it) {
+        if (int ret = mNetworkController->addInterfaceToNetwork(netId, *it)) {
+            return ret;
+        }
+    }
+
     return 0;
 }
 
@@ -182,6 +195,9 @@
 
     ALOGD("Stopping tethering services");
 
+    // Ignore any error.
+    (void) mNetworkController->destroyNetwork(mNetworkController->getNetIdForLocalNetwork());
+
     kill(mDaemonPid, SIGTERM);
     waitpid(mDaemonPid, NULL, 0);
     mDaemonPid = 0;
@@ -291,6 +307,10 @@
         }
         return -1;
     } else {
+        if (isTetheringStarted()) {
+            unsigned netId = mNetworkController->getNetIdForLocalNetwork();
+            return mNetworkController->addInterfaceToNetwork(netId, interface);
+        }
         return 0;
     }
 }
@@ -300,6 +320,12 @@
 
     ALOGD("untetherInterface(%s)", interface);
 
+    if (isTetheringStarted()) {
+        unsigned netId = mNetworkController->getNetIdForLocalNetwork();
+        // Ignore any error.
+        (void) mNetworkController->removeInterfaceFromNetwork(netId, interface);
+    }
+
     for (it = mInterfaces->begin(); it != mInterfaces->end(); ++it) {
         if (!strcmp(interface, *it)) {
             free(*it);
diff --git a/server/TetherController.h b/server/TetherController.h
index 4da10b0..38f7593 100644
--- a/server/TetherController.h
+++ b/server/TetherController.h
@@ -24,14 +24,17 @@
 typedef android::netd::List<char *> InterfaceCollection;
 typedef android::netd::List<struct in_addr> NetAddressCollection;
 
+class NetworkController;
+
 class TetherController {
     InterfaceCollection  *mInterfaces;
     NetAddressCollection *mDnsForwarders;
     pid_t                 mDaemonPid;
     int                   mDaemonFd;
+    NetworkController* const mNetworkController;
 
 public:
-    TetherController();
+    explicit TetherController(NetworkController* networkController);
     virtual ~TetherController();
 
     int setIpFwdEnabled(bool enable);