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