Merge "Iwlan: update OWNERS file"
diff --git a/src/com/google/android/iwlan/IwlanDataService.java b/src/com/google/android/iwlan/IwlanDataService.java
index 1fc1452..92645cd 100644
--- a/src/com/google/android/iwlan/IwlanDataService.java
+++ b/src/com/google/android/iwlan/IwlanDataService.java
@@ -872,8 +872,7 @@
                                 + ", transport: "
                                 + sDefaultDataTransport);
 
-                if (networkConnected == false
-                        || mTunnelStateForApn.get(dataProfile.getApn()) != null) {
+                if (networkConnected == false) {
                     deliverCallback(
                             CALLBACK_TYPE_SETUP_DATACALL_COMPLETE,
                             5 /* DataServiceCallback.RESULT_ERROR_TEMPORARILY_UNAVAILABLE */,
@@ -882,6 +881,39 @@
                     return;
                 }
 
+                TunnelState tunnelState = mTunnelStateForApn.get(dataProfile.getApn());
+
+                // Return the existing PDN if the pduSessionId is the same and the tunnel state is
+                // TUNNEL_UP.
+                if (tunnelState != null) {
+                    if (tunnelState.getPduSessionId() == pduSessionId
+                            && tunnelState.getState() == TunnelState.TUNNEL_UP) {
+                        Log.w(
+                                SUB_TAG,
+                                "The tunnel for " + dataProfile.getApn() + " already exists.");
+                        deliverCallback(
+                                CALLBACK_TYPE_SETUP_DATACALL_COMPLETE,
+                                DataServiceCallback.RESULT_SUCCESS,
+                                callback,
+                                apnTunnelStateToDataCallResponse(dataProfile.getApn()));
+                        return;
+                    } else {
+                        Log.e(
+                                SUB_TAG,
+                                "Force close the existing PDN. pduSessionId = "
+                                        + tunnelState.getPduSessionId()
+                                        + " Tunnel State = "
+                                        + tunnelState.getState());
+                        getTunnelManager().closeTunnel(dataProfile.getApn(), true /* forceClose */);
+                        deliverCallback(
+                                CALLBACK_TYPE_SETUP_DATACALL_COMPLETE,
+                                5 /* DataServiceCallback.RESULT_ERROR_TEMPORARILY_UNAVAILABLE */,
+                                callback,
+                                null);
+                        return;
+                    }
+                }
+
                 TunnelSetupRequest.Builder tunnelReqBuilder =
                         TunnelSetupRequest.builder()
                                 .setApnName(dataProfile.getApn())
diff --git a/src/com/google/android/iwlan/epdg/EpdgTunnelManager.java b/src/com/google/android/iwlan/epdg/EpdgTunnelManager.java
index d2b98b1..95e8a8c 100644
--- a/src/com/google/android/iwlan/epdg/EpdgTunnelManager.java
+++ b/src/com/google/android/iwlan/epdg/EpdgTunnelManager.java
@@ -110,6 +110,7 @@
     private static final int EVENT_IPSEC_TRANSFORM_CREATED = 7;
     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 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;
@@ -434,27 +435,10 @@
         @Override
         public void onOpened(IkeSessionConfiguration sessionConfiguration) {
             Log.d(TAG, "Ike session opened for apn: " + mApnName);
-            TunnelConfig tunnelConfig = mApnNameToTunnelConfig.get(mApnName);
-            tunnelConfig.setPcscfAddrList(sessionConfiguration.getPcscfServers());
-
-            boolean enabledFastReauth =
-                    (boolean)
-                            getConfig(
-                                    CarrierConfigManager.Iwlan
-                                            .KEY_SUPPORTS_EAP_AKA_FAST_REAUTH_BOOL);
-            Log.d(
-                    TAG,
-                    "CarrierConfigManager.Iwlan.KEY_SUPPORTS_EAP_AKA_FAST_REAUTH_BOOL "
-                            + enabledFastReauth);
-            if (enabledFastReauth) {
-                EapInfo eapInfo = sessionConfiguration.getEapInfo();
-                if (eapInfo != null && eapInfo instanceof EapAkaInfo) {
-                    mNextReauthId = ((EapAkaInfo) eapInfo).getReauthId();
-                    Log.d(TAG, "Update ReauthId: " + Arrays.toString(mNextReauthId));
-                } else {
-                    mNextReauthId = null;
-                }
-            }
+            mHandler.sendMessage(
+                    mHandler.obtainMessage(
+                            EVENT_IKE_SESSION_OPENED,
+                            new IkeSessionOpenedData(mApnName, sessionConfiguration)));
         }
 
         @Override
@@ -1523,6 +1507,34 @@
                     tunnelConfig.getIkeSession().close();
                     break;
 
+                case EVENT_IKE_SESSION_OPENED:
+                    IkeSessionOpenedData ikeSessionOpenedData = (IkeSessionOpenedData) msg.obj;
+                    IkeSessionConfiguration sessionConfiguration =
+                            ikeSessionOpenedData.mIkeSessionConfiguration;
+
+                    tunnelConfig = mApnNameToTunnelConfig.get(ikeSessionOpenedData.mApnName);
+                    tunnelConfig.setPcscfAddrList(sessionConfiguration.getPcscfServers());
+
+                    boolean enabledFastReauth =
+                            (boolean)
+                                    getConfig(
+                                            CarrierConfigManager.Iwlan
+                                                    .KEY_SUPPORTS_EAP_AKA_FAST_REAUTH_BOOL);
+                    Log.d(
+                            TAG,
+                            "CarrierConfigManager.Iwlan.KEY_SUPPORTS_EAP_AKA_FAST_REAUTH_BOOL "
+                                    + enabledFastReauth);
+
+                    if (enabledFastReauth) {
+                        EapInfo eapInfo = sessionConfiguration.getEapInfo();
+                        if (eapInfo != null && eapInfo instanceof EapAkaInfo) {
+                            mNextReauthId = ((EapAkaInfo) eapInfo).getReauthId();
+                            Log.d(TAG, "Update ReauthId: " + Arrays.toString(mNextReauthId));
+                        } else {
+                            mNextReauthId = null;
+                        }
+                    }
+                    break;
                 default:
                     throw new IllegalStateException("Unexpected value: " + msg.what);
             }
@@ -1722,6 +1734,7 @@
         }
     }
 
