Accept RIOs with prefix length in the closed interval [48, 64]

This change adds the appropriate initialization code and constants to
accept what is believed to be a reasonable range of RIOs. Prior to this
change, only RIOs with prefix length of zero were accepted.

RIO bounds are set in such a way that we fail closed, that is, we only
start accepting RIOs if we've successfully applied the limits [48, 64].

Bug: 33333670
Test: as follows
  - built (angler)
  - flashed
  - booted
  - runtest -x netd_integration_test.cpp passed
  - runtest.py frameworks-net passed
  - runtest.py frameworks-wifi passed

Change-Id: I35497f5d2c0a23069bf7b000ccbdd7aad5709ef3
diff --git a/server/InterfaceController.cpp b/server/InterfaceController.cpp
index ed5d8d0..cb1f0c2 100644
--- a/server/InterfaceController.cpp
+++ b/server/InterfaceController.cpp
@@ -19,6 +19,8 @@
 #include <malloc.h>
 #include <sys/socket.h>
 
+#include <functional>
+
 #define LOG_TAG "InterfaceController"
 #include <android-base/file.h>
 #include <android-base/stringprintf.h>
@@ -47,6 +49,11 @@
 
 const char wl_util_path[] = "/vendor/xbin/wlutil";
 
+constexpr int kRouteInfoMinPrefixLen = 48;
+
+// RFC 7421 prefix length.
+constexpr int kRouteInfoMaxPrefixLen = 64;
+
 inline bool isNormalPathComponent(const char *component) {
     return (strcmp(component, ".") != 0) &&
            (strcmp(component, "..") != 0) &&
@@ -70,26 +77,36 @@
     return WriteStringToFile(value, path) ? 0 : -1;
 }
 
-void setOnAllInterfaces(const char* dirname, const char* basename, const char* value) {
-    // Set the default value, which is used by any interfaces that are created in the future.
-    writeValueToPath(dirname, "default", basename, value);
-
-    // Set the value on all the interfaces that currently exist.
-    DIR* dir = opendir(dirname);
+// Run @fn on each interface as well as 'default' in the path @dirname.
+void forEachInterface(const std::string& dirname,
+                      std::function<void(const std::string& path, const std::string& iface)> fn) {
+    // Run on default, which controls the behavior of any interfaces that are created in the future.
+    fn(dirname, "default");
+    DIR* dir = opendir(dirname.c_str());
     if (!dir) {
-        ALOGE("Can't list %s: %s", dirname, strerror(errno));
+        ALOGE("Can't list %s: %s", dirname.c_str(), strerror(errno));
         return;
     }
-    dirent* d;
-    while ((d = readdir(dir))) {
-        if ((d->d_type != DT_DIR) || !isInterfaceName(d->d_name)) {
+    while (true) {
+        const dirent *ent = readdir(dir);
+        if (!ent) {
+            break;
+        }
+        if ((ent->d_type != DT_DIR) || !isInterfaceName(ent->d_name)) {
             continue;
         }
-        writeValueToPath(dirname, d->d_name, basename, value);
+        fn(dirname, ent->d_name);
     }
     closedir(dir);
 }
 
+void setOnAllInterfaces(const char* dirname, const char* basename, const char* value) {
+    auto fn = [basename, value](const std::string& path, const std::string& iface) {
+        writeValueToPath(path.c_str(), iface.c_str(), basename, value);
+    };
+    forEachInterface(dirname, fn);
+}
+
 void setIPv6UseOutgoingInterfaceAddrsOnly(const char *value) {
     setOnAllInterfaces(ipv6_proc_path, "use_oif_addrs_only", value);
 }
@@ -109,6 +126,21 @@
     return StringPrintf("%s/%s/%s/%s/%s", proc_net_path, family, which, interface, parameter);
 }
 
+void setAcceptIPv6RIO(int min, int max) {
+    auto fn = [min, max](const std::string& prefix, const std::string& iface) {
+        int rv = writeValueToPath(prefix.c_str(), iface.c_str(), "accept_ra_rt_info_min_plen",
+                                  std::to_string(min).c_str());
+        if (rv != 0) {
+            // Only update max_plen if the write to min_plen succeeded. This ordering will prevent
+            // RIOs from being accepted unless both min and max are written successfully.
+            return;
+        }
+        writeValueToPath(prefix.c_str(), iface.c_str(), "accept_ra_rt_info_max_plen",
+                         std::to_string(max).c_str());
+    };
+    forEachInterface(ipv6_proc_path, fn);
+}
+
 }  // namespace
 
 void InterfaceController::initializeAll() {
@@ -119,6 +151,9 @@
     // by always setting accept_ra to 2.
     setAcceptRA("2");
 
+    // Accept RIOs with prefix length in the closed interval [48, 64].
+    setAcceptIPv6RIO(kRouteInfoMinPrefixLen, kRouteInfoMaxPrefixLen);
+
     setAcceptRARouteTable(-RouteController::ROUTE_TABLE_OFFSET_FROM_INDEX);
 
     // Enable optimistic DAD for IPv6 addresses on all interfaces.