• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (C) 2023 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 android.net;
17 
18 import static com.android.internal.annotations.VisibleForTesting.Visibility;
19 
20 import android.annotation.FlaggedApi;
21 import android.annotation.NonNull;
22 import android.os.Parcel;
23 import android.os.Parcelable;
24 import android.os.SystemClock;
25 
26 import com.android.internal.annotations.VisibleForTesting;
27 import com.android.net.flags.Flags;
28 import com.android.net.module.util.HexDump;
29 
30 import java.util.Objects;
31 
32 /**
33  * This class represents a snapshot of the state of an IpSecTransform
34  *
35  * <p>This class provides the current state of an IpSecTransform, enabling link metric analysis by
36  * the caller. Use cases include understanding transform usage, such as packet and byte counts, as
37  * well as observing out-of-order delivery by checking the bitmap. Additionally, callers can query
38  * IpSecTransformStates at two timestamps. By comparing the changes in packet counts and sequence
39  * numbers, callers can estimate IPsec data loss in the inbound direction.
40  */
41 @FlaggedApi(Flags.FLAG_IPSEC_TRANSFORM_STATE)
42 public final class IpSecTransformState implements Parcelable {
43     private final long mTimestamp;
44     private final long mTxHighestSequenceNumber;
45     private final long mRxHighestSequenceNumber;
46     private final long mPacketCount;
47     private final long mByteCount;
48     private final byte[] mReplayBitmap;
49 
IpSecTransformState( long timestamp, long txHighestSequenceNumber, long rxHighestSequenceNumber, long packetCount, long byteCount, byte[] replayBitmap)50     private IpSecTransformState(
51             long timestamp,
52             long txHighestSequenceNumber,
53             long rxHighestSequenceNumber,
54             long packetCount,
55             long byteCount,
56             byte[] replayBitmap) {
57         mTimestamp = timestamp;
58         mTxHighestSequenceNumber = txHighestSequenceNumber;
59         mRxHighestSequenceNumber = rxHighestSequenceNumber;
60         mPacketCount = packetCount;
61         mByteCount = byteCount;
62 
63         Objects.requireNonNull(replayBitmap, "replayBitmap is null");
64         mReplayBitmap = replayBitmap.clone();
65 
66         validate();
67     }
68 
validate()69     private void validate() {
70         Objects.requireNonNull(mReplayBitmap, "mReplayBitmap is null");
71     }
72 
73     /**
74      * Deserializes a IpSecTransformState from a PersistableBundle.
75      *
76      * @hide
77      */
78     @VisibleForTesting(visibility = Visibility.PRIVATE)
IpSecTransformState(@onNull Parcel in)79     public IpSecTransformState(@NonNull Parcel in) {
80         Objects.requireNonNull(in, "The input PersistableBundle is null");
81         mTimestamp = in.readLong();
82         mTxHighestSequenceNumber = in.readLong();
83         mRxHighestSequenceNumber = in.readLong();
84         mPacketCount = in.readLong();
85         mByteCount = in.readLong();
86         mReplayBitmap = HexDump.hexStringToByteArray(in.readString());
87 
88         validate();
89     }
90 
91     // Parcelable methods
92 
93     @Override
describeContents()94     public int describeContents() {
95         return 0;
96     }
97 
98     @Override
writeToParcel(@onNull Parcel out, int flags)99     public void writeToParcel(@NonNull Parcel out, int flags) {
100         out.writeLong(mTimestamp);
101         out.writeLong(mTxHighestSequenceNumber);
102         out.writeLong(mRxHighestSequenceNumber);
103         out.writeLong(mPacketCount);
104         out.writeLong(mByteCount);
105         out.writeString(HexDump.toHexString(mReplayBitmap));
106     }
107 
108     @NonNull
109     public static final Parcelable.Creator<IpSecTransformState> CREATOR =
110             new Parcelable.Creator<IpSecTransformState>() {
111                 @NonNull
112                 public IpSecTransformState createFromParcel(Parcel in) {
113                     return new IpSecTransformState(in);
114                 }
115 
116                 @NonNull
117                 public IpSecTransformState[] newArray(int size) {
118                     return new IpSecTransformState[size];
119                 }
120             };
121 
122     /**
123      * Retrieve the timestamp (milliseconds) when this state was created, as per {@link
124      * SystemClock#elapsedRealtime}
125      *
126      * @see Builder#setTimestampMillis(long)
127      */
getTimestampMillis()128     public long getTimestampMillis() {
129         return mTimestamp;
130     }
131 
132     /**
133      * Retrieve the highest sequence number sent so far as an unsigned long
134      *
135      * @see Builder#setTxHighestSequenceNumber(long)
136      */
getTxHighestSequenceNumber()137     public long getTxHighestSequenceNumber() {
138         return mTxHighestSequenceNumber;
139     }
140 
141     /**
142      * Retrieve the highest sequence number received so far as an unsigned long
143      *
144      * @see Builder#setRxHighestSequenceNumber(long)
145      */
getRxHighestSequenceNumber()146     public long getRxHighestSequenceNumber() {
147         return mRxHighestSequenceNumber;
148     }
149 
150     /**
151      * Retrieve the number of packets processed so far as an unsigned long.
152      *
153      * <p>The packet count direction (inbound or outbound) aligns with the direction in which the
154      * IpSecTransform is applied to.
155      *
156      * @see Builder#setPacketCount(long)
157      */
getPacketCount()158     public long getPacketCount() {
159         return mPacketCount;
160     }
161 
162     /**
163      * Retrieve the number of bytes processed so far as an unsigned long
164      *
165      * <p>The byte count direction (inbound or outbound) aligns with the direction in which the
166      * IpSecTransform is applied to.
167      *
168      * @see Builder#setByteCount(long)
169      */
getByteCount()170     public long getByteCount() {
171         return mByteCount;
172     }
173 
174     /**
175      * Retrieve the replay bitmap
176      *
177      * <p>This bitmap represents a replay window, allowing the caller to observe out-of-order
178      * delivery. The last bit represents the highest sequence number received so far and bits for
179      * the received packets will be marked as true.
180      *
181      * <p>The size of a replay bitmap will never change over the lifetime of an IpSecTransform
182      *
183      * <p>The replay bitmap is solely useful for inbound IpSecTransforms. For outbound
184      * IpSecTransforms, all bits will be unchecked.
185      *
186      * @see Builder#setReplayBitmap(byte[])
187      */
188     @NonNull
getReplayBitmap()189     public byte[] getReplayBitmap() {
190         return mReplayBitmap.clone();
191     }
192 
193     /**
194      * Builder class for testing purposes
195      *
196      * <p>Except for testing, IPsec callers normally do not instantiate {@link IpSecTransformState}
197      * themselves but instead get a reference via {@link IpSecTransformState}
198      */
199     @FlaggedApi(Flags.FLAG_IPSEC_TRANSFORM_STATE)
200     public static final class Builder {
201         private long mTimestamp;
202         private long mTxHighestSequenceNumber;
203         private long mRxHighestSequenceNumber;
204         private long mPacketCount;
205         private long mByteCount;
206         private byte[] mReplayBitmap;
207 
Builder()208         public Builder() {
209             mTimestamp = SystemClock.elapsedRealtime();
210         }
211 
212         /**
213          * Set the timestamp (milliseconds) when this state was created
214          *
215          * @see IpSecTransformState#getTimestampMillis()
216          */
217         @NonNull
setTimestampMillis(long timestamp)218         public Builder setTimestampMillis(long timestamp) {
219             mTimestamp = timestamp;
220             return this;
221         }
222 
223         /**
224          * Set the highest sequence number sent so far as an unsigned long
225          *
226          * @see IpSecTransformState#getTxHighestSequenceNumber()
227          */
228         @NonNull
setTxHighestSequenceNumber(long seqNum)229         public Builder setTxHighestSequenceNumber(long seqNum) {
230             mTxHighestSequenceNumber = seqNum;
231             return this;
232         }
233 
234         /**
235          * Set the highest sequence number received so far as an unsigned long
236          *
237          * @see IpSecTransformState#getRxHighestSequenceNumber()
238          */
239         @NonNull
setRxHighestSequenceNumber(long seqNum)240         public Builder setRxHighestSequenceNumber(long seqNum) {
241             mRxHighestSequenceNumber = seqNum;
242             return this;
243         }
244 
245         /**
246          * Set the number of packets processed so far as an unsigned long
247          *
248          * @see IpSecTransformState#getPacketCount()
249          */
250         @NonNull
setPacketCount(long packetCount)251         public Builder setPacketCount(long packetCount) {
252             mPacketCount = packetCount;
253             return this;
254         }
255 
256         /**
257          * Set the number of bytes processed so far as an unsigned long
258          *
259          * @see IpSecTransformState#getByteCount()
260          */
261         @NonNull
setByteCount(long byteCount)262         public Builder setByteCount(long byteCount) {
263             mByteCount = byteCount;
264             return this;
265         }
266 
267         /**
268          * Set the replay bitmap
269          *
270          * @see IpSecTransformState#getReplayBitmap()
271          */
272         @NonNull
setReplayBitmap(@onNull byte[] bitMap)273         public Builder setReplayBitmap(@NonNull byte[] bitMap) {
274             mReplayBitmap = bitMap.clone();
275             return this;
276         }
277 
278         /**
279          * Build and validate the IpSecTransformState
280          *
281          * @return an immutable IpSecTransformState instance
282          */
283         @NonNull
build()284         public IpSecTransformState build() {
285             return new IpSecTransformState(
286                     mTimestamp,
287                     mTxHighestSequenceNumber,
288                     mRxHighestSequenceNumber,
289                     mPacketCount,
290                     mByteCount,
291                     mReplayBitmap);
292         }
293     }
294 }
295