+    // Data received from IkeSessionStateMachine on successful EVENT_CHILD_SESSION_OPENED.
     private static final class TunnelOpenedData {
         final String mApnName;
         final List<InetAddress> mInternalDnsServers;
@@ -1737,6 +1750,20 @@
         }
     }
 
+    // Data received from IkeSessionStateMachine on successful EVENT_IKE_SESSION_OPENED.
+    private static final class IkeSessionOpenedData {
+        final String mApnName;
+        final IkeSessionConfiguration mIkeSessionConfiguration;
+
+        private IkeSessionOpenedData(
+                String apnName, IkeSessionConfiguration ikeSessionConfiguration) {
+            mApnName = apnName;
+            mIkeSessionConfiguration = ikeSessionConfiguration;
+        }
+    }
+
+    // Data received from IkeSessionStateMachine if either IKE session or Child session have been
+    // closed, normally or exceptionally.
     private static final class SessionClosedData {
         final String mApnName;
         final IwlanError mIwlanError;
@@ -1951,6 +1978,11 @@
     }
 
     @VisibleForTesting
+    TunnelConfig getTunnelConfigForApn(String apnName) {
+        return mApnNameToTunnelConfig.get(apnName);
+    }
+
+    @VisibleForTesting
     long reportIwlanError(String apnName, IwlanError error) {
         return ErrorPolicyManager.getInstance(mContext, mSlotId).reportIwlanError(apnName, error);
     }
diff --git a/test/com/google/android/iwlan/epdg/EpdgTunnelManagerTest.java b/test/com/google/android/iwlan/epdg/EpdgTunnelManagerTest.java
index 97b409c..4d1760c 100644
--- a/test/com/google/android/iwlan/epdg/EpdgTunnelManagerTest.java
+++ b/test/com/google/android/iwlan/epdg/EpdgTunnelManagerTest.java
@@ -36,6 +36,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.IkeSessionParams;
 import android.net.ipsec.ike.SaProposal;
 import android.net.ipsec.ike.TunnelModeChildSessionParams;
@@ -103,6 +104,7 @@
     @Mock TelephonyManager mMockTelephonyManager;
     @Mock EpdgTunnelManager.IkeSessionCreator mMockIkeSessionCreator;
     @Mock IkeException mMockIkeException;
+    @Mock IkeSessionConfiguration mMockIkeSessionConfiguration;
 
     @Before
     public void setUp() throws Exception {
@@ -928,6 +930,32 @@
     }
 
     @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, null, 0);
+
+        List<InetAddress> ipList = new ArrayList<>();
+        ipList.add(InetAddress.getByName(TEST_IP_ADDRESS));
+        when(mMockIkeSessionConfiguration.getPcscfServers()).thenReturn(ipList);
+
+        PersistableBundle bundle = new PersistableBundle();
+        setupMockForGetConfig(bundle);
+
+        mEpdgTunnelManager
+                .getTmIkeSessionCallback(testApnName)
+                .onOpened(mMockIkeSessionConfiguration);
+        mTestLooper.dispatchAll();
+
+        EpdgTunnelManager.TunnelConfig testApnTunnelConfig =
+                mEpdgTunnelManager.getTunnelConfigForApn(testApnName);
+        assertEquals(testApnTunnelConfig.getPcscfAddrList(), ipList);
+    }
+
+    @Test
     public void testSetIkeTrafficSelectorsIPv4() throws Exception {
         testSetIkeTrafficSelectors(ApnSetting.PROTOCOL_IP, false);
     }