Store SPI in LocalRequest

Store SPI in LocalRequest to show which IKE/Child SA is related
to this request. This allows the IkeSessionStateMachine to figure
out if this request is scheduled for a deleted SA

Bug: 147831323
Test: atest FrameworksIkeTests
Change-Id: I30f43e2b7137688b6e68de1cbb6ceea43355dacc
diff --git a/src/java/com/android/internal/net/ipsec/ike/IkeLocalRequestScheduler.java b/src/java/com/android/internal/net/ipsec/ike/IkeLocalRequestScheduler.java
index ebf368a..ed20e2f 100644
--- a/src/java/com/android/internal/net/ipsec/ike/IkeLocalRequestScheduler.java
+++ b/src/java/com/android/internal/net/ipsec/ike/IkeLocalRequestScheduler.java
@@ -15,6 +15,11 @@
  */
 package com.android.internal.net.ipsec.ike;
 
+import static com.android.internal.net.ipsec.ike.AbstractSessionStateMachine.CMD_LOCAL_REQUEST_CREATE_CHILD;
+import static com.android.internal.net.ipsec.ike.AbstractSessionStateMachine.CMD_LOCAL_REQUEST_REKEY_CHILD;
+import static com.android.internal.net.ipsec.ike.IkeSessionStateMachine.CMD_LOCAL_REQUEST_CREATE_IKE;
+import static com.android.internal.net.ipsec.ike.IkeSessionStateMachine.CMD_LOCAL_REQUEST_DPD;
+
 import android.net.ipsec.ike.ChildSessionCallback;
 import android.net.ipsec.ike.ChildSessionParams;
 
@@ -27,6 +32,8 @@
  * <p>LocalRequestScheduler is running on the IkeSessionStateMachine thread.
  */
 public final class IkeLocalRequestScheduler {
+    public static int SPI_NOT_INCLUDED = 0;
+
     private final LinkedList<LocalRequest> mRequestQueue = new LinkedList<>();
 
     private final IProcedureConsumer mConsumer;
@@ -69,15 +76,15 @@
     }
 
     /**
-     * This class represents a user requested or internally scheduled IKE procedure that will be
-     * initiated locally.
+     * This class represents the common information of procedures that will be locally initiated.
      */
