• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (C) 2020 The Android Open Source Project
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  *      http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16 package com.android.internal.net.ipsec.ike.utils;
17 
18 import android.util.CloseGuard;
19 import android.util.Pair;
20 
21 import com.android.internal.annotations.VisibleForTesting;
22 
23 import java.io.IOException;
24 import java.net.InetAddress;
25 import java.util.HashSet;
26 import java.util.Set;
27 
28 /**
29  * This class represents a reserved IKE SPI.
30  *
31  * <p>This class is created to avoid assigning same SPI to the same address.
32  *
33  * <p>Objects of this type are used to track reserved IKE SPI to avoid SPI collision. They can be
34  * obtained by calling {@link #allocateSecurityParameterIndex()} and must be released by calling
35  * {@link #close()} when they are no longer needed.
36  *
37  * <p>This class MUST only be called from IKE worker thread. Methods that allocate and close IKE
38  * SPI resource are not thread safe.
39  *
40  * <p>This class follows the pattern of {@link IpSecManager.SecurityParameterIndex}.
41  */
42 public final class IkeSecurityParameterIndex implements AutoCloseable {
43     // Package private Set to remember assigned IKE SPIs to avoid SPI collision. MUST be
44     // accessed only by IkeSecurityParameterIndex and IkeSpiGenerator
45     static final Set<Pair<InetAddress, Long>> sAssignedIkeSpis = new HashSet<>();
46 
47     private InetAddress mSourceAddress;
48     private final long mSpi;
49     private final CloseGuard mCloseGuard = new CloseGuard();
50 
51     // Package private constructor that MUST only be called from IkeSpiGenerator
IkeSecurityParameterIndex(InetAddress sourceAddress, long spi)52     IkeSecurityParameterIndex(InetAddress sourceAddress, long spi) {
53         mSourceAddress = sourceAddress;
54         mSpi = spi;
55         mCloseGuard.open("close");
56     }
57 
58     /**
59      * Get the underlying SPI held by this object.
60      *
61      * @return the underlying IKE SPI.
62      */
getSpi()63     public long getSpi() {
64         return mSpi;
65     }
66 
67     /** Gets the current source address for this IkeSecurityParameterIndex. */
68     @VisibleForTesting
getSourceAddress()69     public InetAddress getSourceAddress() {
70         return mSourceAddress;
71     }
72 
73     /** Release an SPI that was previously reserved. */
74     @Override
close()75     public void close() {
76         sAssignedIkeSpis.remove(new Pair<InetAddress, Long>(mSourceAddress, mSpi));
77         mCloseGuard.close();
78     }
79 
80     /** Check that the IkeSecurityParameterIndex was closed properly. */
81     @Override
finalize()82     protected void finalize() throws Throwable {
83         if (mCloseGuard != null) {
84             mCloseGuard.warnIfOpen();
85         }
86         close();
87     }
88 
89     /** Migrate this IkeSecurityParameterIndex to the specified InetAddress. */
migrate(InetAddress newSourceAddress)90     public void migrate(InetAddress newSourceAddress) throws IOException {
91         if (mSourceAddress.equals(newSourceAddress)) {
92             // not actually migrating - this is a no op
93             return;
94         }
95 
96         if (!sAssignedIkeSpis.add(new Pair<>(newSourceAddress, mSpi))) {
97             throw new IOException(
98                     String.format(
99                             "SPI colllision migrating IKE SPI <%s, %d> to <%s, %d>",
100                             mSourceAddress.getHostAddress(),
101                             mSpi,
102                             newSourceAddress.getHostAddress(),
103                             mSpi));
104         }
105 
106         sAssignedIkeSpis.remove(new Pair<InetAddress, Long>(mSourceAddress, mSpi));
107         mSourceAddress = newSourceAddress;
108     }
109 }
110