/* * Copyright 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.google.android.iwlan.epdg; import static org.junit.Assert.assertArrayEquals; import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertFalse; import static org.junit.Assert.assertNotNull; import static org.junit.Assert.assertNull; import static org.junit.Assert.assertTrue; import static org.mockito.Mockito.*; import static org.mockito.Mockito.atLeastOnce; import static org.mockito.Mockito.spy; import static org.mockito.Mockito.verify; import static org.mockito.Mockito.when; import android.content.Context; import android.net.ConnectivityManager; import android.net.InetAddresses; import android.net.IpSecManager; import android.net.IpSecTransform; import android.net.LinkAddress; import android.net.LinkProperties; import android.net.Network; import android.net.ipsec.ike.ChildSessionCallback; import android.net.ipsec.ike.ChildSessionConfiguration; import android.net.ipsec.ike.ChildSessionParams; import android.net.ipsec.ike.IkeFqdnIdentification; import android.net.ipsec.ike.IkeSession; import android.net.ipsec.ike.IkeSessionCallback; import android.net.ipsec.ike.IkeSessionConfiguration; import android.net.ipsec.ike.IkeSessionConnectionInfo; import android.net.ipsec.ike.IkeSessionParams; import android.net.ipsec.ike.SaProposal; import android.net.ipsec.ike.TunnelModeChildSessionParams; import android.net.ipsec.ike.exceptions.IkeException; import android.net.ipsec.ike.exceptions.IkeInternalException; import android.net.ipsec.ike.exceptions.IkeProtocolException; import android.net.ipsec.ike.ike3gpp.Ike3gppBackoffTimer; import android.net.ipsec.ike.ike3gpp.Ike3gppData; import android.net.ipsec.ike.ike3gpp.Ike3gppExtension; import android.os.PersistableBundle; import android.os.test.TestLooper; import android.telephony.CarrierConfigManager; import android.telephony.SubscriptionInfo; import android.telephony.SubscriptionManager; import android.telephony.TelephonyManager; import android.telephony.data.ApnSetting; import com.google.android.iwlan.IwlanError; import org.junit.Before; import org.junit.Ignore; import org.junit.Rule; import org.junit.Test; import org.junit.runner.RunWith; import org.junit.runners.JUnit4; import org.mockito.ArgumentCaptor; import org.mockito.Mock; import org.mockito.internal.util.reflection.FieldSetter; import org.mockito.junit.MockitoJUnit; import org.mockito.junit.MockitoRule; import java.io.IOException; import java.net.Inet4Address; import java.net.Inet6Address; import java.net.InetAddress; import java.util.ArrayList; import java.util.Arrays; import java.util.LinkedList; import java.util.List; import java.util.Queue; import java.util.concurrent.Executor; @RunWith(JUnit4.class) public class EpdgTunnelManagerTest { public static final int DEFAULT_SLOT_INDEX = 0; public static final int DEFAULT_SUBID = 0; public static final int DEFAULT_TOKEN = 0; private static final String EPDG_ADDRESS = "127.0.0.1"; private static final String TEST_APN_NAME = "www.xyz.com"; private static final ArrayList EXPECTED_LOCAL_ADDRESSES = new ArrayList<>( Arrays.asList( new InetAddress[] {InetAddresses.parseNumericAddress("201.1.100.10")})); private static final ArrayList EXPECTED_EPDG_ADDRESSES = new ArrayList<>( Arrays.asList( new InetAddress[] {InetAddresses.parseNumericAddress(EPDG_ADDRESS)})); private static final ArrayList EXPECTED_INTERNAL_ADDRESSES = new ArrayList<>( Arrays.asList( new LinkAddress[] { new LinkAddress( InetAddresses.parseNumericAddress("198.50.100.10"), 24) })); private static final ArrayList EXPECTED_PCSCF_ADDRESSES = new ArrayList<>( Arrays.asList( new InetAddress[] { InetAddresses.parseNumericAddress("198.51.100.10") })); private static final ArrayList EXPECTED_DNS_ADDRESSES = new ArrayList<>( Arrays.asList( new InetAddress[] { InetAddresses.parseNumericAddress("198.50.100.10") })); private EpdgTunnelManager mEpdgTunnelManager; private class IwlanTunnelCallback implements EpdgTunnelManager.TunnelCallback { public void onOpened(String apnName, TunnelLinkProperties linkProperties) {} public void onClosed(String apnName, IwlanError error) {} } private static class IwlanTunnelCallbackMetrics implements EpdgTunnelManager.TunnelCallbackMetrics { public void onOpened( String apnName, String epdgServerAddress, int epdgServerSelectionDuration, int ikeTunnelEstablishmentDuration) {} public void onClosed( String apnName, String epdgServerAddress, int epdgServerSelectionDuration, int ikeTunnelEstablishmentDuration) {} } @Rule public final MockitoRule mockito = MockitoJUnit.rule(); private TestLooper mTestLooper = new TestLooper(); @Mock private Context mMockContext; @Mock private IwlanTunnelCallback mMockIwlanTunnelCallback; @Mock private IwlanTunnelCallbackMetrics mMockIwlanTunnelCallbackMetrics; @Mock private IkeSession mMockIkeSession; @Mock private EpdgSelector mMockEpdgSelector; @Mock private Network mMockNetwork; @Mock CarrierConfigManager mMockCarrierConfigManager; @Mock ConnectivityManager mMockConnectivityManager; @Mock SubscriptionManager mMockSubscriptionManager; @Mock SubscriptionInfo mMockSubscriptionInfo; @Mock TelephonyManager mMockTelephonyManager; @Mock IpSecManager mMockIpSecManager; @Mock EpdgTunnelManager.IkeSessionCreator mMockIkeSessionCreator; @Mock IkeException mMockIkeException; @Mock IkeSessionConfiguration mMockIkeSessionConfiguration; @Mock ChildSessionConfiguration mMockChildSessionConfiguration; @Mock IpSecManager.IpSecTunnelInterface mMockIpSecTunnelInterface; @Mock IkeSessionConnectionInfo mMockIkeSessionConnectionInfo; @Mock IpSecTransform mMockedIpSecTransformIn; @Mock IpSecTransform mMockedIpSecTransformOut; @Mock LinkProperties mMockLinkProperties; Queue mSpyPendingBringUpRequests; class IkeSessionArgumentCaptors { ArgumentCaptor mIkeSessionParamsCaptor = ArgumentCaptor.forClass(IkeSessionParams.class); ArgumentCaptor mChildSessionParamsCaptor = ArgumentCaptor.forClass(ChildSessionParams.class); ArgumentCaptor mIkeSessionCallbackCaptor = ArgumentCaptor.forClass(IkeSessionCallback.class); ArgumentCaptor mChildSessionCallbackCaptor = ArgumentCaptor.forClass(ChildSessionCallback.class); } @Before public void setUp() throws Exception { EpdgTunnelManager.resetAllInstances(); mEpdgTunnelManager = spy(EpdgTunnelManager.getInstance(mMockContext, DEFAULT_SLOT_INDEX)); when(mMockContext.getSystemService(eq(IpSecManager.class))).thenReturn(mMockIpSecManager); doReturn(mTestLooper.getLooper()).when(mEpdgTunnelManager).getLooper(); setVariable(mEpdgTunnelManager, "mContext", mMockContext); mEpdgTunnelManager.initHandler(); mEpdgTunnelManager.resetTunnelManagerState(); doReturn(mMockEpdgSelector).when(mEpdgTunnelManager).getEpdgSelector(); when(mEpdgTunnelManager.getIkeSessionCreator()).thenReturn(mMockIkeSessionCreator); mSpyPendingBringUpRequests = spy(new LinkedList<>()); setVariable(mEpdgTunnelManager, "mPendingBringUpRequests", mSpyPendingBringUpRequests); doAnswer(i -> mSpyPendingBringUpRequests.remove()).when(mSpyPendingBringUpRequests).poll(); when(mMockEpdgSelector.getValidatedServerList( anyInt(), anyInt(), anyBoolean(), anyBoolean(), eq(mMockNetwork), any(EpdgSelector.EpdgSelectorCallback.class))) .thenReturn(new IwlanError(IwlanError.NO_ERROR)); // initialize carrier configuration PersistableBundle bundle = new PersistableBundle(); setupMockForGetConfig(bundle); when(mMockIkeSessionConfiguration.getPcscfServers()).thenReturn(EXPECTED_PCSCF_ADDRESSES); when(mMockChildSessionConfiguration.getInternalDnsServers()) .thenReturn(EXPECTED_DNS_ADDRESSES); when(mMockChildSessionConfiguration.getInternalAddresses()) .thenReturn(EXPECTED_INTERNAL_ADDRESSES); when(mMockIpSecManager.createIpSecTunnelInterface(any(), any(), any())) .thenReturn(mMockIpSecTunnelInterface); when(mMockIpSecTunnelInterface.getInterfaceName()).thenReturn("wlan0"); when(mMockIkeSessionConnectionInfo.getNetwork()).thenReturn(mMockNetwork); doReturn(EXPECTED_LOCAL_ADDRESSES) .when(mEpdgTunnelManager) .getAddressForNetwork(any(), any()); } @Test public void testBringUpTunnelWithInvalidProtocol() { boolean ret = mEpdgTunnelManager.bringUpTunnel( getBasicTunnelSetupRequest(TEST_APN_NAME, ApnSetting.PROTOCOL_PPP), mMockIwlanTunnelCallback, mMockIwlanTunnelCallbackMetrics); assertFalse(ret); } @Test public void testBringUpTunnelWithInvalidPduSessionId() { boolean ret = mEpdgTunnelManager.bringUpTunnel( getBasicTunnelSetupRequest(TEST_APN_NAME, ApnSetting.PROTOCOL_IPV6, 16), mMockIwlanTunnelCallback, mMockIwlanTunnelCallbackMetrics); assertFalse(ret); ret = mEpdgTunnelManager.bringUpTunnel( getBasicTunnelSetupRequest(TEST_APN_NAME, ApnSetting.PROTOCOL_IPV6, -1), mMockIwlanTunnelCallback, mMockIwlanTunnelCallbackMetrics); assertFalse(ret); } @Test public void testBringUpTunnelWithValidProtocols() { String testApnName1 = "www.xyz.com1"; String testApnName2 = "www.xyz.com2"; String testApnName3 = "www.xyz.com3"; TunnelSetupRequest TSR_v4 = getBasicTunnelSetupRequest(testApnName1, ApnSetting.PROTOCOL_IP); TunnelSetupRequest TSR_v6 = getBasicTunnelSetupRequest(testApnName2, ApnSetting.PROTOCOL_IPV6); TunnelSetupRequest TSR_v4v6 = getBasicTunnelSetupRequest(testApnName3, ApnSetting.PROTOCOL_IPV4V6); doReturn(true).when(mEpdgTunnelManager).canBringUpTunnel(eq(testApnName1)); doReturn(true).when(mEpdgTunnelManager).canBringUpTunnel(eq(testApnName2)); doReturn(true).when(mEpdgTunnelManager).canBringUpTunnel(eq(testApnName3)); boolean ret = mEpdgTunnelManager.bringUpTunnel( TSR_v4, mMockIwlanTunnelCallback, mMockIwlanTunnelCallbackMetrics); assertTrue(ret); ret = mEpdgTunnelManager.bringUpTunnel( TSR_v6, mMockIwlanTunnelCallback, mMockIwlanTunnelCallbackMetrics); assertTrue(ret); ret = mEpdgTunnelManager.bringUpTunnel( TSR_v4v6, mMockIwlanTunnelCallback, mMockIwlanTunnelCallbackMetrics); assertTrue(ret); } @Test public void testBringUpTunnelWithNullApn() { TunnelSetupRequest TSR = getBasicTunnelSetupRequest(TEST_APN_NAME, ApnSetting.PROTOCOL_IP); when(mEpdgTunnelManager.getTunnelSetupRequestApnName(TSR)).thenReturn(null); boolean ret = mEpdgTunnelManager.bringUpTunnel( TSR, mMockIwlanTunnelCallback, mMockIwlanTunnelCallbackMetrics); assertFalse(ret); verify(mEpdgTunnelManager).getTunnelSetupRequestApnName(TSR); } @Test public void testBringUpTunnelWithExistApn() { TunnelSetupRequest TSR = getBasicTunnelSetupRequest(TEST_APN_NAME, ApnSetting.PROTOCOL_IP); when(mEpdgTunnelManager.isTunnelConfigContainExistApn(TEST_APN_NAME)).thenReturn(true); boolean ret = mEpdgTunnelManager.bringUpTunnel( TSR, mMockIwlanTunnelCallback, mMockIwlanTunnelCallbackMetrics); assertFalse(ret); verify(mEpdgTunnelManager).isTunnelConfigContainExistApn(TEST_APN_NAME); } @Test public void testBringUPTunnelWithNoBringUpInProcess() { String testApnName2 = "www.abc.com"; TunnelSetupRequest TSR = getBasicTunnelSetupRequest(TEST_APN_NAME, ApnSetting.PROTOCOL_IP); mEpdgTunnelManager.putApnNameToTunnelConfig( testApnName2, mMockIkeSession, mMockIwlanTunnelCallback, mMockIwlanTunnelCallbackMetrics, null, 0); doReturn(true).when(mEpdgTunnelManager).canBringUpTunnel(eq(TEST_APN_NAME)); boolean ret = mEpdgTunnelManager.bringUpTunnel( TSR, mMockIwlanTunnelCallback, mMockIwlanTunnelCallbackMetrics); assertTrue(ret); } @Test public void testBringUPTunnelSuccess() throws Exception { TunnelSetupRequest TSR = getBasicTunnelSetupRequest(TEST_APN_NAME, ApnSetting.PROTOCOL_IP); doReturn(true).when(mEpdgTunnelManager).canBringUpTunnel(eq(TEST_APN_NAME)); PersistableBundle bundle = new PersistableBundle(); setupMockForGetConfig(bundle); boolean ret = mEpdgTunnelManager.bringUpTunnel( TSR, mMockIwlanTunnelCallback, mMockIwlanTunnelCallbackMetrics); assertTrue(ret); mTestLooper.dispatchAll(); verify(mMockEpdgSelector) .getValidatedServerList( anyInt(), eq(EpdgSelector.PROTO_FILTER_IPV4), eq(false), eq(false), eq(mMockNetwork), any()); } private void setupTunnelBringup(String apnName, int transactionId) throws Exception { setupMockForGetConfig(null); doReturn(null) .when(mMockIkeSessionCreator) .createIkeSession( eq(mMockContext), any(IkeSessionParams.class), any(ChildSessionParams.class), any(Executor.class), any(IkeSessionCallback.class), any(ChildSessionCallback.class)); doReturn(true).when(mEpdgTunnelManager).canBringUpTunnel(eq(apnName)); boolean ret = mEpdgTunnelManager.bringUpTunnel( getBasicTunnelSetupRequest(apnName, ApnSetting.PROTOCOL_IP), mMockIwlanTunnelCallback, mMockIwlanTunnelCallbackMetrics); assertTrue(ret); mTestLooper.dispatchAll(); mEpdgTunnelManager.sendSelectionRequestComplete( EXPECTED_EPDG_ADDRESSES, new IwlanError(IwlanError.NO_ERROR), transactionId); mTestLooper.dispatchAll(); } private void setupTunnelBringup() throws Exception { setupTunnelBringup(TEST_APN_NAME, 1 /* transactionId */); } @Test @Ignore("b/239753287- Telus carrier errors out on parsing DEVICE_IDENTITY response") public void testBringUpTunnelSetsDeviceIdentityImeiSv() throws Exception { when(mMockContext.getSystemService(eq(TelephonyManager.class))) .thenReturn(mMockTelephonyManager); when(mMockTelephonyManager.createForSubscriptionId(DEFAULT_SUBID)) .thenReturn(mMockTelephonyManager); String TEST_IMEI = "012345678901234"; String TEST_IMEI_SUFFIX = "56"; String EXPECTED_IMEISV = TEST_IMEI.substring(0, TEST_IMEI.length() - 1) + TEST_IMEI_SUFFIX; when(mMockTelephonyManager.getImei()).thenReturn(TEST_IMEI); when(mMockTelephonyManager.getDeviceSoftwareVersion()).thenReturn(TEST_IMEI_SUFFIX); setupTunnelBringup(); ArgumentCaptor ikeSessionParamsCaptor = ArgumentCaptor.forClass(IkeSessionParams.class); verify(mMockIkeSessionCreator, atLeastOnce()) .createIkeSession( eq(mMockContext), ikeSessionParamsCaptor.capture(), any(ChildSessionParams.class), any(Executor.class), any(IkeSessionCallback.class), any(ChildSessionCallback.class)); IkeSessionParams ikeSessionParams = ikeSessionParamsCaptor.getValue(); assertEquals( ikeSessionParams.getIke3gppExtension().getIke3gppParams().getMobileDeviceIdentity(), EXPECTED_IMEISV); } @Test @Ignore("b/239753287- Telus carrier errors out on parsing DEVICE_IDENTITY response") public void testBringUpTunnelSetsDeviceIdentityImei() throws Exception { when(mMockContext.getSystemService(eq(TelephonyManager.class))) .thenReturn(mMockTelephonyManager); when(mMockTelephonyManager.createForSubscriptionId(DEFAULT_SUBID)) .thenReturn(mMockTelephonyManager); String TEST_IMEI = "012345678901234"; when(mMockTelephonyManager.getImei()).thenReturn(TEST_IMEI); when(mMockTelephonyManager.getDeviceSoftwareVersion()).thenReturn(null); setupTunnelBringup(); ArgumentCaptor ikeSessionParamsCaptor = ArgumentCaptor.forClass(IkeSessionParams.class); verify(mMockIkeSessionCreator, atLeastOnce()) .createIkeSession( eq(mMockContext), ikeSessionParamsCaptor.capture(), any(ChildSessionParams.class), any(Executor.class), any(IkeSessionCallback.class), any(ChildSessionCallback.class)); IkeSessionParams ikeSessionParams = ikeSessionParamsCaptor.getValue(); assertEquals( ikeSessionParams.getIke3gppExtension().getIke3gppParams().getMobileDeviceIdentity(), TEST_IMEI); } @Test @Ignore("b/239753287- Telus carrier errors out on parsing DEVICE_IDENTITY response") public void testBringUpTunnelNoDeviceIdentityWhenImeiUnavailable() throws Exception { when(mMockContext.getSystemService(eq(TelephonyManager.class))) .thenReturn(mMockTelephonyManager); when(mMockTelephonyManager.createForSubscriptionId(DEFAULT_SUBID)) .thenReturn(mMockTelephonyManager); when(mMockTelephonyManager.getImei()).thenReturn(null); setupTunnelBringup(); ArgumentCaptor ikeSessionParamsCaptor = ArgumentCaptor.forClass(IkeSessionParams.class); verify(mMockIkeSessionCreator, atLeastOnce()) .createIkeSession( eq(mMockContext), ikeSessionParamsCaptor.capture(), any(ChildSessionParams.class), any(Executor.class), any(IkeSessionCallback.class), any(ChildSessionCallback.class)); IkeSessionParams ikeSessionParams = ikeSessionParamsCaptor.getValue(); assertEquals( ikeSessionParams.getIke3gppExtension().getIke3gppParams().getMobileDeviceIdentity(), null); } @Test public void testBringUpTunnelWithMobilityOptions() throws Exception { doReturn(null) .when(mMockIkeSessionCreator) .createIkeSession( eq(mMockContext), any(IkeSessionParams.class), any(ChildSessionParams.class), any(Executor.class), any(IkeSessionCallback.class), any(ChildSessionCallback.class)); doReturn(true).when(mEpdgTunnelManager).canBringUpTunnel(eq(TEST_APN_NAME)); boolean ret = mEpdgTunnelManager.bringUpTunnel( getBasicTunnelSetupRequest(TEST_APN_NAME, ApnSetting.PROTOCOL_IP), mMockIwlanTunnelCallback, mMockIwlanTunnelCallbackMetrics); assertTrue(ret); mTestLooper.dispatchAll(); mEpdgTunnelManager.sendSelectionRequestComplete( EXPECTED_EPDG_ADDRESSES, new IwlanError(IwlanError.NO_ERROR), 1); mTestLooper.dispatchAll(); ArgumentCaptor ikeSessionParamsCaptor = ArgumentCaptor.forClass(IkeSessionParams.class); verify(mMockIkeSessionCreator, atLeastOnce()) .createIkeSession( eq(mMockContext), ikeSessionParamsCaptor.capture(), any(ChildSessionParams.class), any(Executor.class), any(IkeSessionCallback.class), any(ChildSessionCallback.class)); IkeSessionParams ikeSessionParams = ikeSessionParamsCaptor.getValue(); assertTrue(ikeSessionParams.hasIkeOption(IkeSessionParams.IKE_OPTION_MOBIKE)); assertTrue(ikeSessionParams.hasIkeOption(IkeSessionParams.IKE_OPTION_REKEY_MOBILITY)); } @Test public void testInitialContactForFirstTunnelOnly() throws Exception { final String firstApnName = "ims"; final String secondApnName = "mms"; IkeSessionArgumentCaptors firstTunnelArgumentCaptors = verifyBringUpTunnelWithDnsQuery(firstApnName); ChildSessionCallback firstCallback = firstTunnelArgumentCaptors.mChildSessionCallbackCaptor.getValue(); IkeSessionArgumentCaptors secondTunnelArgumentCaptors = verifyBringUpTunnel(secondApnName, true /* needPendingBringUpReq */); verifyTunnelOnOpened(firstApnName, firstCallback); ChildSessionCallback secondCallback = secondTunnelArgumentCaptors.mChildSessionCallbackCaptor.getValue(); verifyTunnelOnOpened(secondApnName, secondCallback); IkeSessionParams firstTunnelParams = firstTunnelArgumentCaptors.mIkeSessionParamsCaptor.getValue(); IkeSessionParams secondTunnelParams = secondTunnelArgumentCaptors.mIkeSessionParamsCaptor.getValue(); assertTrue(firstTunnelParams.hasIkeOption(IkeSessionParams.IKE_OPTION_INITIAL_CONTACT)); assertFalse(secondTunnelParams.hasIkeOption(IkeSessionParams.IKE_OPTION_INITIAL_CONTACT)); } @Test public void testCloseTunnelWithNoTunnelForApn() throws Exception { String testApnName = "www.xyz.com"; boolean ret = mEpdgTunnelManager.closeTunnel(testApnName, false /*forceClose*/); assertTrue(ret); mTestLooper.dispatchAll(); verify(mEpdgTunnelManager).closePendingRequestsForApn(eq(testApnName)); } @Test public void testCloseTunnelWithForceClose() throws Exception { String testApnName = "www.xyz.com"; mEpdgTunnelManager.putApnNameToTunnelConfig( testApnName, mMockIkeSession, mMockIwlanTunnelCallback, mMockIwlanTunnelCallbackMetrics, null, 0); boolean ret = mEpdgTunnelManager.closeTunnel(testApnName, true /*forceClose*/); assertTrue(ret); mTestLooper.dispatchAll(); verify(mMockIkeSession).kill(); verify(mEpdgTunnelManager).closePendingRequestsForApn(eq(testApnName)); } @Test public void testCloseTunnelWithNonForceClose() throws Exception { String testApnName = "www.xyz.com"; mEpdgTunnelManager.putApnNameToTunnelConfig( testApnName, mMockIkeSession, mMockIwlanTunnelCallback, mMockIwlanTunnelCallbackMetrics, null, 0); boolean ret = mEpdgTunnelManager.closeTunnel(testApnName, false /*forceClose*/); assertTrue(ret); mTestLooper.dispatchAll(); verify(mMockIkeSession).close(); verify(mEpdgTunnelManager).closePendingRequestsForApn(eq(testApnName)); } @Test public void testRekeyAndNattTimerFromCarrierConfig() throws Exception { String testApnName = "www.xyz.com"; // Test values int hardTime = 50000; int softTime = 20000; int hardTimeChild = 10000; int softTimeChild = 1000; int nattTimer = 60; PersistableBundle bundle = new PersistableBundle(); bundle.putInt(CarrierConfigManager.Iwlan.KEY_IKE_REKEY_HARD_TIMER_SEC_INT, hardTime); bundle.putInt(CarrierConfigManager.Iwlan.KEY_IKE_REKEY_SOFT_TIMER_SEC_INT, softTime); bundle.putInt( CarrierConfigManager.Iwlan.KEY_CHILD_SA_REKEY_HARD_TIMER_SEC_INT, hardTimeChild); bundle.putInt( CarrierConfigManager.Iwlan.KEY_CHILD_SA_REKEY_SOFT_TIMER_SEC_INT, softTimeChild); bundle.putInt(CarrierConfigManager.Iwlan.KEY_NATT_KEEP_ALIVE_TIMER_SEC_INT, nattTimer); setupMockForGetConfig(bundle); when(mMockEpdgSelector.getValidatedServerList( anyInt(), anyInt(), eq(false), eq(false), eq(mMockNetwork), any(EpdgSelector.EpdgSelectorCallback.class))) .thenReturn(new IwlanError(IwlanError.NO_ERROR)); doReturn(null) .when(mMockIkeSessionCreator) .createIkeSession( eq(mMockContext), any(IkeSessionParams.class), any(ChildSessionParams.class), any(Executor.class), any(IkeSessionCallback.class), any(ChildSessionCallback.class)); doReturn(true).when(mEpdgTunnelManager).canBringUpTunnel(eq(testApnName)); boolean ret = mEpdgTunnelManager.bringUpTunnel( getBasicTunnelSetupRequest(TEST_APN_NAME, ApnSetting.PROTOCOL_IP), mMockIwlanTunnelCallback, mMockIwlanTunnelCallbackMetrics); assertTrue(ret); mTestLooper.dispatchAll(); mEpdgTunnelManager.sendSelectionRequestComplete( EXPECTED_EPDG_ADDRESSES, new IwlanError(IwlanError.NO_ERROR), 1); mTestLooper.dispatchAll(); ArgumentCaptor ikeSessionParamsCaptor = ArgumentCaptor.forClass(IkeSessionParams.class); ArgumentCaptor childSessionParamsCaptor = ArgumentCaptor.forClass(ChildSessionParams.class); verify(mMockIkeSessionCreator) .createIkeSession( eq(mMockContext), ikeSessionParamsCaptor.capture(), childSessionParamsCaptor.capture(), any(Executor.class), any(IkeSessionCallback.class), any(ChildSessionCallback.class)); IkeSessionParams ikeSessionParams = ikeSessionParamsCaptor.getValue(); ChildSessionParams childSessionParams = childSessionParamsCaptor.getValue(); assertEquals(ikeSessionParams.getHardLifetimeSeconds(), hardTime); assertEquals(ikeSessionParams.getSoftLifetimeSeconds(), softTime); assertEquals(childSessionParams.getHardLifetimeSeconds(), hardTimeChild); assertEquals(childSessionParams.getSoftLifetimeSeconds(), softTimeChild); assertEquals(ikeSessionParams.getNattKeepAliveDelaySeconds(), nattTimer); } @Test public void testSetRetransmissionTimeoutsFromCarrierConfig() throws Exception { String testApnName = "www.xyz.com"; int[] testTimeouts = {1000, 1200, 1400, 1600, 2000, 4000}; PersistableBundle bundle = new PersistableBundle(); bundle.putIntArray( CarrierConfigManager.Iwlan.KEY_RETRANSMIT_TIMER_MSEC_INT_ARRAY, testTimeouts); setupMockForGetConfig(bundle); when(mMockEpdgSelector.getValidatedServerList( anyInt(), anyInt(), eq(false), eq(false), eq(mMockNetwork), any(EpdgSelector.EpdgSelectorCallback.class))) .thenReturn(new IwlanError(IwlanError.NO_ERROR)); doReturn(null) .when(mMockIkeSessionCreator) .createIkeSession( eq(mMockContext), any(IkeSessionParams.class), any(ChildSessionParams.class), any(Executor.class), any(IkeSessionCallback.class), any(ChildSessionCallback.class)); doReturn(true).when(mEpdgTunnelManager).canBringUpTunnel(eq(testApnName)); boolean ret = mEpdgTunnelManager.bringUpTunnel( getBasicTunnelSetupRequest(TEST_APN_NAME, ApnSetting.PROTOCOL_IP), mMockIwlanTunnelCallback, mMockIwlanTunnelCallbackMetrics); assertTrue(ret); mTestLooper.dispatchAll(); mEpdgTunnelManager.sendSelectionRequestComplete( EXPECTED_EPDG_ADDRESSES, new IwlanError(IwlanError.NO_ERROR), 1); mTestLooper.dispatchAll(); ArgumentCaptor ikeSessionParamsCaptor = ArgumentCaptor.forClass(IkeSessionParams.class); verify(mMockIkeSessionCreator) .createIkeSession( eq(mMockContext), ikeSessionParamsCaptor.capture(), any(ChildSessionParams.class), any(Executor.class), any(IkeSessionCallback.class), any(ChildSessionCallback.class)); IkeSessionParams ikeSessionParams = ikeSessionParamsCaptor.getValue(); assertArrayEquals(ikeSessionParams.getRetransmissionTimeoutsMillis(), testTimeouts); } @Test public void testSetDpdDelayFromCarrierConfig() throws Exception { String testApnName = "www.xyz.com"; // Test values int testDpdDelay = 600; PersistableBundle bundle = new PersistableBundle(); bundle.putInt(CarrierConfigManager.Iwlan.KEY_DPD_TIMER_SEC_INT, testDpdDelay); setupMockForGetConfig(bundle); when(mMockEpdgSelector.getValidatedServerList( anyInt(), anyInt(), eq(false), eq(false), eq(mMockNetwork), any(EpdgSelector.EpdgSelectorCallback.class))) .thenReturn(new IwlanError(IwlanError.NO_ERROR)); doReturn(null) .when(mMockIkeSessionCreator) .createIkeSession( eq(mMockContext), any(IkeSessionParams.class), any(ChildSessionParams.class), any(Executor.class), any(IkeSessionCallback.class), any(ChildSessionCallback.class)); doReturn(true).when(mEpdgTunnelManager).canBringUpTunnel(eq(testApnName)); boolean ret = mEpdgTunnelManager.bringUpTunnel( getBasicTunnelSetupRequest(TEST_APN_NAME, ApnSetting.PROTOCOL_IP), mMockIwlanTunnelCallback, mMockIwlanTunnelCallbackMetrics); assertTrue(ret); mTestLooper.dispatchAll(); mEpdgTunnelManager.sendSelectionRequestComplete( EXPECTED_EPDG_ADDRESSES, new IwlanError(IwlanError.NO_ERROR), 1); mTestLooper.dispatchAll(); ArgumentCaptor ikeSessionParamsCaptor = ArgumentCaptor.forClass(IkeSessionParams.class); verify(mMockIkeSessionCreator) .createIkeSession( eq(mMockContext), ikeSessionParamsCaptor.capture(), any(ChildSessionParams.class), any(Executor.class), any(IkeSessionCallback.class), any(ChildSessionCallback.class)); IkeSessionParams ikeSessionParams = ikeSessionParamsCaptor.getValue(); assertEquals(ikeSessionParams.getDpdDelaySeconds(), testDpdDelay); } @Test public void testGetValidEpdgAddress_DiffAddr() throws Exception { String testApnName = "www.xyz.com"; List ipList1 = new ArrayList<>(); ipList1.add(InetAddress.getByName("1.1.1.1")); mEpdgTunnelManager.validateAndSetEpdgAddress(ipList1); IwlanError error = new IwlanError(new IkeInternalException(new IOException())); doReturn(0L).when(mEpdgTunnelManager).reportIwlanError(eq(testApnName), eq(error)); setupMockForGetConfig(null); when(mMockEpdgSelector.getValidatedServerList( anyInt(), anyInt(), eq(false), eq(false), eq(mMockNetwork), any(EpdgSelector.EpdgSelectorCallback.class))) .thenReturn(new IwlanError(IwlanError.NO_ERROR)); doReturn(null) .doReturn(null) .when(mMockIkeSessionCreator) .createIkeSession( eq(mMockContext), any(IkeSessionParams.class), any(ChildSessionParams.class), any(Executor.class), any(IkeSessionCallback.class), any(ChildSessionCallback.class)); doReturn(true).when(mEpdgTunnelManager).canBringUpTunnel(eq(testApnName)); boolean ret = mEpdgTunnelManager.bringUpTunnel( getBasicTunnelSetupRequest(TEST_APN_NAME, ApnSetting.PROTOCOL_IP), mMockIwlanTunnelCallback, mMockIwlanTunnelCallbackMetrics); assertTrue(ret); mTestLooper.dispatchAll(); ArrayList ipList2 = new ArrayList<>(); ipList2.add(InetAddress.getByName("8.8.8.8")); mEpdgTunnelManager.sendSelectionRequestComplete( ipList2, new IwlanError(IwlanError.NO_ERROR), 1); mTestLooper.dispatchAll(); EpdgTunnelManager.TmIkeSessionCallback ikeSessionCallback = verifyCreateIkeSession(ipList2.get(0)); ikeSessionCallback.onClosedExceptionally( new IkeInternalException(new IOException("Retransmitting failure"))); mTestLooper.dispatchAll(); verify(mEpdgTunnelManager, times(1)).reportIwlanError(eq(testApnName), eq(error)); verify(mMockIwlanTunnelCallback, times(1)).onClosed(eq(testApnName), eq(error)); } @Test public void testGetValidEpdgAddress_NextAddr() throws Exception { String testApnName = "www.xyz.com"; List ipList1 = new ArrayList<>(); ipList1.add(InetAddress.getByName("1.1.1.1")); ipList1.add(InetAddress.getByName("8.8.8.8")); mEpdgTunnelManager.validateAndSetEpdgAddress(ipList1); IwlanError error = new IwlanError(new IkeInternalException(new IOException())); doReturn(0L).when(mEpdgTunnelManager).reportIwlanError(eq(testApnName), eq(error)); setupMockForGetConfig(null); when(mMockEpdgSelector.getValidatedServerList( anyInt(), anyInt(), eq(false), eq(false), eq(mMockNetwork), any(EpdgSelector.EpdgSelectorCallback.class))) .thenReturn(new IwlanError(IwlanError.NO_ERROR)); doReturn(null) .doReturn(null) .when(mMockIkeSessionCreator) .createIkeSession( eq(mMockContext), any(IkeSessionParams.class), any(ChildSessionParams.class), any(Executor.class), any(IkeSessionCallback.class), any(ChildSessionCallback.class)); doReturn(true).when(mEpdgTunnelManager).canBringUpTunnel(eq(testApnName)); boolean ret = mEpdgTunnelManager.bringUpTunnel( getBasicTunnelSetupRequest(TEST_APN_NAME, ApnSetting.PROTOCOL_IP), mMockIwlanTunnelCallback, mMockIwlanTunnelCallbackMetrics); assertTrue(ret); mTestLooper.dispatchAll(); ArrayList ipList2 = new ArrayList<>(); ipList2.add(InetAddress.getByName("1.1.1.1")); ipList2.add(InetAddress.getByName("8.8.8.8")); mEpdgTunnelManager.sendSelectionRequestComplete( ipList2, new IwlanError(IwlanError.NO_ERROR), 1); mTestLooper.dispatchAll(); EpdgTunnelManager.TmIkeSessionCallback ikeSessionCallback = verifyCreateIkeSession(ipList2.get(1)); ikeSessionCallback.onClosedExceptionally( new IkeInternalException(new IOException("Retransmitting failure"))); mTestLooper.dispatchAll(); verify(mEpdgTunnelManager, times(1)).reportIwlanError(eq(testApnName), eq(error)); verify(mMockIwlanTunnelCallback, times(1)).onClosed(eq(testApnName), eq(error)); } private EpdgTunnelManager.TmIkeSessionCallback verifyCreateIkeSession(InetAddress ip) throws Exception { ArgumentCaptor ikeSessionParamsCaptor = ArgumentCaptor.forClass(IkeSessionParams.class); ArgumentCaptor ikeSessionCallbackCaptor = ArgumentCaptor.forClass(EpdgTunnelManager.TmIkeSessionCallback.class); verify(mMockIkeSessionCreator, atLeastOnce()) .createIkeSession( eq(mMockContext), ikeSessionParamsCaptor.capture(), any(ChildSessionParams.class), any(Executor.class), ikeSessionCallbackCaptor.capture(), any(ChildSessionCallback.class)); IkeSessionParams ikeSessionParams = ikeSessionParamsCaptor.getValue(); assertEquals(ikeSessionParams.getServerHostname(), ip.getHostAddress()); return ikeSessionCallbackCaptor.getValue(); } @Test public void testIpv6PrefixMatching() throws Exception { InetAddress a1 = InetAddress.getByName("2600:381:4872:5d1e:ac45:69c7:bab2:639b"); LinkAddress l1 = new LinkAddress(a1, 64); InetAddress src = InetAddress.getByName("2600:381:4872:5d1e:0:10:3582:a501"); EpdgTunnelManager.TunnelConfig tf = mEpdgTunnelManager.new TunnelConfig(null, null, null, src, 64); assertTrue(tf.isPrefixSameAsSrcIP(l1)); // different prefix length LinkAddress l2 = new LinkAddress(a1, 63); assertFalse(tf.isPrefixSameAsSrcIP(l2)); } @Test public void testBackOffTimeCalculation() throws Exception { int transactionId = 1; // unit: 10 mins value: 2 expectedTime: 1200 (10 * 60 * 2) verifyBackOffTimer("00000010", 1200, transactionId++); // unit: 1 hour value: 4 expectedTime: 14400 (1 * 60 * 60 * 4) verifyBackOffTimer("00100100", 14400, transactionId++); // unit: 10 hours value: 3 expectedTime: (10 * 60 * 60 * 3) verifyBackOffTimer("01000011", 108000, transactionId++); // unit: 2 secs value: 21 expectedTime: 42 (2 * 21) verifyBackOffTimer("01110101", 42, transactionId++); // unit: 30 secs value: 31 expectedTime: 930 (30 * 31) verifyBackOffTimer("10011111", 930, transactionId++); // unit: 1 min value: 25 expectedTime: 1500 (1 * 60 * 25) verifyBackOffTimer("10111001", 1500, transactionId++); // unit: 1 hour value: 12 expectedTime: 43200 (1 * 60 * 60 * 12) verifyBackOffTimer("11001100", 43200, transactionId++); // deactivate - Should not report backoff time. verifyBackOffTimer("11100100", -1, transactionId++); } private void verifyBackOffTimer(String backoffByte, long expectedBackoffTime, int transactionId) throws Exception { String testApnName = "www.xyz.com"; IwlanError error = new IwlanError(new IkeInternalException(new Exception())); Ike3gppBackoffTimer mockIke3gppBackoffTimer = mock(Ike3gppBackoffTimer.class); List ike3gppInfoList = new ArrayList<>(); ike3gppInfoList.add(mockIke3gppBackoffTimer); doReturn(Ike3gppData.DATA_TYPE_NOTIFY_BACKOFF_TIMER) .when(mockIke3gppBackoffTimer) .getDataType(); doReturn((byte) (int) Integer.parseInt(backoffByte, 2)) .when(mockIke3gppBackoffTimer) .getBackoffTimer(); // if back off time expected is negative normal reportIwlanError should be called. if (expectedBackoffTime < 0) { doReturn(0L).when(mEpdgTunnelManager).reportIwlanError(eq(testApnName), eq(error)); } else { doReturn(0L) .when(mEpdgTunnelManager) .reportIwlanError(eq(testApnName), eq(error), anyLong()); } setupMockForGetConfig(null); when(mMockEpdgSelector.getValidatedServerList( anyInt(), anyInt(), eq(false), eq(false), eq(mMockNetwork), any(EpdgSelector.EpdgSelectorCallback.class))) .thenReturn(new IwlanError(IwlanError.NO_ERROR)); doReturn(null) .doReturn(null) .when(mMockIkeSessionCreator) .createIkeSession( eq(mMockContext), any(IkeSessionParams.class), any(ChildSessionParams.class), any(Executor.class), any(IkeSessionCallback.class), any(ChildSessionCallback.class)); doReturn(true).when(mEpdgTunnelManager).canBringUpTunnel(eq(testApnName)); boolean ret = mEpdgTunnelManager.bringUpTunnel( getBasicTunnelSetupRequest(TEST_APN_NAME, ApnSetting.PROTOCOL_IP), mMockIwlanTunnelCallback, mMockIwlanTunnelCallbackMetrics); assertTrue(ret); mTestLooper.dispatchAll(); mEpdgTunnelManager.sendSelectionRequestComplete( EXPECTED_EPDG_ADDRESSES, new IwlanError(IwlanError.NO_ERROR), transactionId); mTestLooper.dispatchAll(); ArgumentCaptor ikeSessionParamsCaptor = ArgumentCaptor.forClass(IkeSessionParams.class); ArgumentCaptor ikeSessionCallbackCaptor = ArgumentCaptor.forClass(EpdgTunnelManager.TmIkeSessionCallback.class); verify(mMockIkeSessionCreator, atLeastOnce()) .createIkeSession( eq(mMockContext), ikeSessionParamsCaptor.capture(), any(ChildSessionParams.class), any(Executor.class), ikeSessionCallbackCaptor.capture(), any(ChildSessionCallback.class)); IkeSessionParams ikeSessionParams = ikeSessionParamsCaptor.getValue(); assertEquals( ikeSessionParams.getServerHostname(), EXPECTED_EPDG_ADDRESSES.get(0).getHostAddress()); Ike3gppExtension.Ike3gppDataListener ike3gppCallback = ikeSessionParams.getIke3gppExtension().getIke3gppDataListener(); ike3gppCallback.onIke3gppDataReceived(ike3gppInfoList); EpdgTunnelManager.TmIkeSessionCallback ikeSessionCallback = ikeSessionCallbackCaptor.getValue(); ikeSessionCallback.onClosedExceptionally(new IkeInternalException(new Exception())); mTestLooper.dispatchAll(); // if expected backoff time is negative - verify that backoff time is not reported. if (expectedBackoffTime < 0) { verify(mEpdgTunnelManager, times(1)).reportIwlanError(eq(testApnName), eq(error)); } else { // Else - Verify reportIwlanError with correct backoff time is being called. verify(mEpdgTunnelManager, times(1)) .reportIwlanError(eq(testApnName), eq(error), eq(expectedBackoffTime)); } verify(mMockIwlanTunnelCallback, atLeastOnce()).onClosed(eq(testApnName), eq(error)); } private TunnelSetupRequest getBasicTunnelSetupRequest(String apnName, int apnIpProtocol) { return getBasicTunnelSetupRequest(apnName, apnIpProtocol, 1); } private TunnelSetupRequest getBasicTunnelSetupRequest( String apnName, int apnIpProtocol, int pduSessionId) { TunnelSetupRequest ret = TunnelSetupRequest.builder() .setApnName(apnName) .setNetwork(mMockNetwork) .setIsRoaming(false /*isRoaming*/) .setIsEmergency(false /*IsEmergency*/) .setRequestPcscf(false /*requestPcscf*/) .setApnIpProtocol(apnIpProtocol) .setPduSessionId(pduSessionId) .build(); return ret; } private TunnelSetupRequest getHandoverTunnelSetupRequest(String apnName, int apnIpProtocol) { TunnelSetupRequest.Builder bld = TunnelSetupRequest.builder(); bld.setApnName(apnName) .setNetwork(mMockNetwork) .setIsRoaming(false /*isRoaming*/) .setIsEmergency(false /*IsEmergency*/) .setRequestPcscf(false /*requestPcscf*/) .setApnIpProtocol(apnIpProtocol) .setPduSessionId(1); switch (apnIpProtocol) { case ApnSetting.PROTOCOL_IP: bld.setSrcIpv4Address(InetAddresses.parseNumericAddress("10.10.10.10")); break; case ApnSetting.PROTOCOL_IPV6: bld.setSrcIpv6Address( InetAddresses.parseNumericAddress( "2001:0db8:85a3:0000:0000:8a2e:0370:7334")); break; case ApnSetting.PROTOCOL_IPV4V6: bld.setSrcIpv4Address(InetAddresses.parseNumericAddress("10.10.10.10")); bld.setSrcIpv6Address( InetAddresses.parseNumericAddress( "2001:0db8:85a3:0000:0000:8a2e:0370:7334")); break; } return bld.build(); } private void setupMockForGetConfig(PersistableBundle bundle) { if (bundle == null) { bundle = new PersistableBundle(); } bundle.putIntArray( CarrierConfigManager.Iwlan.KEY_SUPPORTED_INTEGRITY_ALGORITHMS_INT_ARRAY, new int[] { SaProposal.INTEGRITY_ALGORITHM_HMAC_SHA1_96, SaProposal.INTEGRITY_ALGORITHM_HMAC_SHA2_256_128, SaProposal.INTEGRITY_ALGORITHM_HMAC_SHA2_384_192, SaProposal.INTEGRITY_ALGORITHM_HMAC_SHA2_512_256, }); when(mMockContext.getSystemService(eq(CarrierConfigManager.class))) .thenReturn(mMockCarrierConfigManager); when(mMockContext.getSystemService(eq(ConnectivityManager.class))) .thenReturn(mMockConnectivityManager); when(mMockContext.getSystemService(eq(SubscriptionManager.class))) .thenReturn(mMockSubscriptionManager); when(mMockContext.getSystemService(eq(TelephonyManager.class))) .thenReturn(mMockTelephonyManager); when(mMockSubscriptionManager.getActiveSubscriptionInfoForSimSlotIndex(DEFAULT_SLOT_INDEX)) .thenReturn(mMockSubscriptionInfo); when(mMockSubscriptionInfo.getSubscriptionId()).thenReturn(DEFAULT_SUBID); when(mMockSubscriptionInfo.getMncString()).thenReturn("344"); when(mMockTelephonyManager.createForSubscriptionId(DEFAULT_SUBID)) .thenReturn(mMockTelephonyManager); when(mMockCarrierConfigManager.getConfigForSubId(DEFAULT_SLOT_INDEX)).thenReturn(bundle); } private void setVariable(Object target, String variableName, Object value) throws Exception { FieldSetter.setField(target, target.getClass().getDeclaredField(variableName), value); } @Test public void testHandleOnClosedWithEpdgAddressSelected_True() throws Exception { String testApnName = "www.xyz.com"; IwlanError error = new IwlanError(IwlanError.NETWORK_FAILURE); doReturn(0L).when(mEpdgTunnelManager).reportIwlanError(eq(testApnName), eq(error)); mEpdgTunnelManager.putApnNameToTunnelConfig( testApnName, mMockIkeSession, mMockIwlanTunnelCallback, mMockIwlanTunnelCallbackMetrics, null, 0); int token = mEpdgTunnelManager.incrementAndGetCurrentTokenForApn(testApnName); mEpdgTunnelManager.setIsEpdgAddressSelected(true); mEpdgTunnelManager.setEpdgAddress(InetAddresses.parseNumericAddress(EPDG_ADDRESS)); mEpdgTunnelManager.getTmIkeSessionCallback(testApnName, token).onClosed(); mTestLooper.dispatchAll(); verify(mMockIwlanTunnelCallback, times(1)).onClosed(eq(testApnName), eq(error)); verify(mEpdgTunnelManager, times(2)).resetTunnelManagerState(); verify(mEpdgTunnelManager, times(1)).reportIwlanError(eq(testApnName), eq(error)); } @Test public void testHandleOnClosedWithEpdgAddressSelected_False() throws Exception { String testApnName = "www.xyz.com"; IwlanError error = new IwlanError(IwlanError.NETWORK_FAILURE); doReturn(0L).when(mEpdgTunnelManager).reportIwlanError(eq(testApnName), eq(error)); PersistableBundle bundle = new PersistableBundle(); setupMockForGetConfig(bundle); doReturn(true).when(mEpdgTunnelManager).canBringUpTunnel(eq(testApnName)); boolean ret = mEpdgTunnelManager.bringUpTunnel( getBasicTunnelSetupRequest(TEST_APN_NAME, ApnSetting.PROTOCOL_IP), mMockIwlanTunnelCallback, mMockIwlanTunnelCallbackMetrics); assertTrue(ret); mTestLooper.dispatchAll(); mEpdgTunnelManager.sendSelectionRequestComplete( EXPECTED_EPDG_ADDRESSES, new IwlanError(IwlanError.NO_ERROR), 1); mTestLooper.dispatchAll(); mEpdgTunnelManager.setIsEpdgAddressSelected(false); mEpdgTunnelManager.getTmIkeSessionCallback(testApnName, DEFAULT_TOKEN).onClosed(); mTestLooper.dispatchAll(); verify(mMockIwlanTunnelCallback, times(1)).onClosed(eq(testApnName), eq(error)); verify(mEpdgTunnelManager, times(2)).resetTunnelManagerState(); verify(mEpdgTunnelManager, times(1)).reportIwlanError(eq(testApnName), eq(error)); } private void setOneTunnelOpened(String apnName) throws Exception { mEpdgTunnelManager.putApnNameToTunnelConfig( apnName, mMockIkeSession, mMockIwlanTunnelCallback, mMockIwlanTunnelCallbackMetrics, null, 0); setVariable(mEpdgTunnelManager, "mLocalAddresses", EXPECTED_LOCAL_ADDRESSES); mEpdgTunnelManager.validateAndSetEpdgAddress(EXPECTED_EPDG_ADDRESSES); mEpdgTunnelManager.setIsEpdgAddressSelected(true); } private IkeSessionArgumentCaptors verifyBringUpTunnelWithDnsQuery(String apnName) { return verifyBringUpTunnelWithDnsQuery(apnName, null); } private IkeSessionArgumentCaptors verifyBringUpTunnelWithDnsQuery( String apnName, IkeSession ikeSession) { reset(mMockIwlanTunnelCallback); IkeSessionArgumentCaptors ikeSessionArgumentCaptors = new IkeSessionArgumentCaptors(); verifyBringUpTunnel(apnName, true /* needPendingBringUpReq */); doReturn(ikeSession) .when(mMockIkeSessionCreator) .createIkeSession( eq(mMockContext), ikeSessionArgumentCaptors.mIkeSessionParamsCaptor.capture(), ikeSessionArgumentCaptors.mChildSessionParamsCaptor.capture(), any(Executor.class), ikeSessionArgumentCaptors.mIkeSessionCallbackCaptor.capture(), ikeSessionArgumentCaptors.mChildSessionCallbackCaptor.capture()); mEpdgTunnelManager.sendSelectionRequestComplete( EXPECTED_EPDG_ADDRESSES, new IwlanError(IwlanError.NO_ERROR), 1); mTestLooper.dispatchAll(); verify(mMockIkeSessionCreator, times(1)) .createIkeSession( eq(mMockContext), ikeSessionArgumentCaptors.mIkeSessionParamsCaptor.capture(), ikeSessionArgumentCaptors.mChildSessionParamsCaptor.capture(), any(Executor.class), ikeSessionArgumentCaptors.mIkeSessionCallbackCaptor.capture(), ikeSessionArgumentCaptors.mChildSessionCallbackCaptor.capture()); return ikeSessionArgumentCaptors; } private IkeSessionArgumentCaptors verifyBringUpTunnel( String apnName, boolean needPendingBringUpReq) { reset(mMockIkeSessionCreator); IkeSessionArgumentCaptors ikeSessionArgumentCaptors = new IkeSessionArgumentCaptors(); doReturn(null) .when(mMockIkeSessionCreator) .createIkeSession( eq(mMockContext), ikeSessionArgumentCaptors.mIkeSessionParamsCaptor.capture(), ikeSessionArgumentCaptors.mChildSessionParamsCaptor.capture(), any(Executor.class), ikeSessionArgumentCaptors.mIkeSessionCallbackCaptor.capture(), ikeSessionArgumentCaptors.mChildSessionCallbackCaptor.capture()); doReturn(true).when(mEpdgTunnelManager).canBringUpTunnel(eq(apnName)); boolean ret = mEpdgTunnelManager.bringUpTunnel( getBasicTunnelSetupRequest(apnName, ApnSetting.PROTOCOL_IP), mMockIwlanTunnelCallback, mMockIwlanTunnelCallbackMetrics); assertTrue(ret); mTestLooper.dispatchAll(); verify(mMockIkeSessionCreator, times(needPendingBringUpReq ? 0 : 1)) .createIkeSession( eq(mMockContext), ikeSessionArgumentCaptors.mIkeSessionParamsCaptor.capture(), ikeSessionArgumentCaptors.mChildSessionParamsCaptor.capture(), any(Executor.class), ikeSessionArgumentCaptors.mIkeSessionCallbackCaptor.capture(), ikeSessionArgumentCaptors.mChildSessionCallbackCaptor.capture()); return ikeSessionArgumentCaptors; } private void verifyTunnelOnOpened(String apnName, ChildSessionCallback childSessionCallback) { doReturn(0L) .when(mEpdgTunnelManager) .reportIwlanError(eq(apnName), eq(new IwlanError(IwlanError.NO_ERROR))); mEpdgTunnelManager .getTmIkeSessionCallback(apnName, mEpdgTunnelManager.getCurrentTokenForApn(apnName)) .onOpened(mMockIkeSessionConfiguration); mTestLooper.dispatchAll(); childSessionCallback.onIpSecTransformCreated( mMockedIpSecTransformIn, IpSecManager.DIRECTION_IN); mTestLooper.dispatchAll(); childSessionCallback.onIpSecTransformCreated( mMockedIpSecTransformOut, IpSecManager.DIRECTION_OUT); mTestLooper.dispatchAll(); childSessionCallback.onOpened(mMockChildSessionConfiguration); mTestLooper.dispatchAll(); verify(mEpdgTunnelManager, times(1)) .reportIwlanError(eq(apnName), eq(new IwlanError(IwlanError.NO_ERROR))); verify(mMockIwlanTunnelCallback, times(1)).onOpened(eq(apnName), any()); } @Test public void testHandleOnOpenedWithEpdgAddressSelected_True() throws Exception { final String openedApnName = "ims"; final String toBeOpenedApnName = "mms"; setOneTunnelOpened(openedApnName); IkeSessionArgumentCaptors ikeSessionArgumentCaptors = verifyBringUpTunnel(toBeOpenedApnName, false /* needPendingBringUpReq */); ChildSessionCallback childSessionCallback = ikeSessionArgumentCaptors.mChildSessionCallbackCaptor.getValue(); verifyTunnelOnOpened(toBeOpenedApnName, childSessionCallback); } @Test public void testServicePendingRequests() throws Exception { final String firstApnName = "ims"; final String secondApnName = "mms"; IkeSessionArgumentCaptors firstTunnelArgumentCaptors = verifyBringUpTunnelWithDnsQuery(firstApnName); ChildSessionCallback firstCallback = firstTunnelArgumentCaptors.mChildSessionCallbackCaptor.getValue(); IkeSessionArgumentCaptors secondTunnelArgumentCaptors = verifyBringUpTunnel(secondApnName, true /* needPendingBringUpReq */); verifyTunnelOnOpened(firstApnName, firstCallback); ChildSessionCallback secondCallback = secondTunnelArgumentCaptors.mChildSessionCallbackCaptor.getValue(); verifyTunnelOnOpened(secondApnName, secondCallback); } @Test public void testHandleOnClosedExceptionallyWithEpdgAddressSelected_True() throws Exception { String testApnName = "www.xyz.com"; IwlanError error = new IwlanError(mMockIkeException); doReturn(0L).when(mEpdgTunnelManager).reportIwlanError(eq(testApnName), eq(error)); mEpdgTunnelManager.putApnNameToTunnelConfig( testApnName, mMockIkeSession, mMockIwlanTunnelCallback, mMockIwlanTunnelCallbackMetrics, null, 0); int token = mEpdgTunnelManager.incrementAndGetCurrentTokenForApn(testApnName); mEpdgTunnelManager.setIsEpdgAddressSelected(true); mEpdgTunnelManager.setEpdgAddress(InetAddresses.parseNumericAddress(EPDG_ADDRESS)); mEpdgTunnelManager .getTmIkeSessionCallback(testApnName, token) .onClosedExceptionally(mMockIkeException); mTestLooper.dispatchAll(); verify(mMockIwlanTunnelCallback, times(1)).onClosed(eq(testApnName), eq(error)); verify(mEpdgTunnelManager, times(2)).resetTunnelManagerState(); verify(mEpdgTunnelManager, times(1)).reportIwlanError(eq(testApnName), eq(error)); } @Test public void testHandleOnClosedExceptionallyWithEpdgAddressSelected_False() throws Exception { String testApnName = "www.xyz.com"; IwlanError error = new IwlanError(mMockIkeException); doReturn(0L).when(mEpdgTunnelManager).reportIwlanError(eq(testApnName), eq(error)); PersistableBundle bundle = new PersistableBundle(); setupMockForGetConfig(bundle); doReturn(true).when(mEpdgTunnelManager).canBringUpTunnel(eq(testApnName)); boolean ret = mEpdgTunnelManager.bringUpTunnel( getBasicTunnelSetupRequest(TEST_APN_NAME, ApnSetting.PROTOCOL_IP), mMockIwlanTunnelCallback, mMockIwlanTunnelCallbackMetrics); assertTrue(ret); mTestLooper.dispatchAll(); mEpdgTunnelManager.sendSelectionRequestComplete( EXPECTED_EPDG_ADDRESSES, new IwlanError(IwlanError.NO_ERROR), 1); mTestLooper.dispatchAll(); mEpdgTunnelManager.setIsEpdgAddressSelected(false); mEpdgTunnelManager .getTmIkeSessionCallback(testApnName, DEFAULT_TOKEN) .onClosedExceptionally(mMockIkeException); mTestLooper.dispatchAll(); verify(mMockIwlanTunnelCallback, times(1)).onClosed(eq(testApnName), any(IwlanError.class)); verify(mEpdgTunnelManager, times(2)).resetTunnelManagerState(); verify(mEpdgTunnelManager, times(1)).reportIwlanError(eq(testApnName), eq(error)); } @Test public void testIkeSessionOnOpenedUpdatesPcscfAddrInTunnelConfig() throws Exception { String testApnName = "ims"; IwlanError error = new IwlanError(IwlanError.NO_ERROR); doReturn(0L).when(mEpdgTunnelManager).reportIwlanError(eq(testApnName), eq(error)); mEpdgTunnelManager.putApnNameToTunnelConfig( testApnName, mMockIkeSession, mMockIwlanTunnelCallback, mMockIwlanTunnelCallbackMetrics, null, 0); int token = mEpdgTunnelManager.incrementAndGetCurrentTokenForApn(testApnName); when(mMockIkeSessionConfiguration.getPcscfServers()).thenReturn(EXPECTED_EPDG_ADDRESSES); mEpdgTunnelManager .getTmIkeSessionCallback(testApnName, token) .onOpened(mMockIkeSessionConfiguration); mTestLooper.dispatchAll(); EpdgTunnelManager.TunnelConfig testApnTunnelConfig = mEpdgTunnelManager.getTunnelConfigForApn(testApnName); assertEquals(testApnTunnelConfig.getPcscfAddrList(), EXPECTED_EPDG_ADDRESSES); } @Test public void testIkeSessionClosesWhenChildSessionTransformThrows() throws Exception { String testApnName = "ims"; doThrow(new IllegalArgumentException()) .when(mMockIpSecManager) .applyTunnelModeTransform(eq(mMockIpSecTunnelInterface), anyInt(), any()); IkeSessionArgumentCaptors ikeSessionArgumentCaptors = verifyBringUpTunnelWithDnsQuery(testApnName, mMockIkeSession); ChildSessionCallback childSessionCallback = ikeSessionArgumentCaptors.mChildSessionCallbackCaptor.getValue(); childSessionCallback.onIpSecTransformCreated( mMockedIpSecTransformIn, IpSecManager.DIRECTION_IN); mTestLooper.dispatchAll(); verify(mMockIkeSession, times(1)).close(); } @Test public void testIkeSessionConnectionInfoChangedSetsUnderlyingNetwork() throws Exception { String testApnName = "ims"; when(mMockConnectivityManager.getLinkProperties(any())).thenReturn(mMockLinkProperties); IkeSessionArgumentCaptors ikeSessionArgumentCaptors = verifyBringUpTunnelWithDnsQuery(testApnName, mMockIkeSession); ChildSessionCallback childSessionCallback = ikeSessionArgumentCaptors.mChildSessionCallbackCaptor.getValue(); childSessionCallback.onIpSecTransformCreated( mMockedIpSecTransformIn, IpSecManager.DIRECTION_IN); mEpdgTunnelManager .getTmIkeSessionCallback(testApnName, DEFAULT_TOKEN) .onIkeSessionConnectionInfoChanged(mMockIkeSessionConnectionInfo); mTestLooper.dispatchAll(); verify(mMockIpSecTunnelInterface, times(1)).setUnderlyingNetwork(mMockNetwork); } @Test public void testIkeSessionConnectionInfoChangedWithNullLinkPropertiesDoesNothing() throws Exception { String testApnName = "ims"; when(mMockConnectivityManager.getLinkProperties(any())).thenReturn(null); IkeSessionArgumentCaptors ikeSessionArgumentCaptors = verifyBringUpTunnelWithDnsQuery(testApnName, mMockIkeSession); ChildSessionCallback childSessionCallback = ikeSessionArgumentCaptors.mChildSessionCallbackCaptor.getValue(); childSessionCallback.onIpSecTransformCreated( mMockedIpSecTransformIn, IpSecManager.DIRECTION_IN); mEpdgTunnelManager .getTmIkeSessionCallback(testApnName, DEFAULT_TOKEN) .onIkeSessionConnectionInfoChanged(mMockIkeSessionConnectionInfo); mTestLooper.dispatchAll(); verify(mMockIpSecTunnelInterface, times(0)).setUnderlyingNetwork(any()); } @Test public void testSetIkeTrafficSelectorsIPv4() throws Exception { testSetIkeTrafficSelectors(ApnSetting.PROTOCOL_IP, false); } @Test public void testSetIkeTrafficSelectorsIPv6() throws Exception { testSetIkeTrafficSelectors(ApnSetting.PROTOCOL_IPV6, false); } @Test public void testSetIkeTrafficSelectorsIPv4v6() throws Exception { testSetIkeTrafficSelectors(ApnSetting.PROTOCOL_IPV4V6, false); } @Test public void testSetIkeTrafficSelectorsIPv4_handover() throws Exception { testSetIkeTrafficSelectors(ApnSetting.PROTOCOL_IP, true); } @Test public void testSetIkeTrafficSelectorsIPv6_handover() throws Exception { testSetIkeTrafficSelectors(ApnSetting.PROTOCOL_IPV6, true); } @Test public void testSetIkeTrafficSelectorsIPv4v6_handover() throws Exception { testSetIkeTrafficSelectors(ApnSetting.PROTOCOL_IPV4V6, true); } private void testSetIkeTrafficSelectors(int apnProtocol, boolean handover) throws Exception { String testApnName = "www.xyz.com"; PersistableBundle bundle = new PersistableBundle(); setupMockForGetConfig(bundle); when(mMockEpdgSelector.getValidatedServerList( anyInt(), anyInt(), eq(false), eq(false), eq(mMockNetwork), any(EpdgSelector.EpdgSelectorCallback.class))) .thenReturn(new IwlanError(IwlanError.NO_ERROR)); doReturn(null) .when(mMockIkeSessionCreator) .createIkeSession( eq(mMockContext), any(IkeSessionParams.class), any(ChildSessionParams.class), any(Executor.class), any(IkeSessionCallback.class), any(ChildSessionCallback.class)); doReturn(true).when(mEpdgTunnelManager).canBringUpTunnel(eq(testApnName)); boolean ret; if (handover) { ret = mEpdgTunnelManager.bringUpTunnel( getHandoverTunnelSetupRequest(TEST_APN_NAME, apnProtocol), mMockIwlanTunnelCallback, mMockIwlanTunnelCallbackMetrics); } else { ret = mEpdgTunnelManager.bringUpTunnel( getBasicTunnelSetupRequest(TEST_APN_NAME, apnProtocol), mMockIwlanTunnelCallback, mMockIwlanTunnelCallbackMetrics); } assertTrue(ret); mTestLooper.dispatchAll(); mEpdgTunnelManager.sendSelectionRequestComplete( EXPECTED_EPDG_ADDRESSES, new IwlanError(IwlanError.NO_ERROR), 1); mTestLooper.dispatchAll(); ArgumentCaptor ikeSessionParamsCaptor = ArgumentCaptor.forClass(IkeSessionParams.class); ArgumentCaptor childSessionParamsCaptor = ArgumentCaptor.forClass(ChildSessionParams.class); verify(mMockIkeSessionCreator) .createIkeSession( eq(mMockContext), ikeSessionParamsCaptor.capture(), childSessionParamsCaptor.capture(), any(Executor.class), any(IkeSessionCallback.class), any(ChildSessionCallback.class)); ChildSessionParams childSessionParams = childSessionParamsCaptor.getValue(); switch (apnProtocol) { case ApnSetting.PROTOCOL_IPV4V6: assertEquals(childSessionParams.getInboundTrafficSelectors().size(), 2); assertEquals(childSessionParams.getOutboundTrafficSelectors().size(), 2); assertTrue( childSessionParams.getInboundTrafficSelectors().get(0).endingAddress != childSessionParams .getInboundTrafficSelectors() .get(1) .endingAddress); assertTrue( childSessionParams.getInboundTrafficSelectors().get(0).startingAddress != childSessionParams .getInboundTrafficSelectors() .get(1) .startingAddress); break; case ApnSetting.PROTOCOL_IPV6: assertEquals(childSessionParams.getInboundTrafficSelectors().size(), 1); assertEquals(childSessionParams.getOutboundTrafficSelectors().size(), 1); assertEquals( childSessionParams.getOutboundTrafficSelectors().get(0), childSessionParams.getInboundTrafficSelectors().get(0)); assertEquals( childSessionParams.getInboundTrafficSelectors().get(0).endingAddress, InetAddresses.parseNumericAddress( "ffff:ffff:ffff:ffff:ffff:ffff:ffff:ffff")); assertEquals( childSessionParams.getInboundTrafficSelectors().get(0).startingAddress, InetAddresses.parseNumericAddress("::")); break; case ApnSetting.PROTOCOL_IP: assertEquals(childSessionParams.getInboundTrafficSelectors().size(), 1); assertEquals(childSessionParams.getOutboundTrafficSelectors().size(), 1); assertEquals( childSessionParams.getOutboundTrafficSelectors().get(0), childSessionParams.getInboundTrafficSelectors().get(0)); assertEquals( childSessionParams.getInboundTrafficSelectors().get(0).endingAddress, InetAddresses.parseNumericAddress("255.255.255.255")); assertEquals( childSessionParams.getInboundTrafficSelectors().get(0).startingAddress, InetAddresses.parseNumericAddress("0.0.0.0")); break; } } @Test public void testN1modeCapabilityInclusion() throws Exception { { testN1modeCapability(8); } } @Test public void testN1modeCapabilityNonInclusion() throws Exception { { testN1modeCapability(0); } } @Test public void testReportIwlanErrorIkeProtocolException() throws Exception { String testApnName = "www.xyz.com"; IkeProtocolException mockException = mock(IkeProtocolException.class); doReturn(IkeProtocolException.ERROR_TYPE_INVALID_IKE_SPI) .when(mockException) .getErrorType(); doReturn(new byte[0]).when(mockException).getErrorData(); IwlanError error = new IwlanError(mockException); doReturn(0L).when(mEpdgTunnelManager).reportIwlanError(eq(testApnName), eq(error)); mEpdgTunnelManager.putApnNameToTunnelConfig( testApnName, mMockIkeSession, mMockIwlanTunnelCallback, mMockIwlanTunnelCallbackMetrics, null, 0); int token = mEpdgTunnelManager.incrementAndGetCurrentTokenForApn(testApnName); mEpdgTunnelManager.setIsEpdgAddressSelected(true); mEpdgTunnelManager.setEpdgAddress(InetAddresses.parseNumericAddress(EPDG_ADDRESS)); mEpdgTunnelManager .getTmIkeSessionCallback(testApnName, token) .onClosedExceptionally(mockException); mTestLooper.dispatchAll(); verify(mMockIwlanTunnelCallback, times(1)).onClosed(eq(testApnName), eq(error)); verify(mEpdgTunnelManager, times(2)).resetTunnelManagerState(); verify(mEpdgTunnelManager, times(1)).reportIwlanError(eq(testApnName), eq(error)); } @Test public void testReportIwlanErrorServerSelectionFailed() throws Exception { String testApnName = "www.xyz.com"; IwlanError error = new IwlanError(IwlanError.EPDG_SELECTOR_SERVER_SELECTION_FAILED); doReturn(0L).when(mEpdgTunnelManager).reportIwlanError(eq(testApnName), eq(error)); doReturn(true).when(mEpdgTunnelManager).canBringUpTunnel(eq(testApnName)); PersistableBundle bundle = new PersistableBundle(); setupMockForGetConfig(bundle); boolean ret = mEpdgTunnelManager.bringUpTunnel( getBasicTunnelSetupRequest(TEST_APN_NAME, ApnSetting.PROTOCOL_IP), mMockIwlanTunnelCallback, mMockIwlanTunnelCallbackMetrics); assertTrue(ret); mTestLooper.dispatchAll(); mEpdgTunnelManager.sendSelectionRequestComplete(null, error, 1); mTestLooper.dispatchAll(); mEpdgTunnelManager.setIsEpdgAddressSelected(false); verify(mEpdgTunnelManager, times(1)).reportIwlanError(eq(testApnName), eq(error)); } @Test public void testNeverReportIwlanErrorWhenCloseAnOpenedTunnel() throws Exception { IkeInternalException ikeException = new IkeInternalException(new IOException("Retransmitting failure")); IkeSessionArgumentCaptors ikeSessionArgumentCaptors = verifyBringUpTunnelWithDnsQuery(TEST_APN_NAME); ChildSessionCallback childSessionCallback = ikeSessionArgumentCaptors.mChildSessionCallbackCaptor.getValue(); verifyTunnelOnOpened(TEST_APN_NAME, childSessionCallback); reset(mEpdgTunnelManager); // reset number of times of reportIwlanError() mEpdgTunnelManager .getTmIkeSessionCallback(TEST_APN_NAME, 0) .onClosedExceptionally(ikeException); mTestLooper.dispatchAll(); verify(mEpdgTunnelManager, never()).reportIwlanError(eq(TEST_APN_NAME), any()); verify(mMockIwlanTunnelCallback, times(1)) .onClosed(eq(TEST_APN_NAME), eq(new IwlanError(ikeException))); } @Test public void testCanBringUpTunnel() throws Exception { String testApnName = "www.xyz.com"; IwlanError error = new IwlanError(mMockIkeException); doReturn(false).when(mEpdgTunnelManager).canBringUpTunnel(eq(testApnName)); doReturn(error).when(mEpdgTunnelManager).getLastError(eq(testApnName)); PersistableBundle bundle = new PersistableBundle(); setupMockForGetConfig(bundle); boolean ret = mEpdgTunnelManager.bringUpTunnel( getBasicTunnelSetupRequest(TEST_APN_NAME, ApnSetting.PROTOCOL_IP), mMockIwlanTunnelCallback, mMockIwlanTunnelCallbackMetrics); assertTrue(ret); mTestLooper.dispatchAll(); verify(mMockIwlanTunnelCallback, times(1)).onClosed(eq(testApnName), eq(error)); } private void testN1modeCapability(int pduSessionId) throws Exception { String testApnName = "www.xyz.com"; int PDU_SESSION_ID = pduSessionId; byte PDU_SESSION_ID_BYTE = (byte) PDU_SESSION_ID; PersistableBundle bundle = new PersistableBundle(); setupMockForGetConfig(bundle); when(mMockEpdgSelector.getValidatedServerList( anyInt(), anyInt(), eq(false), eq(false), eq(mMockNetwork), any(EpdgSelector.EpdgSelectorCallback.class))) .thenReturn(new IwlanError(IwlanError.NO_ERROR)); doReturn(null) .when(mMockIkeSessionCreator) .createIkeSession( eq(mMockContext), any(IkeSessionParams.class), any(ChildSessionParams.class), any(Executor.class), any(IkeSessionCallback.class), any(ChildSessionCallback.class)); doReturn(true).when(mEpdgTunnelManager).canBringUpTunnel(eq(testApnName)); boolean ret; ret = mEpdgTunnelManager.bringUpTunnel( getBasicTunnelSetupRequest( TEST_APN_NAME, ApnSetting.PROTOCOL_IPV6, PDU_SESSION_ID), mMockIwlanTunnelCallback, mMockIwlanTunnelCallbackMetrics); assertTrue(ret); mTestLooper.dispatchAll(); mEpdgTunnelManager.sendSelectionRequestComplete( EXPECTED_EPDG_ADDRESSES, new IwlanError(IwlanError.NO_ERROR), 1); mTestLooper.dispatchAll(); ArgumentCaptor ikeSessionParamsCaptor = ArgumentCaptor.forClass(IkeSessionParams.class); ArgumentCaptor childSessionParamsCaptor = ArgumentCaptor.forClass(ChildSessionParams.class); verify(mMockIkeSessionCreator) .createIkeSession( eq(mMockContext), ikeSessionParamsCaptor.capture(), childSessionParamsCaptor.capture(), any(Executor.class), any(IkeSessionCallback.class), any(ChildSessionCallback.class)); IkeSessionParams ikeSessionParams = ikeSessionParamsCaptor.getValue(); if (pduSessionId == 0) { assertNull(ikeSessionParams.getIke3gppExtension()); } else { byte pduSessionIdByte = ikeSessionParams.getIke3gppExtension().getIke3gppParams().getPduSessionId(); assertEquals(pduSessionIdByte, PDU_SESSION_ID_BYTE); } } @Test public void testInvalidNattTimerFromCarrierConfig() throws Exception { String testApnName = "www.xyz.com"; int nattTimer = 4500; // valid range for natt timer is 0-3600 int ikeDefaultNattTimerValue = 20; // default value for natt timer is 20 secs PersistableBundle bundle = new PersistableBundle(); bundle.putInt(CarrierConfigManager.Iwlan.KEY_NATT_KEEP_ALIVE_TIMER_SEC_INT, nattTimer); setupMockForGetConfig(bundle); when(mMockEpdgSelector.getValidatedServerList( anyInt(), anyInt(), eq(false), eq(false), eq(mMockNetwork), any(EpdgSelector.EpdgSelectorCallback.class))) .thenReturn(new IwlanError(IwlanError.NO_ERROR)); doReturn(null) .when(mMockIkeSessionCreator) .createIkeSession( eq(mMockContext), any(IkeSessionParams.class), any(ChildSessionParams.class), any(Executor.class), any(IkeSessionCallback.class), any(ChildSessionCallback.class)); doReturn(true).when(mEpdgTunnelManager).canBringUpTunnel(eq(testApnName)); boolean ret = mEpdgTunnelManager.bringUpTunnel( getBasicTunnelSetupRequest(TEST_APN_NAME, ApnSetting.PROTOCOL_IP), mMockIwlanTunnelCallback, mMockIwlanTunnelCallbackMetrics); assertTrue(ret); mTestLooper.dispatchAll(); mEpdgTunnelManager.sendSelectionRequestComplete( EXPECTED_EPDG_ADDRESSES, new IwlanError(IwlanError.NO_ERROR), 1); mTestLooper.dispatchAll(); ArgumentCaptor ikeSessionParamsCaptor = ArgumentCaptor.forClass(IkeSessionParams.class); verify(mMockIkeSessionCreator) .createIkeSession( eq(mMockContext), ikeSessionParamsCaptor.capture(), any(ChildSessionParams.class), any(Executor.class), any(IkeSessionCallback.class), any(ChildSessionCallback.class)); IkeSessionParams ikeSessionParams = ikeSessionParamsCaptor.getValue(); assertEquals(ikeSessionParams.getNattKeepAliveDelaySeconds(), ikeDefaultNattTimerValue); } @Test public void testTunnelSetupRequestParams() throws Exception { String testApnName = "www.xyz.com"; Inet6Address testAddressV6 = Inet6Address.getByAddress("25.25.25.25", new byte[16], 0); Inet4Address testAddressV4 = (Inet4Address) Inet4Address.getByName("30.30.30.30"); int pduSessionId = 5; boolean isRoaming = false; boolean isEmergency = true; boolean requestPcscf = true; int ipv6AddressLen = 64; TunnelSetupRequest tsr = TunnelSetupRequest.builder() .setApnName(testApnName) .setNetwork(mMockNetwork) .setApnIpProtocol(ApnSetting.PROTOCOL_IPV4V6) .setSrcIpv6Address(testAddressV6) .setSrcIpv6AddressPrefixLength(ipv6AddressLen) .setSrcIpv4Address(testAddressV4) .setPduSessionId(pduSessionId) .setIsRoaming(isRoaming) .setIsEmergency(isEmergency) .setRequestPcscf(requestPcscf) .build(); setupMockForGetConfig(null); when(mMockEpdgSelector.getValidatedServerList( anyInt(), anyInt(), eq(isRoaming), eq(isEmergency), eq(mMockNetwork), any(EpdgSelector.EpdgSelectorCallback.class))) .thenReturn(new IwlanError(IwlanError.NO_ERROR)); doReturn(null) .when(mMockIkeSessionCreator) .createIkeSession( eq(mMockContext), any(IkeSessionParams.class), any(ChildSessionParams.class), any(Executor.class), any(IkeSessionCallback.class), any(ChildSessionCallback.class)); doReturn(true).when(mEpdgTunnelManager).canBringUpTunnel(eq(testApnName)); boolean ret = mEpdgTunnelManager.bringUpTunnel( tsr, mMockIwlanTunnelCallback, mMockIwlanTunnelCallbackMetrics); assertTrue(ret); mTestLooper.dispatchAll(); // verify isRoaming, isEmergency and Network variables. verify(mMockEpdgSelector) .getValidatedServerList( anyInt(), anyInt(), // only Ipv6 address is added eq(isRoaming), eq(isEmergency), eq(mMockNetwork), any(EpdgSelector.EpdgSelectorCallback.class)); mEpdgTunnelManager.sendSelectionRequestComplete( EXPECTED_EPDG_ADDRESSES, new IwlanError(IwlanError.NO_ERROR), 1); mTestLooper.dispatchAll(); ArgumentCaptor ikeSessionParamsCaptor = ArgumentCaptor.forClass(IkeSessionParams.class); ArgumentCaptor childSessionParamsCaptor = ArgumentCaptor.forClass(TunnelModeChildSessionParams.class); verify(mMockIkeSessionCreator) .createIkeSession( eq(mMockContext), ikeSessionParamsCaptor.capture(), childSessionParamsCaptor.capture(), any(Executor.class), any(IkeSessionCallback.class), any(ChildSessionCallback.class)); IkeSessionParams ikeSessionParams = ikeSessionParamsCaptor.getValue(); TunnelModeChildSessionParams childSessionParams = childSessionParamsCaptor.getValue(); // apnName verification. By default remote identification is type fqdn IkeFqdnIdentification ikeId = (IkeFqdnIdentification) ikeSessionParams.getRemoteIdentification(); assertEquals(ikeId.fqdn, testApnName); // verify Network assertEquals(ikeSessionParams.getNetwork(), mMockNetwork); // verify requestPcscf (true) with Apn protocol IPV6 // it should add the pcscf config requests of type ConfigRequestIpv6PcscfServer and // ConfigRequestIpv4PcscfServer assertTrue( ikeSessionParams.getConfigurationRequests().stream() .anyMatch(c -> c instanceof IkeSessionParams.ConfigRequestIpv6PcscfServer)); assertTrue( ikeSessionParams.getConfigurationRequests().stream() .anyMatch(c -> c instanceof IkeSessionParams.ConfigRequestIpv4PcscfServer)); // verify pduSessionID assertEquals( ikeSessionParams.getIke3gppExtension().getIke3gppParams().getPduSessionId(), pduSessionId); // verify src ipv6 and src ipv4 address List configRequests = childSessionParams.getConfigurationRequests(); boolean ipv6ConfigRequestPresent = false; boolean ipv4ConfigRequestPresent = true; for (TunnelModeChildSessionParams.TunnelModeChildConfigRequest configRequest : configRequests) { if (configRequest instanceof TunnelModeChildSessionParams.ConfigRequestIpv6Address) { ipv6ConfigRequestPresent = true; assertEquals( ((TunnelModeChildSessionParams.ConfigRequestIpv6Address) configRequest) .getAddress(), testAddressV6); assertEquals( ((TunnelModeChildSessionParams.ConfigRequestIpv6Address) configRequest) .getPrefixLength(), ipv6AddressLen); } if (configRequest instanceof TunnelModeChildSessionParams.ConfigRequestIpv4Address) { ipv4ConfigRequestPresent = true; assertEquals( ((TunnelModeChildSessionParams.ConfigRequestIpv4Address) configRequest) .getAddress(), testAddressV4); } } assertTrue(ipv6ConfigRequestPresent); assertTrue(ipv4ConfigRequestPresent); } @Test public void testBringupTunnelFailWithInvalidSimState() throws Exception { String testApnName = "www.xyz.com"; IwlanError error = new IwlanError(IwlanError.SIM_NOT_READY_EXCEPTION); doReturn(0L).when(mEpdgTunnelManager).reportIwlanError(eq(testApnName), eq(error)); doReturn(true).when(mEpdgTunnelManager).canBringUpTunnel(eq(testApnName)); PersistableBundle bundle = new PersistableBundle(); setupMockForGetConfig(bundle); when(mMockSubscriptionManager.getActiveSubscriptionInfoForSimSlotIndex(DEFAULT_SLOT_INDEX)) .thenReturn(null); boolean ret = mEpdgTunnelManager.bringUpTunnel( getBasicTunnelSetupRequest(TEST_APN_NAME, ApnSetting.PROTOCOL_IP), mMockIwlanTunnelCallback, mMockIwlanTunnelCallbackMetrics); assertTrue(ret); mTestLooper.dispatchAll(); mEpdgTunnelManager.sendSelectionRequestComplete( EXPECTED_EPDG_ADDRESSES, new IwlanError(IwlanError.NO_ERROR), 1); mTestLooper.dispatchAll(); verify(mMockIwlanTunnelCallback, times(1)).onClosed(eq(testApnName), eq(error)); } @Test public void testBringupTunnelFailWithInvalidNai() throws Exception { String testApnName = "www.xyz.com"; IwlanError error = new IwlanError(IwlanError.SIM_NOT_READY_EXCEPTION); doReturn(0L).when(mEpdgTunnelManager).reportIwlanError(eq(testApnName), eq(error)); doReturn(true).when(mEpdgTunnelManager).canBringUpTunnel(eq(testApnName)); PersistableBundle bundle = new PersistableBundle(); setupMockForGetConfig(bundle); when(mMockSubscriptionManager.getActiveSubscriptionInfoForSimSlotIndex(DEFAULT_SLOT_INDEX)) .thenReturn(mMockSubscriptionInfo) .thenReturn(null); boolean ret = mEpdgTunnelManager.bringUpTunnel( getBasicTunnelSetupRequest(TEST_APN_NAME, ApnSetting.PROTOCOL_IP), mMockIwlanTunnelCallback, mMockIwlanTunnelCallbackMetrics); assertTrue(ret); mTestLooper.dispatchAll(); mEpdgTunnelManager.sendSelectionRequestComplete( EXPECTED_EPDG_ADDRESSES, new IwlanError(IwlanError.NO_ERROR), 1); mTestLooper.dispatchAll(); verify(mMockIwlanTunnelCallback, times(1)).onClosed(eq(testApnName), eq(error)); } @Test public void testCloseTunnelWithEpdgSelectionIncomplete() throws Exception { // Bring up tunnel doReturn(true).when(mEpdgTunnelManager).canBringUpTunnel(eq(TEST_APN_NAME)); boolean ret = mEpdgTunnelManager.bringUpTunnel( getBasicTunnelSetupRequest(TEST_APN_NAME, ApnSetting.PROTOCOL_IP), mMockIwlanTunnelCallback, mMockIwlanTunnelCallbackMetrics); assertTrue(ret); // close tunnel when ePDG selection is incomplete ret = mEpdgTunnelManager.closeTunnel(TEST_APN_NAME, false /*forceClose*/); assertTrue(ret); mTestLooper.dispatchAll(); verify(mMockIwlanTunnelCallbackMetrics, times(1)) .onClosed(eq(TEST_APN_NAME), eq(null), eq(0), eq(0)); } @Test public void testIgnoreSignalFromObsoleteCallback() throws Exception { int transactionId = 0; // testApnName with token 0 setupTunnelBringup(TEST_APN_NAME, ++transactionId); mEpdgTunnelManager.setIsEpdgAddressSelected(true); IwlanError error = new IwlanError(mMockIkeException); doReturn(0L).when(mEpdgTunnelManager).reportIwlanError(eq(TEST_APN_NAME), eq(error)); mEpdgTunnelManager .getTmIkeSessionCallback(TEST_APN_NAME, 0 /* token */) .onClosedExceptionally(mMockIkeException); mTestLooper.dispatchAll(); verify(mMockIwlanTunnelCallback, times(1)).onClosed(eq(TEST_APN_NAME), eq(error)); assertNull(mEpdgTunnelManager.getTunnelConfigForApn(TEST_APN_NAME)); // testApnName1 with token 1 setupTunnelBringup(TEST_APN_NAME, ++transactionId); mEpdgTunnelManager.setIsEpdgAddressSelected(true); // signal from obsolete callback (token 0), ignore it reset(mMockIwlanTunnelCallback); mEpdgTunnelManager .getTmIkeSessionCallback(TEST_APN_NAME, 0 /* token */) .onClosedExceptionally(mMockIkeException); mTestLooper.dispatchAll(); verify(mMockIwlanTunnelCallback, never()).onClosed(eq(TEST_APN_NAME), eq(error)); assertNotNull(mEpdgTunnelManager.getTunnelConfigForApn(TEST_APN_NAME)); // signals from active callback mEpdgTunnelManager .getTmIkeSessionCallback(TEST_APN_NAME, 1 /* token */) .onClosedExceptionally(mMockIkeException); mTestLooper.dispatchAll(); verify(mMockIwlanTunnelCallback, times(1)).onClosed(eq(TEST_APN_NAME), eq(error)); assertNull(mEpdgTunnelManager.getTunnelConfigForApn(TEST_APN_NAME)); } private boolean testIsN1ModeSupported(int[] nrAvailability) { PersistableBundle bundle = new PersistableBundle(); bundle.putIntArray( CarrierConfigManager.KEY_CARRIER_NR_AVAILABILITIES_INT_ARRAY, nrAvailability); setupMockForGetConfig(bundle); return mEpdgTunnelManager.isN1ModeSupported(); } @Test public void testIsN1ModeSupportedTrue() throws Exception { assertTrue( testIsN1ModeSupported( new int[] { CarrierConfigManager.CARRIER_NR_AVAILABILITY_NSA, CarrierConfigManager.CARRIER_NR_AVAILABILITY_SA })); } @Test public void testIsN1ModeSupportedFalse() throws Exception { assertFalse( testIsN1ModeSupported( new int[] {CarrierConfigManager.CARRIER_NR_AVAILABILITY_NSA})); } }