[Tether09] Add RouteUtils and NetdUtils
Add RouteUtils and NetdUtils file to NetworkStack module shared
folder. And it would statically linked into framework and
tethering module.
Bug: 136040414
Test: -build, flash, boot
-atest TetheringTest
Change-Id: I8c2781597b410d12407ddb743f1621bf92d2a852
diff --git a/common/moduleutils/Android.bp b/common/moduleutils/Android.bp
index 6117149..afd82e5 100644
--- a/common/moduleutils/Android.bp
+++ b/common/moduleutils/Android.bp
@@ -18,4 +18,17 @@
filegroup {
name: "net-module-utils-srcs",
srcs: ["src/**/*.java"],
-}
\ No newline at end of file
+}
+
+// Shared utility sources to be used by tethering modules
+filegroup {
+ name: "tethering-module-utils-srcs",
+ srcs: [
+ "src/android/net/ip/InterfaceController.java",
+ "src/android/net/netlink/*.java",
+ "src/android/net/shared/NetdUtils.java",
+ "src/android/net/shared/RouteUtils.java",
+ "src/android/net/util/InterfaceParams.java",
+ "src/android/net/util/SharedLog.java"
+ ],
+}
diff --git a/common/moduleutils/src/android/net/ip/InterfaceController.java b/common/moduleutils/src/android/net/ip/InterfaceController.java
index f32d143..e8fc72c 100644
--- a/common/moduleutils/src/android/net/ip/InterfaceController.java
+++ b/common/moduleutils/src/android/net/ip/InterfaceController.java
@@ -16,6 +16,9 @@
package android.net.ip;
+import static android.net.INetd.IF_STATE_DOWN;
+import static android.net.INetd.IF_STATE_UP;
+
import android.net.INetd;
import android.net.InterfaceConfigurationParcel;
import android.net.LinkAddress;
@@ -48,13 +51,31 @@
mLog = log;
}
- private boolean setInterfaceAddress(LinkAddress addr) {
+ /**
+ * Set the IPv4 address and also optionally bring the interface up or down.
+ */
+ public boolean setInterfaceConfiguration(final LinkAddress ipv4Addr,
+ final Boolean setIfaceUp) {
+ if (!(ipv4Addr.getAddress() instanceof Inet4Address)) {
+ throw new IllegalArgumentException("Invalid or mismatched Inet4Address");
+ }
+ // Note: currently netd only support INetd#IF_STATE_UP and #IF_STATE_DOWN.
+ // Other flags would be ignored.
+
final InterfaceConfigurationParcel ifConfig = new InterfaceConfigurationParcel();
ifConfig.ifName = mIfName;
- ifConfig.ipv4Addr = addr.getAddress().getHostAddress();
- ifConfig.prefixLength = addr.getPrefixLength();
+ ifConfig.ipv4Addr = ipv4Addr.getAddress().getHostAddress();
+ ifConfig.prefixLength = ipv4Addr.getPrefixLength();
+ // Netd ignores hwaddr in interfaceSetCfg.
ifConfig.hwAddr = "";
- ifConfig.flags = new String[0];
+ if (setIfaceUp == null) {
+ // Empty array means no change.
+ ifConfig.flags = new String[0];
+ } else {
+ // Netd ignores any flag that's not IF_STATE_UP or IF_STATE_DOWN in interfaceSetCfg.
+ ifConfig.flags = setIfaceUp.booleanValue()
+ ? new String[] {IF_STATE_UP} : new String[] {IF_STATE_DOWN};
+ }
try {
mNetd.interfaceSetCfg(ifConfig);
} catch (RemoteException | ServiceSpecificException e) {
@@ -68,18 +89,15 @@
/**
* Set the IPv4 address of the interface.
*/
- public boolean setIPv4Address(LinkAddress address) {
- if (!(address.getAddress() instanceof Inet4Address)) {
- return false;
- }
- return setInterfaceAddress(address);
+ public boolean setIPv4Address(final LinkAddress address) {
+ return setInterfaceConfiguration(address, null);
}
/**
* Clear the IPv4Address of the interface.
*/
public boolean clearIPv4Address() {
- return setInterfaceAddress(new LinkAddress("0.0.0.0/0"));
+ return setIPv4Address(new LinkAddress("0.0.0.0/0"));
}
private boolean setEnableIPv6(boolean enabled) {
diff --git a/common/moduleutils/src/android/net/shared/NetdUtils.java b/common/moduleutils/src/android/net/shared/NetdUtils.java
new file mode 100644
index 0000000..0137bb7
--- /dev/null
+++ b/common/moduleutils/src/android/net/shared/NetdUtils.java
@@ -0,0 +1,65 @@
+/*
+ * Copyright (C) 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.net.shared;
+
+import static android.net.RouteInfo.RTN_UNICAST;
+
+import android.net.INetd;
+import android.net.IpPrefix;
+import android.net.RouteInfo;
+import android.net.TetherConfigParcel;
+import android.os.RemoteException;
+import android.os.ServiceSpecificException;
+
+import java.util.ArrayList;
+import java.util.List;
+
+/**
+ * Implements common operations on INetd
+ * @hide
+ */
+public class NetdUtils {
+ /** Start tethering. */
+ public static void tetherStart(final INetd netd, final boolean usingLegacyDnsProxy,
+ final String[] dhcpRange) throws RemoteException, ServiceSpecificException {
+ final TetherConfigParcel config = new TetherConfigParcel();
+ config.usingLegacyDnsProxy = usingLegacyDnsProxy;
+ config.dhcpRanges = dhcpRange;
+ netd.tetherStartWithConfiguration(config);
+ }
+
+ /** Setup interface for tethering. */
+ public static void tetherInterface(final INetd netd, final String iface, final IpPrefix dest)
+ throws RemoteException, ServiceSpecificException {
+ netd.tetherInterfaceAdd(iface);
+
+ netd.networkAddInterface(INetd.LOCAL_NET_ID, iface);
+ List<RouteInfo> routes = new ArrayList<>();
+ routes.add(new RouteInfo(dest, null, iface, RTN_UNICAST));
+ RouteUtils.addRoutesToLocalNetwork(netd, iface, routes);
+ }
+
+ /** Reset interface for tethering. */
+ public static void untetherInterface(final INetd netd, String iface)
+ throws RemoteException, ServiceSpecificException {
+ try {
+ netd.tetherInterfaceRemove(iface);
+ } finally {
+ netd.networkRemoveInterface(INetd.LOCAL_NET_ID, iface);
+ }
+ }
+}
diff --git a/common/moduleutils/src/android/net/shared/RouteUtils.java b/common/moduleutils/src/android/net/shared/RouteUtils.java
new file mode 100644
index 0000000..54ff675
--- /dev/null
+++ b/common/moduleutils/src/android/net/shared/RouteUtils.java
@@ -0,0 +1,115 @@
+/*
+ * Copyright (C) 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package android.net.shared;
+
+import static android.net.RouteInfo.RTN_THROW;
+import static android.net.RouteInfo.RTN_UNICAST;
+import static android.net.RouteInfo.RTN_UNREACHABLE;
+
+import android.net.INetd;
+import android.net.IpPrefix;
+import android.net.RouteInfo;
+import android.os.RemoteException;
+import android.os.ServiceSpecificException;
+
+import java.util.List;
+
+/** @hide*/
+public class RouteUtils {
+
+ /** Used to modify the specified route. */
+ public enum ModifyOperation {
+ ADD,
+ REMOVE,
+ }
+
+ private static String findNextHop(final RouteInfo route) {
+ final String nextHop;
+ switch (route.getType()) {
+ case RTN_UNICAST:
+ if (route.hasGateway()) {
+ nextHop = route.getGateway().getHostAddress();
+ } else {
+ nextHop = INetd.NEXTHOP_NONE;
+ }
+ break;
+ case RTN_UNREACHABLE:
+ nextHop = INetd.NEXTHOP_UNREACHABLE;
+ break;
+ case RTN_THROW:
+ nextHop = INetd.NEXTHOP_THROW;
+ break;
+ default:
+ nextHop = INetd.NEXTHOP_NONE;
+ break;
+ }
+ return nextHop;
+ }
+
+ /** Add |routes| to local network. */
+ public static void addRoutesToLocalNetwork(final INetd netd, final String iface,
+ final List<RouteInfo> routes) {
+
+ for (RouteInfo route : routes) {
+ if (!route.isDefaultRoute()) {
+ modifyRoute(netd, ModifyOperation.ADD, INetd.LOCAL_NET_ID, route);
+ }
+ }
+
+ // IPv6 link local should be activated always.
+ modifyRoute(netd, ModifyOperation.ADD, INetd.LOCAL_NET_ID,
+ new RouteInfo(new IpPrefix("fe80::/64"), null, iface, RTN_UNICAST));
+ }
+
+ /** Remove routes from local network. */
+ public static int removeRoutesFromLocalNetwork(final INetd netd, final List<RouteInfo> routes) {
+ int failures = 0;
+
+ for (RouteInfo route : routes) {
+ try {
+ modifyRoute(netd, ModifyOperation.REMOVE, INetd.LOCAL_NET_ID, route);
+ } catch (IllegalStateException e) {
+ failures++;
+ }
+ }
+
+ return failures;
+ }
+
+ /** Add or remove |route|. */
+ public static void modifyRoute(final INetd netd, final ModifyOperation op, final int netId,
+ final RouteInfo route) {
+ final String ifName = route.getInterface();
+ final String dst = route.getDestination().toString();
+ final String nextHop = findNextHop(route);
+
+ try {
+ switch(op) {
+ case ADD:
+ netd.networkAddRoute(netId, ifName, dst, nextHop);
+ break;
+ case REMOVE:
+ netd.networkRemoveRoute(netId, ifName, dst, nextHop);
+ break;
+ default:
+ throw new IllegalStateException("Unsupported modify operation:" + op);
+ }
+ } catch (RemoteException | ServiceSpecificException e) {
+ throw new IllegalStateException(e);
+ }
+ }
+
+}