Interface-related commands porting

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

Change-Id: Ief3b2a0a55b74db0a794f3f9ca58298a2fcb57dd
diff --git a/tests/binder_test.cpp b/tests/binder_test.cpp
index af74bd2..458a0ed 100644
--- a/tests/binder_test.cpp
+++ b/tests/binder_test.cpp
@@ -24,15 +24,16 @@
 #include <set>
 #include <vector>
 
+#include <dirent.h>
 #include <fcntl.h>
 #include <ifaddrs.h>
-#include <netdb.h>
-#include <sys/socket.h>
-#include <sys/types.h>
-#include <netinet/in.h>
 #include <linux/if.h>
 #include <linux/if_tun.h>
+#include <netdb.h>
+#include <netinet/in.h>
 #include <openssl/base64.h>
+#include <sys/socket.h>
+#include <sys/types.h>
 
 #include <android-base/file.h>
 #include <android-base/macros.h>
@@ -76,10 +77,13 @@
 using android::base::Trim;
 using android::bpf::hasBpfSupport;
 using android::net::INetd;
+using android::net::InterfaceConfigurationParcel;
+using android::net::InterfaceController;
 using android::net::TetherStatsParcel;
 using android::net::TunInterface;
 using android::net::UidRangeParcel;
 using android::net::XfrmController;
+using android::netdutils::sSyscalls;
 
 #define SKIP_IF_BPF_SUPPORTED        \
     do {                             \
@@ -2328,3 +2332,310 @@
     EXPECT_TRUE(status.isOk()) << status.exceptionMessage();
     expectFirewallChildChainsLastRuleDoesNotExist(FIREWALL_POWERSAVE);
 }
