1 /*
2  * Copyright (C) 2021 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.net;
18 
19 import android.annotation.NonNull;
20 import android.annotation.Nullable;
21 import android.annotation.SystemApi;
22 import android.os.Parcel;
23 import android.os.Parcelable;
24 import android.util.Range;
25 
26 import com.android.net.module.util.InetAddressUtils;
27 
28 import java.net.Inet6Address;
29 import java.net.InetAddress;
30 import java.util.Objects;
31 
32 
33 /**
34  * DSCP policy to be set on the requesting NetworkAgent.
35  * @hide
36  */
37 @SystemApi
38 public final class DscpPolicy implements Parcelable {
39      /**
40      * Indicates that the policy does not specify a protocol.
41      */
42     public static final int PROTOCOL_ANY = -1;
43 
44     /**
45      * Indicates that the policy does not specify a port.
46      */
47     public static final int SOURCE_PORT_ANY = -1;
48 
49     /** The unique policy ID. Each requesting network is responsible for maintaining policy IDs
50      * unique within that network. In the case where a policy with an existing ID is created, the
51      * new policy will update the existing policy with the same ID.
52      */
53     private final int mPolicyId;
54 
55     /** The QoS DSCP marking to be added to packets matching the policy. */
56     private final int mDscp;
57 
58     /** The source IP address. */
59     private final @Nullable InetAddress mSrcAddr;
60 
61     /** The destination IP address. */
62     private final @Nullable InetAddress mDstAddr;
63 
64     /** The source port. */
65     private final int mSrcPort;
66 
67     /** The IP protocol that the policy requires. */
68     private final int mProtocol;
69 
70     /** Destination port range. Inclusive range. */
71     private final @Nullable Range<Integer> mDstPortRange;
72 
73     /**
74      * Implement the Parcelable interface
75      *
76      * @hide
77      */
describeContents()78     public int describeContents() {
79         return 0;
80     }
81 
DscpPolicy( int policyId, int dscp, @Nullable InetAddress srcAddr, @Nullable InetAddress dstAddr, int srcPort, int protocol, Range<Integer> dstPortRange)82     /* package */ DscpPolicy(
83             int policyId,
84             int dscp,
85             @Nullable InetAddress srcAddr,
86             @Nullable InetAddress dstAddr,
87             int srcPort,
88             int protocol,
89             Range<Integer> dstPortRange) {
90         this.mPolicyId = policyId;
91         this.mDscp = dscp;
92         this.mSrcAddr = srcAddr;
93         this.mDstAddr = dstAddr;
94         this.mSrcPort = srcPort;
95         this.mProtocol = protocol;
96         this.mDstPortRange = dstPortRange;
97 
98         if (mPolicyId < 1 || mPolicyId > 255) {
99             throw new IllegalArgumentException("Policy ID not in valid range: " + mPolicyId);
100         }
101         if (mDscp < 0 || mDscp > 63) {
102             throw new IllegalArgumentException("DSCP value not in valid range: " + mDscp);
103         }
104         // Since SOURCE_PORT_ANY is the default source port value need to allow it as well.
105         // TODO: Move the default value into this constructor or throw an error from the
106         // instead.
107         if (mSrcPort < -1 || mSrcPort > 65535) {
108             throw new IllegalArgumentException("Source port not in valid range: " + mSrcPort);
109         }
110         if (mDstPortRange != null
111                 && (dstPortRange.getLower() < 0 || mDstPortRange.getLower() > 65535)
112                 && (mDstPortRange.getUpper() < 0 || mDstPortRange.getUpper() > 65535)) {
113             throw new IllegalArgumentException("Destination port not in valid range");
114         }
115         if (mSrcAddr != null && mDstAddr != null && (mSrcAddr instanceof Inet6Address)
116                 != (mDstAddr instanceof Inet6Address)) {
117             throw new IllegalArgumentException("Source/destination address of different family");
118         }
119     }
120 
121     /**
122      * The unique policy ID.
123      *
124      * Each requesting network is responsible for maintaining unique
125      * policy IDs. In the case where a policy with an existing ID is created, the new
126      * policy will update the existing policy with the same ID
127      *
128      * @return Policy ID set in Builder.
129      */
getPolicyId()130     public int getPolicyId() {
131         return mPolicyId;
132     }
133 
134     /**
135      * The QoS DSCP marking to be added to packets matching the policy.
136      *
137      * @return DSCP value set in Builder.
138      */
getDscpValue()139     public int getDscpValue() {
140         return mDscp;
141     }
142 
143     /**
144      * The source IP address.
145      *
146      * @return Source IP address set in Builder or {@code null} if none was set.
147      */
getSourceAddress()148     public @Nullable InetAddress getSourceAddress() {
149         return mSrcAddr;
150     }
151 
152     /**
153      * The destination IP address.
154      *
155      * @return Destination IP address set in Builder or {@code null} if none was set.
156      */
getDestinationAddress()157     public @Nullable InetAddress getDestinationAddress() {
158         return mDstAddr;
159     }
160 
161     /**
162      * The source port.
163      *
164      * @return Source port set in Builder or {@link #SOURCE_PORT_ANY} if no port was set.
165      */
getSourcePort()166     public int getSourcePort() {
167         return mSrcPort;
168     }
169 
170     /**
171      * The IP protocol that the policy requires.
172      *
173      * @return Protocol set in Builder or {@link #PROTOCOL_ANY} if no protocol was set.
174      *         {@link #PROTOCOL_ANY} indicates that any protocol will be matched.
175      */
getProtocol()176     public int getProtocol() {
177         return mProtocol;
178     }
179 
180     /**
181      * Destination port range. Inclusive range.
182      *
183      * @return Range<Integer> set in Builder or {@code null} if none was set.
184      */
getDestinationPortRange()185     public @Nullable Range<Integer> getDestinationPortRange() {
186         return mDstPortRange;
187     }
188 
189     @Override
toString()190     public String toString() {
191         return "DscpPolicy { "
192                 + "policyId = " + mPolicyId + ", "
193                 + "dscp = " + mDscp + ", "
194                 + "srcAddr = " + mSrcAddr + ", "
195                 + "dstAddr = " + mDstAddr + ", "
196                 + "srcPort = " + mSrcPort + ", "
197                 + "protocol = " + mProtocol + ", "
198                 + "dstPortRange = "
199                 + (mDstPortRange == null ? "none" : mDstPortRange.toString())
200                 + " }";
201     }
202 
203     @Override
equals(@ullable Object o)204     public boolean equals(@Nullable Object o) {
205         if (this == o) return true;
206         if (!(o instanceof DscpPolicy)) return false;
207         DscpPolicy that = (DscpPolicy) o;
208         return true
209                 && mPolicyId == that.mPolicyId
210                 && mDscp == that.mDscp
211                 && Objects.equals(mSrcAddr, that.mSrcAddr)
212                 && Objects.equals(mDstAddr, that.mDstAddr)
213                 && mSrcPort == that.mSrcPort
214                 && mProtocol == that.mProtocol
215                 && Objects.equals(mDstPortRange, that.mDstPortRange);
216     }
217 
218     @Override
hashCode()219     public int hashCode() {
220         return Objects.hash(mPolicyId, mDscp, mSrcAddr.hashCode(),
221                 mDstAddr.hashCode(), mSrcPort, mProtocol, mDstPortRange.hashCode());
222     }
223 
224     /** @hide */
225     @Override
writeToParcel(@onNull Parcel dest, int flags)226     public void writeToParcel(@NonNull Parcel dest, int flags) {
227         dest.writeInt(mPolicyId);
228         dest.writeInt(mDscp);
229         InetAddressUtils.parcelInetAddress(dest, mSrcAddr, flags);
230         InetAddressUtils.parcelInetAddress(dest, mDstAddr, flags);
231         dest.writeInt(mSrcPort);
232         dest.writeInt(mProtocol);
233         dest.writeBoolean(mDstPortRange != null ? true : false);
234         if (mDstPortRange != null) {
235             dest.writeInt(mDstPortRange.getLower());
236             dest.writeInt(mDstPortRange.getUpper());
237         }
238     }
239 
240     /** @hide */
DscpPolicy(@onNull Parcel in)241     DscpPolicy(@NonNull Parcel in) {
242         this.mPolicyId = in.readInt();
243         this.mDscp = in.readInt();
244         this.mSrcAddr = InetAddressUtils.unparcelInetAddress(in);
245         this.mDstAddr = InetAddressUtils.unparcelInetAddress(in);
246         this.mSrcPort = in.readInt();
247         this.mProtocol = in.readInt();
248         if (in.readBoolean()) {
249             this.mDstPortRange = new Range<Integer>(in.readInt(), in.readInt());
250         } else {
251             this.mDstPortRange = null;
252         }
253     }
254 
255     /** @hide */
256     public @SystemApi static final @NonNull Parcelable.Creator<DscpPolicy> CREATOR =
257             new Parcelable.Creator<DscpPolicy>() {
258                 @Override
259                 public DscpPolicy[] newArray(int size) {
260                     return new DscpPolicy[size];
261                 }
262 
263                 @Override
264                 public DscpPolicy createFromParcel(@NonNull android.os.Parcel in) {
265                     return new DscpPolicy(in);
266                 }
267             };
268 
269     /**
270      * A builder for {@link DscpPolicy}
271      *
272      */
273     public static final class Builder {
274 
275         private final int mPolicyId;
276         private final int mDscp;
277         private @Nullable InetAddress mSrcAddr;
278         private @Nullable InetAddress mDstAddr;
279         private int mSrcPort = SOURCE_PORT_ANY;
280         private int mProtocol = PROTOCOL_ANY;
281         private @Nullable Range<Integer> mDstPortRange;
282 
283         private long mBuilderFieldsSet = 0L;
284 
285         /**
286          * Creates a new Builder.
287          *
288          * @param policyId The unique policy ID. Each requesting network is responsible for
289          *                 maintaining unique policy IDs. In the case where a policy with an
290          *                 existing ID is created, the new policy will update the existing
291          *                 policy with the same ID
292          * @param dscpValue The DSCP value to set.
293          */
Builder(int policyId, int dscpValue)294         public Builder(int policyId, int dscpValue) {
295             mPolicyId = policyId;
296             mDscp = dscpValue;
297         }
298 
299         /**
300          * Specifies that this policy matches packets with the specified source IP address.
301          */
setSourceAddress(@onNull InetAddress value)302         public @NonNull Builder setSourceAddress(@NonNull InetAddress value) {
303             mSrcAddr = value;
304             return this;
305         }
306 
307         /**
308          * Specifies that this policy matches packets with the specified destination IP address.
309          */
setDestinationAddress(@onNull InetAddress value)310         public @NonNull Builder setDestinationAddress(@NonNull InetAddress value) {
311             mDstAddr = value;
312             return this;
313         }
314 
315         /**
316          * Specifies that this policy matches packets with the specified source port.
317          */
setSourcePort(int value)318         public @NonNull Builder setSourcePort(int value) {
319             mSrcPort = value;
320             return this;
321         }
322 
323         /**
324          * Specifies that this policy matches packets with the specified protocol.
325          */
setProtocol(int value)326         public @NonNull Builder setProtocol(int value) {
327             mProtocol = value;
328             return this;
329         }
330 
331         /**
332          * Specifies that this policy matches packets with the specified destination port range.
333          */
setDestinationPortRange(@onNull Range<Integer> range)334         public @NonNull Builder setDestinationPortRange(@NonNull Range<Integer> range) {
335             mDstPortRange = range;
336             return this;
337         }
338 
339         /**
340          * Constructs a DscpPolicy with the specified parameters.
341          */
build()342         public @NonNull DscpPolicy build() {
343             return new DscpPolicy(
344                     mPolicyId,
345                     mDscp,
346                     mSrcAddr,
347                     mDstAddr,
348                     mSrcPort,
349                     mProtocol,
350                     mDstPortRange);
351         }
352     }
353 }
354