1 /** 2 * Copyright 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 17 package android.telephony.data; 18 19 import android.annotation.IntDef; 20 import android.annotation.NonNull; 21 import android.annotation.Nullable; 22 import android.net.InetAddresses; 23 import android.net.LinkAddress; 24 import android.os.Parcel; 25 import android.os.Parcelable; 26 27 import java.lang.annotation.Retention; 28 import java.lang.annotation.RetentionPolicy; 29 import java.net.InetAddress; 30 import java.net.Inet4Address; 31 import java.util.ArrayList; 32 import java.util.List; 33 import java.util.Objects; 34 35 /** 36 * Class that stores QOS filter parameters as defined in 37 * 3gpp 24.008 10.5.6.12 and 3gpp 24.501 9.11.4.13. 38 * 39 * @hide 40 */ 41 public final class QosBearerFilter implements Parcelable { 42 private @NonNull List<LinkAddress> localAddresses; 43 private @NonNull List<LinkAddress> remoteAddresses; 44 private @Nullable PortRange localPort; 45 private @Nullable PortRange remotePort; 46 47 /** @hide */ 48 @Retention(RetentionPolicy.SOURCE) 49 @IntDef(prefix = "QOS_PROTOCOL_", 50 value = {QOS_PROTOCOL_UNSPECIFIED, QOS_PROTOCOL_TCP, QOS_PROTOCOL_UDP, 51 QOS_PROTOCOL_ESP, QOS_PROTOCOL_AH}) 52 public @interface QosProtocol {} 53 54 public static final int QOS_PROTOCOL_UNSPECIFIED = 55 android.hardware.radio.V1_6.QosProtocol.UNSPECIFIED; 56 public static final int QOS_PROTOCOL_TCP = android.hardware.radio.V1_6.QosProtocol.TCP; 57 public static final int QOS_PROTOCOL_UDP = android.hardware.radio.V1_6.QosProtocol.UDP; 58 public static final int QOS_PROTOCOL_ESP = android.hardware.radio.V1_6.QosProtocol.ESP; 59 public static final int QOS_PROTOCOL_AH = android.hardware.radio.V1_6.QosProtocol.AH; 60 public static final int QOS_MIN_PORT = android.hardware.radio.V1_6.QosPortRange.MIN; 61 /** 62 * Hardcoded in place of android.hardware.radio.V1_6.QosPortRange.MAX as it 63 * returns -1 due to uint16_t to int conversion in java. (TODO: Fix the HAL) 64 */ 65 public static final int QOS_MAX_PORT = 65535; // android.hardware.radio.V1_6.QosPortRange.MIN; 66 67 private @QosProtocol int protocol; 68 69 private int typeOfServiceMask; 70 71 private long flowLabel; 72 73 /** IPSec security parameter index */ 74 private long securityParameterIndex; 75 76 /** @hide */ 77 @Retention(RetentionPolicy.SOURCE) 78 @IntDef(prefix = "QOS_FILTER_DIRECTION_", 79 value = {QOS_FILTER_DIRECTION_DOWNLINK, QOS_FILTER_DIRECTION_UPLINK, 80 QOS_FILTER_DIRECTION_BIDIRECTIONAL}) 81 public @interface QosBearerFilterDirection {} 82 83 public static final int QOS_FILTER_DIRECTION_DOWNLINK = 84 android.hardware.radio.V1_6.QosFilterDirection.DOWNLINK; 85 public static final int QOS_FILTER_DIRECTION_UPLINK = 86 android.hardware.radio.V1_6.QosFilterDirection.UPLINK; 87 public static final int QOS_FILTER_DIRECTION_BIDIRECTIONAL = 88 android.hardware.radio.V1_6.QosFilterDirection.BIDIRECTIONAL; 89 90 private @QosBearerFilterDirection int filterDirection; 91 92 /** 93 * Specified the order in which the filter needs to be matched. 94 * A Lower numerical value has a higher precedence. 95 */ 96 private int precedence; 97 QosBearerFilter()98 QosBearerFilter() { 99 localAddresses = new ArrayList<>(); 100 remoteAddresses = new ArrayList<>(); 101 localPort = new PortRange(); 102 remotePort = new PortRange(); 103 protocol = QOS_PROTOCOL_UNSPECIFIED; 104 filterDirection = QOS_FILTER_DIRECTION_BIDIRECTIONAL; 105 } 106 QosBearerFilter(@onNull List<LinkAddress> localAddresses, @NonNull List<LinkAddress> remoteAddresses, @Nullable PortRange localPort, @Nullable PortRange remotePort, @QosProtocol int protocol, int tos, long flowLabel, long spi, @QosBearerFilterDirection int direction, int precedence)107 public QosBearerFilter(@NonNull List<LinkAddress> localAddresses, 108 @NonNull List<LinkAddress> remoteAddresses, @Nullable PortRange localPort, 109 @Nullable PortRange remotePort, @QosProtocol int protocol, int tos, long flowLabel, 110 long spi, @QosBearerFilterDirection int direction, int precedence) { 111 this.localAddresses = localAddresses; 112 this.remoteAddresses = remoteAddresses; 113 this.localPort = localPort; 114 this.remotePort = remotePort; 115 this.protocol = protocol; 116 this.typeOfServiceMask = tos; 117 this.flowLabel = flowLabel; 118 this.securityParameterIndex = spi; 119 this.filterDirection = direction; 120 this.precedence = precedence; 121 } 122 getLocalAddresses()123 public @NonNull List<LinkAddress> getLocalAddresses() { 124 return localAddresses; 125 } 126 getRemoteAddresses()127 public @NonNull List<LinkAddress> getRemoteAddresses() { 128 return remoteAddresses; 129 } 130 getLocalPortRange()131 public @Nullable PortRange getLocalPortRange() { 132 return localPort; 133 } 134 getRemotePortRange()135 public @Nullable PortRange getRemotePortRange() { 136 return remotePort; 137 } 138 getPrecedence()139 public int getPrecedence() { 140 return precedence; 141 } 142 143 /** @hide */ create( @onNull android.hardware.radio.V1_6.QosFilter qosFilter)144 public static @NonNull QosBearerFilter create( 145 @NonNull android.hardware.radio.V1_6.QosFilter qosFilter) { 146 QosBearerFilter ret = new QosBearerFilter(); 147 148 String[] localAddresses = qosFilter.localAddresses.stream().toArray(String[]::new); 149 if (localAddresses != null) { 150 for (String address : localAddresses) { 151 ret.localAddresses.add(createLinkAddressFromString(address)); 152 } 153 } 154 155 String[] remoteAddresses = qosFilter.remoteAddresses.stream().toArray(String[]::new); 156 if (remoteAddresses != null) { 157 for (String address : remoteAddresses) { 158 ret.remoteAddresses.add(createLinkAddressFromString(address)); 159 } 160 } 161 162 if (qosFilter.localPort != null) { 163 if (qosFilter.localPort.getDiscriminator() 164 == android.hardware.radio.V1_6.MaybePort.hidl_discriminator.range) { 165 final android.hardware.radio.V1_6.PortRange portRange = qosFilter.localPort.range(); 166 ret.localPort.start = portRange.start; 167 ret.localPort.end = portRange.end; 168 } 169 } 170 171 if (qosFilter.remotePort != null) { 172 if (qosFilter.remotePort.getDiscriminator() 173 == android.hardware.radio.V1_6.MaybePort.hidl_discriminator.range) { 174 final android.hardware.radio.V1_6.PortRange portRange 175 = qosFilter.remotePort.range(); 176 ret.remotePort.start = portRange.start; 177 ret.remotePort.end = portRange.end; 178 } 179 } 180 181 ret.protocol = qosFilter.protocol; 182 183 if (qosFilter.tos != null) { 184 if (qosFilter.tos.getDiscriminator() 185 == android.hardware.radio.V1_6.QosFilter.TypeOfService.hidl_discriminator.value) { 186 ret.typeOfServiceMask = qosFilter.tos.value(); 187 } 188 } 189 190 if (qosFilter.flowLabel != null) { 191 if (qosFilter.flowLabel.getDiscriminator() 192 == android.hardware.radio.V1_6.QosFilter.Ipv6FlowLabel.hidl_discriminator.value) { 193 ret.flowLabel = qosFilter.flowLabel.value(); 194 } 195 } 196 197 if (qosFilter.spi != null) { 198 if (qosFilter.spi.getDiscriminator() 199 == android.hardware.radio.V1_6.QosFilter.IpsecSpi.hidl_discriminator.value) { 200 ret.securityParameterIndex = qosFilter.spi.value(); 201 } 202 } 203 204 ret.filterDirection = qosFilter.direction; 205 ret.precedence = qosFilter.precedence; 206 207 return ret; 208 } 209 210 public static class PortRange implements Parcelable { 211 int start; 212 int end; 213 PortRange()214 PortRange() { 215 start = -1; 216 end = -1; 217 } 218 PortRange(Parcel source)219 private PortRange(Parcel source) { 220 start = source.readInt(); 221 end = source.readInt(); 222 } 223 PortRange(int start, int end)224 public PortRange(int start, int end) { 225 this.start = start; 226 this.end = end; 227 } 228 getStart()229 public int getStart() { 230 return start; 231 } 232 getEnd()233 public int getEnd() { 234 return end; 235 } 236 isValid()237 public boolean isValid() { 238 return start >= QOS_MIN_PORT && start <= QOS_MAX_PORT 239 && end >= QOS_MIN_PORT && end <= QOS_MAX_PORT 240 && start <= end; 241 } 242 243 @Override writeToParcel(@onNull Parcel dest, int flags)244 public void writeToParcel(@NonNull Parcel dest, int flags) { 245 dest.writeInt(start); 246 dest.writeInt(end); 247 } 248 249 @Override describeContents()250 public int describeContents() { 251 return 0; 252 } 253 254 public static final @NonNull Parcelable.Creator<PortRange> CREATOR = 255 new Parcelable.Creator<PortRange>() { 256 @Override 257 public PortRange createFromParcel(Parcel source) { 258 return new PortRange(source); 259 } 260 261 @Override 262 public PortRange[] newArray(int size) { 263 return new PortRange[size]; 264 } 265 }; 266 267 @Override toString()268 public String toString() { 269 return "PortRange {" 270 + " start=" + start 271 + " end=" + end + "}"; 272 } 273 274 @Override equals(Object o)275 public boolean equals(Object o) { 276 if (this == o) return true; 277 278 if (o == null || !(o instanceof PortRange)) { 279 return false; 280 } 281 282 PortRange other = (PortRange) o; 283 return start == other.start 284 && end == other.end; 285 } 286 287 @Override hashCode()288 public int hashCode() { 289 return Objects.hash(start, end); 290 } 291 }; 292 293 @Override toString()294 public String toString() { 295 return "QosBearerFilter {" 296 + " localAddresses=" + localAddresses 297 + " remoteAddresses=" + remoteAddresses 298 + " localPort=" + localPort 299 + " remotePort=" + remotePort 300 + " protocol=" + protocol 301 + " typeOfServiceMask=" + typeOfServiceMask 302 + " flowLabel=" + flowLabel 303 + " securityParameterIndex=" + securityParameterIndex 304 + " filterDirection=" + filterDirection 305 + " precedence=" + precedence + "}"; 306 } 307 308 @Override hashCode()309 public int hashCode() { 310 return Objects.hash(localAddresses, remoteAddresses, localPort, 311 remotePort, protocol, typeOfServiceMask, flowLabel, 312 securityParameterIndex, filterDirection, precedence); 313 } 314 315 @Override equals(Object o)316 public boolean equals(Object o) { 317 if (this == o) return true; 318 319 if (o == null || !(o instanceof QosBearerFilter)) { 320 return false; 321 } 322 323 QosBearerFilter other = (QosBearerFilter) o; 324 325 return localAddresses.size() == other.localAddresses.size() 326 && localAddresses.containsAll(other.localAddresses) 327 && remoteAddresses.size() == other.remoteAddresses.size() 328 && remoteAddresses.containsAll(other.remoteAddresses) 329 && Objects.equals(localPort, other.localPort) 330 && Objects.equals(remotePort, other.remotePort) 331 && protocol == other.protocol 332 && typeOfServiceMask == other.typeOfServiceMask 333 && flowLabel == other.flowLabel 334 && securityParameterIndex == other.securityParameterIndex 335 && filterDirection == other.filterDirection 336 && precedence == other.precedence; 337 } 338 createLinkAddressFromString(String addressString)339 private static LinkAddress createLinkAddressFromString(String addressString) { 340 addressString = addressString.trim(); 341 InetAddress address = null; 342 int prefixLength = -1; 343 try { 344 String[] pieces = addressString.split("/", 2); 345 address = InetAddresses.parseNumericAddress(pieces[0]); 346 if (pieces.length == 1) { 347 prefixLength = (address instanceof Inet4Address) ? 32 : 128; 348 } else if (pieces.length == 2) { 349 prefixLength = Integer.parseInt(pieces[1]); 350 } 351 } catch (NullPointerException e) { // Null string. 352 } catch (ArrayIndexOutOfBoundsException e) { // No prefix length. 353 } catch (NumberFormatException e) { // Non-numeric prefix. 354 } catch (IllegalArgumentException e) { // Invalid IP address. 355 } 356 357 if (address == null || prefixLength == -1) { 358 throw new IllegalArgumentException("Invalid link address " + addressString); 359 } 360 361 return new LinkAddress(address, prefixLength, 0, 0, 362 LinkAddress.LIFETIME_UNKNOWN, LinkAddress.LIFETIME_UNKNOWN); 363 } 364 QosBearerFilter(Parcel source)365 private QosBearerFilter(Parcel source) { 366 localAddresses = new ArrayList<>(); 367 source.readList(localAddresses, LinkAddress.class.getClassLoader()); 368 remoteAddresses = new ArrayList<>(); 369 source.readList(remoteAddresses, LinkAddress.class.getClassLoader()); 370 localPort = source.readParcelable(PortRange.class.getClassLoader()); 371 remotePort = source.readParcelable(PortRange.class.getClassLoader()); 372 protocol = source.readInt(); 373 typeOfServiceMask = source.readInt(); 374 flowLabel = source.readLong(); 375 securityParameterIndex = source.readLong(); 376 filterDirection = source.readInt(); 377 precedence = source.readInt(); 378 } 379 380 @Override writeToParcel(@onNull Parcel dest, int flags)381 public void writeToParcel(@NonNull Parcel dest, int flags) { 382 dest.writeList(localAddresses); 383 dest.writeList(remoteAddresses); 384 dest.writeParcelable(localPort, flags); 385 dest.writeParcelable(remotePort, flags); 386 dest.writeInt(protocol); 387 dest.writeInt(typeOfServiceMask); 388 dest.writeLong(flowLabel); 389 dest.writeLong(securityParameterIndex); 390 dest.writeInt(filterDirection); 391 dest.writeInt(precedence); 392 } 393 394 @Override describeContents()395 public int describeContents() { 396 return 0; 397 } 398 399 public static final @NonNull Parcelable.Creator<QosBearerFilter> CREATOR = 400 new Parcelable.Creator<QosBearerFilter>() { 401 @Override 402 public QosBearerFilter createFromParcel(Parcel source) { 403 return new QosBearerFilter(source); 404 } 405 406 @Override 407 public QosBearerFilter[] newArray(int size) { 408 return new QosBearerFilter[size]; 409 } 410 }; 411 } 412