Interface-related commands porting

Test: built, flashed, booted
      system/netd/tests/runtests.sh passes

Change-Id: Ief3b2a0a55b74db0a794f3f9ca58298a2fcb57dd
diff --git a/server/InterfaceController.cpp b/server/InterfaceController.cpp
index fde7f4f..78e08d0 100644
--- a/server/InterfaceController.cpp
+++ b/server/InterfaceController.cpp
@@ -18,14 +18,17 @@
 #include <errno.h>
 #include <malloc.h>
 #include <net/if.h>
+#include <net/if_arp.h>
 #include <sys/socket.h>
 
 #include <functional>
+
 #define LOG_TAG "InterfaceController"
 #include <android-base/file.h>
 #include <android-base/properties.h>
 #include <android-base/stringprintf.h>
 #include <android-base/strings.h>
+#include <linux/if_ether.h>
 #include <log/log.h>
 #include <logwrap/logwrap.h>
 #include <netutils/ifc.h>
@@ -53,6 +56,13 @@
 using android::netdutils::toString;
 using android::netdutils::status::ok;
 
+#define RETURN_STATUS_IF_IFCERROR(exp)                           \
+    do {                                                         \
+        if ((exp) == -1) {                                       \
+            return statusFromErrno(errno, "Failed to add addr"); \
+        }                                                        \
+    } while (0);
+
 namespace {
 
 const char ipv4_proc_path[] = "/proc/sys/net/ipv4/conf";
@@ -104,7 +114,7 @@
         const char* dirname, const char* subdirname, const char* basename,
         const char* value) {
     std::string path(StringPrintf("%s/%s/%s", dirname, subdirname, basename));
-    return WriteStringToFile(value, path) ? 0 : -1;
+    return WriteStringToFile(value, path) ? 0 : -EREMOTEIO;
 }
 
 // Run @fn on each interface as well as 'default' in the path @dirname.
