Add directly-connected routes to the main table.

Change-Id: I545555d273ea9d321eab08fef12a32ca17e33dff
diff --git a/CommandListener.cpp b/CommandListener.cpp
index f6e507a..112b55e 100644
--- a/CommandListener.cpp
+++ b/CommandListener.cpp
@@ -1712,7 +1712,14 @@
         }
         const char* interface = argv[4];
         const char* destination = argv[5];
-        const char* nexthop = argc == 7 ? argv[6] : NULL;
+        const char* nexthop = NULL;
+        // If the nexthop (gateway) is equal to INADDR_ANY or in6addr_any, the route is a directly
+        // connected route, and we should not set nexthop.
+        // TODO: This doesn't catch all the ways of representing the "any" address (e.g.: "0/0",
+        // "::0", etc). Fix the callers to not pass us a nexthop in the first place in such cases.
+        if (argc == 7 && strcmp(argv[6], "0.0.0.0") && strcmp(argv[6], "::")) {
+            nexthop = argv[6];
+        }
         if (!strcmp(argv[2], "add")) {
             if (!sNetCtrl->addRoute(netId, interface, destination, nexthop)) {
                 return operationError(client, "addRoute() failed");
diff --git a/RouteController.cpp b/RouteController.cpp
index 916a873..2a6ef3d 100644
--- a/RouteController.cpp
+++ b/RouteController.cpp
@@ -195,13 +195,27 @@
     return runIpRuleCommand(action, RULE_PRIORITY_DEFAULT_NETWORK, table, fwmark, mask, NULL);
 }
 
-bool modifyRoute(const char* interface, const char* destination, const char* nexthop, bool add) {
+bool modifyRoute(const char* interface, const char* destination, const char* nexthop,
+                 const char* action) {
     uint32_t table = getRouteTableForInterface(interface);
     if (!table) {
         return false;
     }
 
-    return runIpRouteCommand(add ? ADD : DEL, table, interface, destination, nexthop);
+    if (!runIpRouteCommand(action, table, interface, destination, nexthop)) {
+        return false;
+    }
+
+    // If there's no nexthop, this is a directly connected route. Add it to the main table also, to
+    // let the kernel find it when validating nexthops when global routes are added. Don't do this
+    // for IPv6, since all directly-connected routes in v6 are link-local and should already be in
+    // the main table.
+    if (!nexthop && !strchr(destination, ':') &&
+        !runIpRouteCommand(action, RT_TABLE_MAIN, interface, destination, NULL)) {
+        return false;
+    }
+
+    return true;
 }
 
 bool flushRoutes(const char* interface) {
@@ -260,10 +274,10 @@
 
 bool RouteController::addRoute(const char* interface, const char* destination,
                                const char* nexthop) {
-    return modifyRoute(interface, destination, nexthop, true);
+    return modifyRoute(interface, destination, nexthop, ADD);
 }
 
 bool RouteController::removeRoute(const char* interface, const char* destination,
                                   const char* nexthop) {
-    return modifyRoute(interface, destination, nexthop, false);
+    return modifyRoute(interface, destination, nexthop, DEL);
 }