+
+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()));
+}
+
+android::netdutils::StatusOr<ifreq> ioctlByIfName(const std::string& ifName, unsigned long flag) {
+    const auto& sys = sSyscalls.get();
+    auto fd = sys.socket(AF_INET, SOCK_DGRAM | SOCK_CLOEXEC, 0);
+    EXPECT_TRUE(isOk(fd.status()));
+
+    struct ifreq ifr = {};
+    strlcpy(ifr.ifr_name, ifName.c_str(), IFNAMSIZ);
+
+    return sys.ioctl(fd.value(), flag, &ifr);
+}
+
+std::string getInterfaceHwAddr(const std::string& ifName) {
+    auto res = ioctlByIfName(ifName, SIOCGIFHWADDR);
+
+    unsigned char hwaddr[ETH_ALEN] = {};
+    if (isOk(res.status())) {
+        memcpy((void*) hwaddr, &res.value().ifr_hwaddr.sa_data, ETH_ALEN);
+    }
+
+    return hwAddrToStr(hwaddr);
+}
+
+int getInterfaceIPv4Prefix(const std::string& ifName) {
+    auto res = ioctlByIfName(ifName, SIOCGIFNETMASK);
+
+    int prefixLength = 0;
+    if (isOk(res.status())) {
+        prefixLength = ipv4NetmaskToPrefixLength(
+                ((struct sockaddr_in*) &res.value().ifr_addr)->sin_addr.s_addr);
+    }
+
+    return prefixLength;
+}
+
+std::string getInterfaceIPv4Addr(const std::string& ifName) {
+    auto res = ioctlByIfName(ifName, SIOCGIFADDR);
+
+    struct in_addr addr = {};
+    if (isOk(res.status())) {
+        addr.s_addr = ((struct sockaddr_in*) &res.value().ifr_addr)->sin_addr.s_addr;
+    }
+
+    return std::string(inet_ntoa(addr));
+}
+
+std::vector<std::string> getInterfaceFlags(const std::string& ifName) {
+    auto res = ioctlByIfName(ifName, SIOCGIFFLAGS);
+
+    unsigned flags = 0;
+    if (isOk(res.status())) {
+        flags = res.value().ifr_flags;
+    }
+
+    std::vector<std::string> ifFlags;
+    ifFlags.push_back(flags & IFF_UP ? toStdString(INetd::IF_STATE_UP())
+                                     : toStdString(INetd::IF_STATE_DOWN()));
+
+    if (flags & IFF_BROADCAST) ifFlags.push_back(toStdString(INetd::IF_FLAG_BROADCAST()));
+    if (flags & IFF_LOOPBACK) ifFlags.push_back(toStdString(INetd::IF_FLAG_LOOPBACK()));
+    if (flags & IFF_POINTOPOINT) ifFlags.push_back(toStdString(INetd::IF_FLAG_POINTOPOINT()));
+    if (flags & IFF_RUNNING) ifFlags.push_back(toStdString(INetd::IF_FLAG_RUNNING()));
+    if (flags & IFF_MULTICAST) ifFlags.push_back(toStdString(INetd::IF_FLAG_MULTICAST()));
+
+    return ifFlags;
+}
+
+bool compareListInterface(const std::vector<std::string>& interfaceList) {
+    const auto& res = InterfaceController::getIfaceNames();
+    EXPECT_TRUE(isOk(res));
+
+    std::vector<std::string> resIfList;
+    resIfList.reserve(res.value().size());
+    resIfList.insert(end(resIfList), begin(res.value()), end(res.value()));
+
+    return resIfList == interfaceList;
+}
+
+int getInterfaceIPv6PrivacyExtensions(const std::string& ifName) {
+    std::string path = StringPrintf("/proc/sys/net/ipv6/conf/%s/use_tempaddr", ifName.c_str());
+    return readIntFromPath(path);
+}
+
+bool getInterfaceEnableIPv6(const std::string& ifName) {
+    std::string path = StringPrintf("/proc/sys/net/ipv6/conf/%s/disable_ipv6", ifName.c_str());
+
+    int disableIPv6 = readIntFromPath(path);
+    return !disableIPv6;
+}
+
+int getInterfaceMtu(const std::string& ifName) {
+    std::string path = StringPrintf("/sys/class/net/%s/mtu", ifName.c_str());
+    return readIntFromPath(path);
+}
+
+void expectInterfaceList(const std::vector<std::string>& interfaceList) {
+    EXPECT_TRUE(compareListInterface(interfaceList));
+}
+
+void expectCurrentInterfaceConfigurationEquals(const std::string& ifName,
+                                               const InterfaceConfigurationParcel& interfaceCfg) {
+    EXPECT_EQ(getInterfaceIPv4Addr(ifName), interfaceCfg.ipv4Addr);
+    EXPECT_EQ(getInterfaceIPv4Prefix(ifName), interfaceCfg.prefixLength);
+    EXPECT_EQ(getInterfaceHwAddr(ifName), interfaceCfg.hwAddr);
+    EXPECT_EQ(getInterfaceFlags(ifName), interfaceCfg.flags);
+}
+
+void expectCurrentInterfaceConfigurationAlmostEqual(const InterfaceConfigurationParcel& setCfg) {
+    EXPECT_EQ(getInterfaceIPv4Addr(setCfg.ifName), setCfg.ipv4Addr);
+    EXPECT_EQ(getInterfaceIPv4Prefix(setCfg.ifName), setCfg.prefixLength);
+
+    const auto& ifFlags = getInterfaceFlags(setCfg.ifName);
+    for (const auto& flag : setCfg.flags) {
+        EXPECT_TRUE(std::find(ifFlags.begin(), ifFlags.end(), flag) != ifFlags.end());
+    }
+}
+
+void expectInterfaceIPv6PrivacyExtensions(const std::string& ifName, bool enable) {
+    int v6PrivacyExtensions = getInterfaceIPv6PrivacyExtensions(ifName);
+    EXPECT_EQ(v6PrivacyExtensions, enable ? 2 : 0);
+}
+
+void expectInterfaceNoAddr(const std::string& ifName) {
+    // noAddr
+    EXPECT_EQ(getInterfaceIPv4Addr(ifName), "0.0.0.0");
+    // noPrefix
+    EXPECT_EQ(getInterfaceIPv4Prefix(ifName), 0);
+}
+
+void expectInterfaceEnableIPv6(const std::string& ifName, bool enable) {
+    int enableIPv6 = getInterfaceEnableIPv6(ifName);
+    EXPECT_EQ(enableIPv6, enable);
+}
+
+void expectInterfaceMtu(const std::string& ifName, const int mtu) {
+    int mtuSize = getInterfaceMtu(ifName);
+    EXPECT_EQ(mtu, mtuSize);
+}
+
+InterfaceConfigurationParcel makeInterfaceCfgParcel(const std::string& ifName,
+                                                    const std::string& addr, int prefixLength,
+                                                    const std::vector<std::string>& flags) {
+    InterfaceConfigurationParcel cfg;
+    cfg.ifName = ifName;
+    cfg.hwAddr = "";
+    cfg.ipv4Addr = addr;
+    cfg.prefixLength = prefixLength;
+    cfg.flags = flags;
+    return cfg;
+}
+
+void expectTunFlags(const InterfaceConfigurationParcel& interfaceCfg) {
+    std::vector<std::string> expectedFlags = {"up", "point-to-point", "running", "multicast"};
+    std::vector<std::string> unexpectedFlags = {"down", "broadcast"};
+
+    for (const auto& flag : expectedFlags) {
+        EXPECT_TRUE(std::find(interfaceCfg.flags.begin(), interfaceCfg.flags.end(), flag) !=
+                    interfaceCfg.flags.end());
+    }
+
+    for (const auto& flag : unexpectedFlags) {
+        EXPECT_TRUE(std::find(interfaceCfg.flags.begin(), interfaceCfg.flags.end(), flag) ==
+                    interfaceCfg.flags.end());
+    }
+}
+
+}  // namespace
+
+TEST_F(BinderTest, InterfaceList) {
+    std::vector<std::string> interfaceListResult;
+
+    binder::Status status = mNetd->interfaceGetList(&interfaceListResult);
+    EXPECT_TRUE(status.isOk()) << status.exceptionMessage();
+    expectInterfaceList(interfaceListResult);
+}
+
+TEST_F(BinderTest, InterfaceGetCfg) {
+    InterfaceConfigurationParcel interfaceCfgResult;
+
+    // Add test physical network
+    EXPECT_TRUE(mNetd->networkCreatePhysical(TEST_NETID1, INetd::PERMISSION_NONE).isOk());
+    EXPECT_TRUE(mNetd->networkAddInterface(TEST_NETID1, sTun.name()).isOk());
+
+    binder::Status status = mNetd->interfaceGetCfg(sTun.name(), &interfaceCfgResult);
+    EXPECT_TRUE(status.isOk()) << status.exceptionMessage();
+    expectCurrentInterfaceConfigurationEquals(sTun.name(), interfaceCfgResult);
+    expectTunFlags(interfaceCfgResult);
+
+    // Remove test physical network
+    EXPECT_TRUE(mNetd->networkDestroy(TEST_NETID1).isOk());
+}
+
+TEST_F(BinderTest, InterfaceSetCfg) {
+    const std::string testAddr = "192.0.2.3";
+    const int testPrefixLength = 24;
+    std::vector<std::string> upFlags = {"up"};
+    std::vector<std::string> downFlags = {"down"};
+
+    // Add test physical network
+    EXPECT_TRUE(mNetd->networkCreatePhysical(TEST_NETID1, INetd::PERMISSION_NONE).isOk());
+    EXPECT_TRUE(mNetd->networkAddInterface(TEST_NETID1, sTun.name()).isOk());
+
+    // Set tun interface down.
+    auto interfaceCfg = makeInterfaceCfgParcel(sTun.name(), testAddr, testPrefixLength, downFlags);
+    binder::Status status = mNetd->interfaceSetCfg(interfaceCfg);
+    EXPECT_TRUE(status.isOk()) << status.exceptionMessage();
+    expectCurrentInterfaceConfigurationAlmostEqual(interfaceCfg);
+
+    // Set tun interface up again.
+    interfaceCfg = makeInterfaceCfgParcel(sTun.name(), testAddr, testPrefixLength, upFlags);
+    status = mNetd->interfaceSetCfg(interfaceCfg);
+    EXPECT_TRUE(status.isOk()) << status.exceptionMessage();
+    status = mNetd->interfaceClearAddrs(sTun.name());
+    EXPECT_TRUE(status.isOk()) << status.exceptionMessage();
+
+    // Remove test physical network
+    EXPECT_TRUE(mNetd->networkDestroy(TEST_NETID1).isOk());
+}
+
+TEST_F(BinderTest, InterfaceSetIPv6PrivacyExtensions) {
+    // enable
+    binder::Status status = mNetd->interfaceSetIPv6PrivacyExtensions(sTun.name(), true);
+    EXPECT_TRUE(status.isOk()) << status.exceptionMessage();
+    expectInterfaceIPv6PrivacyExtensions(sTun.name(), true);
+
+    // disable
+    status = mNetd->interfaceSetIPv6PrivacyExtensions(sTun.name(), false);
+    EXPECT_TRUE(status.isOk()) << status.exceptionMessage();
+    expectInterfaceIPv6PrivacyExtensions(sTun.name(), false);
+}
+
+TEST_F(BinderTest, InterfaceClearAddr) {
+    const std::string testAddr = "192.0.2.3";
+    const int testPrefixLength = 24;
+    std::vector<std::string> noFlags{};
+
+    // Add test physical network
+    EXPECT_TRUE(mNetd->networkCreatePhysical(TEST_NETID1, INetd::PERMISSION_NONE).isOk());
+    EXPECT_TRUE(mNetd->networkAddInterface(TEST_NETID1, sTun.name()).isOk());
+
+    auto interfaceCfg = makeInterfaceCfgParcel(sTun.name(), testAddr, testPrefixLength, noFlags);
+    binder::Status status = mNetd->interfaceSetCfg(interfaceCfg);
+    EXPECT_TRUE(status.isOk()) << status.exceptionMessage();
+    expectCurrentInterfaceConfigurationAlmostEqual(interfaceCfg);
+
+    status = mNetd->interfaceClearAddrs(sTun.name());
+    EXPECT_TRUE(status.isOk()) << status.exceptionMessage();
+    expectInterfaceNoAddr(sTun.name());
+
+    // Remove test physical network
+    EXPECT_TRUE(mNetd->networkDestroy(TEST_NETID1).isOk());
+}
+
+TEST_F(BinderTest, InterfaceSetEnableIPv6) {
+    // Add test physical network
+    EXPECT_TRUE(mNetd->networkCreatePhysical(TEST_NETID1, INetd::PERMISSION_NONE).isOk());
+    EXPECT_TRUE(mNetd->networkAddInterface(TEST_NETID1, sTun.name()).isOk());
+
+    // disable
+    binder::Status status = mNetd->interfaceSetEnableIPv6(sTun.name(), false);
+    EXPECT_TRUE(status.isOk()) << status.exceptionMessage();
+    expectInterfaceEnableIPv6(sTun.name(), false);
+
+    // enable
+    status = mNetd->interfaceSetEnableIPv6(sTun.name(), true);
+    EXPECT_TRUE(status.isOk()) << status.exceptionMessage();
+    expectInterfaceEnableIPv6(sTun.name(), true);
+
+    // Remove test physical network
+    EXPECT_TRUE(mNetd->networkDestroy(TEST_NETID1).isOk());
+}
+
+TEST_F(BinderTest, InterfaceSetMtu) {
+    const int testMtu = 1200;
+
+    // Add test physical network
+    EXPECT_TRUE(mNetd->networkCreatePhysical(TEST_NETID1, INetd::PERMISSION_NONE).isOk());
+    EXPECT_TRUE(mNetd->networkAddInterface(TEST_NETID1, sTun.name()).isOk());
+
+    binder::Status status = mNetd->interfaceSetMtu(sTun.name(), testMtu);
+    EXPECT_TRUE(status.isOk()) << status.exceptionMessage();
+    expectInterfaceMtu(sTun.name(), testMtu);
+
+    // Remove test physical network
+    EXPECT_TRUE(mNetd->networkDestroy(TEST_NETID1).isOk());
+}