• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (C) 2021 The Android Open Source Project
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  *      http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16 
17 package android.ipsec.ike.cts;
18 
19 import static android.net.ipsec.ike.IkeSessionConfiguration.EXTENSION_TYPE_FRAGMENTATION;
20 import static android.net.ipsec.ike.IkeSessionConfiguration.EXTENSION_TYPE_MOBIKE;
21 import static android.net.ipsec.ike.IkeSessionParams.ESP_ENCAP_TYPE_AUTO;
22 import static android.net.ipsec.ike.IkeSessionParams.ESP_IP_VERSION_AUTO;
23 import static android.net.ipsec.ike.IkeSessionParams.IKE_OPTION_MOBIKE;
24 import static android.net.ipsec.ike.IkeSessionParams.IKE_OPTION_REKEY_MOBILITY;
25 import static android.net.ipsec.ike.SaProposal.DH_GROUP_2048_BIT_MODP;
26 import static android.net.ipsec.ike.SaProposal.ENCRYPTION_ALGORITHM_AES_CBC;
27 import static android.net.ipsec.ike.SaProposal.INTEGRITY_ALGORITHM_AES_CMAC_96;
28 import static android.net.ipsec.ike.SaProposal.KEY_LEN_AES_128;
29 import static android.net.ipsec.ike.SaProposal.PSEUDORANDOM_FUNCTION_AES128_CMAC;
30 
31 import static org.junit.Assert.assertEquals;
32 import static org.junit.Assert.assertFalse;
33 import static org.junit.Assert.assertNotNull;
34 import static org.junit.Assert.assertTrue;
35 import static org.junit.Assert.fail;
36 
37 import android.net.Network;
38 import android.net.ipsec.ike.IkeSaProposal;
39 import android.net.ipsec.ike.IkeSession;
40 import android.net.ipsec.ike.IkeSessionConfiguration;
41 import android.net.ipsec.ike.IkeSessionConnectionInfo;
42 import android.net.ipsec.ike.IkeSessionParams;
43 import android.net.ipsec.ike.exceptions.IkeException;
44 import android.net.ipsec.ike.exceptions.IkeNetworkLostException;
45 import android.platform.test.annotations.AppModeFull;
46 
47 import androidx.test.ext.junit.runners.AndroidJUnit4;
48 import androidx.test.filters.SdkSuppress;
49 
50 import com.android.modules.utils.build.SdkLevel;
51 import com.android.testutils.DevSdkIgnoreRule;
52 
53 import org.junit.After;
54 import org.junit.Before;
55 import org.junit.Rule;
56 import org.junit.Test;
57 import org.junit.runner.RunWith;
58 
59 import java.net.InetAddress;
60 import java.util.Arrays;
61 
62 @RunWith(AndroidJUnit4.class)
63 @AppModeFull(reason = "MANAGE_IPSEC_TUNNELS permission can't be granted to instant apps")
64 @SdkSuppress(minSdkVersion = 31, codeName = "S")
65 public class IkeSessionMobikeTest extends IkeSessionPskTestBase {
66     @Rule public final DevSdkIgnoreRule ignoreRule = new DevSdkIgnoreRule();
67 
68     private static final String IKE_INIT_RESP =
69             "46b8eca1e0d72a189b9f8e0158e1c0a52120222000000000000001d022000030"
70                     + "0000002c010100040300000c0100000c800e0080030000080300000803000008"
71                     + "02000008000000080400000e28000108000e0000164d3413d855a1642d4d6355"
72                     + "a8ef6666bfaa28a4b5264600c9ffbaef7930bd33af49022926013aae0a48d764"
73                     + "750ccb3987605957e31a2ef0e6838cfa67af989933c2879434081c4e9787f0d4"
74                     + "4da0d7dacca5589702a4537ee4fb18e8db21a948b245260f55212a1c619f61c6"
75                     + "fa1caaff4474082f9714b14ef4bcc7b2b8f43fcb939931119e53b05274faec65"
76                     + "2816c563529e60c1a88183eba9c456ecb644faf57b726b83e3242e08489d95e9"
77                     + "81e59c7ad82cf3cdfb00fe0213c4e65d61e88bbefbd536261027da722a2bbf89"
78                     + "c6378e63ce6fbcef282421e5576bba1b2faa3c4c2d41028f91df7ba165a24a18"
79                     + "fcba4f96db3e5e0eed76dc7c3c432362dd4a82d32900002461cbd03c08819730"
80                     + "f1060ed0c0446f784eb8dd884d3f73f54eb2b0c3071cc4f32900001c00004004"
81                     + "07150f3fd9584dbebb7e88ad256c7bfb9b0bb55a2900001c00004005e3aa3788"
82                     + "7040e38dbb4de8fd435161cce904ec59290000080000402e290000100000402f"
83                     + "00020003000400050000000800004014";
84     private static final String IKE_AUTH_RESP =
85             "46b8eca1e0d72a189b9f8e0158e1c0a52e20232000000001000000fc240000e0"
86                     + "1a666eb2a02b37682436a18fff5e9cef67b9096d6c7887ed235f8b5173c9469e"
87                     + "361621b66849de2dbcabf956b3d055cafafd503530543540e81dac9bf8fb8826"
88                     + "e08bc99e9ed2185d8f1322c8885abe4f98a9832c694da775eaa4ae69f17b8cbf"
89                     + "b009bf82b4bf4012bca489595631c3168cd417f813e7d177d2ceb70766a0773c"
90                     + "8819d8763627ddc9455ae3d5a5a03224020a66c8e58c8073c4a1fcf5d67cfa95"
91                     + "15de86b392a63ff54ff5572302b9ce7725085b05839252794c3680f5d8f34019"
92                     + "fa1930ea045d2a9987850e2049235c7328ef148370b6a3403408b987";
93     private static final String IKE_UPDATE_SA_RESP =
94             "46b8eca1e0d72a189b9f8e0158e1c0a52e202520000000020000007c29000060"
95                     + "a1fd35f112d92d1df19ce734f6edf56ccda1bfd44ef6de428a097e04d5b40b28"
96                     + "3897e42f23dd53e444dc6c676cf9a7d9d73bb3975d663ec351fb5ae4e56a55d8"
97                     + "cbcf376a3b99cc6fd858621cc78b3017d895e4309f09a444028dba85";
98     private static final String IKE_CREATE_CHILD_RESP =
99             "46b8eca1e0d72a189b9f8e0158e1c0a52e20242000000003000000cc210000b0"
100                     + "e6bb78203dbe2189806c5cecef5040b8c4c0253895c7c0acea6483a1f0f72425"
101                     + "77ab46e18d553329d4ae1bd31cf57eec6ec31ceb1f2ed6b1195cac98b4b97a25"
102                     + "115d14c414e44dba8ebbdaf502e43f98a09036bee0ea2a621176300874a3eae8"
103                     + "c988357255b4e5923928d335b0ef62a565333fae6a64c85ac30e7da34ceeade4"
104                     + "1a161bcad0b51f8209ee1fdaf53d50359ad6b986ecd4290c9f69a34c64ddc0eb"
105                     + "73b8f3231f3f4e057404c18d";
106     private static final String IKE_DELETE_CHILD_RESP =
107             "46b8eca1e0d72a189b9f8e0158e1c0a52e202520000000040000004c2a000030"
108                     + "53d97806d48ce44e0d4e1adf1de36778f77c3823bfaf8186cc71d4dc73497099"
109                     + "a9049e7be8a2013affd56ab7";
110     private static final String DELETE_IKE_RESP =
111             "46b8eca1e0d72a189b9f8e0158e1c0a52e202520000000050000004c00000030"
112                     + "818e6679fef4924a27452805c98125660d4396ab002f5ae45dcf75ef0d1e2190"
113                     + "273b1c4527ba26ce37574852";
114 
115     private TunNetworkContext mSecondaryTunNetworkContext;
116 
117     private InetAddress mSecondaryLocalAddr;
118 
119     private IkeSession mIkeSession;
120 
121     @Before
setUp()122     public void setUp() throws Exception {
123         super.setUp();
124 
125         mSecondaryLocalAddr = getNextAvailableIpv4AddressLocal();
126 
127         mSecondaryTunNetworkContext = new TunNetworkContext(mSecondaryLocalAddr);
128     }
129 
130     @After
tearDown()131     public void tearDown() throws Exception {
132         mSecondaryTunNetworkContext.close();
133 
134         if (mIkeSession != null) {
135             mIkeSession.kill();
136         }
137 
138         super.tearDown();
139     }
140 
141     @Override
getIkeSessionParams(InetAddress remoteAddress)142     protected IkeSessionParams getIkeSessionParams(InetAddress remoteAddress) {
143         return createIkeParamsBuilderBase(remoteAddress)
144                 .addIkeOption(IkeSessionParams.IKE_OPTION_MOBIKE)
145                 .build();
146     }
147 
148     @Test
testMigrateNetworks()149     public void testMigrateNetworks() throws Exception {
150         if (!hasTunnelsFeature()) return;
151 
152         final IkeSession ikeSession =
153                 setupAndVerifyIkeSessionWithMobility(
154                         IKE_INIT_RESP,
155                         IKE_AUTH_RESP,
156                         mRemoteAddress,
157                         true /* mobikeSupportedByServer */,
158                         new int[] {IKE_OPTION_MOBIKE});
159 
160         final IpSecTransformCallRecord firstTransformRecordA =
161                 mFirstChildSessionCallback.awaitNextCreatedIpSecTransform();
162         final IpSecTransformCallRecord firstTransformRecordB =
163                 mFirstChildSessionCallback.awaitNextCreatedIpSecTransform();
164         verifyCreateIpSecTransformPair(firstTransformRecordA, firstTransformRecordB);
165 
166         // Local request message ID starts from 2 because there is one IKE_INIT message and a single
167         // IKE_AUTH message.
168         int expectedMsgId = 2;
169 
170         // TODO (b/277662795): Generate canned values and add testing for encap-type-change
171         // migrations
172         setNetworkAndVerifyConnectionInfoChange(
173                 ikeSession,
174                 mSecondaryTunNetworkContext,
175                 expectedMsgId++,
176                 IKE_UPDATE_SA_RESP,
177                 ESP_IP_VERSION_AUTO,
178                 mSecondaryLocalAddr,
179                 mRemoteAddress);
180 
181         if (hasTunnelMigrationFeature()) {
182             verifyTransformsMigratedAndGetTransforms();
183 
184             // TODO (b/277662795): Verify closing IKE session. Will require regenerating
185             // DELETE_IKE_RESP for the kernel-MOBIKE case, where the message ID is 3 instead of 5
186         } else {
187             final IpSecTransformCallRecord[] migrateRecords =
188                     injectCreateChildRespAndVerifyTransformsMigrated(
189                             mSecondaryTunNetworkContext, expectedMsgId++, IKE_CREATE_CHILD_RESP);
190             injectDeleteChildRespAndVerifyTransformsDeleted(
191                     mSecondaryTunNetworkContext,
192                     expectedMsgId++,
193                     IKE_DELETE_CHILD_RESP,
194                     firstTransformRecordA,
195                     firstTransformRecordB);
196 
197             // Close IKE Session
198             ikeSession.close();
199             mSecondaryTunNetworkContext.tunUtils.awaitReqAndInjectResp(
200                     IKE_DETERMINISTIC_INITIATOR_SPI,
201                     expectedMsgId++,
202                     true /* expectedUseEncap */,
203                     DELETE_IKE_RESP);
204             verifyCloseIkeAndChildBlocking(migrateRecords[0], migrateRecords[1]);
205         }
206     }
207 
setupAndVerifyIkeSessionWithMobility( String ikeInitRespHex, String ikeAuthRespHex, InetAddress remoteAddress, boolean mobikeSupportedByServer, int[] ikeOptions)208     private IkeSession setupAndVerifyIkeSessionWithMobility(
209             String ikeInitRespHex,
210             String ikeAuthRespHex,
211             InetAddress remoteAddress,
212             boolean mobikeSupportedByServer,
213             int[] ikeOptions)
214             throws Exception {
215         final IkeSaProposal saProposal =
216                 new IkeSaProposal.Builder()
217                         .addEncryptionAlgorithm(ENCRYPTION_ALGORITHM_AES_CBC, KEY_LEN_AES_128)
218                         .addIntegrityAlgorithm(INTEGRITY_ALGORITHM_AES_CMAC_96)
219                         .addPseudorandomFunction(PSEUDORANDOM_FUNCTION_AES128_CMAC)
220                         .addDhGroup(DH_GROUP_2048_BIT_MODP)
221                         .build();
222 
223         final IkeSessionParams.Builder ikeParamsBuilder =
224                 createIkeParamsBuilderBase(remoteAddress, saProposal);
225         for (int option : ikeOptions) {
226             ikeParamsBuilder.addIkeOption(option);
227         }
228 
229         final IkeSessionParams ikeParams = ikeParamsBuilder.build();
230 
231         final IkeSession ikeSession = openIkeSessionWithTunnelModeChild(remoteAddress, ikeParams);
232         performSetupIkeAndFirstChildBlocking(
233                 ikeInitRespHex, true /* expectedAuthUseEncap */, ikeAuthRespHex);
234         if (mobikeSupportedByServer) {
235             verifyIkeSessionSetupBlocking(EXTENSION_TYPE_FRAGMENTATION, EXTENSION_TYPE_MOBIKE);
236         } else {
237             verifyIkeSessionSetupBlocking(EXTENSION_TYPE_FRAGMENTATION);
238         }
239 
240         verifyChildSessionSetupBlocking(
241                 mFirstChildSessionCallback,
242                 Arrays.asList(TUNNEL_MODE_INBOUND_TS),
243                 Arrays.asList(TUNNEL_MODE_OUTBOUND_TS),
244                 Arrays.asList(EXPECTED_INTERNAL_LINK_ADDR));
245         return ikeSession;
246     }
247 
setNetworkAndVerifyConnectionInfoChange( IkeSession ikeSession, TunNetworkContext tunNetworkContext, int expectedMsgId, String ikeUpdateSaResp, int ipVersion, InetAddress expectedLocalAddress, InetAddress expectedRemoteAddress)248     private void setNetworkAndVerifyConnectionInfoChange(
249             IkeSession ikeSession,
250             TunNetworkContext tunNetworkContext,
251             int expectedMsgId,
252             String ikeUpdateSaResp,
253             int ipVersion,
254             InetAddress expectedLocalAddress,
255             InetAddress expectedRemoteAddress)
256             throws Exception {
257         ikeSession.setNetwork(tunNetworkContext.tunNetwork, ipVersion, ESP_ENCAP_TYPE_AUTO,
258                 IkeSessionParams.NATT_KEEPALIVE_INTERVAL_AUTO);
259 
260         tunNetworkContext.tunUtils.awaitReqAndInjectResp(
261                 IKE_DETERMINISTIC_INITIATOR_SPI,
262                 expectedMsgId,
263                 true /* expectedUseEncap */,
264                 ikeUpdateSaResp);
265 
266         verifyConnectionInfoChange(tunNetworkContext.tunNetwork, expectedLocalAddress,
267                 expectedRemoteAddress);
268     }
269 
verifyConnectionInfoChange( Network expectedNetwork, InetAddress expectedLocalAddress, InetAddress expectedRemoteAddress)270     private void verifyConnectionInfoChange(
271             Network expectedNetwork,
272             InetAddress expectedLocalAddress,
273             InetAddress expectedRemoteAddress) throws Exception {
274         final IkeSessionConnectionInfo connectionInfo =
275                 mIkeSessionCallback.awaitOnIkeSessionConnectionInfoChanged();
276         assertNotNull(connectionInfo);
277         assertEquals(expectedNetwork, connectionInfo.getNetwork());
278         assertEquals(expectedLocalAddress, connectionInfo.getLocalAddress());
279         assertEquals(expectedRemoteAddress, connectionInfo.getRemoteAddress());
280     }
281 
injectCreateChildRespAndVerifyTransformsMigrated( TunNetworkContext tunNetworkContext, int expectedMsgId, String ikeCreateChildResp)282     private IpSecTransformCallRecord[] injectCreateChildRespAndVerifyTransformsMigrated(
283             TunNetworkContext tunNetworkContext, int expectedMsgId, String ikeCreateChildResp)
284             throws Exception {
285         tunNetworkContext.tunUtils.awaitReqAndInjectResp(
286                 IKE_DETERMINISTIC_INITIATOR_SPI,
287                 expectedMsgId,
288                 true /* expectedUseEncap */,
289                 ikeCreateChildResp);
290 
291         return verifyTransformsMigratedAndGetTransforms();
292     }
293 
verifyTransformsMigratedAndGetTransforms()294     private IpSecTransformCallRecord[] verifyTransformsMigratedAndGetTransforms() throws Exception {
295         final IpSecTransformCallRecord[] migrateRecords =
296                 mFirstChildSessionCallback.awaitNextMigratedIpSecTransform();
297         assertNotNull(migrateRecords);
298         verifyCreateIpSecTransformPair(migrateRecords[0], migrateRecords[1]);
299         return migrateRecords;
300     }
301 
injectDeleteChildRespAndVerifyTransformsDeleted( TunNetworkContext tunNetworkContext, int expectedMsgId, String ikeDeleteChildResp, IpSecTransformCallRecord transformRecordA, IpSecTransformCallRecord transformRecordB)302     private void injectDeleteChildRespAndVerifyTransformsDeleted(
303             TunNetworkContext tunNetworkContext,
304             int expectedMsgId,
305             String ikeDeleteChildResp,
306             IpSecTransformCallRecord transformRecordA,
307             IpSecTransformCallRecord transformRecordB)
308             throws Exception {
309         tunNetworkContext.tunUtils.awaitReqAndInjectResp(
310                 IKE_DETERMINISTIC_INITIATOR_SPI,
311                 expectedMsgId,
312                 true /* expectedUseEncap */,
313                 ikeDeleteChildResp);
314 
315         verifyDeleteIpSecTransformPair(
316                 mFirstChildSessionCallback, transformRecordA, transformRecordB);
317     }
318 
319     @Test
testNetworkDied()320     public void testNetworkDied() throws Exception {
321         if (!hasTunnelsFeature()) return;
322 
323         final IkeSession ikeSession =
324                 setupAndVerifyIkeSessionWithMobility(
325                         IKE_INIT_RESP,
326                         IKE_AUTH_RESP,
327                         mRemoteAddress,
328                         true /* mobikeSupportedByServer */,
329                         new int[] {IKE_OPTION_MOBIKE});
330 
331         // Teardown test network to kill the IKE Session
332         mTunNetworkContext.close();
333 
334         final IkeException exception = mIkeSessionCallback.awaitNextOnErrorException();
335         assertTrue(exception instanceof IkeNetworkLostException);
336         final IkeNetworkLostException networkLostException = (IkeNetworkLostException) exception;
337         assertEquals(mTunNetworkContext.tunNetwork, networkLostException.getNetwork());
338 
339         ikeSession.kill();
340     }
341 
342     @Test
testSetNetworkWithoutMobikeEnabled()343     public void testSetNetworkWithoutMobikeEnabled() throws Exception {
344         if (!hasTunnelsFeature()) return;
345 
346         final String ikeInitResp =
347                 "46B8ECA1E0D72A1821D31742E82FA9232120222000000000000001D022000030"
348                         + "0000002C010100040300000C0100000C800E0080030000080300000803000008"
349                         + "02000008000000080400000E28000108000E0000CE0DFFE121D30D2B5C4DBEC4"
350                         + "AEBD2F8D83F0F8EC5E2998CE98BD90492D8AA6C9360F32AE98402F853DF12FA9"
351                         + "A64ABFBB83D5FFAD1F18B6CB6FEBAB222AF5C98D4575BE2380B42F2A4E5B7B0B"
352                         + "5528F372C4E70B5B7D01D706E3F1C2E4A9E8A687C427DDB1002B190A4D73BBBA"
353                         + "E41801798408D73870657B846B84A5D9292A007A9EDA719CA3A820BB513EBE59"
354                         + "C6BF5BEB7CC9A86F0722D98F6E73B5BBC2F5EEDB39992D036406B54BF0355534"
355                         + "960D4771623ECFC561211F0580EEC051BD477076F4454E185DA7744E7B7D145B"
356                         + "08C874529C2BFE387BB7C09FCD762CEBFF6C2DE0C4912DF5747B16F51D0A9570"
357                         + "37EC652A1F025C4E80DEE9D91BF0DFEE17F3EF6F29000024196ADD342DBD954F"
358                         + "A1160542E5F312A6A44A9D19AF6799698A781F4CF717CD722900001C00004004"
359                         + "3EFFE36169090E6F6B6CB5B5BD321257E67C2B922900001C000040050AB409D2"
360                         + "60D9EE157D15483E001603BB43D918C1290000080000402E290000100000402F"
361                         + "00020003000400050000000800004014";
362         final String IkeAuthRespWithoutMobikeSupport =
363                 "46B8ECA1E0D72A1821D31742E82FA9232E20232000000001000000EC240000D0"
364                         + "493A4E97A90AE4F3CB4561D82F9123C22436EE0BAB686965D1EF7C724B2B3979"
365                         + "594D3CBCF70C3C78F46B2D9F198DCB07CEE0F774A51CF4224B4A3223500214F2"
366                         + "0AFBB7472156EF8FF03391D03A2D78001EE0B23AD5818BDAC15F348F3D97E54D"
367                         + "0C6A3DBC7F89A764A883631CFCB6C8C5A4E939E7AF7AC744D6530A88CD8EDDAC"
368                         + "F003BD73CE73A79D7ADDF53F9B3CCCBBF92F21FB29317F4151B17F0BC5F98CEE"
369                         + "89B739E4A46BC80B10D34B159CCFA847F12F85DEE5B8AED854DC460EA92BE17A"
370                         + "E2C1F56C7497001BF5B22E88";
371         final String createChildResp =
372                 "46B8ECA1E0D72A1821D31742E82FA9232E20242000000002000000CC210000B0"
373                         + "10869163B82783B650AD180040F191A516588586F051F77147F06FDDC70EA4A3"
374                         + "C4FCCD61C1E3AF3672150207F0AAB3540D4E20AB4F89B70D5D8F57E6A6AD2A42"
375                         + "F95516715BB3317B62878DA4D77170FD29994D8553300F05DC28973899F58FE2"
376                         + "A60D0C1158B7A711F20FC2A2F95351A14650F63160746CCEF73F32033B766DD4"
377                         + "730712D9EBB2D58CB1635CBF74559FA66CB56CFBE506CBC86C89F604D1A80E73"
378                         + "9B269A1CE93F46451C3307E4";
379         final String deleteChildResp =
380                 "46B8ECA1E0D72A1821D31742E82FA9232E202520000000030000004C2A000030"
381                         + "E2D0B074AF644A5AA58F999AA376450780BB66BBCB64C84BD8E5CBC9549A2A1A"
382                         + "524091EFE5D1ADE9694813B1";
383         final String deleteIkeResp =
384                 "46B8ECA1E0D72A1821D31742E82FA9232E202520000000040000004C00000030"
385                         + "59205A0B069A0D6C95B044B16DC655BA28A968463CCBCF60996EE56897C14F2C"
386                         + "FF9F15D1120A78DD2DE2E1C9";
387 
388         final int[] ikeOptions =
389                 SdkLevel.isAtLeastT()
390                         ? new int[] {IKE_OPTION_MOBIKE, IKE_OPTION_REKEY_MOBILITY}
391                         : new int[] {IKE_OPTION_MOBIKE};
392         final IkeSession ikeSession =
393                 setupAndVerifyIkeSessionWithMobility(
394                         ikeInitResp,
395                         IkeAuthRespWithoutMobikeSupport,
396                         mRemoteAddress,
397                         false /* mobikeSupportedByServer */,
398                         ikeOptions);
399 
400         final IpSecTransformCallRecord firstTransformRecordA =
401                 mFirstChildSessionCallback.awaitNextCreatedIpSecTransform();
402         final IpSecTransformCallRecord firstTransformRecordB =
403                 mFirstChildSessionCallback.awaitNextCreatedIpSecTransform();
404         verifyCreateIpSecTransformPair(firstTransformRecordA, firstTransformRecordB);
405 
406         // Rekey-based mobility
407         ikeSession.setNetwork(mSecondaryTunNetworkContext.tunNetwork);
408         verifyConnectionInfoChange(mSecondaryTunNetworkContext.tunNetwork, mSecondaryLocalAddr,
409                 mRemoteAddress);
410 
411         // Local request message ID starts from 2 because there is one IKE_INIT message and a single
412         // IKE_AUTH message.
413         int expectedMsgId = 2;
414         final IpSecTransformCallRecord[] migrateRecords =
415                 injectCreateChildRespAndVerifyTransformsMigrated(
416                         mSecondaryTunNetworkContext, expectedMsgId++, createChildResp);
417         injectDeleteChildRespAndVerifyTransformsDeleted(
418                 mSecondaryTunNetworkContext,
419                 expectedMsgId++,
420                 deleteChildResp,
421                 firstTransformRecordA,
422                 firstTransformRecordB);
423 
424         // Close IKE Session
425         ikeSession.close();
426         mSecondaryTunNetworkContext.tunUtils.awaitReqAndInjectResp(
427                 IKE_DETERMINISTIC_INITIATOR_SPI,
428                 expectedMsgId++,
429                 true /* expectedUseEncap */,
430                 deleteIkeResp);
431         verifyCloseIkeAndChildBlocking(migrateRecords[0], migrateRecords[1]);
432     }
433 
434     @Test
testSetNetworkWithoutOptionMobike()435     public void testSetNetworkWithoutOptionMobike() throws Exception {
436         if (!hasTunnelsFeature()) return;
437 
438         final String ikeInitResp =
439                 "46B8ECA1E0D72A18B45427679F9245D421202220000000000000015022000030"
440                         + "0000002C010100040300000C0100000C800E0080030000080300000203000008"
441                         + "0200000200000008040000022800008800020000A7AA3435D088EC1A2B7C2A47"
442                         + "1FA1B85F1066C9B2006E7C353FB5B5FDBC2A88347ED2C6F5B7A265D03AE34039"
443                         + "6AAC0145CFCC93F8BDB219DDFF22A603B8856A5DC59B6FAB7F17C5660CF38670"
444                         + "8794FC72F273ADEB7A4F316519794AED6F8AB61F95DFB360FAF18C6C8CABE471"
445                         + "6E18FE215348C2E582171A57FC41146B16C4AFE429000024A634B61C0E5C90C6"
446                         + "8D8818B0955B125A9B1DF47BBD18775710792E651083105C2900001C00004004"
447                         + "406FA3C5685A16B9B72C7F2EEE9993462C619ABE2900001C00004005AF905A87"
448                         + "0A32222AA284A7070585601208A282F0290000080000402E290000100000402F"
449                         + "00020003000400050000000800004014";
450         final String IkeAuthRespWithoutMobikeSupport =
451                 "46B8ECA1E0D72A18B45427679F9245D42E20232000000001000000EC240000D0"
452                         + "0D06D37198F3F0962DE8170D66F1A9008267F98CDD956D984BDCED2FC7FAF84A"
453                         + "A6664EF25049B46B93C9ED420488E0C172AA6635BF4011C49792EF2B88FE7190"
454                         + "E8859FEEF51724FD20C46E7B9A9C3DC4708EF7005707A18AB747C903ABCEAC5C"
455                         + "6ECF5A5FC13633DCE3844A920ED10EF202F115DBFBB5D6D2D7AB1F34EB08DE7C"
456                         + "A54DCE0A3A582753345CA2D05A0EFDB9DC61E81B2483B7D13EEE0A815D37252C"
457                         + "23D2F29E9C30658227D2BB0C9E1A481EAA80BC6BE9006BEDC13E925A755A0290"
458                         + "AEC4164D29997F52ED7DCC2E";
459 
460         // Open IKE Session without IKE_OPTION_MOBIKE
461         mIkeSession =
462                 openIkeSessionWithTunnelModeChild(
463                         mRemoteAddress, createIkeParamsBuilderBase(mRemoteAddress).build());
464         performSetupIkeAndFirstChildBlocking(ikeInitResp, IkeAuthRespWithoutMobikeSupport);
465 
466         verifyIkeSessionSetupBlocking();
467 
468         final IkeSessionConfiguration ikeConfig = mIkeSessionCallback.awaitIkeConfig();
469         assertFalse(ikeConfig.isIkeExtensionEnabled(IkeSessionConfiguration.EXTENSION_TYPE_MOBIKE));
470 
471         try {
472             // manually change network when IKE_OPTION_MOBIKE is not set
473             mIkeSession.setNetwork(mSecondaryTunNetworkContext.tunNetwork);
474 
475             fail("Expected error for setNetwork() when IKE_OPTION_MOBIKE is not set");
476         } catch (IllegalStateException expected) {
477         }
478     }
479 
480     /** The MOBIKE spec explicitly disallows Transport mode. */
481     @Test(expected = IllegalArgumentException.class)
testStartSessionWithMobikeAndTransportMode()482     public void testStartSessionWithMobikeAndTransportMode() {
483         mIkeSession = openIkeSessionWithTransportModeChild(mRemoteAddress);
484     }
485 }
486