Implement INetd 1.1.

Bug: 73032258
Test: builds, boots
Test: VtsHalNetNetdV1_0TargetTest and VtsHalNetNetdV1_1TargetTest pass
Change-Id: I0a802d4766c8138fe0cb4d49759453fe30d72518
diff --git a/server/Android.mk b/server/Android.mk
index 120d5be..2597aa1 100644
--- a/server/Android.mk
+++ b/server/Android.mk
@@ -72,6 +72,7 @@
 
 LOCAL_SHARED_LIBRARIES := \
         android.system.net.netd@1.0 \
+        android.system.net.netd@1.1 \
         libbinder \
         libbpf    \
         libcrypto \
diff --git a/server/NetdHwService.cpp b/server/NetdHwService.cpp
index a4f9fbb..65afe9b 100644
--- a/server/NetdHwService.cpp
+++ b/server/NetdHwService.cpp
@@ -20,37 +20,38 @@
 #include "Controllers.h"
 #include "Fwmark.h"
 #include "NetdHwService.h"
+#include "RouteController.h"
+#include "TetherController.h"
 
 using android::hardware::configureRpcThreadpool;
 using android::hardware::IPCThreadState;
 using android::hardware::Void;
 
+// Tells TetherController::enableForwarding who is requesting forwarding, so that TetherController
+// can manage/refcount requests to enable forwarding by multiple parties such as the framework, this
+// hwbinder interface, and the legacy "ndc ipfwd enable <requester>" commands.
+namespace {
+constexpr const char* FORWARDING_REQUESTER = "NetdHwService";
+}
+
 namespace android {
 namespace net {
 
-/**
- * This lock exists to make NetdHwService RPCs (which come in on multiple HwBinder threads)
- * coexist with the commands in CommandListener.cpp. These are presumed not thread-safe because
- * CommandListener has only one user (NetworkManagementService), which is connected through a
- * FrameworkListener that passes in commands one at a time.
- */
-extern android::RWLock gBigNetdLock;
-
-static INetd::StatusCode toHalStatus(int ret) {
+static StatusCode toHalStatus(int ret) {
     switch(ret) {
         case 0:
-            return INetd::StatusCode::OK;
+            return StatusCode::OK;
         case -EINVAL:
-            return INetd::StatusCode::INVALID_ARGUMENTS;
+            return StatusCode::INVALID_ARGUMENTS;
         case -EEXIST:
-            return INetd::StatusCode::ALREADY_EXISTS;
+            return StatusCode::ALREADY_EXISTS;
         case -ENONET:
-            return INetd::StatusCode::NO_NETWORK;
+            return StatusCode::NO_NETWORK;
         case -EPERM:
-            return INetd::StatusCode::PERMISSION_DENIED;
+            return StatusCode::PERMISSION_DENIED;
         default:
             ALOGE("HAL service error=%d", ret);
-            return INetd::StatusCode::UNKNOWN_ERROR;
+            return StatusCode::UNKNOWN_ERROR;
     }
 }
 
@@ -79,15 +80,84 @@
     return Void();
 }
 
-Return<INetd::StatusCode> NetdHwService::destroyOemNetwork(uint64_t netHandle) {
-    unsigned netId = netHandleToNetId(netHandle);
-    if ((netId < NetworkController::MIN_OEM_ID) ||
-            (netId > NetworkController::MAX_OEM_ID)) {
-        return INetd::StatusCode::INVALID_ARGUMENTS;
+// Vendor code can only modify OEM networks. All other networks are managed by ConnectivityService.
+#define RETURN_IF_NOT_OEM_NETWORK(netId)              \
+    if (((netId) < NetworkController::MIN_OEM_ID) ||  \
+        ((netId) > NetworkController::MAX_OEM_ID)) {  \
+        return StatusCode::INVALID_ARGUMENTS;  \
     }
 
+Return<StatusCode> NetdHwService::destroyOemNetwork(uint64_t netHandle) {
+    unsigned netId = netHandleToNetId(netHandle);
+    RETURN_IF_NOT_OEM_NETWORK(netId);
+
     return toHalStatus(gCtls->netCtrl.destroyNetwork(netId));
 }
 
+const char* maybeNullString(const hidl_string& nexthop) {
+    // HIDL strings can't be null, but RouteController wants null instead of an empty string.
+    const char* nh = nexthop.c_str();
+    if (nh && !*nh) {
+        nh = nullptr;
+    }
+    return nh;
+}
+
+Return <StatusCode> NetdHwService::addRouteToOemNetwork(
+        uint64_t networkHandle, const hidl_string& ifname, const hidl_string& destination,
+        const hidl_string& nexthop) {
+    unsigned netId = netHandleToNetId(networkHandle);
+    RETURN_IF_NOT_OEM_NETWORK(netId);
+
+    return toHalStatus(gCtls->netCtrl.addRoute(netId, ifname.c_str(), destination.c_str(),
+                                               maybeNullString(nexthop), false, INVALID_UID));
+}
+
+Return <StatusCode> NetdHwService::removeRouteFromOemNetwork(
+        uint64_t networkHandle, const hidl_string& ifname, const hidl_string& destination,
+        const hidl_string& nexthop) {
+    unsigned netId = netHandleToNetId(networkHandle);
+    RETURN_IF_NOT_OEM_NETWORK(netId);
+
+    return toHalStatus(gCtls->netCtrl.removeRoute(netId, ifname.c_str(), destination.c_str(),
+                                                  maybeNullString(nexthop), false, INVALID_UID));
+}
+
+Return <StatusCode> NetdHwService::addInterfaceToOemNetwork(uint64_t networkHandle,
+                                                            const hidl_string& ifname) {
+    unsigned netId = netHandleToNetId(networkHandle);
+    RETURN_IF_NOT_OEM_NETWORK(netId);
+
+    return toHalStatus(gCtls->netCtrl.addInterfaceToNetwork(netId, ifname.c_str()));
+}
+
+Return <StatusCode> NetdHwService::removeInterfaceFromOemNetwork(uint64_t networkHandle,
+                                                                 const hidl_string& ifname) {
+    unsigned netId = netHandleToNetId(networkHandle);
+    RETURN_IF_NOT_OEM_NETWORK(netId);
+
+    return toHalStatus(gCtls->netCtrl.removeInterfaceFromNetwork(netId, ifname.c_str()));
+}
+
+Return <StatusCode> NetdHwService::setIpForwardEnable(bool enable) {
+    android::RWLock::AutoWLock _lock(gCtls->tetherCtrl.lock);
+
+    bool success = enable ? gCtls->tetherCtrl.enableForwarding(FORWARDING_REQUESTER) :
+                            gCtls->tetherCtrl.disableForwarding(FORWARDING_REQUESTER);
+
+    return success ? StatusCode::OK : StatusCode::UNKNOWN_ERROR;
+}
+
+Return <StatusCode> NetdHwService::setForwardingBetweenInterfaces(
+        const hidl_string& inputIfName, const hidl_string& outputIfName, bool enable) {
+    android::RWLock::AutoWLock _lock(gCtls->tetherCtrl.lock);
+
+    // TODO: check that one interface is an OEM interface and the other is another OEM interface, an
+    // IPsec interface or a dummy interface.
+    int ret = enable ? RouteController::enableTethering(inputIfName.c_str(), outputIfName.c_str()) :
+                       RouteController::disableTethering(inputIfName.c_str(), outputIfName.c_str());
+    return toHalStatus(ret);
+}
+
 }  // namespace net
 }  // namespace android
diff --git a/server/NetdHwService.h b/server/NetdHwService.h
index f938dd6..a814fe4 100644
--- a/server/NetdHwService.h
+++ b/server/NetdHwService.h
@@ -17,19 +17,38 @@
 #ifndef ANDROID_NET_HW_SERVICE_H
 #define ANDROID_NET_HW_SERVICE_H
 
-#include <android/system/net/netd/1.0/INetd.h>
+#include <android/system/net/netd/1.1/INetd.h>
 
 using android::hardware::Return;
-using android::system::net::netd::V1_0::INetd;
+using android::hardware::hidl_string;
+using android::system::net::netd::V1_1::INetd;
+using StatusCode = android::system::net::netd::V1_1::INetd::StatusCode;
 
 namespace android {
 namespace net {
 
 class NetdHwService : public INetd {
 public:
+    // 1.0
     status_t start();
     Return<void> createOemNetwork(createOemNetwork_cb _hidl_cb) override;
-    Return<INetd::StatusCode> destroyOemNetwork(uint64_t netHandle) override;
+    Return<StatusCode> destroyOemNetwork(uint64_t netHandle) override;
+
+    // 1.1
+    Return <StatusCode> addRouteToOemNetwork(
+            uint64_t networkHandle, const hidl_string& ifname, const hidl_string& destination,
+            const hidl_string& nexthop) override;
+    Return <StatusCode> removeRouteFromOemNetwork(
+            uint64_t networkHandle, const hidl_string& ifname, const hidl_string& destination,
+            const hidl_string& nexthop) override;
+    Return <StatusCode> addInterfaceToOemNetwork(uint64_t networkHandle,
+                                                 const hidl_string& ifname) override;
+    Return <StatusCode> removeInterfaceFromOemNetwork(uint64_t networkHandle,
+                                                      const hidl_string& ifname) override;
+    Return <StatusCode> setIpForwardEnable(bool enable) override;
+    Return <StatusCode> setForwardingBetweenInterfaces(const hidl_string& inputIfName,
+                                                       const hidl_string& outputIfName,
+                                                       bool enable) override;
 };
 
 }  // namespace net