-    public static class LocalRequest {
+    public abstract static class LocalRequest {
         public final int procedureType;
-        // TODO: Also store specific payloads for INFO exchange.
+
         private boolean mIsCancelled;
 
         LocalRequest(int type) {
+            validateTypeOrThrow(type);
             procedureType = type;
             mIsCancelled = false;
         }
@@ -89,6 +96,40 @@
         void cancel() {
             mIsCancelled = true;
         }
+
+        protected abstract void validateTypeOrThrow(int type);
+
+        protected abstract boolean isChildRequest();
+    }
+
+    /**
+     * This class represents a user requested or internally scheduled IKE procedure that will be
+     * initiated locally.
+     */
+    public static class IkeLocalRequest extends LocalRequest {
+        public long remoteSpi;
+
+        /** Schedule a request for the IKE Session */
+        IkeLocalRequest(int type) {
+            this(type, SPI_NOT_INCLUDED);
+        }
+
+        /** Schedule a request for an IKE SA that is identified by the remoteIkeSpi */
+        IkeLocalRequest(int type, long remoteIkeSpi) {
+            super(type);
+            remoteSpi = remoteIkeSpi;
+        }
+
+        @Override
+        protected void validateTypeOrThrow(int type) {
+            if (type >= CMD_LOCAL_REQUEST_CREATE_IKE && type <= CMD_LOCAL_REQUEST_DPD) return;
+            throw new IllegalArgumentException("Invalid IKE procedure type: " + type);
+        }
+
+        @Override
+        protected boolean isChildRequest() {
+            return false;
+        }
     }
 
     /**
@@ -96,14 +137,44 @@
      * initiated locally.
      */
     public static class ChildLocalRequest extends LocalRequest {
+        public int remoteSpi;
         public final ChildSessionCallback childSessionCallback;
         public final ChildSessionParams childSessionParams;
 
+        /** Schedule a request for a Child Session that is identified by the childCallback */
         ChildLocalRequest(
                 int type, ChildSessionCallback childCallback, ChildSessionParams childParams) {
+            this(type, SPI_NOT_INCLUDED, childCallback, childParams);
+        }
+
+        /** Schedule a request for a Child SA that is identified by the remoteChildSpi */
+        ChildLocalRequest(int type, int remoteChildSpi, ChildSessionParams childParams) {
+            this(type, remoteChildSpi, null /*childCallback*/, childParams);
+        }
+
+        private ChildLocalRequest(
+                int type,
+                int remoteChildSpi,
+                ChildSessionCallback childCallback,
+                ChildSessionParams childParams) {
             super(type);
             childSessionParams = childParams;
             childSessionCallback = childCallback;
+            remoteSpi = remoteChildSpi;
+        }
+
+        @Override
+        protected void validateTypeOrThrow(int type) {
+            if (type >= CMD_LOCAL_REQUEST_CREATE_CHILD && type <= CMD_LOCAL_REQUEST_REKEY_CHILD) {
+                return;
+            }
+
+            throw new IllegalArgumentException("Invalid Child procedure type: " + type);
+        }
+
+        @Override
+        protected boolean isChildRequest() {
+            return true;
         }
     }
 
diff --git a/src/java/com/android/internal/net/ipsec/ike/IkeSessionStateMachine.java b/src/java/com/android/internal/net/ipsec/ike/IkeSessionStateMachine.java
index 8ad60e9..47e12db 100644
--- a/src/java/com/android/internal/net/ipsec/ike/IkeSessionStateMachine.java
+++ b/src/java/com/android/internal/net/ipsec/ike/IkeSessionStateMachine.java
@@ -77,6 +77,7 @@
 import com.android.internal.net.eap.IEapCallback;
 import com.android.internal.net.ipsec.ike.ChildSessionStateMachine.CreateChildSaHelper;
 import com.android.internal.net.ipsec.ike.IkeLocalRequestScheduler.ChildLocalRequest;
+import com.android.internal.net.ipsec.ike.IkeLocalRequestScheduler.IkeLocalRequest;
 import com.android.internal.net.ipsec.ike.IkeLocalRequestScheduler.LocalRequest;
 import com.android.internal.net.ipsec.ike.SaRecord.IkeSaRecord;
 import com.android.internal.net.ipsec.ike.crypto.IkeCipher;
@@ -191,8 +192,6 @@
     @VisibleForTesting
     static final long TEMP_FAILURE_RETRY_TIMEOUT_MS = TimeUnit.MINUTES.toMillis(5L);
 
-    // TODO: Allow users to configure IKE lifetime
-
     // Package private IKE exchange subtypes describe the specific function of a IKE
     // request/response exchange. It helps IkeSessionStateMachine to do message validation according
     // to the subtype specific rules.
@@ -549,7 +548,8 @@
 
     /** Initiates IKE setup procedure. */
     public void openSession() {
-        sendMessage(CMD_LOCAL_REQUEST_CREATE_IKE, new LocalRequest(CMD_LOCAL_REQUEST_CREATE_IKE));
+        sendMessage(
+                CMD_LOCAL_REQUEST_CREATE_IKE, new IkeLocalRequest(CMD_LOCAL_REQUEST_CREATE_IKE));
     }
 
     /** Schedules a Create Child procedure. */
@@ -588,7 +588,8 @@
 
     /** Initiates Delete IKE procedure. */
     public void closeSession() {
-        sendMessage(CMD_LOCAL_REQUEST_DELETE_IKE, new LocalRequest(CMD_LOCAL_REQUEST_DELETE_IKE));
+        sendMessage(
+                CMD_LOCAL_REQUEST_DELETE_IKE, new IkeLocalRequest(CMD_LOCAL_REQUEST_DELETE_IKE));
     }
 
     /** Forcibly close IKE Session. */
@@ -1104,6 +1105,12 @@
         }
 
         private void executeLocalRequest(LocalRequest req, Message message) {
+            if (!isRequestForCurrentSa(req)) {
+                logd("Request is for a deleted SA. Ignore it.");
+                mScheduler.readyForNextProcedure();
+                return;
+            }
+
             switch (req.procedureType) {
                 case CMD_LOCAL_REQUEST_REKEY_IKE:
                     transitionTo(mRekeyIkeLocalCreate);
@@ -1123,6 +1130,26 @@
                                     "Invalid local request procedure type: " + req.procedureType));
             }
         }
