Merge changes I77e34a92,I8f13159b,Ic8ab66ff,Id9494f69 am: e19a117397

Original change: https://android-review.googlesource.com/c/platform/frameworks/base/+/1666342

Change-Id: I7c06c950ba50d3cb5f22f5e72da59fc53dafde92
This commit is contained in:
Benedict Wong
2021-04-08 22:11:11 +00:00
committed by Automerger Merge Worker
8 changed files with 647 additions and 46 deletions

View File

@@ -16,6 +16,7 @@
package com.android.server; package com.android.server;
import static android.Manifest.permission.DUMP;
import static android.net.NetworkCapabilities.NET_CAPABILITY_NOT_RESTRICTED; import static android.net.NetworkCapabilities.NET_CAPABILITY_NOT_RESTRICTED;
import static android.net.NetworkCapabilities.TRANSPORT_WIFI; import static android.net.NetworkCapabilities.TRANSPORT_WIFI;
import static android.net.vcn.VcnManager.VCN_STATUS_CODE_ACTIVE; import static android.net.vcn.VcnManager.VCN_STATUS_CODE_ACTIVE;
@@ -69,6 +70,7 @@ import android.util.Slog;
import com.android.internal.annotations.GuardedBy; import com.android.internal.annotations.GuardedBy;
import com.android.internal.annotations.VisibleForTesting; import com.android.internal.annotations.VisibleForTesting;
import com.android.internal.annotations.VisibleForTesting.Visibility; import com.android.internal.annotations.VisibleForTesting.Visibility;
import com.android.internal.util.IndentingPrintWriter;
import com.android.net.module.util.LocationPermissionChecker; import com.android.net.module.util.LocationPermissionChecker;
import com.android.server.vcn.TelephonySubscriptionTracker; import com.android.server.vcn.TelephonySubscriptionTracker;
import com.android.server.vcn.Vcn; import com.android.server.vcn.Vcn;
@@ -76,7 +78,9 @@ import com.android.server.vcn.VcnContext;
import com.android.server.vcn.VcnNetworkProvider; import com.android.server.vcn.VcnNetworkProvider;
import com.android.server.vcn.util.PersistableBundleUtils; import com.android.server.vcn.util.PersistableBundleUtils;
import java.io.FileDescriptor;
import java.io.IOException; import java.io.IOException;
import java.io.PrintWriter;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.Collections; import java.util.Collections;
import java.util.List; import java.util.List;
@@ -929,6 +933,33 @@ public class VcnManagementService extends IVcnManagementService.Stub {
} }
} }
/**
* Dumps the state of the VcnManagementService for logging and debugging purposes.
*
* <p>PII and credentials MUST NEVER be dumped here.
*/
@Override
protected void dump(FileDescriptor fd, PrintWriter writer, String[] args) {
mContext.enforceCallingOrSelfPermission(DUMP, TAG);
final IndentingPrintWriter pw = new IndentingPrintWriter(writer, " ");
pw.println("VcnManagementService dump:");
pw.increaseIndent();
mNetworkProvider.dump(pw);
synchronized (mLock) {
pw.println("mVcns:");
for (Vcn vcn : mVcns.values()) {
vcn.dump(pw);
}
pw.println();
}
pw.decreaseIndent();
}
// TODO(b/180452282): Make name more generic and implement directly with VcnManagementService // TODO(b/180452282): Make name more generic and implement directly with VcnManagementService
/** Callback for Vcn signals sent up to VcnManagementService. */ /** Callback for Vcn signals sent up to VcnManagementService. */
public interface VcnCallback { public interface VcnCallback {

View File

@@ -38,6 +38,7 @@ import android.util.Slog;
import com.android.internal.annotations.VisibleForTesting; import com.android.internal.annotations.VisibleForTesting;
import com.android.internal.annotations.VisibleForTesting.Visibility; import com.android.internal.annotations.VisibleForTesting.Visibility;
import com.android.internal.util.IndentingPrintWriter;
import com.android.server.VcnManagementService.VcnCallback; import com.android.server.VcnManagementService.VcnCallback;
import com.android.server.vcn.TelephonySubscriptionTracker.TelephonySubscriptionSnapshot; import com.android.server.vcn.TelephonySubscriptionTracker.TelephonySubscriptionSnapshot;
@@ -328,6 +329,8 @@ public class Vcn extends Handler {
private void handleNetworkRequested( private void handleNetworkRequested(
@NonNull NetworkRequest request, int score, int providerId) { @NonNull NetworkRequest request, int score, int providerId) {
Slog.v(getLogTag(), "Received request " + request);
if (score > getNetworkScore()) { if (score > getNetworkScore()) {
if (VDBG) { if (VDBG) {
Slog.v( Slog.v(
@@ -409,6 +412,26 @@ public class Vcn extends Handler {
return TAG + " [" + mSubscriptionGroup.hashCode() + "]"; return TAG + " [" + mSubscriptionGroup.hashCode() + "]";
} }
/**
* Dumps the state of this Vcn for logging and debugging purposes.
*
* <p>PII and credentials MUST NEVER be dumped here.
*/
public void dump(IndentingPrintWriter pw) {
pw.println("Vcn (" + mSubscriptionGroup + "):");
pw.increaseIndent();
pw.println("mCurrentStatus: " + mCurrentStatus);
pw.println("mVcnGatewayConnections:");
for (VcnGatewayConnection gw : mVcnGatewayConnections.values()) {
gw.dump(pw);
}
pw.println();
pw.decreaseIndent();
}
/** Retrieves the network score for a VCN Network */ /** Retrieves the network score for a VCN Network */
// Package visibility for use in VcnGatewayConnection // Package visibility for use in VcnGatewayConnection
static int getNetworkScore() { static int getNetworkScore() {

View File

@@ -77,6 +77,7 @@ import android.util.Slog;
import com.android.internal.annotations.VisibleForTesting; import com.android.internal.annotations.VisibleForTesting;
import com.android.internal.annotations.VisibleForTesting.Visibility; import com.android.internal.annotations.VisibleForTesting.Visibility;
import com.android.internal.util.IndentingPrintWriter;
import com.android.internal.util.State; import com.android.internal.util.State;
import com.android.internal.util.StateMachine; import com.android.internal.util.StateMachine;
import com.android.internal.util.WakeupMessage; import com.android.internal.util.WakeupMessage;
@@ -84,6 +85,7 @@ import com.android.server.vcn.TelephonySubscriptionTracker.TelephonySubscription
import com.android.server.vcn.UnderlyingNetworkTracker.UnderlyingNetworkRecord; import com.android.server.vcn.UnderlyingNetworkTracker.UnderlyingNetworkRecord;
import com.android.server.vcn.UnderlyingNetworkTracker.UnderlyingNetworkTrackerCallback; import com.android.server.vcn.UnderlyingNetworkTracker.UnderlyingNetworkTrackerCallback;
import com.android.server.vcn.Vcn.VcnGatewayStatusCallback; import com.android.server.vcn.Vcn.VcnGatewayStatusCallback;
import com.android.server.vcn.util.MtuUtils;
import java.io.IOException; import java.io.IOException;
import java.net.Inet4Address; import java.net.Inet4Address;
@@ -448,6 +450,44 @@ public class VcnGatewayConnection extends StateMachine {
*/ */
private static final int EVENT_SAFE_MODE_TIMEOUT_EXCEEDED = 10; private static final int EVENT_SAFE_MODE_TIMEOUT_EXCEEDED = 10;
/**
* Sent when an IKE has completed migration, and created updated transforms for application.
*
* <p>Only relevant in the Connected state.
*
* @param arg1 The session token for the IKE Session that completed migration, used to prevent
* out-of-date signals from propagating.
* @param obj @NonNull An EventMigrationCompletedInfo instance with relevant data.
*/
private static final int EVENT_MIGRATION_COMPLETED = 11;
private static class EventMigrationCompletedInfo implements EventInfo {
@NonNull public final IpSecTransform inTransform;
@NonNull public final IpSecTransform outTransform;
EventMigrationCompletedInfo(
@NonNull IpSecTransform inTransform, @NonNull IpSecTransform outTransform) {
this.inTransform = Objects.requireNonNull(inTransform);
this.outTransform = Objects.requireNonNull(outTransform);
}
@Override
public int hashCode() {
return Objects.hash(inTransform, outTransform);
}
@Override
public boolean equals(@Nullable Object other) {
if (!(other instanceof EventMigrationCompletedInfo)) {
return false;
}
final EventMigrationCompletedInfo rhs = (EventMigrationCompletedInfo) other;
return Objects.equals(inTransform, rhs.inTransform)
&& Objects.equals(outTransform, rhs.outTransform);
}
}
@VisibleForTesting(visibility = Visibility.PRIVATE) @VisibleForTesting(visibility = Visibility.PRIVATE)
@NonNull @NonNull
final DisconnectedState mDisconnectedState = new DisconnectedState(); final DisconnectedState mDisconnectedState = new DisconnectedState();
@@ -574,7 +614,7 @@ public class VcnGatewayConnection extends StateMachine {
* <p>Set in Connected state, always @NonNull in Connected, Migrating states, @Nullable * <p>Set in Connected state, always @NonNull in Connected, Migrating states, @Nullable
* otherwise. * otherwise.
*/ */
private NetworkAgent mNetworkAgent; private VcnNetworkAgent mNetworkAgent;
@Nullable private WakeupMessage mTeardownTimeoutAlarm; @Nullable private WakeupMessage mTeardownTimeoutAlarm;
@Nullable private WakeupMessage mDisconnectRequestAlarm; @Nullable private WakeupMessage mDisconnectRequestAlarm;
@@ -1053,6 +1093,14 @@ public class VcnGatewayConnection extends StateMachine {
sendMessageAndAcquireWakeLock(EVENT_SESSION_CLOSED, token); sendMessageAndAcquireWakeLock(EVENT_SESSION_CLOSED, token);
} }
private void migrationCompleted(
int token, @NonNull IpSecTransform inTransform, @NonNull IpSecTransform outTransform) {
sendMessageAndAcquireWakeLock(
EVENT_MIGRATION_COMPLETED,
token,
new EventMigrationCompletedInfo(inTransform, outTransform));
}
private void childTransformCreated( private void childTransformCreated(
int token, @NonNull IpSecTransform transform, int direction) { int token, @NonNull IpSecTransform transform, int direction) {
sendMessageAndAcquireWakeLock( sendMessageAndAcquireWakeLock(
@@ -1148,7 +1196,9 @@ public class VcnGatewayConnection extends StateMachine {
case EVENT_SETUP_COMPLETED: // Fallthrough case EVENT_SETUP_COMPLETED: // Fallthrough
case EVENT_DISCONNECT_REQUESTED: // Fallthrough case EVENT_DISCONNECT_REQUESTED: // Fallthrough
case EVENT_TEARDOWN_TIMEOUT_EXPIRED: // Fallthrough case EVENT_TEARDOWN_TIMEOUT_EXPIRED: // Fallthrough
case EVENT_SUBSCRIPTIONS_CHANGED: case EVENT_SUBSCRIPTIONS_CHANGED: // Fallthrough
case EVENT_SAFE_MODE_TIMEOUT_EXCEEDED: // Fallthrough
case EVENT_MIGRATION_COMPLETED:
logUnexpectedEvent(msg.what); logUnexpectedEvent(msg.what);
break; break;
default: default:
@@ -1440,30 +1490,32 @@ public class VcnGatewayConnection extends StateMachine {
private abstract class ConnectedStateBase extends ActiveBaseState { private abstract class ConnectedStateBase extends ActiveBaseState {
protected void updateNetworkAgent( protected void updateNetworkAgent(
@NonNull IpSecTunnelInterface tunnelIface, @NonNull IpSecTunnelInterface tunnelIface,
@NonNull NetworkAgent agent, @NonNull VcnNetworkAgent agent,
@NonNull VcnChildSessionConfiguration childConfig) { @NonNull VcnChildSessionConfiguration childConfig) {
final NetworkCapabilities caps = final NetworkCapabilities caps =
buildNetworkCapabilities(mConnectionConfig, mUnderlying); buildNetworkCapabilities(mConnectionConfig, mUnderlying);
final LinkProperties lp = final LinkProperties lp =
buildConnectedLinkProperties(mConnectionConfig, tunnelIface, childConfig); buildConnectedLinkProperties(
mConnectionConfig, tunnelIface, childConfig, mUnderlying);
agent.sendNetworkCapabilities(caps); agent.sendNetworkCapabilities(caps);
agent.sendLinkProperties(lp); agent.sendLinkProperties(lp);
} }
protected NetworkAgent buildNetworkAgent( protected VcnNetworkAgent buildNetworkAgent(
@NonNull IpSecTunnelInterface tunnelIface, @NonNull IpSecTunnelInterface tunnelIface,
@NonNull VcnChildSessionConfiguration childConfig) { @NonNull VcnChildSessionConfiguration childConfig) {
final NetworkCapabilities caps = final NetworkCapabilities caps =
buildNetworkCapabilities(mConnectionConfig, mUnderlying); buildNetworkCapabilities(mConnectionConfig, mUnderlying);
final LinkProperties lp = final LinkProperties lp =
buildConnectedLinkProperties(mConnectionConfig, tunnelIface, childConfig); buildConnectedLinkProperties(
mConnectionConfig, tunnelIface, childConfig, mUnderlying);
final NetworkAgentConfig nac = final NetworkAgentConfig nac =
new NetworkAgentConfig.Builder() new NetworkAgentConfig.Builder()
.setLegacyType(ConnectivityManager.TYPE_MOBILE) .setLegacyType(ConnectivityManager.TYPE_MOBILE)
.build(); .build();
final NetworkAgent agent = final VcnNetworkAgent agent =
mDeps.newNetworkAgent( mDeps.newNetworkAgent(
mVcnContext, mVcnContext,
TAG, TAG,
@@ -1472,15 +1524,21 @@ public class VcnGatewayConnection extends StateMachine {
Vcn.getNetworkScore(), Vcn.getNetworkScore(),
nac, nac,
mVcnContext.getVcnNetworkProvider(), mVcnContext.getVcnNetworkProvider(),
() -> { (agentRef) -> {
Slog.d(TAG, "NetworkAgent was unwanted"); // Only trigger teardown if the NetworkAgent hasn't been replaced or
// If network agent has already been torn down, skip sending the // changed. This guards against two cases - the first where
// disconnect. Unwanted() is always called, even when networkAgents // unwanted() may be called as a result of the
// are unregistered in teardownNetwork(), so prevent duplicate // NetworkAgent.unregister() call, which might trigger a teardown
// notifications. // instead of just a Network disconnect, as well as the case where a
if (mNetworkAgent != null) { // new NetworkAgent replaces an old one before the unwanted() call
teardownAsynchronously(); // is processed.
if (mNetworkAgent != agentRef) {
Slog.d(TAG, "unwanted() called on stale NetworkAgent");
return;
} }
Slog.d(TAG, "NetworkAgent was unwanted");
teardownAsynchronously();
} /* networkUnwantedCallback */, } /* networkUnwantedCallback */,
(status) -> { (status) -> {
if (status == NetworkAgent.VALIDATION_STATUS_VALID) { if (status == NetworkAgent.VALIDATION_STATUS_VALID) {
@@ -1620,12 +1678,36 @@ public class VcnGatewayConnection extends StateMachine {
case EVENT_SAFE_MODE_TIMEOUT_EXCEEDED: case EVENT_SAFE_MODE_TIMEOUT_EXCEEDED:
handleSafeModeTimeoutExceeded(); handleSafeModeTimeoutExceeded();
break; break;
case EVENT_MIGRATION_COMPLETED:
final EventMigrationCompletedInfo migrationCompletedInfo =
(EventMigrationCompletedInfo) msg.obj;
handleMigrationCompleted(migrationCompletedInfo);
break;
default: default:
logUnhandledMessage(msg); logUnhandledMessage(msg);
break; break;
} }
} }
private void handleMigrationCompleted(EventMigrationCompletedInfo migrationCompletedInfo) {
applyTransform(
mCurrentToken,
mTunnelIface,
mUnderlying.network,
migrationCompletedInfo.inTransform,
IpSecManager.DIRECTION_IN);
applyTransform(
mCurrentToken,
mTunnelIface,
mUnderlying.network,
migrationCompletedInfo.outTransform,
IpSecManager.DIRECTION_OUT);
updateNetworkAgent(mTunnelIface, mNetworkAgent, mChildConfig);
}
private void handleUnderlyingNetworkChanged(@NonNull Message msg) { private void handleUnderlyingNetworkChanged(@NonNull Message msg) {
final UnderlyingNetworkRecord oldUnderlying = mUnderlying; final UnderlyingNetworkRecord oldUnderlying = mUnderlying;
mUnderlying = ((EventUnderlyingNetworkChangedInfo) msg.obj).newUnderlying; mUnderlying = ((EventUnderlyingNetworkChangedInfo) msg.obj).newUnderlying;
@@ -1815,7 +1897,10 @@ public class VcnGatewayConnection extends StateMachine {
private static LinkProperties buildConnectedLinkProperties( private static LinkProperties buildConnectedLinkProperties(
@NonNull VcnGatewayConnectionConfig gatewayConnectionConfig, @NonNull VcnGatewayConnectionConfig gatewayConnectionConfig,
@NonNull IpSecTunnelInterface tunnelIface, @NonNull IpSecTunnelInterface tunnelIface,
@NonNull VcnChildSessionConfiguration childConfig) { @NonNull VcnChildSessionConfiguration childConfig,
@Nullable UnderlyingNetworkRecord underlying) {
final VcnControlPlaneIkeConfig controlPlaneConfig =
(VcnControlPlaneIkeConfig) gatewayConnectionConfig.getControlPlaneConfig();
final LinkProperties lp = new LinkProperties(); final LinkProperties lp = new LinkProperties();
lp.setInterfaceName(tunnelIface.getInterfaceName()); lp.setInterfaceName(tunnelIface.getInterfaceName());
@@ -1831,7 +1916,12 @@ public class VcnGatewayConnection extends StateMachine {
lp.addRoute(new RouteInfo(new IpPrefix(Inet6Address.ANY, 0), null /*gateway*/, lp.addRoute(new RouteInfo(new IpPrefix(Inet6Address.ANY, 0), null /*gateway*/,
null /*iface*/, RouteInfo.RTN_UNICAST)); null /*iface*/, RouteInfo.RTN_UNICAST));
lp.setMtu(gatewayConnectionConfig.getMaxMtu()); final int underlyingMtu = (underlying == null) ? 0 : underlying.linkProperties.getMtu();
lp.setMtu(
MtuUtils.getMtu(
controlPlaneConfig.getChildSessionParams().getSaProposals(),
gatewayConnectionConfig.getMaxMtu(),
underlyingMtu));
return lp; return lp;
} }
@@ -1912,8 +2002,7 @@ public class VcnGatewayConnection extends StateMachine {
@NonNull IpSecTransform inIpSecTransform, @NonNull IpSecTransform inIpSecTransform,
@NonNull IpSecTransform outIpSecTransform) { @NonNull IpSecTransform outIpSecTransform) {
Slog.v(TAG, "ChildTransformsMigrated; token " + mToken); Slog.v(TAG, "ChildTransformsMigrated; token " + mToken);
onIpSecTransformCreated(inIpSecTransform, IpSecManager.DIRECTION_IN); migrationCompleted(mToken, inIpSecTransform, outIpSecTransform);
onIpSecTransformCreated(outIpSecTransform, IpSecManager.DIRECTION_OUT);
} }
@Override @Override
@@ -1924,6 +2013,27 @@ public class VcnGatewayConnection extends StateMachine {
} }
} }
/**
* Dumps the state of this VcnGatewayConnection for logging and debugging purposes.
*
* <p>PII and credentials MUST NEVER be dumped here.
*/
public void dump(IndentingPrintWriter pw) {
pw.println("VcnGatewayConnection (" + mConnectionConfig.getGatewayConnectionName() + "):");
pw.increaseIndent();
pw.println("Current state: " + getCurrentState().getClass().getSimpleName());
pw.println("mIsQuitting: " + mIsQuitting);
pw.println("mIsInSafeMode: " + mIsInSafeMode);
pw.println("mCurrentToken: " + mCurrentToken);
pw.println("mFailedAttempts: " + mFailedAttempts);
pw.println(
"mNetworkAgent.getNetwork(): "
+ (mNetworkAgent == null ? null : mNetworkAgent.getNetwork()));
pw.decreaseIndent();
}
@VisibleForTesting(visibility = Visibility.PRIVATE) @VisibleForTesting(visibility = Visibility.PRIVATE)
void setTunnelInterface(IpSecTunnelInterface tunnelIface) { void setTunnelInterface(IpSecTunnelInterface tunnelIface) {
mTunnelIface = tunnelIface; mTunnelIface = tunnelIface;
@@ -1965,12 +2075,12 @@ public class VcnGatewayConnection extends StateMachine {
} }
@VisibleForTesting(visibility = Visibility.PRIVATE) @VisibleForTesting(visibility = Visibility.PRIVATE)
NetworkAgent getNetworkAgent() { VcnNetworkAgent getNetworkAgent() {
return mNetworkAgent; return mNetworkAgent;
} }
@VisibleForTesting(visibility = Visibility.PRIVATE) @VisibleForTesting(visibility = Visibility.PRIVATE)
void setNetworkAgent(@Nullable NetworkAgent networkAgent) { void setNetworkAgent(@Nullable VcnNetworkAgent networkAgent) {
mNetworkAgent = networkAgent; mNetworkAgent = networkAgent;
} }
@@ -2058,8 +2168,8 @@ public class VcnGatewayConnection extends StateMachine {
return new WakeupMessage(vcnContext.getContext(), handler, tag, runnable); return new WakeupMessage(vcnContext.getContext(), handler, tag, runnable);
} }
/** Builds a new NetworkAgent. */ /** Builds a new VcnNetworkAgent. */
public NetworkAgent newNetworkAgent( public VcnNetworkAgent newNetworkAgent(
@NonNull VcnContext vcnContext, @NonNull VcnContext vcnContext,
@NonNull String tag, @NonNull String tag,
@NonNull NetworkCapabilities caps, @NonNull NetworkCapabilities caps,
@@ -2067,27 +2177,18 @@ public class VcnGatewayConnection extends StateMachine {
@NonNull int score, @NonNull int score,
@NonNull NetworkAgentConfig nac, @NonNull NetworkAgentConfig nac,
@NonNull NetworkProvider provider, @NonNull NetworkProvider provider,
@NonNull Runnable networkUnwantedCallback, @NonNull Consumer<VcnNetworkAgent> networkUnwantedCallback,
@NonNull Consumer<Integer> validationStatusCallback) { @NonNull Consumer<Integer> validationStatusCallback) {
return new NetworkAgent( return new VcnNetworkAgent(
vcnContext.getContext(), vcnContext,
vcnContext.getLooper(),
tag, tag,
caps, caps,
lp, lp,
score, score,
nac, nac,
provider) { provider,
@Override networkUnwantedCallback,
public void onNetworkUnwanted() { validationStatusCallback);
networkUnwantedCallback.run();
}
@Override
public void onValidationStatus(int status, @Nullable Uri redirectUri) {
validationStatusCallback.accept(status);
}
};
} }
/** Gets the elapsed real time since boot, in millis. */ /** Gets the elapsed real time since boot, in millis. */
@@ -2203,4 +2304,73 @@ public class VcnGatewayConnection extends StateMachine {
mImpl.release(); mImpl.release();
} }
} }
/** Proxy Implementation of NetworkAgent, used for testing. */
@VisibleForTesting(visibility = Visibility.PRIVATE)
public static class VcnNetworkAgent {
private final NetworkAgent mImpl;
public VcnNetworkAgent(
@NonNull VcnContext vcnContext,
@NonNull String tag,
@NonNull NetworkCapabilities caps,
@NonNull LinkProperties lp,
@NonNull int score,
@NonNull NetworkAgentConfig nac,
@NonNull NetworkProvider provider,
@NonNull Consumer<VcnNetworkAgent> networkUnwantedCallback,
@NonNull Consumer<Integer> validationStatusCallback) {
mImpl =
new NetworkAgent(
vcnContext.getContext(),
vcnContext.getLooper(),
tag,
caps,
lp,
score,
nac,
provider) {
@Override
public void onNetworkUnwanted() {
networkUnwantedCallback.accept(VcnNetworkAgent.this);
}
@Override
public void onValidationStatus(int status, @Nullable Uri redirectUri) {
validationStatusCallback.accept(status);
}
};
}
/** Registers the underlying NetworkAgent */
public void register() {
mImpl.register();
}
/** Marks the underlying NetworkAgent as connected */
public void markConnected() {
mImpl.markConnected();
}
/** Unregisters the underlying NetworkAgent */
public void unregister() {
mImpl.unregister();
}
/** Sends new NetworkCapabilities for the underlying NetworkAgent */
public void sendNetworkCapabilities(@NonNull NetworkCapabilities caps) {
mImpl.sendNetworkCapabilities(caps);
}
/** Sends new LinkProperties for the underlying NetworkAgent */
public void sendLinkProperties(@NonNull LinkProperties lp) {
mImpl.sendLinkProperties(lp);
}
/** Retrieves the Network for the underlying NetworkAgent */
@Nullable
public Network getNetwork() {
return mImpl.getNetwork();
}
}
} }

View File

@@ -29,6 +29,7 @@ import android.util.Slog;
import com.android.internal.annotations.VisibleForTesting; import com.android.internal.annotations.VisibleForTesting;
import com.android.internal.annotations.VisibleForTesting.Visibility; import com.android.internal.annotations.VisibleForTesting.Visibility;
import com.android.internal.util.IndentingPrintWriter;
import java.util.Objects; import java.util.Objects;
import java.util.Set; import java.util.Set;
@@ -129,10 +130,50 @@ public class VcnNetworkProvider extends NetworkProvider {
mScore = score; mScore = score;
mProviderId = providerId; mProviderId = providerId;
} }
/**
* Dumps the state of this NetworkRequestEntry for logging and debugging purposes.
*
* <p>PII and credentials MUST NEVER be dumped here.
*/
public void dump(IndentingPrintWriter pw) {
pw.println("NetworkRequestEntry:");
pw.increaseIndent();
pw.println("mRequest: " + mRequest);
pw.println("mScore: " + mScore);
pw.println("mProviderId: " + mProviderId);
pw.decreaseIndent();
}
} }
// package-private // package-private
interface NetworkRequestListener { interface NetworkRequestListener {
void onNetworkRequested(@NonNull NetworkRequest request, int score, int providerId); void onNetworkRequested(@NonNull NetworkRequest request, int score, int providerId);
} }
/**
* Dumps the state of this VcnNetworkProvider for logging and debugging purposes.
*
* <p>PII and credentials MUST NEVER be dumped here.
*/
public void dump(IndentingPrintWriter pw) {
pw.println("VcnNetworkProvider:");
pw.increaseIndent();
pw.println("mListeners:");
for (NetworkRequestListener listener : mListeners) {
pw.println(listener);
}
pw.println();
pw.println("mRequests.values:");
for (NetworkRequestEntry entry : mRequests.values()) {
entry.dump(pw);
}
pw.println();
pw.decreaseIndent();
}
} }

View File

@@ -0,0 +1,155 @@
/*
* Copyright (C) 2021 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.vcn.util;
import static android.net.ipsec.ike.SaProposal.ENCRYPTION_ALGORITHM_3DES;
import static android.net.ipsec.ike.SaProposal.ENCRYPTION_ALGORITHM_AES_CBC;
import static android.net.ipsec.ike.SaProposal.ENCRYPTION_ALGORITHM_AES_CTR;
import static android.net.ipsec.ike.SaProposal.ENCRYPTION_ALGORITHM_AES_GCM_12;
import static android.net.ipsec.ike.SaProposal.ENCRYPTION_ALGORITHM_AES_GCM_16;
import static android.net.ipsec.ike.SaProposal.ENCRYPTION_ALGORITHM_AES_GCM_8;
import static android.net.ipsec.ike.SaProposal.ENCRYPTION_ALGORITHM_CHACHA20_POLY1305;
import static android.net.ipsec.ike.SaProposal.INTEGRITY_ALGORITHM_AES_CMAC_96;
import static android.net.ipsec.ike.SaProposal.INTEGRITY_ALGORITHM_AES_XCBC_96;
import static android.net.ipsec.ike.SaProposal.INTEGRITY_ALGORITHM_HMAC_SHA1_96;
import static android.net.ipsec.ike.SaProposal.INTEGRITY_ALGORITHM_HMAC_SHA2_256_128;
import static android.net.ipsec.ike.SaProposal.INTEGRITY_ALGORITHM_HMAC_SHA2_384_192;
import static android.net.ipsec.ike.SaProposal.INTEGRITY_ALGORITHM_HMAC_SHA2_512_256;
import static android.net.ipsec.ike.SaProposal.INTEGRITY_ALGORITHM_NONE;
import static com.android.net.module.util.NetworkStackConstants.IPV6_MIN_MTU;
import static java.lang.Math.max;
import static java.util.Collections.unmodifiableMap;
import android.annotation.NonNull;
import android.net.ipsec.ike.ChildSaProposal;
import android.util.ArrayMap;
import android.util.Pair;
import android.util.Slog;
import java.util.List;
import java.util.Map;
/** @hide */
public class MtuUtils {
private static final String TAG = MtuUtils.class.getSimpleName();
/**
* Max ESP overhead possible
*
* <p>60 (Outer IPv4 + options) + 8 (UDP encap) + 4 (SPI) + 4 (Seq) + 2 (Pad + NextHeader)
*/
private static final int GENERIC_ESP_OVERHEAD_MAX = 78;
/** Maximum overheads of authentication algorithms, keyed on IANA-defined constants */
private static final Map<Integer, Integer> AUTH_ALGORITHM_OVERHEAD;
static {
final Map<Integer, Integer> map = new ArrayMap<>();
map.put(INTEGRITY_ALGORITHM_NONE, 0);
map.put(INTEGRITY_ALGORITHM_HMAC_SHA1_96, 12);
map.put(INTEGRITY_ALGORITHM_AES_XCBC_96, 12);
map.put(INTEGRITY_ALGORITHM_HMAC_SHA2_256_128, 32);
map.put(INTEGRITY_ALGORITHM_HMAC_SHA2_384_192, 48);
map.put(INTEGRITY_ALGORITHM_HMAC_SHA2_512_256, 64);
map.put(INTEGRITY_ALGORITHM_AES_CMAC_96, 12);
AUTH_ALGORITHM_OVERHEAD = unmodifiableMap(map);
}
/** Maximum overheads of encryption algorithms, keyed on IANA-defined constants */
private static final Map<Integer, Integer> CRYPT_ALGORITHM_OVERHEAD;
static {
final Map<Integer, Integer> map = new ArrayMap<>();
map.put(ENCRYPTION_ALGORITHM_3DES, 15); // 8 (IV) + 7 (Max pad)
map.put(ENCRYPTION_ALGORITHM_AES_CBC, 31); // 16 (IV) + 15 (Max pad)
map.put(ENCRYPTION_ALGORITHM_AES_CTR, 11); // 8 (IV) + 3 (Max pad)
CRYPT_ALGORITHM_OVERHEAD = unmodifiableMap(map);
}
/** Maximum overheads of combined mode algorithms, keyed on IANA-defined constants */
private static final Map<Integer, Integer> AUTHCRYPT_ALGORITHM_OVERHEAD;
static {
final Map<Integer, Integer> map = new ArrayMap<>();
map.put(ENCRYPTION_ALGORITHM_AES_GCM_8, 19); // 8 (IV) + 3 (Max pad) + 8 (ICV)
map.put(ENCRYPTION_ALGORITHM_AES_GCM_12, 23); // 8 (IV) + 3 (Max pad) + 12 (ICV)
map.put(ENCRYPTION_ALGORITHM_AES_GCM_16, 27); // 8 (IV) + 3 (Max pad) + 16 (ICV)
map.put(ENCRYPTION_ALGORITHM_CHACHA20_POLY1305, 27); // 8 (IV) + 3 (Max pad) + 16 (ICV)
AUTHCRYPT_ALGORITHM_OVERHEAD = unmodifiableMap(map);
}
/**
* Calculates the MTU of the inner interface based on the parameters provided
*
* <p>The MTU of the inner interface will be the minimum of the following:
*
* <ul>
* <li>The MTU of the outer interface, minus the greatest ESP overhead (based on proposed
* algorithms).
* <li>The maximum MTU as provided in the arguments.
* </ul>
*/
public static int getMtu(
@NonNull List<ChildSaProposal> childProposals, int maxMtu, int underlyingMtu) {
if (underlyingMtu <= 0) {
return IPV6_MIN_MTU;
}
boolean hasUnknownAlgorithm = false;
int maxAuthOverhead = 0;
int maxCryptOverhead = 0;
int maxAuthCryptOverhead = 0;
for (ChildSaProposal proposal : childProposals) {
for (Pair<Integer, Integer> encryptionAlgoPair : proposal.getEncryptionAlgorithms()) {
final int algo = encryptionAlgoPair.first;
if (AUTHCRYPT_ALGORITHM_OVERHEAD.containsKey(algo)) {
maxAuthCryptOverhead =
max(maxAuthCryptOverhead, AUTHCRYPT_ALGORITHM_OVERHEAD.get(algo));
continue;
} else if (CRYPT_ALGORITHM_OVERHEAD.containsKey(algo)) {
maxCryptOverhead = max(maxCryptOverhead, CRYPT_ALGORITHM_OVERHEAD.get(algo));
continue;
}
Slog.wtf(TAG, "Unknown encryption algorithm requested: " + algo);
return IPV6_MIN_MTU;
}
for (int algo : proposal.getIntegrityAlgorithms()) {
if (AUTH_ALGORITHM_OVERHEAD.containsKey(algo)) {
maxAuthOverhead = max(maxAuthOverhead, AUTH_ALGORITHM_OVERHEAD.get(algo));
continue;
}
Slog.wtf(TAG, "Unknown integrity algorithm requested: " + algo);
return IPV6_MIN_MTU;
}
}
// Return minimum of maxMtu, and the adjusted MTUs based on algorithms.
final int combinedModeMtu = underlyingMtu - maxAuthCryptOverhead - GENERIC_ESP_OVERHEAD_MAX;
final int normalModeMtu =
underlyingMtu - maxCryptOverhead - maxAuthOverhead - GENERIC_ESP_OVERHEAD_MAX;
return Math.min(Math.min(maxMtu, combinedModeMtu), normalModeMtu);
}
}

View File

@@ -26,6 +26,7 @@ import static android.net.vcn.VcnManager.VCN_ERROR_CODE_NETWORK_ERROR;
import static com.android.server.vcn.VcnGatewayConnection.VcnChildSessionConfiguration; import static com.android.server.vcn.VcnGatewayConnection.VcnChildSessionConfiguration;
import static com.android.server.vcn.VcnGatewayConnection.VcnIkeSession; import static com.android.server.vcn.VcnGatewayConnection.VcnIkeSession;
import static com.android.server.vcn.VcnGatewayConnection.VcnNetworkAgent;
import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertFalse; import static org.junit.Assert.assertFalse;
@@ -46,15 +47,19 @@ import android.net.LinkAddress;
import android.net.LinkProperties; import android.net.LinkProperties;
import android.net.NetworkAgent; import android.net.NetworkAgent;
import android.net.NetworkCapabilities; import android.net.NetworkCapabilities;
import android.net.ipsec.ike.ChildSaProposal;
import android.net.ipsec.ike.exceptions.AuthenticationFailedException; import android.net.ipsec.ike.exceptions.AuthenticationFailedException;
import android.net.ipsec.ike.exceptions.IkeException; import android.net.ipsec.ike.exceptions.IkeException;
import android.net.ipsec.ike.exceptions.IkeInternalException; import android.net.ipsec.ike.exceptions.IkeInternalException;
import android.net.ipsec.ike.exceptions.TemporaryFailureException; import android.net.ipsec.ike.exceptions.TemporaryFailureException;
import android.net.vcn.VcnControlPlaneIkeConfig;
import android.net.vcn.VcnManager.VcnErrorCode; import android.net.vcn.VcnManager.VcnErrorCode;
import androidx.test.filters.SmallTest; import androidx.test.filters.SmallTest;
import androidx.test.runner.AndroidJUnit4; import androidx.test.runner.AndroidJUnit4;
import com.android.server.vcn.util.MtuUtils;
import org.junit.Before; import org.junit.Before;
import org.junit.Test; import org.junit.Test;
import org.junit.runner.RunWith; import org.junit.runner.RunWith;
@@ -73,13 +78,13 @@ import java.util.function.Consumer;
@SmallTest @SmallTest
public class VcnGatewayConnectionConnectedStateTest extends VcnGatewayConnectionTestBase { public class VcnGatewayConnectionConnectedStateTest extends VcnGatewayConnectionTestBase {
private VcnIkeSession mIkeSession; private VcnIkeSession mIkeSession;
private NetworkAgent mNetworkAgent; private VcnNetworkAgent mNetworkAgent;
@Before @Before
public void setUp() throws Exception { public void setUp() throws Exception {
super.setUp(); super.setUp();
mNetworkAgent = mock(NetworkAgent.class); mNetworkAgent = mock(VcnNetworkAgent.class);
doReturn(mNetworkAgent) doReturn(mNetworkAgent)
.when(mDeps) .when(mDeps)
.newNetworkAgent(any(), any(), any(), any(), anyInt(), any(), any(), any(), any()); .newNetworkAgent(any(), any(), any(), any(), anyInt(), any(), any(), any(), any());
@@ -152,7 +157,9 @@ public class VcnGatewayConnectionConnectedStateTest extends VcnGatewayConnection
} }
@Test @Test
public void testMigratedTransformsAreApplied() throws Exception { public void testMigration() throws Exception {
triggerChildOpened();
getChildSessionCallback() getChildSessionCallback()
.onIpSecTransformsMigrated(makeDummyIpSecTransform(), makeDummyIpSecTransform()); .onIpSecTransformsMigrated(makeDummyIpSecTransform(), makeDummyIpSecTransform());
mTestLooper.dispatchAll(); mTestLooper.dispatchAll();
@@ -170,6 +177,17 @@ public class VcnGatewayConnectionConnectedStateTest extends VcnGatewayConnection
} }
assertEquals(mGatewayConnection.mConnectedState, mGatewayConnection.getCurrentState()); assertEquals(mGatewayConnection.mConnectedState, mGatewayConnection.getCurrentState());
final List<ChildSaProposal> saProposals =
((VcnControlPlaneIkeConfig) mConfig.getControlPlaneConfig())
.getChildSessionParams()
.getSaProposals();
final int expectedMtu =
MtuUtils.getMtu(
saProposals,
mConfig.getMaxMtu(),
TEST_UNDERLYING_NETWORK_RECORD_1.linkProperties.getMtu());
verify(mNetworkAgent).sendLinkProperties(argThat(lp -> expectedMtu == lp.getMtu()));
} }
private void triggerChildOpened() { private void triggerChildOpened() {
@@ -299,8 +317,9 @@ public class VcnGatewayConnectionConnectedStateTest extends VcnGatewayConnection
.removeAddressFromTunnelInterface( .removeAddressFromTunnelInterface(
eq(TEST_IPSEC_TUNNEL_RESOURCE_ID), eq(TEST_INTERNAL_ADDR), any()); eq(TEST_IPSEC_TUNNEL_RESOURCE_ID), eq(TEST_INTERNAL_ADDR), any());
// TODO(b/184579891): Also verify link properties updated and sent when sendLinkProperties verify(mNetworkAgent).sendLinkProperties(argThat(
// is mockable lp -> newInternalAddrs.equals(lp.getLinkAddresses())
&& Collections.singletonList(TEST_DNS_ADDR_2).equals(lp.getDnsServers())));
// Verify that IpSecTunnelInterface only created once // Verify that IpSecTunnelInterface only created once
verify(mIpSecSvc).createTunnelInterface(any(), any(), any(), any(), any()); verify(mIpSecSvc).createTunnelInterface(any(), any(), any(), any(), any());
@@ -323,6 +342,66 @@ public class VcnGatewayConnectionConnectedStateTest extends VcnGatewayConnection
assertFalse(mGatewayConnection.isInSafeMode()); assertFalse(mGatewayConnection.isInSafeMode());
} }
private Consumer<VcnNetworkAgent> setupNetworkAndGetUnwantedCallback() {
triggerChildOpened();
mTestLooper.dispatchAll();
final ArgumentCaptor<Consumer<VcnNetworkAgent>> unwantedCallbackCaptor =
ArgumentCaptor.forClass(Consumer.class);
verify(mDeps)
.newNetworkAgent(
any(),
any(),
any(),
any(),
anyInt(),
any(),
any(),
unwantedCallbackCaptor.capture(),
any());
return unwantedCallbackCaptor.getValue();
}
@Test
public void testUnwantedNetworkAgentTriggersTeardown() throws Exception {
final Consumer<VcnNetworkAgent> unwantedCallback = setupNetworkAndGetUnwantedCallback();
unwantedCallback.accept(mNetworkAgent);
mTestLooper.dispatchAll();
assertTrue(mGatewayConnection.isQuitting());
assertEquals(mGatewayConnection.mDisconnectingState, mGatewayConnection.getCurrentState());
}
@Test
public void testUnwantedNetworkAgentWithDisconnectedNetworkAgent() throws Exception {
final Consumer<VcnNetworkAgent> unwantedCallback = setupNetworkAndGetUnwantedCallback();
mGatewayConnection.setNetworkAgent(null);
unwantedCallback.accept(mNetworkAgent);
mTestLooper.dispatchAll();
// Verify that the call was ignored; the state machine is still running, and the state has
// not changed.
assertFalse(mGatewayConnection.isQuitting());
assertEquals(mGatewayConnection.mConnectedState, mGatewayConnection.getCurrentState());
}
@Test
public void testUnwantedNetworkAgentWithNewNetworkAgent() throws Exception {
final Consumer<VcnNetworkAgent> unwantedCallback = setupNetworkAndGetUnwantedCallback();
final VcnNetworkAgent testAgent = mock(VcnNetworkAgent.class);
mGatewayConnection.setNetworkAgent(testAgent);
unwantedCallback.accept(mNetworkAgent);
mTestLooper.dispatchAll();
assertFalse(mGatewayConnection.isQuitting());
assertEquals(mGatewayConnection.mConnectedState, mGatewayConnection.getCurrentState());
assertEquals(testAgent, mGatewayConnection.getNetworkAgent());
}
@Test @Test
public void testChildSessionClosedTriggersDisconnect() throws Exception { public void testChildSessionClosedTriggersDisconnect() throws Exception {
// Verify scheduled but not canceled when entering ConnectedState // Verify scheduled but not canceled when entering ConnectedState

View File

@@ -18,6 +18,7 @@ package com.android.server.vcn;
import static com.android.server.vcn.UnderlyingNetworkTracker.UnderlyingNetworkRecord; import static com.android.server.vcn.UnderlyingNetworkTracker.UnderlyingNetworkRecord;
import static com.android.server.vcn.VcnGatewayConnection.VcnIkeSession; import static com.android.server.vcn.VcnGatewayConnection.VcnIkeSession;
import static com.android.server.vcn.VcnGatewayConnection.VcnNetworkAgent;
import static com.android.server.vcn.VcnTestUtils.setupIpSecManager; import static com.android.server.vcn.VcnTestUtils.setupIpSecManager;
import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertEquals;
@@ -44,7 +45,6 @@ import android.net.IpSecTunnelInterfaceResponse;
import android.net.LinkAddress; import android.net.LinkAddress;
import android.net.LinkProperties; import android.net.LinkProperties;
import android.net.Network; import android.net.Network;
import android.net.NetworkAgent;
import android.net.NetworkCapabilities; import android.net.NetworkCapabilities;
import android.net.ipsec.ike.ChildSessionCallback; import android.net.ipsec.ike.ChildSessionCallback;
import android.net.ipsec.ike.IkeSessionCallback; import android.net.ipsec.ike.IkeSessionCallback;
@@ -90,12 +90,18 @@ public class VcnGatewayConnectionTestBase {
protected static final int TEST_SUB_ID = 5; protected static final int TEST_SUB_ID = 5;
protected static final long ELAPSED_REAL_TIME = 123456789L; protected static final long ELAPSED_REAL_TIME = 123456789L;
protected static final String TEST_IPSEC_TUNNEL_IFACE = "IPSEC_IFACE"; protected static final String TEST_IPSEC_TUNNEL_IFACE = "IPSEC_IFACE";
protected static final UnderlyingNetworkRecord TEST_UNDERLYING_NETWORK_RECORD_1 = protected static final UnderlyingNetworkRecord TEST_UNDERLYING_NETWORK_RECORD_1 =
new UnderlyingNetworkRecord( new UnderlyingNetworkRecord(
new Network(0), new Network(0),
new NetworkCapabilities(), new NetworkCapabilities(),
new LinkProperties(), new LinkProperties(),
false /* blocked */); false /* blocked */);
static {
TEST_UNDERLYING_NETWORK_RECORD_1.linkProperties.setMtu(1500);
}
protected static final UnderlyingNetworkRecord TEST_UNDERLYING_NETWORK_RECORD_2 = protected static final UnderlyingNetworkRecord TEST_UNDERLYING_NETWORK_RECORD_2 =
new UnderlyingNetworkRecord( new UnderlyingNetworkRecord(
new Network(1), new Network(1),
@@ -103,6 +109,10 @@ public class VcnGatewayConnectionTestBase {
new LinkProperties(), new LinkProperties(),
false /* blocked */); false /* blocked */);
static {
TEST_UNDERLYING_NETWORK_RECORD_2.linkProperties.setMtu(1460);
}
protected static final TelephonySubscriptionSnapshot TEST_SUBSCRIPTION_SNAPSHOT = protected static final TelephonySubscriptionSnapshot TEST_SUBSCRIPTION_SNAPSHOT =
new TelephonySubscriptionSnapshot( new TelephonySubscriptionSnapshot(
Collections.singletonMap(TEST_SUB_ID, TEST_SUB_GRP), Collections.EMPTY_MAP); Collections.singletonMap(TEST_SUB_ID, TEST_SUB_GRP), Collections.EMPTY_MAP);
@@ -278,8 +288,8 @@ public class VcnGatewayConnectionTestBase {
protected void verifySafeModeTimeoutNotifiesCallbackAndUnregistersNetworkAgent( protected void verifySafeModeTimeoutNotifiesCallbackAndUnregistersNetworkAgent(
@NonNull State expectedState) { @NonNull State expectedState) {
// Set a NetworkAgent, and expect it to be unregistered and cleared // Set a VcnNetworkAgent, and expect it to be unregistered and cleared
final NetworkAgent mockNetworkAgent = mock(NetworkAgent.class); final VcnNetworkAgent mockNetworkAgent = mock(VcnNetworkAgent.class);
mGatewayConnection.setNetworkAgent(mockNetworkAgent); mGatewayConnection.setNetworkAgent(mockNetworkAgent);
// SafeMode timer starts when VcnGatewayConnection exits DisconnectedState (the initial // SafeMode timer starts when VcnGatewayConnection exits DisconnectedState (the initial

View File

@@ -0,0 +1,92 @@
/*
* Copyright (C) 2020 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.vcn.util;
import static android.net.ipsec.ike.SaProposal.ENCRYPTION_ALGORITHM_AES_CBC;
import static android.net.ipsec.ike.SaProposal.ENCRYPTION_ALGORITHM_AES_GCM_12;
import static android.net.ipsec.ike.SaProposal.ENCRYPTION_ALGORITHM_AES_GCM_16;
import static android.net.ipsec.ike.SaProposal.ENCRYPTION_ALGORITHM_AES_GCM_8;
import static android.net.ipsec.ike.SaProposal.INTEGRITY_ALGORITHM_HMAC_SHA2_256_128;
import static android.net.ipsec.ike.SaProposal.KEY_LEN_AES_256;
import static com.android.net.module.util.NetworkStackConstants.ETHER_MTU;
import static com.android.net.module.util.NetworkStackConstants.IPV6_MIN_MTU;
import static com.android.server.vcn.util.MtuUtils.getMtu;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertTrue;
import static java.util.Collections.emptyList;
import android.net.ipsec.ike.ChildSaProposal;
import androidx.test.filters.SmallTest;
import androidx.test.runner.AndroidJUnit4;
import org.junit.Test;
import org.junit.runner.RunWith;
import java.util.Arrays;
import java.util.List;
@RunWith(AndroidJUnit4.class)
@SmallTest
public class MtuUtilsTest {
@Test
public void testUnderlyingMtuZero() {
assertEquals(
IPV6_MIN_MTU, getMtu(emptyList(), ETHER_MTU /* maxMtu */, 0 /* underlyingMtu */));
}
@Test
public void testClampsToMaxMtu() {
assertEquals(0, getMtu(emptyList(), 0 /* maxMtu */, IPV6_MIN_MTU /* underlyingMtu */));
}
@Test
public void testNormalModeAlgorithmLessThanUnderlyingMtu() {
final List<ChildSaProposal> saProposals =
Arrays.asList(
new ChildSaProposal.Builder()
.addEncryptionAlgorithm(
ENCRYPTION_ALGORITHM_AES_CBC, KEY_LEN_AES_256)
.addIntegrityAlgorithm(INTEGRITY_ALGORITHM_HMAC_SHA2_256_128)
.build());
final int actualMtu =
getMtu(saProposals, ETHER_MTU /* maxMtu */, ETHER_MTU /* underlyingMtu */);
assertTrue(ETHER_MTU > actualMtu);
}
@Test
public void testCombinedModeAlgorithmLessThanUnderlyingMtu() {
final List<ChildSaProposal> saProposals =
Arrays.asList(
new ChildSaProposal.Builder()
.addEncryptionAlgorithm(
ENCRYPTION_ALGORITHM_AES_GCM_16, KEY_LEN_AES_256)
.addEncryptionAlgorithm(
ENCRYPTION_ALGORITHM_AES_GCM_12, KEY_LEN_AES_256)
.addEncryptionAlgorithm(
ENCRYPTION_ALGORITHM_AES_GCM_8, KEY_LEN_AES_256)
.build());
final int actualMtu =
getMtu(saProposals, ETHER_MTU /* maxMtu */, ETHER_MTU /* underlyingMtu */);
assertTrue(ETHER_MTU > actualMtu);
}
}