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