Implement network default set/clear.

(cherry picked from commit 4cc7df247a7ec67da3b5edfb9356077fbbf0150c)

Change-Id: Ib35d54816884c6a6ba28231c9b1f54e362d1d16a
diff --git a/CommandListener.cpp b/CommandListener.cpp
index 34a28fa..34f356c 100644
--- a/CommandListener.cpp
+++ b/CommandListener.cpp
@@ -1728,11 +1728,35 @@
         return success(client);
     }
 
+    //    0       1      2      3
+    // network default  set  <netId>
+    // network default clear
+    if (!strcmp(argv[1], "default")) {
+        if (argc < 3) {
+            return syntaxError(client, "Missing argument");
+        }
+        unsigned netId = NETID_UNSET;
+        if (!strcmp(argv[2], "set")) {
+            if (argc < 4) {
+                return syntaxError(client, "Missing netId");
+            }
+            // strtoul() returns 0 on errors, which is fine because 0 is an invalid netId.
+            netId = strtoul(argv[3], NULL, 0);
+            if (!sNetCtrl->isNetIdValid(netId)) {
+                return paramError(client, "Invalid netId");
+            }
+        } else if (strcmp(argv[2], "clear")) {
+            return syntaxError(client, "Unknown argument");
+        }
+        if (!sNetCtrl->setDefaultNetwork(netId)) {
+            return operationError(client, "setDefaultNetwork() failed");
+        }
+        return success(client);
+    }
+
     // network dns <add|remove> <netId> <num-resolvers> <resolver1> .. <resolverN> [searchDomain1] .. [searchDomainM]
     // network route <add|remove> <other-route-params>
     // network legacy <uid> route <add|remove> <other-route-params>
-    // network default set <netId>
-    // network default clear
     // network vpn create <netId> [owner_uid]
     // network vpn destroy <netId>
     // network <bind|unbind> <netId> <uid1> .. <uidN>
diff --git a/NetworkController.cpp b/NetworkController.cpp
index 185f7d7..14c63f3 100644
--- a/NetworkController.cpp
+++ b/NetworkController.cpp
@@ -51,12 +51,51 @@
 }
 
 unsigned NetworkController::getDefaultNetwork() const {
+    android::RWLock::AutoRLock lock(mRWLock);
     return mDefaultNetId;
 }
 
