From e3c862242cc8a00b1862a35260c1c9c6f6ac38c7 Mon Sep 17 00:00:00 2001 From: Po-Chun Lee Date: Wed, 18 May 2022 23:59:32 +0000 Subject: Add test cases of tunnel opened for EpdgTunnelManager 1. testHandleOnOpenedWithEpdgAddressSelected_True 2. testServicePendingRequests Bug: 233123329 Test: atest IwlanTests(new) Change-Id: If9108e763411f97bbbbeb80ef14d8cf9c1910769 --- .../android/iwlan/epdg/EpdgTunnelManagerTest.java | 239 ++++++++++++++++----- 1 file changed, 185 insertions(+), 54 deletions(-) diff --git a/test/com/google/android/iwlan/epdg/EpdgTunnelManagerTest.java b/test/com/google/android/iwlan/epdg/EpdgTunnelManagerTest.java index 5960e00..b301c48 100644 --- a/test/com/google/android/iwlan/epdg/EpdgTunnelManagerTest.java +++ b/test/com/google/android/iwlan/epdg/EpdgTunnelManagerTest.java @@ -29,9 +29,12 @@ import static org.mockito.Mockito.when; import android.content.Context; import android.net.InetAddresses; +import android.net.IpSecManager; +import android.net.IpSecTransform; import android.net.LinkAddress; 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; @@ -81,14 +84,35 @@ public class EpdgTunnelManagerTest { public static final int DEFAULT_SLOT_INDEX = 0; public static final int DEFAULT_SUBID = 0; - private static final String TEST_IP_ADDRESS = "127.0.0.1"; + 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(TEST_IP_ADDRESS) + 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; @@ -111,13 +135,23 @@ public class EpdgTunnelManagerTest { @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 IpSecTransform mMockedIpSecTransformIn; + @Mock IpSecTransform mMockedIpSecTransformOut; + + ArgumentCaptor mChildSessionCallbackCaptor; @Before public void setUp() throws Exception { 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(); @@ -138,12 +172,23 @@ public class EpdgTunnelManagerTest { PersistableBundle bundle = new PersistableBundle(); setupMockForGetConfig(bundle); - // Fake local address - List testLocalAddressList = new ArrayList(); - InetAddress testInetaddr = InetAddress.getByName(TEST_IP_ADDRESS); - testLocalAddressList.add(testInetaddr); + when(mMockIkeSessionConfiguration.getPcscfServers()).thenReturn(EXPECTED_PCSCF_ADDRESSES); - doReturn(testLocalAddressList).when(mEpdgTunnelManager).getAddressForNetwork(any(), any()); + 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"); + + mChildSessionCallbackCaptor = ArgumentCaptor.forClass(ChildSessionCallback.class); + + doReturn(EXPECTED_LOCAL_ADDRESSES) + .when(mEpdgTunnelManager) + .getAddressForNetwork(any(), any()); } @Test @@ -280,10 +325,8 @@ public class EpdgTunnelManagerTest { assertTrue(ret); mTestLooper.dispatchAll(); - ArrayList ipList = new ArrayList<>(); - ipList.add(InetAddress.getByName(TEST_IP_ADDRESS)); mEpdgTunnelManager.sendSelectionRequestComplete( - ipList, new IwlanError(IwlanError.NO_ERROR), 1); + EXPECTED_EPDG_ADDRESSES, new IwlanError(IwlanError.NO_ERROR), 1); mTestLooper.dispatchAll(); } @@ -502,10 +545,8 @@ public class EpdgTunnelManagerTest { assertTrue(ret); mTestLooper.dispatchAll(); - ArrayList ipList = new ArrayList<>(); - ipList.add(InetAddress.getByName(TEST_IP_ADDRESS)); mEpdgTunnelManager.sendSelectionRequestComplete( - ipList, new IwlanError(IwlanError.NO_ERROR), 1); + EXPECTED_EPDG_ADDRESSES, new IwlanError(IwlanError.NO_ERROR), 1); mTestLooper.dispatchAll(); ArgumentCaptor ikeSessionParamsCaptor = @@ -570,10 +611,8 @@ public class EpdgTunnelManagerTest { assertTrue(ret); mTestLooper.dispatchAll(); - ArrayList ipList = new ArrayList<>(); - ipList.add(InetAddress.getByName(TEST_IP_ADDRESS)); mEpdgTunnelManager.sendSelectionRequestComplete( - ipList, new IwlanError(IwlanError.NO_ERROR), 1); + EXPECTED_EPDG_ADDRESSES, new IwlanError(IwlanError.NO_ERROR), 1); mTestLooper.dispatchAll(); ArgumentCaptor ikeSessionParamsCaptor = @@ -629,10 +668,8 @@ public class EpdgTunnelManagerTest { assertTrue(ret); mTestLooper.dispatchAll(); - ArrayList ipList = new ArrayList<>(); - ipList.add(InetAddress.getByName(TEST_IP_ADDRESS)); mEpdgTunnelManager.sendSelectionRequestComplete( - ipList, new IwlanError(IwlanError.NO_ERROR), 1); + EXPECTED_EPDG_ADDRESSES, new IwlanError(IwlanError.NO_ERROR), 1); mTestLooper.dispatchAll(); ArgumentCaptor ikeSessionParamsCaptor = @@ -870,10 +907,8 @@ public class EpdgTunnelManagerTest { assertTrue(ret); mTestLooper.dispatchAll(); - ArrayList ipList = new ArrayList<>(); - ipList.add(InetAddress.getByName("1.1.1.1")); mEpdgTunnelManager.sendSelectionRequestComplete( - ipList, new IwlanError(IwlanError.NO_ERROR), transactionId); + EXPECTED_EPDG_ADDRESSES, new IwlanError(IwlanError.NO_ERROR), transactionId); mTestLooper.dispatchAll(); ArgumentCaptor ikeSessionParamsCaptor = @@ -889,7 +924,9 @@ public class EpdgTunnelManagerTest { ikeSessionCallbackCaptor.capture(), any(ChildSessionCallback.class)); IkeSessionParams ikeSessionParams = ikeSessionParamsCaptor.getValue(); - assertEquals(ikeSessionParams.getServerHostname(), ipList.get(0).getHostAddress()); + assertEquals( + ikeSessionParams.getServerHostname(), + EXPECTED_EPDG_ADDRESSES.get(0).getHostAddress()); Ike3gppExtension.Ike3gppDataListener ike3gppCallback = ikeSessionParams.getIke3gppExtension().getIke3gppDataListener(); @@ -1025,10 +1062,8 @@ public class EpdgTunnelManagerTest { assertTrue(ret); mTestLooper.dispatchAll(); - ArrayList ipList = new ArrayList<>(); - ipList.add(InetAddress.getByName(TEST_IP_ADDRESS)); mEpdgTunnelManager.sendSelectionRequestComplete( - ipList, new IwlanError(IwlanError.NO_ERROR), 1); + EXPECTED_EPDG_ADDRESSES, new IwlanError(IwlanError.NO_ERROR), 1); mTestLooper.dispatchAll(); mEpdgTunnelManager.setIsEpdgAddressSelected(false); @@ -1041,6 +1076,121 @@ public class EpdgTunnelManagerTest { verify(mEpdgTunnelManager, times(1)).reportIwlanError(eq(testApnName), eq(error)); } + private void setOneTunnelOpened(String apnName) throws Exception { + mEpdgTunnelManager.putApnNameToTunnelConfig( + apnName, mMockIkeSession, mMockIwlanTunnelCallback, null, 0); + setVariable(mEpdgTunnelManager, "mLocalAddresses", EXPECTED_LOCAL_ADDRESSES); + mEpdgTunnelManager.validateAndSetEpdgAddress(EXPECTED_EPDG_ADDRESSES); + mEpdgTunnelManager.setIsEpdgAddressSelected(true); + } + + private ChildSessionCallback verifyBringUpTunnelWithDnsQuery(String apnName) { + reset(mMockIwlanTunnelCallback); + + doReturn(null) + .when(mMockIkeSessionCreator) + .createIkeSession( + eq(mMockContext), + any(IkeSessionParams.class), + any(ChildSessionParams.class), + any(Executor.class), + any(IkeSessionCallback.class), + mChildSessionCallbackCaptor.capture()); + + verifyBringUpTunnel(apnName, true /* needPendingBringUpReq */); + + mEpdgTunnelManager.sendSelectionRequestComplete( + EXPECTED_EPDG_ADDRESSES, new IwlanError(IwlanError.NO_ERROR), 1); + mTestLooper.dispatchAll(); + + verify(mMockIkeSessionCreator, times(1)) + .createIkeSession( + eq(mMockContext), + any(IkeSessionParams.class), + any(ChildSessionParams.class), + any(Executor.class), + any(IkeSessionCallback.class), + mChildSessionCallbackCaptor.capture()); + + return mChildSessionCallbackCaptor.getValue(); + } + + private ChildSessionCallback verifyBringUpTunnel( + String apnName, boolean needPendingBringUpReq) { + reset(mMockIkeSessionCreator); + + doReturn(null) + .when(mMockIkeSessionCreator) + .createIkeSession( + eq(mMockContext), + any(IkeSessionParams.class), + any(ChildSessionParams.class), + any(Executor.class), + any(IkeSessionCallback.class), + mChildSessionCallbackCaptor.capture()); + + doReturn(true).when(mEpdgTunnelManager).canBringUpTunnel(eq(apnName)); + + boolean ret = + mEpdgTunnelManager.bringUpTunnel( + getBasicTunnelSetupRequest(apnName, ApnSetting.PROTOCOL_IP), + mMockIwlanTunnelCallback); + assertTrue(ret); + mTestLooper.dispatchAll(); + + verify(mMockIkeSessionCreator, times(needPendingBringUpReq ? 0 : 1)) + .createIkeSession( + eq(mMockContext), + any(IkeSessionParams.class), + any(ChildSessionParams.class), + any(Executor.class), + any(IkeSessionCallback.class), + mChildSessionCallbackCaptor.capture()); + + return needPendingBringUpReq ? null : mChildSessionCallbackCaptor.getValue(); + } + + private void verifyTunnelOnOpened(String apnName) { + verifyTunnelOnOpened(apnName, mChildSessionCallbackCaptor.getValue()); + } + + private void verifyTunnelOnOpened(String apnName, ChildSessionCallback childSessionCallback) { + mEpdgTunnelManager.getTmIkeSessionCallback(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(mMockIwlanTunnelCallback, times(1)).onOpened(eq(apnName), any()); + } + + @Test + public void testHandleOnOpenedWithEpdgAddressSelected_True() throws Exception { + final String openedApnName = "ims"; + final String toBeOpenedApnName = "mms"; + + setOneTunnelOpened(openedApnName); + + verifyBringUpTunnel(toBeOpenedApnName, false /* needPendingBringUpReq */); + verifyTunnelOnOpened(toBeOpenedApnName); + } + + @Test + public void testServicePendingRequests() throws Exception { + final String firstApnName = "ims"; + final String secondApnName = "mms"; + + ChildSessionCallback firstCallback = verifyBringUpTunnelWithDnsQuery(firstApnName); + verifyBringUpTunnel(secondApnName, true /* needPendingBringUpReq */); + verifyTunnelOnOpened(firstApnName, firstCallback); + verifyTunnelOnOpened(secondApnName, mChildSessionCallbackCaptor.getValue()); + } + @Test public void testHandleOnClosedExceptionallyWithEpdgAddressSelected_True() throws Exception { String testApnName = "www.xyz.com"; @@ -1081,10 +1231,8 @@ public class EpdgTunnelManagerTest { assertTrue(ret); mTestLooper.dispatchAll(); - ArrayList ipList = new ArrayList<>(); - ipList.add(InetAddress.getByName(TEST_IP_ADDRESS)); mEpdgTunnelManager.sendSelectionRequestComplete( - ipList, new IwlanError(IwlanError.NO_ERROR), 1); + EXPECTED_EPDG_ADDRESSES, new IwlanError(IwlanError.NO_ERROR), 1); mTestLooper.dispatchAll(); mEpdgTunnelManager.setIsEpdgAddressSelected(false); @@ -1108,12 +1256,7 @@ public class EpdgTunnelManagerTest { mEpdgTunnelManager.putApnNameToTunnelConfig( testApnName, mMockIkeSession, mMockIwlanTunnelCallback, null, 0); - List ipList = new ArrayList<>(); - ipList.add(InetAddress.getByName(TEST_IP_ADDRESS)); - when(mMockIkeSessionConfiguration.getPcscfServers()).thenReturn(ipList); - - PersistableBundle bundle = new PersistableBundle(); - setupMockForGetConfig(bundle); + when(mMockIkeSessionConfiguration.getPcscfServers()).thenReturn(EXPECTED_EPDG_ADDRESSES); mEpdgTunnelManager .getTmIkeSessionCallback(testApnName) @@ -1122,7 +1265,7 @@ public class EpdgTunnelManagerTest { EpdgTunnelManager.TunnelConfig testApnTunnelConfig = mEpdgTunnelManager.getTunnelConfigForApn(testApnName); - assertEquals(testApnTunnelConfig.getPcscfAddrList(), ipList); + assertEquals(testApnTunnelConfig.getPcscfAddrList(), EXPECTED_EPDG_ADDRESSES); } @Test @@ -1198,10 +1341,8 @@ public class EpdgTunnelManagerTest { assertTrue(ret); mTestLooper.dispatchAll(); - ArrayList ipList = new ArrayList<>(); - ipList.add(InetAddress.getByName(TEST_IP_ADDRESS)); mEpdgTunnelManager.sendSelectionRequestComplete( - ipList, new IwlanError(IwlanError.NO_ERROR), 1); + EXPECTED_EPDG_ADDRESSES, new IwlanError(IwlanError.NO_ERROR), 1); mTestLooper.dispatchAll(); ArgumentCaptor ikeSessionParamsCaptor = @@ -1393,10 +1534,8 @@ public class EpdgTunnelManagerTest { assertTrue(ret); mTestLooper.dispatchAll(); - ArrayList ipList = new ArrayList<>(); - ipList.add(InetAddress.getByName(TEST_IP_ADDRESS)); mEpdgTunnelManager.sendSelectionRequestComplete( - ipList, new IwlanError(IwlanError.NO_ERROR), 1); + EXPECTED_EPDG_ADDRESSES, new IwlanError(IwlanError.NO_ERROR), 1); mTestLooper.dispatchAll(); ArgumentCaptor ikeSessionParamsCaptor = @@ -1461,10 +1600,8 @@ public class EpdgTunnelManagerTest { assertTrue(ret); mTestLooper.dispatchAll(); - ArrayList ipList = new ArrayList<>(); - ipList.add(InetAddress.getByName(TEST_IP_ADDRESS)); mEpdgTunnelManager.sendSelectionRequestComplete( - ipList, new IwlanError(IwlanError.NO_ERROR), 1); + EXPECTED_EPDG_ADDRESSES, new IwlanError(IwlanError.NO_ERROR), 1); mTestLooper.dispatchAll(); ArgumentCaptor ikeSessionParamsCaptor = @@ -1543,10 +1680,8 @@ public class EpdgTunnelManagerTest { eq(mMockNetwork), any(EpdgSelector.EpdgSelectorCallback.class)); - ArrayList ipList = new ArrayList<>(); - ipList.add(InetAddress.getByName(TEST_IP_ADDRESS)); mEpdgTunnelManager.sendSelectionRequestComplete( - ipList, new IwlanError(IwlanError.NO_ERROR), 1); + EXPECTED_EPDG_ADDRESSES, new IwlanError(IwlanError.NO_ERROR), 1); mTestLooper.dispatchAll(); ArgumentCaptor ikeSessionParamsCaptor = @@ -1640,10 +1775,8 @@ public class EpdgTunnelManagerTest { assertTrue(ret); mTestLooper.dispatchAll(); - ArrayList ipList = new ArrayList<>(); - ipList.add(InetAddress.getByName(TEST_IP_ADDRESS)); mEpdgTunnelManager.sendSelectionRequestComplete( - ipList, new IwlanError(IwlanError.NO_ERROR), 1); + EXPECTED_EPDG_ADDRESSES, new IwlanError(IwlanError.NO_ERROR), 1); mTestLooper.dispatchAll(); verify(mMockIwlanTunnelCallback, times(1)).onClosed(eq(testApnName), eq(error)); @@ -1671,10 +1804,8 @@ public class EpdgTunnelManagerTest { assertTrue(ret); mTestLooper.dispatchAll(); - ArrayList ipList = new ArrayList<>(); - ipList.add(InetAddress.getByName(TEST_IP_ADDRESS)); mEpdgTunnelManager.sendSelectionRequestComplete( - ipList, new IwlanError(IwlanError.NO_ERROR), 1); + EXPECTED_EPDG_ADDRESSES, new IwlanError(IwlanError.NO_ERROR), 1); mTestLooper.dispatchAll(); verify(mMockIwlanTunnelCallback, times(1)).onClosed(eq(testApnName), eq(error)); -- cgit v1.2.3 From 4293ec507f851608c80dc8e9e579f2f785a20e75 Mon Sep 17 00:00:00 2001 From: Aswin Sankar Date: Sat, 21 May 2022 00:57:07 +0000 Subject: EpdgTunnelManager: Handle IAE on applying transforms - When IKE session is closed (in a concurrent thread) immediately after Child session transforms are created, IpSecService may throw an IllegalArgumentException when TunnelManager attempts to apply the transforms. - This race condition cannot be protected by synchronization, so we handle the exception and defensively attempt to (re)close the IKE session. Bug:232242677 Test: New UT EpdgTunnelManagerTest# testIkeSessionClosesWhenChildSessionTransformThrows() Change-Id: I7f3de84e5ab377a1ac919097e41290fd0ac502a0 Merged-In: I7f3de84e5ab377a1ac919097e41290fd0ac502a0 --- .../android/iwlan/epdg/EpdgTunnelManager.java | 13 +++++++---- .../android/iwlan/epdg/EpdgTunnelManagerTest.java | 27 ++++++++++++++++++---- 2 files changed, 30 insertions(+), 10 deletions(-) diff --git a/src/com/google/android/iwlan/epdg/EpdgTunnelManager.java b/src/com/google/android/iwlan/epdg/EpdgTunnelManager.java index 1c824b7..7df872f 100644 --- a/src/com/google/android/iwlan/epdg/EpdgTunnelManager.java +++ b/src/com/google/android/iwlan/epdg/EpdgTunnelManager.java @@ -531,11 +531,12 @@ public class EpdgTunnelManager { } } - private class TmChildSessionCallBack implements ChildSessionCallback { + @VisibleForTesting + class TmChildSessionCallback implements ChildSessionCallback { private final String mApnName; - TmChildSessionCallBack(String apnName) { + TmChildSessionCallback(String apnName) { this.mApnName = apnName; } @@ -750,7 +751,7 @@ public class EpdgTunnelManager { buildChildSessionParams(setupRequest), Executors.newSingleThreadExecutor(), getTmIkeSessionCallback(apnName), - new TmChildSessionCallBack(apnName)); + new TmChildSessionCallback(apnName)); boolean isSrcIpv6Present = setupRequest.srcIpv6Address().isPresent(); putApnNameToTunnelConfig( @@ -1521,8 +1522,10 @@ public class EpdgTunnelManager { tunnelConfig.getIface(), transformData.getDirection(), transformData.getTransform()); - } catch (IOException e) { - Log.e(TAG, "Failed to apply tunnel transform."); + } catch (IOException | IllegalArgumentException e) { + // If the IKE session was closed before the transform could be applied, the + // IpSecService will throw an IAE on processing the IpSecTunnelInterface id. + Log.e(TAG, "Failed to apply tunnel transform." + e); closeIkeSession( apnName, new IwlanError(IwlanError.TUNNEL_TRANSFORM_FAILED)); } diff --git a/test/com/google/android/iwlan/epdg/EpdgTunnelManagerTest.java b/test/com/google/android/iwlan/epdg/EpdgTunnelManagerTest.java index b301c48..2386ccd 100644 --- a/test/com/google/android/iwlan/epdg/EpdgTunnelManagerTest.java +++ b/test/com/google/android/iwlan/epdg/EpdgTunnelManagerTest.java @@ -1084,10 +1084,13 @@ public class EpdgTunnelManagerTest { mEpdgTunnelManager.setIsEpdgAddressSelected(true); } - private ChildSessionCallback verifyBringUpTunnelWithDnsQuery(String apnName) { + private ChildSessionCallback verifyBringUpTunnelWithDnsQuery( + String apnName, IkeSession ikeSession) { reset(mMockIwlanTunnelCallback); - doReturn(null) + verifyBringUpTunnel(apnName, true /* needPendingBringUpReq */); + + doReturn(ikeSession) .when(mMockIkeSessionCreator) .createIkeSession( eq(mMockContext), @@ -1097,8 +1100,6 @@ public class EpdgTunnelManagerTest { any(IkeSessionCallback.class), mChildSessionCallbackCaptor.capture()); - verifyBringUpTunnel(apnName, true /* needPendingBringUpReq */); - mEpdgTunnelManager.sendSelectionRequestComplete( EXPECTED_EPDG_ADDRESSES, new IwlanError(IwlanError.NO_ERROR), 1); mTestLooper.dispatchAll(); @@ -1185,7 +1186,7 @@ public class EpdgTunnelManagerTest { final String firstApnName = "ims"; final String secondApnName = "mms"; - ChildSessionCallback firstCallback = verifyBringUpTunnelWithDnsQuery(firstApnName); + ChildSessionCallback firstCallback = verifyBringUpTunnelWithDnsQuery(firstApnName, null); verifyBringUpTunnel(secondApnName, true /* needPendingBringUpReq */); verifyTunnelOnOpened(firstApnName, firstCallback); verifyTunnelOnOpened(secondApnName, mChildSessionCallbackCaptor.getValue()); @@ -1268,6 +1269,22 @@ public class EpdgTunnelManagerTest { 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()); + ChildSessionCallback childSessionCallback = + verifyBringUpTunnelWithDnsQuery(testApnName, mMockIkeSession); + childSessionCallback.onIpSecTransformCreated( + mMockedIpSecTransformIn, IpSecManager.DIRECTION_IN); + mTestLooper.dispatchAll(); + + verify(mMockIkeSession, times(1)).close(); + } + @Test public void testSetIkeTrafficSelectorsIPv4() throws Exception { testSetIkeTrafficSelectors(ApnSetting.PROTOCOL_IP, false); -- cgit v1.2.3 From adc4d719111d5703b57e9896ef2f003dd2e46343 Mon Sep 17 00:00:00 2001 From: Aswin Sankar Date: Fri, 20 May 2022 15:04:25 -0700 Subject: Handle unexpected payload on IkeSessionConnectionInfoChanged - When IKE Library's MOBIKE module calls IkeSessionCallback#onIkeSessionConnectionInfoChanged, TunnelManager needs to update IpSecTunnelInterface's underlying network with the payload. - If the payload is invalid (eg. because NW was lost) IKE session would throw an IllegalArgumentException (IAE). - TunnelManager needs to ensure the Network object's LinkProperties is non-null, and handle any thrown IAE. Test: New unit tests: EpdgTunnelManagerTest# testIkeSessionConnectionInfoChangedSetsUnderlyingNetwork() testIkeSessionConnectionInfoChangedWithNullLinkPropertiesDoesNothing() Bug: 232309601 Change-Id: Ia672304edcbfd6f862e753c7e513fbf19fca5338 Merged-In: Ia672304edcbfd6f862e753c7e513fbf19fca5338 --- .../android/iwlan/epdg/EpdgTunnelManager.java | 60 +++++++++++++++++++--- .../android/iwlan/epdg/EpdgTunnelManagerTest.java | 47 +++++++++++++++++ 2 files changed, 99 insertions(+), 8 deletions(-) diff --git a/src/com/google/android/iwlan/epdg/EpdgTunnelManager.java b/src/com/google/android/iwlan/epdg/EpdgTunnelManager.java index 7df872f..ea78893 100644 --- a/src/com/google/android/iwlan/epdg/EpdgTunnelManager.java +++ b/src/com/google/android/iwlan/epdg/EpdgTunnelManager.java @@ -22,6 +22,7 @@ import static android.system.OsConstants.AF_INET; import static android.system.OsConstants.AF_INET6; import android.content.Context; +import android.net.ConnectivityManager; import android.net.InetAddresses; import android.net.IpPrefix; import android.net.IpSecManager; @@ -113,6 +114,7 @@ public class EpdgTunnelManager { private static final int EVENT_IPSEC_TRANSFORM_DELETED = 8; private static final int EVENT_UPDATE_NETWORK = 9; private static final int EVENT_IKE_SESSION_OPENED = 10; + private static final int EVENT_IKE_SESSION_CONNECTION_INFO_CHANGED = 11; private static final int IKE_HARD_LIFETIME_SEC_MINIMUM = 300; private static final int IKE_HARD_LIFETIME_SEC_MAXIMUM = 86400; private static final int IKE_SOFT_LIFETIME_SEC_MINIMUM = 120; @@ -481,14 +483,17 @@ public class EpdgTunnelManager { @Override public void onIkeSessionConnectionInfoChanged( IkeSessionConnectionInfo ikeSessionConnectionInfo) { - Log.d(TAG, "Ike session connection info changed for apn: " + mApnName); - TunnelConfig tunnelConfig = mApnNameToTunnelConfig.get(mApnName); - IpSecManager.IpSecTunnelInterface tunnelInterface = tunnelConfig.getIface(); - try { - tunnelInterface.setUnderlyingNetwork(ikeSessionConnectionInfo.getNetwork()); - } catch (IOException e) { - Log.e(TAG, "IOException while updating underlying network for apn: " + mApnName); - } + Network network = ikeSessionConnectionInfo.getNetwork(); + Log.d( + TAG, + "Ike session connection info changed for apn: " + + mApnName + + " Network: " + + network); + mHandler.sendMessage( + mHandler.obtainMessage( + EVENT_IKE_SESSION_CONNECTION_INFO_CHANGED, + new IkeSessionConnectionInfoData(mApnName, ikeSessionConnectionInfo))); } } @@ -1577,6 +1582,34 @@ public class EpdgTunnelManager { } } break; + + case EVENT_IKE_SESSION_CONNECTION_INFO_CHANGED: + IkeSessionConnectionInfoData ikeSessionConnectionInfoData = + (IkeSessionConnectionInfoData) msg.obj; + network = ikeSessionConnectionInfoData.mIkeSessionConnectionInfo.getNetwork(); + apnName = ikeSessionConnectionInfoData.mApnName; + + ConnectivityManager connectivityManager = + mContext.getSystemService(ConnectivityManager.class); + if (connectivityManager.getLinkProperties(network) == null) { + Log.e(TAG, "Network " + network + " has null LinkProperties!"); + return; + } + + tunnelConfig = mApnNameToTunnelConfig.get(apnName); + tunnelInterface = tunnelConfig.getIface(); + try { + tunnelInterface.setUnderlyingNetwork(network); + } catch (IOException | IllegalArgumentException e) { + Log.e( + TAG, + "Failed to update underlying network for apn: " + + apnName + + " exception: " + + e); + } + break; + default: throw new IllegalStateException("Unexpected value: " + msg.what); } @@ -1804,6 +1837,17 @@ public class EpdgTunnelManager { } } + private static final class IkeSessionConnectionInfoData { + final String mApnName; + final IkeSessionConnectionInfo mIkeSessionConnectionInfo; + + private IkeSessionConnectionInfoData( + String apnName, IkeSessionConnectionInfo ikeSessionConnectionInfo) { + mApnName = apnName; + mIkeSessionConnectionInfo = ikeSessionConnectionInfo; + } + } + // Data received from IkeSessionStateMachine if either IKE session or Child session have been // closed, normally or exceptionally. private static final class SessionClosedData { diff --git a/test/com/google/android/iwlan/epdg/EpdgTunnelManagerTest.java b/test/com/google/android/iwlan/epdg/EpdgTunnelManagerTest.java index 2386ccd..f2cba73 100644 --- a/test/com/google/android/iwlan/epdg/EpdgTunnelManagerTest.java +++ b/test/com/google/android/iwlan/epdg/EpdgTunnelManagerTest.java @@ -28,10 +28,12 @@ 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; @@ -40,6 +42,7 @@ 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; @@ -132,6 +135,7 @@ public class EpdgTunnelManagerTest { @Mock private EpdgSelector mMockEpdgSelector; @Mock private Network mMockNetwork; @Mock CarrierConfigManager mMockCarrierConfigManager; + @Mock ConnectivityManager mMockConnectivityManager; @Mock SubscriptionManager mMockSubscriptionManager; @Mock SubscriptionInfo mMockSubscriptionInfo; @Mock TelephonyManager mMockTelephonyManager; @@ -141,8 +145,10 @@ public class EpdgTunnelManagerTest { @Mock IkeSessionConfiguration mMockIkeSessionConfiguration; @Mock ChildSessionConfiguration mMockChildSessionConfiguration; @Mock IpSecManager.IpSecTunnelInterface mMockIpSecTunnelInterface; + @Mock IkeSessionConnectionInfo mMockIkeSessionConnectionInfo; @Mock IpSecTransform mMockedIpSecTransformIn; @Mock IpSecTransform mMockedIpSecTransformOut; + @Mock LinkProperties mMockLinkProperties; ArgumentCaptor mChildSessionCallbackCaptor; @@ -184,6 +190,8 @@ public class EpdgTunnelManagerTest { when(mMockIpSecTunnelInterface.getInterfaceName()).thenReturn("wlan0"); + when(mMockIkeSessionConnectionInfo.getNetwork()).thenReturn(mMockNetwork); + mChildSessionCallbackCaptor = ArgumentCaptor.forClass(ChildSessionCallback.class); doReturn(EXPECTED_LOCAL_ADDRESSES) @@ -1008,6 +1016,8 @@ public class EpdgTunnelManagerTest { }); 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))) @@ -1285,6 +1295,43 @@ public class EpdgTunnelManagerTest { verify(mMockIkeSession, times(1)).close(); } + @Test + public void testIkeSessionConnectionInfoChangedSetsUnderlyingNetwork() throws Exception { + String testApnName = "ims"; + when(mMockConnectivityManager.getLinkProperties(any())).thenReturn(mMockLinkProperties); + + ChildSessionCallback childSessionCallback = + verifyBringUpTunnelWithDnsQuery(testApnName, mMockIkeSession); + childSessionCallback.onIpSecTransformCreated( + mMockedIpSecTransformIn, IpSecManager.DIRECTION_IN); + + mEpdgTunnelManager + .getTmIkeSessionCallback(testApnName) + .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); + + ChildSessionCallback childSessionCallback = + verifyBringUpTunnelWithDnsQuery(testApnName, mMockIkeSession); + childSessionCallback.onIpSecTransformCreated( + mMockedIpSecTransformIn, IpSecManager.DIRECTION_IN); + + mEpdgTunnelManager + .getTmIkeSessionCallback(testApnName) + .onIkeSessionConnectionInfoChanged(mMockIkeSessionConnectionInfo); + mTestLooper.dispatchAll(); + + verify(mMockIpSecTunnelInterface, times(0)).setUnderlyingNetwork(any()); + } + @Test public void testSetIkeTrafficSelectorsIPv4() throws Exception { testSetIkeTrafficSelectors(ApnSetting.PROTOCOL_IP, false); -- cgit v1.2.3