@@ -193,6 +203,7 @@
 
 namespace android {
 namespace net {
+std::mutex InterfaceController::mutex;
 
 android::netdutils::Status InterfaceController::enableStablePrivacyAddresses(
         const std::string& iface,
@@ -261,8 +272,7 @@
 
 int InterfaceController::setEnableIPv6(const char *interface, const int on) {
     if (!isIfaceName(interface)) {
-        errno = ENOENT;
-        return -1;
+        return -ENOENT;
     }
     // When disable_ipv6 changes from 1 to 0, the kernel starts autoconf.
     // When disable_ipv6 changes from 0 to 1, the kernel clears all autoconf
@@ -327,7 +337,7 @@
 int InterfaceController::setIPv6PrivacyExtensions(const char *interface, const int on) {
     if (!isIfaceName(interface)) {
         errno = ENOENT;
-        return -1;
+        return -errno;
     }
     // 0: disable IPv6 privacy addresses
     // 2: enable IPv6 privacy addresses and prefer them over non-privacy ones.
@@ -353,7 +363,7 @@
 {
     if (!isIfaceName(interface)) {
         errno = ENOENT;
-        return -1;
+        return -errno;
     }
     return writeValueToPath(sys_net_path, interface, "mtu", mtu);
 }
@@ -442,5 +452,118 @@
     return ifacePairs;
 }
 
+namespace {
+
+std::string hwAddrToStr(unsigned char* hwaddr) {
+    return StringPrintf("%02x:%02x:%02x:%02x:%02x:%02x", hwaddr[0], hwaddr[1], hwaddr[2], hwaddr[3],
+                        hwaddr[4], hwaddr[5]);
+}
+
+int ipv4NetmaskToPrefixLength(in_addr_t mask) {
+    int prefixLength = 0;
+    uint32_t m = ntohl(mask);
+    while (m & (1 << 31)) {
+        prefixLength++;
+        m = m << 1;
+    }
+    return prefixLength;
+}
+
+std::string toStdString(const String16& s) {
+    return std::string(String8(s.string()));
+}
+
+}  // namespace
+
+Status InterfaceController::setCfg(const InterfaceConfigurationParcel& cfg) {
+    const auto& sys = sSyscalls.get();
+    ASSIGN_OR_RETURN(auto fd, sys.socket(AF_INET, SOCK_DGRAM | SOCK_CLOEXEC, 0));
+    struct ifreq ifr = {
+            .ifr_addr = {.sa_family = AF_INET},  // Clear the IPv4 address.
+    };
+    strlcpy(ifr.ifr_name, cfg.ifName.c_str(), IFNAMSIZ);
+
+    // Make sure that clear IPv4 address before set flag
+    // SIOCGIFFLAGS might override ifr and caused clear IPv4 addr ioctl error
+    RETURN_IF_NOT_OK(sys.ioctl(fd, SIOCSIFADDR, &ifr));
+
+    if (!cfg.flags.empty()) {
+        RETURN_IF_NOT_OK(sys.ioctl(fd, SIOCGIFFLAGS, &ifr));
+        uint16_t flags = ifr.ifr_flags;
+
+        for (const auto& flag : cfg.flags) {
+            if (flag == toStdString(INetd::IF_STATE_UP())) {
+                ifr.ifr_flags = ifr.ifr_flags | IFF_UP;
+            } else if (flag == toStdString(INetd::IF_STATE_DOWN())) {
+                ifr.ifr_flags = (ifr.ifr_flags & (~IFF_UP));
+            }
+        }
+
+        if (ifr.ifr_flags != flags) {
+            RETURN_IF_NOT_OK(sys.ioctl(fd, SIOCSIFFLAGS, &ifr));
+        }
+    }
+
+    RETURN_STATUS_IF_IFCERROR(
+            ifc_add_address(cfg.ifName.c_str(), cfg.ipv4Addr.c_str(), cfg.prefixLength));
+
+    return ok;
+}
+
+StatusOr<InterfaceConfigurationParcel> InterfaceController::getCfg(const std::string& ifName) {
+    struct in_addr addr = {};
+    int prefixLength = 0;
+    unsigned char hwaddr[ETH_ALEN] = {};
+    unsigned flags = 0;
+    InterfaceConfigurationParcel cfgResult;
+
+    const auto& sys = sSyscalls.get();
+    ASSIGN_OR_RETURN(auto fd, sys.socket(AF_INET, SOCK_DGRAM | SOCK_CLOEXEC, 0));
+
+    struct ifreq ifr = {};
+    strlcpy(ifr.ifr_name, ifName.c_str(), IFNAMSIZ);
+
+    if (isOk(sys.ioctl(fd, SIOCGIFADDR, &ifr))) {
+        addr.s_addr = ((struct sockaddr_in*) &ifr.ifr_addr)->sin_addr.s_addr;
+    }
+
+    if (isOk(sys.ioctl(fd, SIOCGIFNETMASK, &ifr))) {
+        prefixLength =
+                ipv4NetmaskToPrefixLength(((struct sockaddr_in*) &ifr.ifr_addr)->sin_addr.s_addr);
+    }
+
+    if (isOk(sys.ioctl(fd, SIOCGIFFLAGS, &ifr))) {
+        flags = ifr.ifr_flags;
+    }
+
+    // ETH_ALEN is for ARPHRD_ETHER, it is better to check the sa_family.
+    // However, we keep old design for the consistency.
+    if (isOk(sys.ioctl(fd, SIOCGIFHWADDR, &ifr))) {
+        memcpy((void*) hwaddr, &ifr.ifr_hwaddr.sa_data, ETH_ALEN);
+    } else {
+        ALOGW("Failed to retrieve HW addr for %s (%s)", ifName.c_str(), strerror(errno));
+    }
+
+    cfgResult.ifName = ifName;
+    cfgResult.hwAddr = hwAddrToStr(hwaddr);
+    cfgResult.ipv4Addr = std::string(inet_ntoa(addr));
+    cfgResult.prefixLength = prefixLength;
+    cfgResult.flags.push_back(flags & IFF_UP ? toStdString(INetd::IF_STATE_UP())
+                                             : toStdString(INetd::IF_STATE_DOWN()));
+
+    if (flags & IFF_BROADCAST) cfgResult.flags.push_back(toStdString(INetd::IF_FLAG_BROADCAST()));
+    if (flags & IFF_LOOPBACK) cfgResult.flags.push_back(toStdString(INetd::IF_FLAG_LOOPBACK()));
+    if (flags & IFF_POINTOPOINT)
+        cfgResult.flags.push_back(toStdString(INetd::IF_FLAG_POINTOPOINT()));
+    if (flags & IFF_RUNNING) cfgResult.flags.push_back(toStdString(INetd::IF_FLAG_RUNNING()));
+    if (flags & IFF_MULTICAST) cfgResult.flags.push_back(toStdString(INetd::IF_FLAG_MULTICAST()));
+
+    return cfgResult;
+}
+
+int InterfaceController::clearAddrs(const std::string& ifName) {
+    return ifc_clear_addresses(ifName.c_str());
+}
+
 }  // namespace net
 }  // namespace android