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:
@@ -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 {
|
||||||
|
|||||||
@@ -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() {
|
||||||
|
|||||||
@@ -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();
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -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();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
155
services/core/java/com/android/server/vcn/util/MtuUtils.java
Normal file
155
services/core/java/com/android/server/vcn/util/MtuUtils.java
Normal 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);
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -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
|
||||||
|
|||||||
@@ -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
|
||||||
|
|||||||
92
tests/vcn/java/com/android/server/vcn/util/MtuUtilsTest.java
Normal file
92
tests/vcn/java/com/android/server/vcn/util/MtuUtilsTest.java
Normal 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);
|
||||||
|
}
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user