Merge "Increase the service bind timeout." into main
diff --git a/Tethering/apex/Android.bp b/Tethering/apex/Android.bp
index 9132857..cd8eac8 100644
--- a/Tethering/apex/Android.bp
+++ b/Tethering/apex/Android.bp
@@ -96,6 +96,7 @@
},
binaries: [
"clatd",
+ "ethtool",
"netbpfload",
"ot-daemon",
],
diff --git a/Tethering/tests/privileged/src/android/net/ip/RouterAdvertisementDaemonTest.java b/Tethering/tests/privileged/src/android/net/ip/RouterAdvertisementDaemonTest.java
index 328e3fb..dac5b63 100644
--- a/Tethering/tests/privileged/src/android/net/ip/RouterAdvertisementDaemonTest.java
+++ b/Tethering/tests/privileged/src/android/net/ip/RouterAdvertisementDaemonTest.java
@@ -16,8 +16,6 @@
package android.net.ip;
-import static android.net.RouteInfo.RTN_UNICAST;
-
import static com.android.net.module.util.NetworkStackConstants.ETHER_HEADER_LEN;
import static com.android.net.module.util.NetworkStackConstants.ETHER_TYPE_IPV6;
import static com.android.net.module.util.NetworkStackConstants.ICMPV6_ND_OPTION_MTU;
@@ -42,12 +40,13 @@
import android.net.INetd;
import android.net.IpPrefix;
import android.net.MacAddress;
-import android.net.RouteInfo;
import android.net.ip.RouterAdvertisementDaemon.RaParams;
import android.os.Handler;
import android.os.HandlerThread;
import android.os.IBinder;
import android.os.Looper;
+import android.os.RemoteException;
+import android.os.ServiceSpecificException;
import androidx.test.InstrumentationRegistry;
import androidx.test.filters.SmallTest;
@@ -55,7 +54,6 @@
import com.android.net.module.util.InterfaceParams;
import com.android.net.module.util.Ipv6Utils;
-import com.android.net.module.util.NetdUtils;
import com.android.net.module.util.Struct;
import com.android.net.module.util.structs.EthernetHeader;
import com.android.net.module.util.structs.Icmpv6Header;
@@ -80,7 +78,6 @@
import java.net.InetAddress;
import java.nio.ByteBuffer;
import java.util.HashSet;
-import java.util.List;
@RunWith(AndroidJUnit4.class)
@SmallTest
@@ -332,10 +329,12 @@
// Add a default route "fe80::/64 -> ::" to local network, otherwise, device will fail to
// send the unicast RA out due to the ENETUNREACH error(No route to the peer's link-local
// address is present).
- final String iface = mTetheredParams.name;
- final RouteInfo linkLocalRoute =
- new RouteInfo(new IpPrefix("fe80::/64"), null, iface, RTN_UNICAST);
- NetdUtils.addRoutesToLocalNetwork(sNetd, iface, List.of(linkLocalRoute));
+ try {
+ sNetd.networkAddRoute(INetd.LOCAL_NET_ID, mTetheredParams.name,
+ "fe80::/64", INetd.NEXTHOP_NONE);
+ } catch (RemoteException | ServiceSpecificException e) {
+ throw new IllegalStateException(e);
+ }
final ByteBuffer rs = createRsPacket("fe80::1122:3344:5566:7788");
mTetheredPacketReader.sendResponse(rs);
diff --git a/bpf_progs/netd.h b/bpf_progs/netd.h
index dd27bf9..4958040 100644
--- a/bpf_progs/netd.h
+++ b/bpf_progs/netd.h
@@ -190,7 +190,7 @@
OEM_DENY_2_MATCH = (1 << 10),
OEM_DENY_3_MATCH = (1 << 11),
};
-// LINT.ThenChange(packages/modules/Connectivity/service/src/com/android/server/BpfNetMaps.java)
+// LINT.ThenChange(../framework/src/android/net/BpfNetMapsConstants.java)
enum BpfPermissionMatch {
BPF_PERMISSION_INTERNET = 1 << 2,
diff --git a/framework/aidl-export/android/net/LocalNetworkConfig.aidl b/framework/aidl-export/android/net/LocalNetworkConfig.aidl
new file mode 100644
index 0000000..e2829a5
--- /dev/null
+++ b/framework/aidl-export/android/net/LocalNetworkConfig.aidl
@@ -0,0 +1,20 @@
+/**
+ *
+ * Copyright (C) 2023 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;
+
+@JavaOnlyStableParcelable parcelable LocalNetworkConfig;
diff --git a/framework/src/android/net/BpfNetMapsConstants.java b/framework/src/android/net/BpfNetMapsConstants.java
index 2191682..e0527f5 100644
--- a/framework/src/android/net/BpfNetMapsConstants.java
+++ b/framework/src/android/net/BpfNetMapsConstants.java
@@ -60,7 +60,7 @@
public static final long OEM_DENY_1_MATCH = (1 << 9);
public static final long OEM_DENY_2_MATCH = (1 << 10);
public static final long OEM_DENY_3_MATCH = (1 << 11);
- // LINT.ThenChange(packages/modules/Connectivity/bpf_progs/netd.h)
+ // LINT.ThenChange(../../../../bpf_progs/netd.h)
public static final List<Pair<Long, String>> MATCH_LIST = Arrays.asList(
Pair.create(HAPPY_BOX_MATCH, "HAPPY_BOX_MATCH"),
diff --git a/framework/src/android/net/ConnectivityManager.java b/framework/src/android/net/ConnectivityManager.java
index 2315521..915c20d 100644
--- a/framework/src/android/net/ConnectivityManager.java
+++ b/framework/src/android/net/ConnectivityManager.java
@@ -3811,11 +3811,28 @@
@RequiresPermission(anyOf = {
NetworkStack.PERMISSION_MAINLINE_NETWORK_STACK,
android.Manifest.permission.NETWORK_FACTORY})
- public Network registerNetworkAgent(INetworkAgent na, NetworkInfo ni, LinkProperties lp,
- NetworkCapabilities nc, @NonNull NetworkScore score, NetworkAgentConfig config,
- int providerId) {
+ public Network registerNetworkAgent(@NonNull INetworkAgent na, @NonNull NetworkInfo ni,
+ @NonNull LinkProperties lp, @NonNull NetworkCapabilities nc,
+ @NonNull NetworkScore score, @NonNull NetworkAgentConfig config, int providerId) {
+ return registerNetworkAgent(na, ni, lp, nc, null /* localNetworkConfig */, score, config,
+ providerId);
+ }
+
+ /**
+ * @hide
+ * Register a NetworkAgent with ConnectivityService.
+ * @return Network corresponding to NetworkAgent.
+ */
+ @RequiresPermission(anyOf = {
+ NetworkStack.PERMISSION_MAINLINE_NETWORK_STACK,
+ android.Manifest.permission.NETWORK_FACTORY})
+ public Network registerNetworkAgent(@NonNull INetworkAgent na, @NonNull NetworkInfo ni,
+ @NonNull LinkProperties lp, @NonNull NetworkCapabilities nc,
+ @Nullable LocalNetworkConfig localNetworkConfig, @NonNull NetworkScore score,
+ @NonNull NetworkAgentConfig config, int providerId) {
try {
- return mService.registerNetworkAgent(na, ni, lp, nc, score, config, providerId);
+ return mService.registerNetworkAgent(na, ni, lp, nc, score, localNetworkConfig, config,
+ providerId);
} catch (RemoteException e) {
throw e.rethrowFromSystemServer();
}
diff --git a/framework/src/android/net/IConnectivityManager.aidl b/framework/src/android/net/IConnectivityManager.aidl
index ebe8bca..fe27773 100644
--- a/framework/src/android/net/IConnectivityManager.aidl
+++ b/framework/src/android/net/IConnectivityManager.aidl
@@ -27,6 +27,7 @@
import android.net.IQosCallback;
import android.net.ISocketKeepaliveCallback;
import android.net.LinkProperties;
+import android.net.LocalNetworkConfig;
import android.net.Network;
import android.net.NetworkAgentConfig;
import android.net.NetworkCapabilities;
@@ -146,7 +147,8 @@
void declareNetworkRequestUnfulfillable(in NetworkRequest request);
Network registerNetworkAgent(in INetworkAgent na, in NetworkInfo ni, in LinkProperties lp,
- in NetworkCapabilities nc, in NetworkScore score, in NetworkAgentConfig config,
+ in NetworkCapabilities nc, in NetworkScore score,
+ in LocalNetworkConfig localNetworkConfig, in NetworkAgentConfig config,
in int factorySerialNumber);
NetworkRequest requestNetwork(int uid, in NetworkCapabilities networkCapabilities, int reqType,
diff --git a/framework/src/android/net/INetworkAgentRegistry.aidl b/framework/src/android/net/INetworkAgentRegistry.aidl
index b375b7b..61b27b5 100644
--- a/framework/src/android/net/INetworkAgentRegistry.aidl
+++ b/framework/src/android/net/INetworkAgentRegistry.aidl
@@ -17,6 +17,7 @@
import android.net.DscpPolicy;
import android.net.LinkProperties;
+import android.net.LocalNetworkConfig;
import android.net.Network;
import android.net.NetworkCapabilities;
import android.net.NetworkInfo;
@@ -34,6 +35,7 @@
void sendLinkProperties(in LinkProperties lp);
// TODO: consider replacing this by "markConnected()" and removing
void sendNetworkInfo(in NetworkInfo info);
+ void sendLocalNetworkConfig(in LocalNetworkConfig config);
void sendScore(in NetworkScore score);
void sendExplicitlySelected(boolean explicitlySelected, boolean acceptPartial);
void sendSocketKeepaliveEvent(int slot, int reason);
diff --git a/framework/src/android/net/LocalNetworkConfig.java b/framework/src/android/net/LocalNetworkConfig.java
new file mode 100644
index 0000000..fca7fd1
--- /dev/null
+++ b/framework/src/android/net/LocalNetworkConfig.java
@@ -0,0 +1,168 @@
+/*
+ * Copyright (C) 2023 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;
+
+import android.annotation.NonNull;
+import android.annotation.Nullable;
+import android.os.Parcel;
+import android.os.Parcelable;
+
+/**
+ * A class to communicate configuration info about a local network through {@link NetworkAgent}.
+ * @hide
+ */
+// TODO : @SystemApi
+public final class LocalNetworkConfig implements Parcelable {
+ @Nullable
+ private final NetworkRequest mUpstreamSelector;
+
+ @NonNull
+ private final MulticastRoutingConfig mUpstreamMulticastRoutingConfig;
+
+ @NonNull
+ private final MulticastRoutingConfig mDownstreamMulticastRoutingConfig;
+
+ private LocalNetworkConfig(@Nullable final NetworkRequest upstreamSelector,
+ @Nullable final MulticastRoutingConfig upstreamConfig,
+ @Nullable final MulticastRoutingConfig downstreamConfig) {
+ mUpstreamSelector = upstreamSelector;
+ if (null != upstreamConfig) {
+ mUpstreamMulticastRoutingConfig = upstreamConfig;
+ } else {
+ mUpstreamMulticastRoutingConfig = MulticastRoutingConfig.CONFIG_FORWARD_NONE;
+ }
+ if (null != downstreamConfig) {
+ mDownstreamMulticastRoutingConfig = downstreamConfig;
+ } else {
+ mDownstreamMulticastRoutingConfig = MulticastRoutingConfig.CONFIG_FORWARD_NONE;
+ }
+ }
+
+ /**
+ * Get the request choosing which network traffic from this network is forwarded to and from.
+ *
+ * This may be null if the local network doesn't forward the traffic anywhere.
+ */
+ @Nullable
+ public NetworkRequest getUpstreamSelector() {
+ return mUpstreamSelector;
+ }
+
+ public @NonNull MulticastRoutingConfig getUpstreamMulticastRoutingConfig() {
+ return mUpstreamMulticastRoutingConfig;
+ }
+
+ public @NonNull MulticastRoutingConfig getDownstreamMulticastRoutingConfig() {
+ return mDownstreamMulticastRoutingConfig;
+ }
+
+ @Override
+ public int describeContents() {
+ return 0;
+ }
+
+ @Override
+ public void writeToParcel(@NonNull final Parcel dest, final int flags) {
+ dest.writeParcelable(mUpstreamSelector, flags);
+ dest.writeParcelable(mUpstreamMulticastRoutingConfig, flags);
+ dest.writeParcelable(mDownstreamMulticastRoutingConfig, flags);
+ }
+
+ public static final @NonNull Creator<LocalNetworkConfig> CREATOR = new Creator<>() {
+ public LocalNetworkConfig createFromParcel(Parcel in) {
+ final NetworkRequest upstreamSelector = in.readParcelable(null);
+ final MulticastRoutingConfig upstreamConfig = in.readParcelable(null);
+ final MulticastRoutingConfig downstreamConfig = in.readParcelable(null);
+ return new LocalNetworkConfig(
+ upstreamSelector, upstreamConfig, downstreamConfig);
+ }
+
+ @Override
+ public LocalNetworkConfig[] newArray(final int size) {
+ return new LocalNetworkConfig[size];
+ }
+ };
+
+
+ public static final class Builder {
+ @Nullable
+ NetworkRequest mUpstreamSelector;
+
+ @Nullable
+ MulticastRoutingConfig mUpstreamMulticastRoutingConfig;
+
+ @Nullable
+ MulticastRoutingConfig mDownstreamMulticastRoutingConfig;
+
+ /**
+ * Create a Builder
+ */
+ public Builder() {
+ }
+
+ /**
+ * Set to choose where this local network should forward its traffic to.
+ *
+ * The system will automatically choose the best network matching the request as an
+ * upstream, and set up forwarding between this local network and the chosen upstream.
+ * If no network matches the request, there is no upstream and the traffic is not forwarded.
+ * The caller can know when this changes by listening to link properties changes of
+ * this network with the {@link android.net.LinkProperties#getForwardedNetwork()} getter.
+ *
+ * Set this to null if the local network shouldn't be forwarded. Default is null.
+ */
+ @NonNull
+ public Builder setUpstreamSelector(@Nullable NetworkRequest upstreamSelector) {
+ mUpstreamSelector = upstreamSelector;
+ return this;
+ }
+
+ /**
+ * Set the upstream multicast routing config.
+ *
+ * If null, don't route multicast packets upstream. This is equivalent to a
+ * MulticastRoutingConfig in mode FORWARD_NONE. The default is null.
+ */
+ @NonNull
+ public Builder setUpstreamMulticastRoutingConfig(@Nullable MulticastRoutingConfig cfg) {
+ mUpstreamMulticastRoutingConfig = cfg;
+ return this;
+ }
+
+ /**
+ * Set the downstream multicast routing config.
+ *
+ * If null, don't route multicast packets downstream. This is equivalent to a
+ * MulticastRoutingConfig in mode FORWARD_NONE. The default is null.
+ */
+ @NonNull
+ public Builder setDownstreamMulticastRoutingConfig(@Nullable MulticastRoutingConfig cfg) {
+ mDownstreamMulticastRoutingConfig = cfg;
+ return this;
+ }
+
+ /**
+ * Build the LocalNetworkConfig object.
+ */
+ @NonNull
+ public LocalNetworkConfig build() {
+ return new LocalNetworkConfig(mUpstreamSelector,
+ mUpstreamMulticastRoutingConfig,
+ mDownstreamMulticastRoutingConfig);
+ }
+ }
+}
diff --git a/framework/src/android/net/MulticastRoutingConfig.java b/framework/src/android/net/MulticastRoutingConfig.java
new file mode 100644
index 0000000..ebd9fc5
--- /dev/null
+++ b/framework/src/android/net/MulticastRoutingConfig.java
@@ -0,0 +1,264 @@
+/*
+ * Copyright (C) 2023 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;
+
+import android.annotation.IntDef;
+import android.annotation.NonNull;
+import android.annotation.Nullable;
+import android.os.Parcel;
+import android.os.Parcelable;
+import android.util.ArraySet;
+import android.util.Log;
+
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+import java.net.Inet6Address;
+import java.net.UnknownHostException;
+import java.util.Arrays;
+import java.util.Collections;
+import java.util.Set;
+
+/**
+ * A class representing a configuration for multicast routing.
+ *
+ * Internal usage to Connectivity
+ * @hide
+ */
+// TODO : @SystemApi
+public class MulticastRoutingConfig implements Parcelable {
+ private static final String TAG = MulticastRoutingConfig.class.getSimpleName();
+
+ /** Do not forward any multicast packets. */
+ public static final int FORWARD_NONE = 0;
+ /**
+ * Forward only multicast packets with destination in the list of listening addresses.
+ * Ignore the min scope.
+ */
+ public static final int FORWARD_SELECTED = 1;
+ /**
+ * Forward all multicast packets with scope greater or equal than the min scope.
+ * Ignore the list of listening addresses.
+ */
+ public static final int FORWARD_WITH_MIN_SCOPE = 2;
+
+ @Retention(RetentionPolicy.SOURCE)
+ @IntDef(prefix = { "FORWARD_" }, value = {
+ FORWARD_NONE,
+ FORWARD_SELECTED,
+ FORWARD_WITH_MIN_SCOPE
+ })
+ public @interface MulticastForwardingMode {}
+
+ /**
+ * Not a multicast scope, for configurations that do not use the min scope.
+ */
+ public static final int MULTICAST_SCOPE_NONE = -1;
+
+ public static final MulticastRoutingConfig CONFIG_FORWARD_NONE =
+ new MulticastRoutingConfig(FORWARD_NONE, MULTICAST_SCOPE_NONE, null);
+
+ @MulticastForwardingMode
+ private final int mForwardingMode;
+
+ private final int mMinScope;
+
+ @NonNull
+ private final Set<Inet6Address> mListeningAddresses;
+
+ private MulticastRoutingConfig(@MulticastForwardingMode final int mode, final int scope,
+ @Nullable final Set<Inet6Address> addresses) {
+ mForwardingMode = mode;
+ mMinScope = scope;
+ if (null != addresses) {
+ mListeningAddresses = Collections.unmodifiableSet(new ArraySet<>(addresses));
+ } else {
+ mListeningAddresses = Collections.emptySet();
+ }
+ }
+
+ /**
+ * Returns the forwarding mode.
+ */
+ @MulticastForwardingMode
+ public int getForwardingMode() {
+ return mForwardingMode;
+ }
+
+ /**
+ * Returns the minimal group address scope that is allowed for forwarding.
+ * If the forwarding mode is not FORWARD_WITH_MIN_SCOPE, will be MULTICAST_SCOPE_NONE.
+ */
+ public int getMinScope() {
+ return mMinScope;
+ }
+
+ /**
+ * Returns the list of group addresses listened by the outgoing interface.
+ * The list will be empty if the forwarding mode is not FORWARD_SELECTED.
+ */
+ @NonNull
+ public Set<Inet6Address> getMulticastListeningAddresses() {
+ return mListeningAddresses;
+ }
+
+ private MulticastRoutingConfig(Parcel in) {
+ mForwardingMode = in.readInt();
+ mMinScope = in.readInt();
+ final int count = in.readInt();
+ final ArraySet<Inet6Address> listeningAddresses = new ArraySet<>(count);
+ final byte[] buffer = new byte[16]; // Size of an Inet6Address
+ for (int i = 0; i < count; ++i) {
+ in.readByteArray(buffer);
+ try {
+ listeningAddresses.add((Inet6Address) Inet6Address.getByAddress(buffer));
+ } catch (UnknownHostException e) {
+ Log.wtf(TAG, "Can't read inet6address : " + Arrays.toString(buffer));
+ }
+ }
+ mListeningAddresses = Collections.unmodifiableSet(listeningAddresses);
+ }
+
+ @Override
+ public void writeToParcel(Parcel dest, int flags) {
+ dest.writeInt(mForwardingMode);
+ dest.writeInt(mMinScope);
+ dest.writeInt(mListeningAddresses.size());
+ for (final Inet6Address addr : mListeningAddresses) {
+ dest.writeByteArray(addr.getAddress());
+ }
+ }
+
+ @Override
+ public int describeContents() {
+ return 0;
+ }
+
+ public static final Creator<MulticastRoutingConfig> CREATOR = new Creator<>() {
+ @Override
+ public MulticastRoutingConfig createFromParcel(Parcel in) {
+ return new MulticastRoutingConfig(in);
+ }
+
+ @Override
+ public MulticastRoutingConfig[] newArray(int size) {
+ return new MulticastRoutingConfig[size];
+ }
+ };
+
+ public static class Builder {
+ @MulticastForwardingMode
+ private final int mForwardingMode;
+ private int mMinScope;
+ private final ArraySet<Inet6Address> mListeningAddresses;
+
+ private Builder(@MulticastForwardingMode final int mode, int scope) {
+ mForwardingMode = mode;
+ mMinScope = scope;
+ mListeningAddresses = new ArraySet<>();
+ }
+
+ /**
+ * Create a builder that forwards nothing.
+ * No properties can be set on such a builder.
+ */
+ public static Builder newBuilderForwardingNone() {
+ return new Builder(FORWARD_NONE, MULTICAST_SCOPE_NONE);
+ }
+
+ /**
+ * Create a builder that forwards packets above a certain scope
+ *
+ * The scope can be changed on this builder, but not the listening addresses.
+ * @param scope the initial scope
+ */
+ public static Builder newBuilderWithMinScope(final int scope) {
+ return new Builder(FORWARD_WITH_MIN_SCOPE, scope);
+ }
+
+ /**
+ * Create a builder that forwards a specified list of listening addresses.
+ *
+ * Addresses can be added and removed from this builder, but the scope can't be set.
+ */
+ public static Builder newBuilderWithListeningAddresses() {
+ return new Builder(FORWARD_SELECTED, MULTICAST_SCOPE_NONE);
+ }
+
+ /**
+ * Sets the minimum scope for this multicast routing config.
+ * This is only meaningful (indeed, allowed) for configs in FORWARD_WITH_MIN_SCOPE mode.
+ * @return this builder
+ */
+ public Builder setMinimumScope(final int scope) {
+ if (FORWARD_WITH_MIN_SCOPE != mForwardingMode) {
+ throw new IllegalArgumentException("Can't set the scope on a builder in mode "
+ + modeToString(mForwardingMode));
+ }
+ mMinScope = scope;
+ return this;
+ }
+
+ /**
+ * Add an address to the set of listening addresses.
+ *
+ * This is only meaningful (indeed, allowed) for configs in FORWARD_SELECTED mode.
+ * If this address was already added, this is a no-op.
+ * @return this builder
+ */
+ public Builder addListeningAddress(@NonNull final Inet6Address address) {
+ if (FORWARD_SELECTED != mForwardingMode) {
+ throw new IllegalArgumentException("Can't add an address on a builder in mode "
+ + modeToString(mForwardingMode));
+ }
+ // TODO : should we check that this is a multicast address ?
+ mListeningAddresses.add(address);
+ return this;
+ }
+
+ /**
+ * Remove an address from the set of listening addresses.
+ *
+ * This is only meaningful (indeed, allowed) for configs in FORWARD_SELECTED mode.
+ * If this address was not added, or was already removed, this is a no-op.
+ * @return this builder
+ */
+ public Builder removeListeningAddress(@NonNull final Inet6Address address) {
+ if (FORWARD_SELECTED != mForwardingMode) {
+ throw new IllegalArgumentException("Can't remove an address on a builder in mode "
+ + modeToString(mForwardingMode));
+ }
+ mListeningAddresses.remove(address);
+ return this;
+ }
+
+ /**
+ * Build the config.
+ */
+ public MulticastRoutingConfig build() {
+ return new MulticastRoutingConfig(mForwardingMode, mMinScope, mListeningAddresses);
+ }
+ }
+
+ private static String modeToString(@MulticastForwardingMode final int mode) {
+ switch (mode) {
+ case FORWARD_NONE: return "FORWARD_NONE";
+ case FORWARD_SELECTED: return "FORWARD_SELECTED";
+ case FORWARD_WITH_MIN_SCOPE: return "FORWARD_WITH_MIN_SCOPE";
+ default: return "unknown multicast routing mode " + mode;
+ }
+ }
+}
diff --git a/framework/src/android/net/NetworkAgent.java b/framework/src/android/net/NetworkAgent.java
index 177f7e3..4e9087c 100644
--- a/framework/src/android/net/NetworkAgent.java
+++ b/framework/src/android/net/NetworkAgent.java
@@ -151,7 +151,7 @@
/**
* Sent by the NetworkAgent to ConnectivityService to pass the current
- * NetworkCapabilties.
+ * NetworkCapabilities.
* obj = NetworkCapabilities
* @hide
*/
@@ -443,6 +443,14 @@
public static final int EVENT_UNREGISTER_AFTER_REPLACEMENT = BASE + 29;
/**
+ * Sent by the NetworkAgent to ConnectivityService to pass the new value of the local
+ * network agent config.
+ * obj = {@code Pair<NetworkAgentInfo, LocalNetworkConfig>}
+ * @hide
+ */
+ public static final int EVENT_LOCAL_NETWORK_CONFIG_CHANGED = BASE + 30;
+
+ /**
* DSCP policy was successfully added.
*/
public static final int DSCP_POLICY_STATUS_SUCCESS = 0;
@@ -517,20 +525,47 @@
@NonNull NetworkCapabilities nc, @NonNull LinkProperties lp,
@NonNull NetworkScore score, @NonNull NetworkAgentConfig config,
@Nullable NetworkProvider provider) {
- this(looper, context, logTag, nc, lp, score, config,
+ this(context, looper, logTag, nc, lp, null /* localNetworkConfig */, score, config,
+ provider);
+ }
+
+ /**
+ * Create a new network agent.
+ * @param context a {@link Context} to get system services from.
+ * @param looper the {@link Looper} on which to invoke the callbacks.
+ * @param logTag the tag for logs
+ * @param nc the initial {@link NetworkCapabilities} of this network. Update with
+ * sendNetworkCapabilities.
+ * @param lp the initial {@link LinkProperties} of this network. Update with sendLinkProperties.
+ * @param localNetworkConfig the initial {@link LocalNetworkConfig} of this
+ * network. Update with sendLocalNetworkConfig. Must be
+ * non-null iff the nc have NET_CAPABILITY_LOCAL_NETWORK.
+ * @param score the initial score of this network. Update with sendNetworkScore.
+ * @param config an immutable {@link NetworkAgentConfig} for this agent.
+ * @param provider the {@link NetworkProvider} managing this agent.
+ * @hide
+ */
+ // TODO : expose
+ public NetworkAgent(@NonNull Context context, @NonNull Looper looper, @NonNull String logTag,
+ @NonNull NetworkCapabilities nc, @NonNull LinkProperties lp,
+ @Nullable LocalNetworkConfig localNetworkConfig, @NonNull NetworkScore score,
+ @NonNull NetworkAgentConfig config, @Nullable NetworkProvider provider) {
+ this(looper, context, logTag, nc, lp, localNetworkConfig, score, config,
provider == null ? NetworkProvider.ID_NONE : provider.getProviderId(),
getLegacyNetworkInfo(config));
}
private static class InitialConfiguration {
- public final Context context;
- public final NetworkCapabilities capabilities;
- public final LinkProperties properties;
- public final NetworkScore score;
- public final NetworkAgentConfig config;
- public final NetworkInfo info;
+ @NonNull public final Context context;
+ @NonNull public final NetworkCapabilities capabilities;
+ @NonNull public final LinkProperties properties;
+ @NonNull public final NetworkScore score;
+ @NonNull public final NetworkAgentConfig config;
+ @NonNull public final NetworkInfo info;
+ @Nullable public final LocalNetworkConfig localNetworkConfig;
InitialConfiguration(@NonNull Context context, @NonNull NetworkCapabilities capabilities,
- @NonNull LinkProperties properties, @NonNull NetworkScore score,
+ @NonNull LinkProperties properties,
+ @Nullable LocalNetworkConfig localNetworkConfig, @NonNull NetworkScore score,
@NonNull NetworkAgentConfig config, @NonNull NetworkInfo info) {
this.context = context;
this.capabilities = capabilities;
@@ -538,14 +573,15 @@
this.score = score;
this.config = config;
this.info = info;
+ this.localNetworkConfig = localNetworkConfig;
}
}
private volatile InitialConfiguration mInitialConfiguration;
private NetworkAgent(@NonNull Looper looper, @NonNull Context context, @NonNull String logTag,
@NonNull NetworkCapabilities nc, @NonNull LinkProperties lp,
- @NonNull NetworkScore score, @NonNull NetworkAgentConfig config, int providerId,
- @NonNull NetworkInfo ni) {
+ @Nullable LocalNetworkConfig localNetworkConfig, @NonNull NetworkScore score,
+ @NonNull NetworkAgentConfig config, int providerId, @NonNull NetworkInfo ni) {
mHandler = new NetworkAgentHandler(looper);
LOG_TAG = logTag;
mNetworkInfo = new NetworkInfo(ni);
@@ -556,7 +592,7 @@
mInitialConfiguration = new InitialConfiguration(context,
new NetworkCapabilities(nc, NetworkCapabilities.REDACT_NONE),
- new LinkProperties(lp), score, config, ni);
+ new LinkProperties(lp), localNetworkConfig, score, config, ni);
}
private class NetworkAgentHandler extends Handler {
@@ -723,7 +759,8 @@
mNetwork = cm.registerNetworkAgent(new NetworkAgentBinder(mHandler),
new NetworkInfo(mInitialConfiguration.info),
mInitialConfiguration.properties, mInitialConfiguration.capabilities,
- mInitialConfiguration.score, mInitialConfiguration.config, providerId);
+ mInitialConfiguration.localNetworkConfig, mInitialConfiguration.score,
+ mInitialConfiguration.config, providerId);
mInitialConfiguration = null; // All this memory can now be GC'd
}
return mNetwork;
@@ -1099,6 +1136,18 @@
}
/**
+ * Must be called by the agent when the network's {@link LocalNetworkConfig} changes.
+ * @param config the new LocalNetworkConfig
+ * @hide
+ */
+ public void sendLocalNetworkConfig(@NonNull LocalNetworkConfig config) {
+ Objects.requireNonNull(config);
+ // If the agent doesn't have NET_CAPABILITY_LOCAL_NETWORK, this will be ignored by
+ // ConnectivityService with a Log.wtf.
+ queueOrSendMessage(reg -> reg.sendLocalNetworkConfig(config));
+ }
+
+ /**
* Must be called by the agent to update the score of this network.
*
* @param score the new score.
diff --git a/netbpfload/Android.bp b/netbpfload/Android.bp
index 5480ef7..daa8fad 100644
--- a/netbpfload/Android.bp
+++ b/netbpfload/Android.bp
@@ -45,4 +45,6 @@
// module "netbpfload" variant "android_x86_apex30": should support
// min_sdk_version(30) for "com.android.tethering": newer SDK(34).
min_sdk_version: "30",
+
+ // init_rc: ["netbpfload.rc"],
}
diff --git a/netbpfload/NetBpfLoad.cpp b/netbpfload/NetBpfLoad.cpp
index b44a0bc..d150373 100644
--- a/netbpfload/NetBpfLoad.cpp
+++ b/netbpfload/NetBpfLoad.cpp
@@ -168,7 +168,7 @@
return 0;
}
-int main(int argc, char** argv) {
+int main(int argc, char** argv, char * const envp[]) {
(void)argc;
android::base::InitLogging(argv, &android::base::KernelLogger);
@@ -257,10 +257,12 @@
return 1;
}
- if (android::base::SetProperty("bpf.progs_loaded", "1") == false) {
- ALOGE("Failed to set bpf.progs_loaded property");
- return 1;
+ ALOGI("done, transferring control to platform bpfloader.");
+
+ const char * args[] = { "/system/bin/bpfloader", NULL, };
+ if (execve(args[0], (char**)args, envp)) {
+ ALOGE("FATAL: execve('/system/bin/bpfloader'): %d[%s]", errno, strerror(errno));
}
- return 0;
+ return 1;
}
diff --git a/netbpfload/netbpfload.rc b/netbpfload/netbpfload.rc
new file mode 100644
index 0000000..20fbb9f
--- /dev/null
+++ b/netbpfload/netbpfload.rc
@@ -0,0 +1,85 @@
+# zygote-start is what officially starts netd (see //system/core/rootdir/init.rc)
+# However, on some hardware it's started from post-fs-data as well, which is just
+# a tad earlier. There's no benefit to that though, since on 4.9+ P+ devices netd
+# will just block until bpfloader finishes and sets the bpf.progs_loaded property.
+#
+# It is important that we start netbpfload after:
+# - /sys/fs/bpf is already mounted,
+# - apex (incl. rollback) is initialized (so that in the future we can load bpf
+# programs shipped as part of apex mainline modules)
+# - logd is ready for us to log stuff
+#
+# At the same time we want to be as early as possible to reduce races and thus
+# failures (before memory is fragmented, and cpu is busy running tons of other
+# stuff) and we absolutely want to be before netd and the system boot slot is
+# considered to have booted successfully.
+#
+on load_bpf_programs
+ exec_start netbpfload
+
+service netbpfload /system/bin/netbpfload
+ capabilities CHOWN SYS_ADMIN NET_ADMIN
+ # The following group memberships are a workaround for lack of DAC_OVERRIDE
+ # and allow us to open (among other things) files that we created and are
+ # no longer root owned (due to CHOWN) but still have group read access to
+ # one of the following groups. This is not perfect, but a more correct
+ # solution requires significantly more effort to implement.
+ group root graphics network_stack net_admin net_bw_acct net_bw_stats net_raw system
+ user root
+ #
+ # Set RLIMIT_MEMLOCK to 1GiB for netbpfload
+ #
+ # Actually only 8MiB would be needed if netbpfload ran as its own uid.
+ #
+ # However, while the rlimit is per-thread, the accounting is system wide.
+ # So, for example, if the graphics stack has already allocated 10MiB of
+ # memlock data before netbpfload even gets a chance to run, it would fail
+ # if its memlock rlimit is only 8MiB - since there would be none left for it.
+ #
+ # netbpfload succeeding is critical to system health, since a failure will
+ # cause netd crashloop and thus system server crashloop... and the only
+ # recovery is a full kernel reboot.
+ #
+ # We've had issues where devices would sometimes (rarely) boot into
+ # a crashloop because netbpfload would occasionally lose a boot time
+ # race against the graphics stack's boot time locked memory allocation.
+ #
+ # Thus netbpfload's memlock has to be 8MB higher then the locked memory
+ # consumption of the root uid anywhere else in the system...
+ # But we don't know what that is for all possible devices...
+ #
+ # Ideally, we'd simply grant netbpfload the IPC_LOCK capability and it
+ # would simply ignore it's memlock rlimit... but it turns that this
+ # capability is not even checked by the kernel's bpf system call.
+ #
+ # As such we simply use 1GiB as a reasonable approximation of infinity.
+ #
+ rlimit memlock 1073741824 1073741824
+ oneshot
+ #
+ # How to debug bootloops caused by 'netbpfload-failed'.
+ #
+ # 1. On some lower RAM devices (like wembley) you may need to first enable developer mode
+ # (from the Settings app UI), and change the developer option "Logger buffer sizes"
+ # from the default (wembley: 64kB) to the maximum (1M) per log buffer.
+ # Otherwise buffer will overflow before you manage to dump it and you'll get useless logs.
+ #
+ # 2. comment out 'reboot_on_failure reboot,netbpfload-failed' below
+ # 3. rebuild/reflash/reboot
+ # 4. as the device is booting up capture netbpfload logs via:
+ # adb logcat -s 'NetBpfLoad:*' 'NetBpfLoader:*'
+ #
+ # something like:
+ # $ adb reboot; sleep 1; adb wait-for-device; adb root; sleep 1; adb wait-for-device; adb logcat -s 'NetBpfLoad:*' 'NetBpfLoader:*'
+ # will take care of capturing logs as early as possible
+ #
+ # 5. look through the logs from the kernel's bpf verifier that netbpfload dumps out,
+ # it usually makes sense to search back from the end and find the particular
+ # bpf verifier failure that caused netbpfload to terminate early with an error code.
+ # This will probably be something along the lines of 'too many jumps' or
+ # 'cannot prove return value is 0 or 1' or 'unsupported / unknown operation / helper',
+ # 'invalid bpf_context access', etc.
+ #
+ reboot_on_failure reboot,netbpfload-failed
+ # we're not really updatable, but want to be able to load bpf programs shipped in apexes
+ updatable
diff --git a/service-t/src/com/android/server/net/NetworkStatsService.java b/service-t/src/com/android/server/net/NetworkStatsService.java
index 25e59d5..cc67550 100644
--- a/service-t/src/com/android/server/net/NetworkStatsService.java
+++ b/service-t/src/com/android/server/net/NetworkStatsService.java
@@ -517,11 +517,12 @@
break;
}
case MSG_NOTIFY_NETWORK_STATUS: {
- // If no cached states, ignore.
- if (mLastNetworkStateSnapshots == null) break;
- // TODO (b/181642673): Protect mDefaultNetworks from concurrent accessing.
- handleNotifyNetworkStatus(
- mDefaultNetworks, mLastNetworkStateSnapshots, mActiveIface);
+ synchronized (mStatsLock) {
+ // If no cached states, ignore.
+ if (mLastNetworkStateSnapshots == null) break;
+ handleNotifyNetworkStatus(
+ mDefaultNetworks, mLastNetworkStateSnapshots, mActiveIface);
+ }
break;
}
case MSG_PERFORM_POLL_REGISTER_ALERT: {
diff --git a/service/src/com/android/server/ConnectivityService.java b/service/src/com/android/server/ConnectivityService.java
index c19878c..2797b47 100755
--- a/service/src/com/android/server/ConnectivityService.java
+++ b/service/src/com/android/server/ConnectivityService.java
@@ -166,6 +166,7 @@
import android.net.IpMemoryStore;
import android.net.IpPrefix;
import android.net.LinkProperties;
+import android.net.LocalNetworkConfig;
import android.net.MatchAllNetworkSpecifier;
import android.net.NativeNetworkConfig;
import android.net.NativeNetworkType;
@@ -1798,7 +1799,7 @@
mNoServiceNetwork = new NetworkAgentInfo(null,
new Network(INetd.UNREACHABLE_NET_ID),
new NetworkInfo(TYPE_NONE, 0, "", ""),
- new LinkProperties(), new NetworkCapabilities(),
+ new LinkProperties(), new NetworkCapabilities(), null /* localNetworkConfig */,
new NetworkScore.Builder().setLegacyInt(0).build(), mContext, null,
new NetworkAgentConfig(), this, null, null, 0, INVALID_UID,
mLingerDelayMs, mQosCallbackTracker, mDeps);
@@ -4169,6 +4170,11 @@
updateNetworkInfo(nai, info);
break;
}
+ case NetworkAgent.EVENT_LOCAL_NETWORK_CONFIG_CHANGED: {
+ final LocalNetworkConfig config = (LocalNetworkConfig) arg.second;
+ updateLocalNetworkConfig(nai, config);
+ break;
+ }
case NetworkAgent.EVENT_NETWORK_SCORE_CHANGED: {
updateNetworkScore(nai, (NetworkScore) arg.second);
break;
@@ -8130,13 +8136,18 @@
* @param networkCapabilities the initial capabilites of this network. They can be updated
* later : see {@link #updateCapabilities}.
* @param initialScore the initial score of the network. See {@link NetworkAgentInfo#getScore}.
+ * @param localNetworkConfig config about this local network, or null if not a local network
* @param networkAgentConfig metadata about the network. This is never updated.
* @param providerId the ID of the provider owning this NetworkAgent.
* @return the network created for this agent.
*/
- public Network registerNetworkAgent(INetworkAgent na, NetworkInfo networkInfo,
- LinkProperties linkProperties, NetworkCapabilities networkCapabilities,
- @NonNull NetworkScore initialScore, NetworkAgentConfig networkAgentConfig,
+ public Network registerNetworkAgent(INetworkAgent na,
+ NetworkInfo networkInfo,
+ LinkProperties linkProperties,
+ NetworkCapabilities networkCapabilities,
+ @NonNull NetworkScore initialScore,
+ @Nullable LocalNetworkConfig localNetworkConfig,
+ NetworkAgentConfig networkAgentConfig,
int providerId) {
Objects.requireNonNull(networkInfo, "networkInfo must not be null");
Objects.requireNonNull(linkProperties, "linkProperties must not be null");
@@ -8154,12 +8165,20 @@
// Before U, netd doesn't support PHYSICAL_LOCAL networks so this can't work.
throw new IllegalArgumentException("Local agents are not supported in this version");
}
+ final boolean hasLocalNetworkConfig = null != localNetworkConfig;
+ if (hasLocalCap != hasLocalNetworkConfig) {
+ throw new IllegalArgumentException(null != localNetworkConfig
+ ? "Only local network agents can have a LocalNetworkConfig"
+ : "Local network agents must have a LocalNetworkConfig"
+ );
+ }
final int uid = mDeps.getCallingUid();
final long token = Binder.clearCallingIdentity();
try {
return registerNetworkAgentInternal(na, networkInfo, linkProperties,
- networkCapabilities, initialScore, networkAgentConfig, providerId, uid);
+ networkCapabilities, initialScore, networkAgentConfig, localNetworkConfig,
+ providerId, uid);
} finally {
Binder.restoreCallingIdentity(token);
}
@@ -8167,7 +8186,8 @@
private Network registerNetworkAgentInternal(INetworkAgent na, NetworkInfo networkInfo,
LinkProperties linkProperties, NetworkCapabilities networkCapabilities,
- NetworkScore currentScore, NetworkAgentConfig networkAgentConfig, int providerId,
+ NetworkScore currentScore, NetworkAgentConfig networkAgentConfig,
+ @Nullable LocalNetworkConfig localNetworkConfig, int providerId,
int uid) {
// Make a copy of the passed NI, LP, NC as the caller may hold a reference to them
@@ -8175,6 +8195,7 @@
final NetworkInfo niCopy = new NetworkInfo(networkInfo);
final NetworkCapabilities ncCopy = new NetworkCapabilities(networkCapabilities);
final LinkProperties lpCopy = new LinkProperties(linkProperties);
+ // No need to copy |localNetworkConfiguration| as it is immutable.
// At this point the capabilities/properties are untrusted and unverified, e.g. checks that
// the capabilities' access UIDs comply with security limitations. They will be sanitized
@@ -8182,9 +8203,9 @@
// because some of the checks must happen on the handler thread.
final NetworkAgentInfo nai = new NetworkAgentInfo(na,
new Network(mNetIdManager.reserveNetId()), niCopy, lpCopy, ncCopy,
- currentScore, mContext, mTrackerHandler, new NetworkAgentConfig(networkAgentConfig),
- this, mNetd, mDnsResolver, providerId, uid, mLingerDelayMs,
- mQosCallbackTracker, mDeps);
+ localNetworkConfig, currentScore, mContext, mTrackerHandler,
+ new NetworkAgentConfig(networkAgentConfig), this, mNetd, mDnsResolver, providerId,
+ uid, mLingerDelayMs, mQosCallbackTracker, mDeps);
final String extraInfo = niCopy.getExtraInfo();
final String name = TextUtils.isEmpty(extraInfo)
@@ -8919,6 +8940,16 @@
updateCapabilities(nai.getScore(), nai, nai.networkCapabilities);
}
+ private void updateLocalNetworkConfig(@NonNull final NetworkAgentInfo nai,
+ @NonNull final LocalNetworkConfig config) {
+ if (!nai.networkCapabilities.hasCapability(NET_CAPABILITY_LOCAL_NETWORK)) {
+ Log.wtf(TAG, "Ignoring update of a local network info on non-local network " + nai);
+ return;
+ }
+ // TODO : actually apply the diff.
+ nai.localNetworkConfig = config;
+ }
+
/**
* Returns the interface which requires VPN isolation (ingress interface filtering).
*
@@ -10807,6 +10838,17 @@
Log.d(TAG, "Reevaluating network " + nai.network);
reportNetworkConnectivity(nai.network, !nai.isValidated());
return 0;
+ case "bpf-get-cgroup-program-id": {
+ // Usage : adb shell cmd connectivity bpf-get-cgroup-program-id <type>
+ // Get cgroup bpf program Id for the given type. See BpfUtils#getProgramId
+ // for more detail.
+ // If type can't be parsed, this throws NumberFormatException, which
+ // is passed back to adb who prints it.
+ final int type = Integer.parseInt(getNextArg());
+ final int ret = BpfUtils.getProgramId(type, BpfUtils.CGROUP_PATH);
+ pw.println(ret);
+ return 0;
+ }
default:
return handleDefaultCommands(cmd);
}
diff --git a/service/src/com/android/server/connectivity/NetworkAgentInfo.java b/service/src/com/android/server/connectivity/NetworkAgentInfo.java
index 8d0d711..b0ad978 100644
--- a/service/src/com/android/server/connectivity/NetworkAgentInfo.java
+++ b/service/src/com/android/server/connectivity/NetworkAgentInfo.java
@@ -35,6 +35,7 @@
import android.net.INetworkAgentRegistry;
import android.net.INetworkMonitor;
import android.net.LinkProperties;
+import android.net.LocalNetworkConfig;
import android.net.NattKeepalivePacketData;
import android.net.Network;
import android.net.NetworkAgent;
@@ -173,6 +174,7 @@
// TODO: make this private with a getter.
@NonNull public NetworkCapabilities networkCapabilities;
@NonNull public final NetworkAgentConfig networkAgentConfig;
+ @Nullable public LocalNetworkConfig localNetworkConfig;
// Underlying networks declared by the agent.
// The networks in this list might be declared by a VPN using setUnderlyingNetworks and are
@@ -609,6 +611,7 @@
public NetworkAgentInfo(INetworkAgent na, Network net, NetworkInfo info,
@NonNull LinkProperties lp, @NonNull NetworkCapabilities nc,
+ @Nullable LocalNetworkConfig localNetworkConfig,
@NonNull NetworkScore score, Context context,
Handler handler, NetworkAgentConfig config, ConnectivityService connService, INetd netd,
IDnsResolver dnsResolver, int factorySerialNumber, int creatorUid,
@@ -626,6 +629,7 @@
networkInfo = info;
linkProperties = lp;
networkCapabilities = nc;
+ this.localNetworkConfig = localNetworkConfig;
networkAgentConfig = config;
mConnService = connService;
mConnServiceDeps = deps;
@@ -905,6 +909,12 @@
}
@Override
+ public void sendLocalNetworkConfig(@NonNull final LocalNetworkConfig config) {
+ mHandler.obtainMessage(NetworkAgent.EVENT_LOCAL_NETWORK_CONFIG_CHANGED,
+ new Pair<>(NetworkAgentInfo.this, config)).sendToTarget();
+ }
+
+ @Override
public void sendScore(@NonNull final NetworkScore score) {
mHandler.obtainMessage(NetworkAgent.EVENT_NETWORK_SCORE_CHANGED,
new Pair<>(NetworkAgentInfo.this, score)).sendToTarget();
diff --git a/staticlibs/client-libs/netd/com/android/net/module/util/NetdUtils.java b/staticlibs/client-libs/netd/com/android/net/module/util/NetdUtils.java
index 98fda56..ea18d37 100644
--- a/staticlibs/client-libs/netd/com/android/net/module/util/NetdUtils.java
+++ b/staticlibs/client-libs/netd/com/android/net/module/util/NetdUtils.java
@@ -159,9 +159,11 @@
throws RemoteException, ServiceSpecificException {
netd.tetherInterfaceAdd(iface);
networkAddInterface(netd, iface, maxAttempts, pollingIntervalMs);
- List<RouteInfo> routes = new ArrayList<>();
- routes.add(new RouteInfo(dest, null, iface, RTN_UNICAST));
- addRoutesToLocalNetwork(netd, iface, routes);
+ // Activate a route to dest and IPv6 link local.
+ modifyRoute(netd, ModifyOperation.ADD, INetd.LOCAL_NET_ID,
+ new RouteInfo(dest, null, iface, RTN_UNICAST));
+ modifyRoute(netd, ModifyOperation.ADD, INetd.LOCAL_NET_ID,
+ new RouteInfo(new IpPrefix("fe80::/64"), null, iface, RTN_UNICAST));
}
/**
diff --git a/staticlibs/device/com/android/net/module/util/structs/IaPrefixOption.java b/staticlibs/device/com/android/net/module/util/structs/IaPrefixOption.java
index 176b7bc..e9c39e4 100644
--- a/staticlibs/device/com/android/net/module/util/structs/IaPrefixOption.java
+++ b/staticlibs/device/com/android/net/module/util/structs/IaPrefixOption.java
@@ -108,6 +108,13 @@
}
/**
+ * Check whether or not IA Prefix option has 0 preferred and valid lifetimes.
+ */
+ public boolean withZeroLifetimes() {
+ return preferred == 0 && valid == 0;
+ }
+
+ /**
* Build an IA_PD prefix option with given specific parameters.
*/
public static ByteBuffer build(final short length, final long preferred, final long valid,
diff --git a/tests/cts/net/src/android/net/cts/NetworkAgentTest.kt b/tests/cts/net/src/android/net/cts/NetworkAgentTest.kt
index 5937655..392cba9 100644
--- a/tests/cts/net/src/android/net/cts/NetworkAgentTest.kt
+++ b/tests/cts/net/src/android/net/cts/NetworkAgentTest.kt
@@ -704,6 +704,7 @@
argThat<NetworkInfo> { it.detailedState == NetworkInfo.DetailedState.CONNECTING },
any(LinkProperties::class.java),
any(NetworkCapabilities::class.java),
+ any(), // LocalNetworkConfig TODO : specify when it's public
any(NetworkScore::class.java),
any(NetworkAgentConfig::class.java),
eq(NetworkProvider.ID_NONE))
diff --git a/tests/unit/java/com/android/server/ConnectivityServiceTest.java b/tests/unit/java/com/android/server/ConnectivityServiceTest.java
index cc11361..42b0d59 100755
--- a/tests/unit/java/com/android/server/ConnectivityServiceTest.java
+++ b/tests/unit/java/com/android/server/ConnectivityServiceTest.java
@@ -12833,7 +12833,8 @@
private NetworkAgentInfo fakeNai(NetworkCapabilities nc, NetworkInfo networkInfo) {
return new NetworkAgentInfo(null, new Network(NET_ID), networkInfo, new LinkProperties(),
- nc, new NetworkScore.Builder().setLegacyInt(0).build(),
+ nc, null /* localNetworkConfig */,
+ new NetworkScore.Builder().setLegacyInt(0).build(),
mServiceContext, null, new NetworkAgentConfig(), mService, null, null, 0,
INVALID_UID, TEST_LINGER_DELAY_MS, mQosCallbackTracker,
new ConnectivityService.Dependencies());
diff --git a/tests/unit/java/com/android/server/connectivity/LingerMonitorTest.java b/tests/unit/java/com/android/server/connectivity/LingerMonitorTest.java
index e6c0c83..07883ff 100644
--- a/tests/unit/java/com/android/server/connectivity/LingerMonitorTest.java
+++ b/tests/unit/java/com/android/server/connectivity/LingerMonitorTest.java
@@ -372,9 +372,10 @@
caps.addCapability(0);
caps.addTransportType(transport);
NetworkAgentInfo nai = new NetworkAgentInfo(null, new Network(netId), info,
- new LinkProperties(), caps, new NetworkScore.Builder().setLegacyInt(50).build(),
- mCtx, null, new NetworkAgentConfig.Builder().build(), mConnService, mNetd,
- mDnsResolver, NetworkProvider.ID_NONE, Binder.getCallingUid(), TEST_LINGER_DELAY_MS,
+ new LinkProperties(), caps, null /* localNetworkConfiguration */,
+ new NetworkScore.Builder().setLegacyInt(50).build(), mCtx, null,
+ new NetworkAgentConfig.Builder().build(), mConnService, mNetd, mDnsResolver,
+ NetworkProvider.ID_NONE, Binder.getCallingUid(), TEST_LINGER_DELAY_MS,
mQosCallbackTracker, new ConnectivityService.Dependencies());
if (setEverValidated) {
// As tests in this class deal with testing lingering, most tests are interested
diff --git a/tests/unit/java/com/android/server/connectivity/VpnTest.java b/tests/unit/java/com/android/server/connectivity/VpnTest.java
index d674767..478ff61 100644
--- a/tests/unit/java/com/android/server/connectivity/VpnTest.java
+++ b/tests/unit/java/com/android/server/connectivity/VpnTest.java
@@ -3004,8 +3004,15 @@
profile.mppe = useMppe;
doReturn(new Network[] { new Network(101) }).when(mConnectivityManager).getAllNetworks();
- doReturn(new Network(102)).when(mConnectivityManager).registerNetworkAgent(any(), any(),
- any(), any(), any(), any(), anyInt());
+ doReturn(new Network(102)).when(mConnectivityManager).registerNetworkAgent(
+ any(), // INetworkAgent
+ any(), // NetworkInfo
+ any(), // LinkProperties
+ any(), // NetworkCapabilities
+ any(), // LocalNetworkConfig
+ any(), // NetworkScore
+ any(), // NetworkAgentConfig
+ anyInt()); // provider ID
final Vpn vpn = startLegacyVpn(createVpn(PRIMARY_USER.id), profile);
final TestDeps deps = (TestDeps) vpn.mDeps;
@@ -3027,8 +3034,15 @@
assertEquals("nomppe", mtpdArgs[argsPrefix.length]);
}
- verify(mConnectivityManager, timeout(10_000)).registerNetworkAgent(any(), any(),
- any(), any(), any(), any(), anyInt());
+ verify(mConnectivityManager, timeout(10_000)).registerNetworkAgent(
+ any(), // INetworkAgent
+ any(), // NetworkInfo
+ any(), // LinkProperties
+ any(), // NetworkCapabilities
+ any(), // LocalNetworkConfig
+ any(), // NetworkScore
+ any(), // NetworkAgentConfig
+ anyInt()); // provider ID
}, () -> { // Cleanup
vpn.mVpnRunner.exitVpnRunner();
deps.getStateFile().delete(); // set to delete on exit, but this deletes it earlier
@@ -3053,7 +3067,7 @@
.thenReturn(new Network[] { new Network(101) });
when(mConnectivityManager.registerNetworkAgent(any(), any(), any(), any(),
- any(), any(), anyInt())).thenAnswer(invocation -> {
+ any(), any(), any(), anyInt())).thenAnswer(invocation -> {
// The runner has registered an agent and is now ready.
legacyRunnerReady.open();
return new Network(102);
@@ -3079,7 +3093,7 @@
ArgumentCaptor<NetworkCapabilities> ncCaptor =
ArgumentCaptor.forClass(NetworkCapabilities.class);
verify(mConnectivityManager, timeout(10_000)).registerNetworkAgent(any(), any(),
- lpCaptor.capture(), ncCaptor.capture(), any(), any(), anyInt());
+ lpCaptor.capture(), ncCaptor.capture(), any(), any(), any(), anyInt());
// In this test the expected address is always v4 so /32.
// Note that the interface needs to be specified because RouteInfo objects stored in
diff --git a/tests/unit/java/com/android/server/connectivityservice/CSKeepConnectedTest.kt b/tests/unit/java/com/android/server/connectivityservice/CSKeepConnectedTest.kt
index 86426c2..6220e76 100644
--- a/tests/unit/java/com/android/server/connectivityservice/CSKeepConnectedTest.kt
+++ b/tests/unit/java/com/android/server/connectivityservice/CSKeepConnectedTest.kt
@@ -16,6 +16,7 @@
package com.android.server
+import android.net.LocalNetworkConfig
import android.net.NetworkCapabilities
import android.net.NetworkCapabilities.NET_CAPABILITY_LOCAL_NETWORK
import android.net.NetworkCapabilities.TRANSPORT_WIFI
@@ -45,8 +46,9 @@
.build()
val keepConnectedAgent = Agent(nc = nc, score = FromS(NetworkScore.Builder()
.setKeepConnectedReason(KEEP_CONNECTED_DOWNSTREAM_NETWORK)
- .build()))
- val dontKeepConnectedAgent = Agent(nc = nc)
+ .build()),
+ lnc = LocalNetworkConfig.Builder().build())
+ val dontKeepConnectedAgent = Agent(nc = nc, lnc = LocalNetworkConfig.Builder().build())
doTestKeepConnected(keepConnectedAgent, dontKeepConnectedAgent)
}
diff --git a/tests/unit/java/com/android/server/connectivityservice/CSLocalAgentCreationTests.kt b/tests/unit/java/com/android/server/connectivityservice/CSLocalAgentCreationTests.kt
index 7914e04..cfc3a3d 100644
--- a/tests/unit/java/com/android/server/connectivityservice/CSLocalAgentCreationTests.kt
+++ b/tests/unit/java/com/android/server/connectivityservice/CSLocalAgentCreationTests.kt
@@ -18,6 +18,7 @@
import android.content.pm.PackageManager.FEATURE_LEANBACK
import android.net.INetd
+import android.net.LocalNetworkConfig
import android.net.NativeNetworkConfig
import android.net.NativeNetworkType
import android.net.NetworkCapabilities
@@ -48,6 +49,8 @@
private fun keepConnectedScore() =
FromS(NetworkScore.Builder().setKeepConnectedReason(KEEP_CONNECTED_FOR_TEST).build())
+private fun defaultLnc() = LocalNetworkConfig.Builder().build()
+
@RunWith(DevSdkIgnoreRunner::class)
@SmallTest
@IgnoreUpTo(Build.VERSION_CODES.R)
@@ -93,9 +96,9 @@
addCapability(NET_CAPABILITY_LOCAL_NETWORK)
}.build()
val localAgent = if (sdkLevel >= VERSION_V || sdkLevel == VERSION_U && isTv) {
- Agent(nc = ncTemplate, score = keepConnectedScore())
+ Agent(nc = ncTemplate, score = keepConnectedScore(), lnc = defaultLnc())
} else {
- assertFailsWith<IllegalArgumentException> { Agent(nc = ncTemplate) }
+ assertFailsWith<IllegalArgumentException> { Agent(nc = ncTemplate, lnc = defaultLnc()) }
netdInOrder.verify(netd, never()).networkCreate(any())
return
}
@@ -111,4 +114,18 @@
localAgent.disconnect()
netdInOrder.verify(netd, timeout(TIMEOUT_MS)).networkDestroy(localAgent.network.netId)
}
+
+ @Test
+ fun testBadAgents() {
+ assertFailsWith<IllegalArgumentException> {
+ Agent(nc = NetworkCapabilities.Builder()
+ .addCapability(NET_CAPABILITY_LOCAL_NETWORK)
+ .build(),
+ lnc = null)
+ }
+ assertFailsWith<IllegalArgumentException> {
+ Agent(nc = NetworkCapabilities.Builder().build(),
+ lnc = LocalNetworkConfig.Builder().build())
+ }
+ }
}
diff --git a/tests/unit/java/com/android/server/connectivityservice/CSLocalAgentTests.kt b/tests/unit/java/com/android/server/connectivityservice/CSLocalAgentTests.kt
new file mode 100644
index 0000000..bd3efa9
--- /dev/null
+++ b/tests/unit/java/com/android/server/connectivityservice/CSLocalAgentTests.kt
@@ -0,0 +1,111 @@
+/*
+ * Copyright (C) 2023 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 com.android.server
+
+import android.net.IpPrefix
+import android.net.LinkAddress
+import android.net.LinkProperties
+import android.net.LocalNetworkConfig
+import android.net.NetworkCapabilities
+import android.net.NetworkCapabilities.NET_CAPABILITY_LOCAL_NETWORK
+import android.net.NetworkCapabilities.NET_CAPABILITY_NOT_RESTRICTED
+import android.net.NetworkCapabilities.NET_CAPABILITY_NOT_ROAMING
+import android.net.NetworkCapabilities.NET_CAPABILITY_NOT_SUSPENDED
+import android.net.NetworkCapabilities.NET_CAPABILITY_NOT_VCN_MANAGED
+import android.net.NetworkCapabilities.TRANSPORT_WIFI
+import android.net.NetworkRequest
+import android.net.RouteInfo
+import android.os.Build
+import com.android.testutils.DevSdkIgnoreRule
+import com.android.testutils.DevSdkIgnoreRunner
+import com.android.testutils.RecorderCallback
+import com.android.testutils.RecorderCallback.CallbackEntry.Available
+import com.android.testutils.RecorderCallback.CallbackEntry.BlockedStatus
+import com.android.testutils.RecorderCallback.CallbackEntry.CapabilitiesChanged
+import com.android.testutils.RecorderCallback.CallbackEntry.LinkPropertiesChanged
+import com.android.testutils.TestableNetworkCallback
+import org.junit.Test
+import org.junit.runner.RunWith
+import kotlin.test.assertFailsWith
+
+private fun nc(transport: Int, vararg caps: Int) = NetworkCapabilities.Builder().apply {
+ addTransportType(transport)
+ caps.forEach {
+ addCapability(it)
+ }
+ // Useful capabilities for everybody
+ addCapability(NET_CAPABILITY_NOT_RESTRICTED)
+ addCapability(NET_CAPABILITY_NOT_SUSPENDED)
+ addCapability(NET_CAPABILITY_NOT_ROAMING)
+ addCapability(NET_CAPABILITY_NOT_VCN_MANAGED)
+}.build()
+
+private fun lp(iface: String) = LinkProperties().apply {
+ interfaceName = iface
+ addLinkAddress(LinkAddress(LOCAL_IPV4_ADDRESS, 32))
+ addRoute(RouteInfo(IpPrefix("0.0.0.0/0"), null, null))
+}
+
+@RunWith(DevSdkIgnoreRunner::class)
+@DevSdkIgnoreRule.IgnoreUpTo(Build.VERSION_CODES.TIRAMISU)
+class CSLocalAgentTests : CSTest() {
+ @Test
+ fun testBadAgents() {
+ assertFailsWith<IllegalArgumentException> {
+ Agent(nc = NetworkCapabilities.Builder()
+ .addCapability(NET_CAPABILITY_LOCAL_NETWORK)
+ .build(),
+ lnc = null)
+ }
+ assertFailsWith<IllegalArgumentException> {
+ Agent(nc = NetworkCapabilities.Builder().build(),
+ lnc = LocalNetworkConfig.Builder().build())
+ }
+ }
+
+ @Test
+ fun testUpdateLocalAgentConfig() {
+ deps.setBuildSdk(VERSION_V)
+
+ val cb = TestableNetworkCallback()
+ cm.requestNetwork(NetworkRequest.Builder()
+ .addCapability(NET_CAPABILITY_LOCAL_NETWORK)
+ .build(),
+ cb)
+
+ // Set up a local agent that should forward its traffic to the best DUN upstream.
+ val localAgent = Agent(nc = nc(TRANSPORT_WIFI, NET_CAPABILITY_LOCAL_NETWORK),
+ lp = lp("local0"),
+ lnc = LocalNetworkConfig.Builder().build(),
+ )
+ localAgent.connect()
+
+ cb.expect<Available>(localAgent.network)
+ cb.expect<CapabilitiesChanged>(localAgent.network)
+ cb.expect<LinkPropertiesChanged>(localAgent.network)
+ cb.expect<BlockedStatus>(localAgent.network)
+
+ val newLnc = LocalNetworkConfig.Builder()
+ .setUpstreamSelector(NetworkRequest.Builder()
+ .addTransportType(TRANSPORT_WIFI)
+ .build())
+ .build()
+ localAgent.sendLocalNetworkConfig(newLnc)
+
+ localAgent.disconnect()
+ }
+}
diff --git a/tests/unit/java/com/android/server/connectivityservice/base/CSAgentWrapper.kt b/tests/unit/java/com/android/server/connectivityservice/base/CSAgentWrapper.kt
index 1d0d5df..094ded3 100644
--- a/tests/unit/java/com/android/server/connectivityservice/base/CSAgentWrapper.kt
+++ b/tests/unit/java/com/android/server/connectivityservice/base/CSAgentWrapper.kt
@@ -21,6 +21,7 @@
import android.net.INetworkMonitor
import android.net.INetworkMonitorCallbacks
import android.net.LinkProperties
+import android.net.LocalNetworkConfig
import android.net.Network
import android.net.NetworkAgent
import android.net.NetworkAgentConfig
@@ -69,6 +70,7 @@
nac: NetworkAgentConfig,
val nc: NetworkCapabilities,
val lp: LinkProperties,
+ val lnc: LocalNetworkConfig?,
val score: FromS<NetworkScore>,
val provider: NetworkProvider?
) : TestableNetworkCallback.HasNetwork {
@@ -100,7 +102,7 @@
// Create the actual agent. NetworkAgent is abstract, so make an anonymous subclass.
if (deps.isAtLeastS()) {
agent = object : NetworkAgent(context, csHandlerThread.looper, TAG,
- nc, lp, score.value, nac, provider) {}
+ nc, lp, lnc, score.value, nac, provider) {}
} else {
agent = object : NetworkAgent(context, csHandlerThread.looper, TAG,
nc, lp, 50 /* score */, nac, provider) {}
@@ -165,4 +167,6 @@
agent.unregister()
cb.eventuallyExpect<Lost> { it.network == agent.network }
}
+
+ fun sendLocalNetworkConfig(lnc: LocalNetworkConfig) = agent.sendLocalNetworkConfig(lnc)
}
diff --git a/tests/unit/java/com/android/server/connectivityservice/base/CSTest.kt b/tests/unit/java/com/android/server/connectivityservice/base/CSTest.kt
index 2f78212..0ccbfc3 100644
--- a/tests/unit/java/com/android/server/connectivityservice/base/CSTest.kt
+++ b/tests/unit/java/com/android/server/connectivityservice/base/CSTest.kt
@@ -27,6 +27,7 @@
import android.net.INetd
import android.net.InetAddresses
import android.net.LinkProperties
+import android.net.LocalNetworkConfig
import android.net.NetworkAgentConfig
import android.net.NetworkCapabilities
import android.net.NetworkCapabilities.NET_CAPABILITY_NOT_SUSPENDED
@@ -292,10 +293,11 @@
nc: NetworkCapabilities = defaultNc(),
nac: NetworkAgentConfig = emptyAgentConfig(nc.getLegacyType()),
lp: LinkProperties = defaultLp(),
+ lnc: LocalNetworkConfig? = null,
score: FromS<NetworkScore> = defaultScore(),
provider: NetworkProvider? = null
- ) = CSAgentWrapper(context, deps, csHandlerThread, networkStack, nac, nc, lp, score, provider)
-
+ ) = CSAgentWrapper(context, deps, csHandlerThread, networkStack,
+ nac, nc, lp, lnc, score, provider)
fun Agent(vararg transports: Int, lp: LinkProperties = defaultLp()): CSAgentWrapper {
val nc = NetworkCapabilities.Builder().apply {
transports.forEach {