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