-void NetworkController::setDefaultNetwork(unsigned netId) {
-    android::RWLock::AutoWLock lock(mRWLock);
-    mDefaultNetId = netId;
+bool NetworkController::setDefaultNetwork(unsigned newNetId) {
+    unsigned oldNetId;
+    {
+        android::RWLock::AutoWLock lock(mRWLock);
+        oldNetId = mDefaultNetId;
+        mDefaultNetId = newNetId;
+    }
+
+    if (oldNetId == newNetId) {
+        return true;
+    }
+
+    bool status = true;
+
+    // Add default network rules for the new netId.
+    if (isNetIdValid(newNetId)) {
+        Permission permission = mPermissionsController->getPermissionForNetwork(newNetId);
+
+        typedef std::multimap<unsigned, std::string>::const_iterator Iterator;
+        std::pair<Iterator, Iterator> range = mNetIdToInterfaces.equal_range(newNetId);
+        for (Iterator iter = range.first; iter != range.second; ++iter) {
+            if (!mRouteController->addDefaultNetwork(iter->second.c_str(), permission)) {
+                status = false;
+            }
+        }
+    }
+
+    // Remove the old default network rules.
+    if (isNetIdValid(oldNetId)) {
+        Permission permission = mPermissionsController->getPermissionForNetwork(oldNetId);
+
+        typedef std::multimap<unsigned, std::string>::const_iterator Iterator;
+        std::pair<Iterator, Iterator> range = mNetIdToInterfaces.equal_range(oldNetId);
+        for (Iterator iter = range.first; iter != range.second; ++iter) {
+            if (!mRouteController->removeDefaultNetwork(iter->second.c_str(), permission)) {
+                status = false;
+            }
+        }
+    }
+
+    return status;
 }
 
 void NetworkController::setNetworkForPid(int pid, unsigned netId) {
@@ -176,6 +215,14 @@
     mPermissionsController->setPermissionForNetwork(PERMISSION_NONE, netId);
     mNetIdToInterfaces.erase(netId);
 
+    if (netId == getDefaultNetwork()) {
+        // Could the default network have changed from below us, after we evaluated the 'if', thus
+        // making it wrong to call setDefaultNetwork() now? No, because the default can only change
+        // due to another command from CommandListener, and those are serialized (i.e., they can't
+        // happen in parallel with the destroyNetwork() that we are currently processing).
+        setDefaultNetwork(NETID_UNSET);
+    }
+
     return status;
 }
 
diff --git a/NetworkController.h b/NetworkController.h
index 1063f92..e113bf5 100644
--- a/NetworkController.h
+++ b/NetworkController.h
@@ -51,7 +51,7 @@
 
     void clearNetworkPreference();
     unsigned getDefaultNetwork() const;
-    void setDefaultNetwork(unsigned netId);
+    bool setDefaultNetwork(unsigned netId);
     void setNetworkForPid(int pid, unsigned netId);
     bool setNetworkForUidRange(int uid_start, int uid_end, unsigned netId, bool forward_dns);
     bool clearNetworkForUidRange(int uid_start, int uid_end, unsigned netId);
@@ -91,6 +91,12 @@
     PermissionsController* const mPermissionsController;
     RouteController* const mRouteController;
 
+    // Maps a netId to all its interfaces.
+    //
+    // We need to know interface names to configure incoming packet marking and because routing
+    // tables are associated with interfaces and not with netIds.
+    //
+    // An interface may belong to at most one netId, but a netId may have multiple interfaces.
     std::multimap<unsigned, std::string> mNetIdToInterfaces;
 };
 
