Merge "Send UPDATE_SA_ADDRESSES req on entering Mobike State."
diff --git a/src/java/com/android/internal/net/ipsec/ike/IkeSessionStateMachine.java b/src/java/com/android/internal/net/ipsec/ike/IkeSessionStateMachine.java
index b523c4c..5b67b9b 100644
--- a/src/java/com/android/internal/net/ipsec/ike/IkeSessionStateMachine.java
+++ b/src/java/com/android/internal/net/ipsec/ike/IkeSessionStateMachine.java
@@ -40,6 +40,7 @@
import static com.android.internal.net.ipsec.ike.message.IkeNotifyPayload.NOTIFY_TYPE_NAT_DETECTION_SOURCE_IP;
import static com.android.internal.net.ipsec.ike.message.IkeNotifyPayload.NOTIFY_TYPE_REKEY_SA;
import static com.android.internal.net.ipsec.ike.message.IkeNotifyPayload.NOTIFY_TYPE_SIGNATURE_HASH_ALGORITHMS;
+import static com.android.internal.net.ipsec.ike.message.IkeNotifyPayload.NOTIFY_TYPE_UPDATE_SA_ADDRESSES;
import static com.android.internal.net.ipsec.ike.message.IkePayload.PAYLOAD_TYPE_AUTH;
import static com.android.internal.net.ipsec.ike.message.IkePayload.PAYLOAD_TYPE_CP;
import static com.android.internal.net.ipsec.ike.message.IkePayload.PAYLOAD_TYPE_DELETE;
@@ -524,7 +525,7 @@
@VisibleForTesting final State mRekeyIkeRemoteDelete = new RekeyIkeRemoteDelete();
@VisibleForTesting final State mDeleteIkeLocalDelete = new DeleteIkeLocalDelete();
@VisibleForTesting final State mDpdIkeLocalInfo = new DpdIkeLocalInfo();
- @VisibleForTesting final State mMobikeLocalMigrate = new MobikeLocalMigrateState();
+ @VisibleForTesting final State mMobikeLocalInfo = new MobikeLocalInfo();
/** Constructor for testing. */
@VisibleForTesting
@@ -637,7 +638,7 @@
addState(mRekeyIkeRemoteDelete, mKillIkeSessionParent);
addState(mDeleteIkeLocalDelete, mKillIkeSessionParent);
addState(mDpdIkeLocalInfo, mKillIkeSessionParent);
- addState(mMobikeLocalMigrate, mKillIkeSessionParent);
+ addState(mMobikeLocalInfo, mKillIkeSessionParent);
// CHECKSTYLE:ON IndentationCheck
setInitialState(mInitial);
@@ -1336,7 +1337,7 @@
transitionTo(mChildProcedureOngoing);
break;
case CMD_LOCAL_REQUEST_MOBIKE:
- transitionTo(mMobikeLocalMigrate);
+ transitionTo(mMobikeLocalInfo);
break;
default:
cleanUpAndQuit(
@@ -5010,12 +5011,51 @@
}
/** MobikeLocalMigrateState initiates an UPDATE_SA_ADDRESSES exchange for the IKE Session. */
- class MobikeLocalMigrateState extends DeleteBase {
- // TODO(b/172014224): handle retransmission for the UPDATE_SA_ADDRESSES request
+ class MobikeLocalInfo extends DeleteBase {
+ private Retransmitter mRetransmitter;
@Override
public void enterState() {
- // TODO(b/172014224): send UPDATE_SA_ADDRESSES req to peer
+ mRetransmitter = new EncryptedRetransmitter(buildUpdateSaAddressesReq());
+ }
+
+ private IkeMessage buildUpdateSaAddressesReq() {
+ // Generics required for addNatDetectionPayloadsToList that takes List<IkePayload> and
+ // buildEncryptedInformationalMessage that takes InformationalPayload[].
+ List<? super IkeInformationalPayload> payloadList = new ArrayList<>();
+ payloadList.add(new IkeNotifyPayload(NOTIFY_TYPE_UPDATE_SA_ADDRESSES));
+
+ // Only bother sending NAT detection payloads if NAT-T is supported in this IKE Session
+ if (mSupportNatTraversal) {
+ addNatDetectionPayloadsToList(
+ (List<IkePayload>) payloadList,
+ mLocalAddress,
+ mRemoteAddress,
+ mLocalPort,
+ mIkeSocket.getIkeServerPort(),
+ mCurrentIkeSaRecord.getInitiatorSpi(),
+ mCurrentIkeSaRecord.getResponderSpi());
+ }
+
+ return buildEncryptedInformationalMessage(
+ mCurrentIkeSaRecord,
+ payloadList.toArray(new IkeInformationalPayload[payloadList.size()]),
+ false /* isResp */,
+ mCurrentIkeSaRecord.getLocalRequestMessageId());
+ }
+
+ @Override
+ protected void triggerRetransmit() {
+ mRetransmitter.retransmit();
+ }
+
+ @Override
+ public void exitState() {
+ super.exitState();
+
+ if (mRetransmitter != null) {
+ mRetransmitter.stopRetransmitting();
+ }
}
@Override
@@ -5030,6 +5070,32 @@
}
}
+ private static void addNatDetectionPayloadsToList(
+ List<IkePayload> payloadList,
+ InetAddress localAddr,
+ InetAddress remoteAddr,
+ int localPort,
+ int remotePort,
+ long initIkeSpi,
+ long respIkeSpi) {
+ if (localAddr instanceof Inet4Address) {
+ // Though RFC says Notify-NAT payload is "just after the Ni and Nr payloads (before
+ // the optional CERTREQ payload)", it also says recipient MUST NOT reject " messages
+ // in which the payloads were not in the "right" order" due to the lack of clarity
+ // of the payload order.
+ payloadList.add(
+ new IkeNotifyPayload(
+ NOTIFY_TYPE_NAT_DETECTION_SOURCE_IP,
+ IkeNotifyPayload.generateNatDetectionData(
+ initIkeSpi, respIkeSpi, localAddr, localPort)));
+ payloadList.add(
+ new IkeNotifyPayload(
+ NOTIFY_TYPE_NAT_DETECTION_DESTINATION_IP,
+ IkeNotifyPayload.generateNatDetectionData(
+ initIkeSpi, respIkeSpi, remoteAddr, remotePort)));
+ }
+ }
+
/**
* Helper class to generate IKE SA creation payloads, in both request and response directions.
*/
@@ -5050,22 +5116,15 @@
selectedDhGroup,
IkeSaPayload.createInitialIkeSaPayload(saProposals),
randomFactory);
- if (localAddr instanceof Inet4Address) {
- // Though RFC says Notify-NAT payload is "just after the Ni and Nr payloads (before
- // the optional CERTREQ payload)", it also says recipient MUST NOT reject " messages
- // in which the payloads were not in the "right" order" due to the lack of clarity
- // of the payload order.
- payloadList.add(
- new IkeNotifyPayload(
- NOTIFY_TYPE_NAT_DETECTION_SOURCE_IP,
- IkeNotifyPayload.generateNatDetectionData(
- initIkeSpi, respIkeSpi, localAddr, localPort)));
- payloadList.add(
- new IkeNotifyPayload(
- NOTIFY_TYPE_NAT_DETECTION_DESTINATION_IP,
- IkeNotifyPayload.generateNatDetectionData(
- initIkeSpi, respIkeSpi, remoteAddr, remotePort)));
- }
+
+ addNatDetectionPayloadsToList(
+ payloadList,
+ localAddr,
+ remoteAddr,
+ localPort,
+ remotePort,
+ initIkeSpi,
+ respIkeSpi);
return payloadList;
}
diff --git a/src/java/com/android/internal/net/ipsec/ike/message/IkeNotifyPayload.java b/src/java/com/android/internal/net/ipsec/ike/message/IkeNotifyPayload.java
index f2f365e..4617932 100644
--- a/src/java/com/android/internal/net/ipsec/ike/message/IkeNotifyPayload.java
+++ b/src/java/com/android/internal/net/ipsec/ike/message/IkeNotifyPayload.java
@@ -139,6 +139,12 @@
* the request/response of IKE_AUTH exchange.
*/
public static final int NOTIFY_TYPE_MOBIKE_SUPPORTED = 16396;
+ /**
+ * Used for notifying the Responder that an address change has occurred during a MOBIKE-enabled
+ * IKE Session. Only allowed in Informational exchanges sent after the IKE_AUTH exchange has
+ * finished.
+ */
+ public static final int NOTIFY_TYPE_UPDATE_SA_ADDRESSES = 16400;
/**
* Used in any INFORMATIONAL request for return routability check purposes when performing
@@ -228,6 +234,7 @@
NOTIFY_TYPE_TO_STRING.put(
NOTIFY_TYPE_ESP_TFC_PADDING_NOT_SUPPORTED, "ESP TCP Padding not supported");
NOTIFY_TYPE_TO_STRING.put(NOTIFY_TYPE_MOBIKE_SUPPORTED, "MOBIKE supported");
+ NOTIFY_TYPE_TO_STRING.put(NOTIFY_TYPE_UPDATE_SA_ADDRESSES, "UPDATE_SA_ADDRESSES");
NOTIFY_TYPE_TO_STRING.put(NOTIFY_TYPE_COOKIE2, "COOKIE2");
NOTIFY_TYPE_TO_STRING.put(
NOTIFY_TYPE_IKEV2_FRAGMENTATION_SUPPORTED, "Fragmentation supported");
diff --git a/tests/iketests/src/java/com/android/internal/net/ipsec/ike/IkeSessionStateMachineTest.java b/tests/iketests/src/java/com/android/internal/net/ipsec/ike/IkeSessionStateMachineTest.java
index ce61fd2..904f8a1 100644
--- a/tests/iketests/src/java/com/android/internal/net/ipsec/ike/IkeSessionStateMachineTest.java
+++ b/tests/iketests/src/java/com/android/internal/net/ipsec/ike/IkeSessionStateMachineTest.java
@@ -58,6 +58,7 @@
import static com.android.internal.net.ipsec.ike.message.IkeNotifyPayload.NOTIFY_TYPE_NAT_DETECTION_DESTINATION_IP;
import static com.android.internal.net.ipsec.ike.message.IkeNotifyPayload.NOTIFY_TYPE_NAT_DETECTION_SOURCE_IP;
import static com.android.internal.net.ipsec.ike.message.IkeNotifyPayload.NOTIFY_TYPE_SIGNATURE_HASH_ALGORITHMS;
+import static com.android.internal.net.ipsec.ike.message.IkeNotifyPayload.NOTIFY_TYPE_UPDATE_SA_ADDRESSES;
import static com.android.internal.net.ipsec.ike.message.IkePayload.PAYLOAD_TYPE_AUTH;
import static com.android.internal.net.ipsec.ike.message.IkePayload.PAYLOAD_TYPE_NOTIFY;
import static com.android.internal.net.ipsec.ike.message.IkePayload.PAYLOAD_TYPE_SA;
@@ -5553,16 +5554,58 @@
assertEquals(expectedState, mIkeSessionStateMachine.getCurrentState());
}
- @Test
- public void testSetNetworkIdleState() throws Exception {
+ private IkeNetworkCallbackBase setupIdleStateMachineWithMobike() throws Exception {
IkeNetworkCallbackBase callback =
verifyMobikeEnabled(true /* doesPeerSupportMobike */, mMockDefaultNetwork);
+
+ // reset IkeMessageHelper to make verifying outbound req easier
+ resetMockIkeMessageHelper();
+
mIkeSessionStateMachine.sendMessage(
IkeSessionStateMachine.CMD_FORCE_TRANSITION, mIkeSessionStateMachine.mIdle);
mLooper.dispatchAll();
+ return callback;
+ }
+
+ @Test
+ public void testSetNetworkIdleState() throws Exception {
+ IkeNetworkCallbackBase callback = setupIdleStateMachineWithMobike();
+
verifySetNetwork(
- callback, null /* rekeySaRecord */, mIkeSessionStateMachine.mMobikeLocalMigrate);
+ callback, null /* rekeySaRecord */, mIkeSessionStateMachine.mMobikeLocalInfo);
+
+ // Verify outbound UPDATE_SA_ADDRESSES req is sent in MobikeLocalMigrate
+ verifyUpdateSaAddressesReq(true /* expectNatDetection */);
+ }
+
+ @Test
+ public void testSetNetworkIdleStateWithoutNatDetection() throws Exception {
+ IkeNetworkCallbackBase callback = setupIdleStateMachineWithMobike();
+
+ mIkeSessionStateMachine.mSupportNatTraversal = false;
+ mIkeSessionStateMachine.mLocalNatDetected = false;
+ mIkeSessionStateMachine.mRemoteNatDetected = false;
+
+ verifySetNetwork(
+ callback,
+ mIkeSessionStateMachine.mRemoteInitNewIkeSaRecord,
+ mIkeSessionStateMachine.mMobikeLocalInfo);
+
+ // Verify outbound UPDATE_SA_ADDRESSES req is sent in MobikeLocalMigrate
+ verifyUpdateSaAddressesReq(false /* expectNatDetection */);
+ }
+
+ private void verifyUpdateSaAddressesReq(boolean expectNatDetection) {
+ List<IkePayload> payloadList = verifyOutInfoMsgHeaderAndGetPayloads(false /* isResp */);
+ int expectedPayloads = expectNatDetection ? 3 : 1;
+ assertEquals(expectedPayloads, payloadList.size());
+ assertTrue(isNotifyExist(payloadList, NOTIFY_TYPE_UPDATE_SA_ADDRESSES));
+
+ if (expectNatDetection) {
+ assertTrue(isNotifyExist(payloadList, NOTIFY_TYPE_NAT_DETECTION_SOURCE_IP));
+ assertTrue(isNotifyExist(payloadList, NOTIFY_TYPE_NAT_DETECTION_DESTINATION_IP));
+ }
}
@Test