+
+        // When in Idle state, this IkeSessionStateMachine and all its ChildSessionStateMachines
+        // only have one alive IKE/Child SA respectively. Returns true if this local request is for
+        // the current IKE/Child SA, or false if the request is for a deleted SA.
+        private boolean isRequestForCurrentSa(LocalRequest localRequest) {
+            if (localRequest.isChildRequest()) {
+                ChildLocalRequest req = (ChildLocalRequest) localRequest;
+                if (req.remoteSpi == IkeLocalRequestScheduler.SPI_NOT_INCLUDED
+                        || mRemoteSpiToChildSessionMap.get(req.remoteSpi) != null) {
+                    return true;
+                }
+            } else {
+                IkeLocalRequest req = (IkeLocalRequest) localRequest;
+                if (req.remoteSpi == IkeLocalRequestScheduler.SPI_NOT_INCLUDED
+                        || req.remoteSpi == mCurrentIkeSaRecord.getRemoteSpi()) {
+                    return true;
+                }
+            }
+            return false;
+        }
     }
 
     /**
@@ -2515,7 +2542,7 @@
                                 mIkePrf,
                                 mIkeIntegrity == null ? 0 : mIkeIntegrity.getKeyLength(),
                                 mIkeCipher.getKeyLength(),
-                                new LocalRequest(CMD_LOCAL_REQUEST_REKEY_IKE));
+                                new IkeLocalRequest(CMD_LOCAL_REQUEST_REKEY_IKE));
 
                 addIkeSaRecord(mCurrentIkeSaRecord);
                 ikeInitSuccess = true;
@@ -3672,7 +3699,7 @@
                                 newIntegrity == null ? 0 : newIntegrity.getKeyLength(),
                                 newCipher.getKeyLength(),
                                 isLocalInit,
-                                new LocalRequest(CMD_LOCAL_REQUEST_REKEY_IKE));
+                                new IkeLocalRequest(CMD_LOCAL_REQUEST_REKEY_IKE));
 
                 addIkeSaRecord(newSaRecord);
 
diff --git a/tests/iketests/src/java/com/android/internal/net/ipsec/ike/IkeLocalRequestSchedulerTest.java b/tests/iketests/src/java/com/android/internal/net/ipsec/ike/IkeLocalRequestSchedulerTest.java
index 3406d01..251f83d 100644
--- a/tests/iketests/src/java/com/android/internal/net/ipsec/ike/IkeLocalRequestSchedulerTest.java
+++ b/tests/iketests/src/java/com/android/internal/net/ipsec/ike/IkeLocalRequestSchedulerTest.java
@@ -27,6 +27,7 @@
 import static org.mockito.Mockito.verify;
 
 import com.android.internal.net.ipsec.ike.IkeLocalRequestScheduler.IProcedureConsumer;
+import com.android.internal.net.ipsec.ike.IkeLocalRequestScheduler.IkeLocalRequest;
 import com.android.internal.net.ipsec.ike.IkeLocalRequestScheduler.LocalRequest;
 
 import org.junit.Before;
@@ -109,10 +110,10 @@
 
     @Test
     public void testDoNotProcessCanceledRequest() {
-        LocalRequest[] requestArray = new LocalRequest[4];
+        LocalRequest[] requestArray = new IkeLocalRequest[4];
 
         for (int i = 0; i < requestArray.length; i++) {
-            requestArray[i] = new LocalRequest(CMD_LOCAL_REQUEST_REKEY_IKE);
+            requestArray[i] = new IkeLocalRequest(CMD_LOCAL_REQUEST_REKEY_IKE);
             mScheduler.addRequest(requestArray[i]);
         }
 
diff --git a/tests/iketests/src/java/com/android/internal/net/ipsec/ike/IkeSessionStateMachineTest.java b/tests/iketests/src/java/com/android/internal/net/ipsec/ike/IkeSessionStateMachineTest.java
index f44e3a5..119cf2a 100644
--- a/tests/iketests/src/java/com/android/internal/net/ipsec/ike/IkeSessionStateMachineTest.java
+++ b/tests/iketests/src/java/com/android/internal/net/ipsec/ike/IkeSessionStateMachineTest.java
@@ -101,7 +101,7 @@
 import com.android.internal.net.ipsec.ike.ChildSessionStateMachineFactory.ChildSessionFactoryHelper;
 import com.android.internal.net.ipsec.ike.ChildSessionStateMachineFactory.IChildSessionFactoryHelper;
 import com.android.internal.net.ipsec.ike.IkeLocalRequestScheduler.ChildLocalRequest;
-import com.android.internal.net.ipsec.ike.IkeLocalRequestScheduler.LocalRequest;
+import com.android.internal.net.ipsec.ike.IkeLocalRequestScheduler.IkeLocalRequest;
 import com.android.internal.net.ipsec.ike.IkeSessionStateMachine.IkeSecurityParameterIndex;
 import com.android.internal.net.ipsec.ike.IkeSessionStateMachine.ReceivedIkePacket;
 import com.android.internal.net.ipsec.ike.SaRecord.ISaRecordHelper;
@@ -638,7 +638,7 @@
                 new byte[KEY_LEN_IKE_ENCR],
                 TestUtils.hexStringToByteArray(PRF_KEY_INIT_HEX_STRING),
                 TestUtils.hexStringToByteArray(PRF_KEY_RESP_HEX_STRING),
-                new LocalRequest(CMD_LOCAL_REQUEST_REKEY_IKE));
+                new IkeLocalRequest(CMD_LOCAL_REQUEST_REKEY_IKE));
     }
 
     @Before
@@ -2776,7 +2776,7 @@
         // Send Rekey-Create request
         mIkeSessionStateMachine.sendMessage(
                 IkeSessionStateMachine.CMD_EXECUTE_LOCAL_REQ,
-                new LocalRequest(IkeSessionStateMachine.CMD_LOCAL_REQUEST_REKEY_IKE));
+                new IkeLocalRequest(IkeSessionStateMachine.CMD_LOCAL_REQUEST_REKEY_IKE));
         mLooper.dispatchAll();
         assertTrue(
                 mIkeSessionStateMachine.getCurrentState()
@@ -2823,7 +2823,7 @@
         // Send Rekey-Create request
         mIkeSessionStateMachine.sendMessage(
                 IkeSessionStateMachine.CMD_EXECUTE_LOCAL_REQ,
-                new LocalRequest(IkeSessionStateMachine.CMD_LOCAL_REQUEST_REKEY_IKE));
+                new IkeLocalRequest(IkeSessionStateMachine.CMD_LOCAL_REQUEST_REKEY_IKE));
         mLooper.dispatchAll();
         verifyRetransmissionStarted();
 
@@ -2856,7 +2856,7 @@
         // Send Rekey-Create request
         mIkeSessionStateMachine.sendMessage(
                 IkeSessionStateMachine.CMD_EXECUTE_LOCAL_REQ,
-                new LocalRequest(IkeSessionStateMachine.CMD_LOCAL_REQUEST_REKEY_IKE));
+                new IkeLocalRequest(IkeSessionStateMachine.CMD_LOCAL_REQUEST_REKEY_IKE));
         mLooper.dispatchAll();
         verifyRetransmissionStarted();
         resetMockIkeMessageHelper();
@@ -2887,7 +2887,7 @@
         // Send Rekey-Create request
         mIkeSessionStateMachine.sendMessage(
                 IkeSessionStateMachine.CMD_EXECUTE_LOCAL_REQ,
-                new LocalRequest(IkeSessionStateMachine.CMD_LOCAL_REQUEST_REKEY_IKE));
+                new IkeLocalRequest(IkeSessionStateMachine.CMD_LOCAL_REQUEST_REKEY_IKE));
         mLooper.dispatchAll();
 
         // Mock receiving packet with NO_PROPOSAL_CHOSEN
@@ -2916,7 +2916,7 @@
         // Send Rekey-Create request
         mIkeSessionStateMachine.sendMessage(
                 IkeSessionStateMachine.CMD_EXECUTE_LOCAL_REQ,
-                new LocalRequest(IkeSessionStateMachine.CMD_LOCAL_REQUEST_REKEY_IKE));
+                new IkeLocalRequest(IkeSessionStateMachine.CMD_LOCAL_REQUEST_REKEY_IKE));
         mLooper.dispatchAll();
         resetMockIkeMessageHelper();
 
@@ -2945,7 +2945,7 @@
         // Send Rekey-Create request
         mIkeSessionStateMachine.sendMessage(
                 IkeSessionStateMachine.CMD_EXECUTE_LOCAL_REQ,
-                new LocalRequest(IkeSessionStateMachine.CMD_LOCAL_REQUEST_REKEY_IKE));
+                new IkeLocalRequest(IkeSessionStateMachine.CMD_LOCAL_REQUEST_REKEY_IKE));
         mLooper.dispatchAll();
         resetMockIkeMessageHelper();
 
@@ -2972,7 +2972,7 @@
         // Send Rekey-Create request
         mIkeSessionStateMachine.sendMessage(
                 IkeSessionStateMachine.CMD_EXECUTE_LOCAL_REQ,
-                new LocalRequest(IkeSessionStateMachine.CMD_LOCAL_REQUEST_REKEY_IKE));
+                new IkeLocalRequest(IkeSessionStateMachine.CMD_LOCAL_REQUEST_REKEY_IKE));
         mLooper.dispatchAll();
         verifyRetransmissionStarted();
         resetMockIkeMessageHelper();
@@ -3382,7 +3382,7 @@
         // Send Rekey request on mSpyCurrentIkeSaRecord
         mIkeSessionStateMachine.sendMessage(
                 IkeSessionStateMachine.CMD_EXECUTE_LOCAL_REQ,
-                new LocalRequest(IkeSessionStateMachine.CMD_LOCAL_REQUEST_REKEY_IKE));
+                new IkeLocalRequest(IkeSessionStateMachine.CMD_LOCAL_REQUEST_REKEY_IKE));
 
         // Receive Rekey request on mSpyCurrentIkeSaRecord
         ReceivedIkePacket dummyRekeyIkeRequestReceivedPacket = makeRekeyIkeRequest();
@@ -3469,7 +3469,7 @@
         // Send Rekey-Create request
         mIkeSessionStateMachine.sendMessage(
                 IkeSessionStateMachine.CMD_EXECUTE_LOCAL_REQ,
-                new LocalRequest(IkeSessionStateMachine.CMD_LOCAL_REQUEST_REKEY_IKE));
+                new IkeLocalRequest(IkeSessionStateMachine.CMD_LOCAL_REQUEST_REKEY_IKE));
         mLooper.dispatchAll();
 
         // Prepare "rekeyed" SA
@@ -3705,7 +3705,7 @@
 
         mIkeSessionStateMachine.sendMessage(
                 IkeSessionStateMachine.CMD_EXECUTE_LOCAL_REQ,
-                new LocalRequest(IkeSessionStateMachine.CMD_LOCAL_REQUEST_DELETE_IKE));
+                new IkeLocalRequest(IkeSessionStateMachine.CMD_LOCAL_REQUEST_DELETE_IKE));
         mLooper.dispatchAll();
         verifyRetransmissionStarted();
 
@@ -3736,7 +3736,7 @@
 
         mIkeSessionStateMachine.sendMessage(
                 IkeSessionStateMachine.CMD_EXECUTE_LOCAL_REQ,
-                new LocalRequest(IkeSessionStateMachine.CMD_LOCAL_REQUEST_DELETE_IKE));
+                new IkeLocalRequest(IkeSessionStateMachine.CMD_LOCAL_REQUEST_DELETE_IKE));
         mLooper.dispatchAll();
         verifyRetransmissionStarted();
 
@@ -3758,7 +3758,7 @@
 
         mIkeSessionStateMachine.sendMessage(
                 IkeSessionStateMachine.CMD_EXECUTE_LOCAL_REQ,
-                new LocalRequest(IkeSessionStateMachine.CMD_LOCAL_REQUEST_DELETE_IKE));
+                new IkeLocalRequest(IkeSessionStateMachine.CMD_LOCAL_REQUEST_DELETE_IKE));
         mLooper.dispatchAll();
         verifyRetransmissionStarted();
         resetMockIkeMessageHelper();
@@ -3787,7 +3787,7 @@
         // Send delete request
         mIkeSessionStateMachine.sendMessage(
                 IkeSessionStateMachine.CMD_EXECUTE_LOCAL_REQ,
-                new LocalRequest(IkeSessionStateMachine.CMD_LOCAL_REQUEST_DELETE_IKE));
+                new IkeLocalRequest(IkeSessionStateMachine.CMD_LOCAL_REQUEST_DELETE_IKE));
         mLooper.dispatchAll();
 
         // Receive response with wrong exchange type
@@ -3810,7 +3810,7 @@
 
         mIkeSessionStateMachine.sendMessage(
                 IkeSessionStateMachine.CMD_EXECUTE_LOCAL_REQ,
-                new LocalRequest(IkeSessionStateMachine.CMD_LOCAL_REQUEST_DELETE_IKE));
+                new IkeLocalRequest(IkeSessionStateMachine.CMD_LOCAL_REQUEST_DELETE_IKE));
         mLooper.dispatchAll();
         verifyRetransmissionStarted();
 
@@ -3947,7 +3947,7 @@
 
         mIkeSessionStateMachine.sendMessage(
                 IkeSessionStateMachine.CMD_EXECUTE_LOCAL_REQ,
-                new LocalRequest(IkeSessionStateMachine.CMD_LOCAL_REQUEST_REKEY_IKE));
+                new IkeLocalRequest(IkeSessionStateMachine.CMD_LOCAL_REQUEST_REKEY_IKE));
         mLooper.dispatchAll();
 
         // Verify that the command is executed, and the state machine transitions to the right state
@@ -3970,7 +3970,7 @@
         // Queue a local request, and expect that it is not run (yet)
         mIkeSessionStateMachine.sendMessage(
                 IkeSessionStateMachine.CMD_LOCAL_REQUEST_REKEY_IKE,
-                new LocalRequest(IkeSessionStateMachine.CMD_LOCAL_REQUEST_REKEY_IKE));
+                new IkeLocalRequest(IkeSessionStateMachine.CMD_LOCAL_REQUEST_REKEY_IKE));
         mLooper.dispatchAll();
 
         // Verify that the state machine is still in the Receiving state