diff --git a/RouteController.cpp b/RouteController.cpp
index 737dd9f..a8f6700 100644
--- a/RouteController.cpp
+++ b/RouteController.cpp
@@ -24,13 +24,14 @@
 
 namespace {
 
-const uint32_t RULE_PRIORITY_PER_NETWORK_EXPLICIT = 300;
-const uint32_t RULE_PRIORITY_PER_NETWORK_OIF = 400;
-const uint32_t RULE_PRIORITY_PER_NETWORK_NORMAL = 700;
+const uint32_t RULE_PRIORITY_PER_NETWORK_EXPLICIT  =  300;
+const uint32_t RULE_PRIORITY_PER_NETWORK_INTERFACE =  400;
+const uint32_t RULE_PRIORITY_PER_NETWORK_NORMAL    =  700;
+const uint32_t RULE_PRIORITY_DEFAULT_NETWORK       =  900;
 
-const bool FWMARK_USE_NET_ID = true;
+const bool FWMARK_USE_NET_ID   = true;
 const bool FWMARK_USE_EXPLICIT = true;
-const bool FWMARK_USE_PROTECT = true;
+const bool FWMARK_USE_PROTECT  = true;
 
 uint32_t getRouteTableForInterface(const char* interface) {
     uint32_t index = if_nametoindex(interface);
@@ -38,7 +39,7 @@
 }
 
 bool runIpRuleCommand(const char* action, uint32_t priority, uint32_t table,
-                      uint32_t fwmark, uint32_t mask, const char* oif) {
+                      uint32_t fwmark, uint32_t mask, const char* interface) {
 
     char priorityString[UINT32_STRLEN];
     char tableString[UINT32_STRLEN];
@@ -65,9 +66,9 @@
             argv[argc++] = "fwmark";
             argv[argc++] = fwmarkString;
         }
-        if (oif) {
+        if (interface) {
             argv[argc++] = "oif";
-            argv[argc++] = oif;
+            argv[argc++] = interface;
         }
         if (android_fork_execvp(argc, const_cast<char**>(argv), NULL, false, false)) {
             return false;
@@ -77,8 +78,8 @@
     return true;
 }
 
-bool modifyRules(unsigned netId, const char* interface, Permission permission, bool add,
-                 bool modifyIptables) {
+bool modifyPerNetworkRules(unsigned netId, const char* interface, Permission permission, bool add,
+                           bool modifyIptables) {
     uint32_t table = getRouteTableForInterface(interface);
     if (!table) {
         return false;
@@ -105,7 +106,8 @@
     // knows the outgoing interface (typically for link-local communications).
     fwmark = getFwmark(0, !FWMARK_USE_EXPLICIT, !FWMARK_USE_PROTECT, permission);
     mask = getFwmark(!FWMARK_USE_NET_ID, !FWMARK_USE_EXPLICIT, !FWMARK_USE_PROTECT, permission);
-    if (!runIpRuleCommand(action, RULE_PRIORITY_PER_NETWORK_OIF, table, fwmark, mask, interface)) {
+    if (!runIpRuleCommand(action, RULE_PRIORITY_PER_NETWORK_INTERFACE, table, fwmark, mask,
+                          interface)) {
         return false;
     }
 
@@ -140,20 +142,45 @@
     return true;
 }
 
+bool modifyDefaultNetworkRules(const char* interface, Permission permission, const char* action) {
+    uint32_t table = getRouteTableForInterface(interface);
+    if (!table) {
+        return false;
+    }
+
+    uint32_t fwmark = getFwmark(0, !FWMARK_USE_EXPLICIT, !FWMARK_USE_PROTECT, permission);
+    uint32_t mask = getFwmarkMask(FWMARK_USE_NET_ID, !FWMARK_USE_EXPLICIT, !FWMARK_USE_PROTECT,
+                                  permission);
+
+    if (!runIpRuleCommand(action, RULE_PRIORITY_DEFAULT_NETWORK, table, fwmark, mask, NULL)) {
+        return false;
+    }
+
+    return true;
+}
+
 }  // namespace
 
 bool RouteController::createNetwork(unsigned netId, const char* interface, Permission permission) {
-    return modifyRules(netId, interface, permission, true, true);
+    return modifyPerNetworkRules(netId, interface, permission, true, true);
 }
 
 bool RouteController::destroyNetwork(unsigned netId, const char* interface, Permission permission) {
-    return modifyRules(netId, interface, permission, false, true);
+    return modifyPerNetworkRules(netId, interface, permission, false, true);
     // TODO: Flush the routing table.
 }
 
 bool RouteController::modifyNetworkPermission(unsigned netId, const char* interface,
                                               Permission oldPermission, Permission newPermission) {
     // Add the new rules before deleting the old ones, to avoid race conditions.
-    return modifyRules(netId, interface, newPermission, true, false) &&
-           modifyRules(netId, interface, oldPermission, false, false);
+    return modifyPerNetworkRules(netId, interface, newPermission, true, false) &&
+           modifyPerNetworkRules(netId, interface, oldPermission, false, false);
+}
+
+bool RouteController::addDefaultNetwork(const char* interface, Permission permission) {
+    return modifyDefaultNetworkRules(interface, permission, ADD);
+}
+
+bool RouteController::removeDefaultNetwork(const char* interface, Permission permission) {
+    return modifyDefaultNetworkRules(interface, permission, DEL);
 }
diff --git a/RouteController.h b/RouteController.h
index 65f8f84..1db1da3 100644
--- a/RouteController.h
+++ b/RouteController.h
@@ -27,6 +27,9 @@
     static bool destroyNetwork(unsigned netId, const char* interface, Permission permission);
     static bool modifyNetworkPermission(unsigned netId, const char* interface,
                                         Permission oldPermission, Permission newPermission);
+
+    static bool addDefaultNetwork(const char* interface, Permission permission);
+    static bool removeDefaultNetwork(const char* interface, Permission permission);
 };
 
 #endif  // SYSTEM_NETD_ROUTE_CONTROLLER_H