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 
17 package android.net.wifi;
18 
19 import android.annotation.FlaggedApi;
20 import android.annotation.IntDef;
21 import android.annotation.IntRange;
22 import android.annotation.NonNull;
23 import android.annotation.Nullable;
24 import android.annotation.SystemApi;
25 import android.net.DscpPolicy;
26 import android.os.Build;
27 import android.os.Parcel;
28 import android.os.Parcelable;
29 import android.util.Log;
30 
31 import androidx.annotation.RequiresApi;
32 
33 import com.android.modules.utils.build.SdkLevel;
34 import com.android.wifi.flags.Flags;
35 
36 import java.lang.annotation.Retention;
37 import java.lang.annotation.RetentionPolicy;
38 import java.net.Inet4Address;
39 import java.net.Inet6Address;
40 import java.net.InetAddress;
41 import java.util.Arrays;
42 import java.util.Objects;
43 
44 /**
45  * Parameters for QoS policies requested by system applications.
46  * @hide
47  */
48 @SystemApi
49 public final class QosPolicyParams implements Parcelable {
50     private static final String TAG = "QosPolicyParams";
51 
52     /**
53      * Indicates that the policy does not specify a DSCP value.
54      */
55     public static final int DSCP_ANY = -1;
56 
57     /**
58      * Indicates that the policy does not specify a protocol.
59      */
60     public static final int PROTOCOL_ANY = DscpPolicy.PROTOCOL_ANY;
61 
62     /**
63      * Policy should match packets using the TCP protocol.
64      */
65     public static final int PROTOCOL_TCP = 6;
66 
67     /**
68      * Policy should match packets using the UDP protocol.
69      */
70     public static final int PROTOCOL_UDP = 17;
71 
72     /**
73      * Policy should match packets using the ESP protocol.
74      */
75     public static final int PROTOCOL_ESP = 50;
76 
77     /** @hide */
78     @IntDef(prefix = { "PROTOCOL_" }, value = {
79             PROTOCOL_ANY,
80             PROTOCOL_TCP,
81             PROTOCOL_UDP,
82             PROTOCOL_ESP
83     })
84     @Retention(RetentionPolicy.SOURCE)
85     public @interface Protocol {}
86 
87     /**
88      * Policy should match packets in the uplink direction.
89      */
90     public static final int DIRECTION_UPLINK = 0;
91 
92     /**
93      * Policy should match packets in the downlink direction.
94      */
95     public static final int DIRECTION_DOWNLINK = 1;
96 
97 
98     /** @hide */
99     @IntDef(prefix = { "DIRECTION_" }, value = {
100             DIRECTION_UPLINK,
101             DIRECTION_DOWNLINK,
102     })
103     @Retention(RetentionPolicy.SOURCE)
104     public @interface Direction {}
105 
106     /**
107      * Indicates that the policy does not specify a User Priority.
108      */
109     public static final int USER_PRIORITY_ANY = -1;
110 
111     /**
112      * Policy should be assigned a low background priority.
113      */
114     public static final int USER_PRIORITY_BACKGROUND_LOW = 1;
115 
116     /**
117      * Policy should be assigned a high background priority.
118      */
119     public static final int USER_PRIORITY_BACKGROUND_HIGH = 2;
120 
121     /**
122      * Policy should be assigned a low best-effort priority.
123      */
124     public static final int USER_PRIORITY_BEST_EFFORT_LOW = 0;
125 
126     /**
127      * Policy should be assigned a high best-effort priority.
128      */
129     public static final int USER_PRIORITY_BEST_EFFORT_HIGH = 3;
130 
131     /**
132      * Policy should be assigned a low video priority.
133      */
134     public static final int USER_PRIORITY_VIDEO_LOW = 4;
135 
136     /**
137      * Policy should be assigned a high video priority.
138      */
139     public static final int USER_PRIORITY_VIDEO_HIGH = 5;
140 
141     /**
142      * Policy should be assigned a low voice priority.
143      */
144     public static final int USER_PRIORITY_VOICE_LOW = 6;
145 
146     /**
147      * Policy should be assigned a high voice priority.
148      */
149     public static final int USER_PRIORITY_VOICE_HIGH = 7;
150 
151     /** @hide */
152     @IntDef(prefix = { "USER_PRIORITY_" }, value = {
153             USER_PRIORITY_ANY,
154             USER_PRIORITY_BACKGROUND_LOW,
155             USER_PRIORITY_BACKGROUND_HIGH,
156             USER_PRIORITY_BEST_EFFORT_LOW,
157             USER_PRIORITY_BEST_EFFORT_HIGH,
158             USER_PRIORITY_VIDEO_LOW,
159             USER_PRIORITY_VIDEO_HIGH,
160             USER_PRIORITY_VOICE_LOW,
161             USER_PRIORITY_VOICE_HIGH,
162     })
163     @Retention(RetentionPolicy.SOURCE)
164     public @interface UserPriority {}
165 
166     /**
167      * Indicates that the policy does not specify an IP version.
168      */
169     public static final int IP_VERSION_ANY = -1;
170 
171     /**
172      * Policy should match packets using IPv4.
173      */
174     public static final int IP_VERSION_4 = 4;
175 
176     /**
177      * Policy should match packets using IPv6.
178      */
179     public static final int IP_VERSION_6 = 6;
180 
181     /** @hide */
182     @IntDef(prefix = { "IP_VERSION_" }, value = {
183             IP_VERSION_ANY,
184             IP_VERSION_4,
185             IP_VERSION_6
186     })
187     @Retention(RetentionPolicy.SOURCE)
188     public @interface IpVersion {}
189 
190     /**
191      * Indicates that the policy does not specify a destination port.
192      */
193     public static final int DESTINATION_PORT_ANY = -1;
194 
195     /**
196      * Unique policy ID. See {@link Builder#Builder(int, int)} for more information.
197      */
198     private final int mPolicyId;
199 
200     /**
201      * Translated policy ID. Should only be set by the Wi-Fi service.
202      * @hide
203      */
204     private int mTranslatedPolicyId;
205 
206     // QoS DSCP marking. See {@link Builder#setDscp(int)} for more information.
207     private final int mDscp;
208 
209     // User priority to apply to packets matching the policy. Only applicable to downlink requests.
210     private final int mUserPriority;
211 
212     // Source IP address.
213     private final @Nullable InetAddress mSrcIp;
214 
215     // Destination IP address.
216     private final @Nullable InetAddress mDstIp;
217 
218     // Source port.
219     private final int mSrcPort;
220 
221     // IP protocol that the policy requires.
222     private final @Protocol int mProtocol;
223 
224     // Single destination port. Only applicable to downlink requests.
225     private final int mDstPort;
226 
227     // Destination port range. Inclusive range. Only applicable to uplink requests.
228     private final @Nullable int[] mDstPortRange;
229 
230     // Direction of traffic stream.
231     private final @Direction int mDirection;
232 
233     // IP version. Only applicable to downlink requests.
234     private final @IpVersion int mIpVersion;
235 
236     // Flow label. Only applicable to downlink requests using IPv6.
237     private final @Nullable byte[] mFlowLabel;
238 
239     // QoS characteristics. Mandatory for uplink requests.
240     private final @Nullable QosCharacteristics mQosCharacteristics;
241 
QosPolicyParams(int policyId, int dscp, @UserPriority int userPriority, @Nullable InetAddress srcIp, @Nullable InetAddress dstIp, int srcPort, @Protocol int protocol, @Nullable int[] dstPortRange, @Direction int direction, @IpVersion int ipVersion, int dstPort, @Nullable byte[] flowLabel, @Nullable QosCharacteristics qosCharacteristics)242     private QosPolicyParams(int policyId, int dscp, @UserPriority int userPriority,
243             @Nullable InetAddress srcIp, @Nullable InetAddress dstIp, int srcPort,
244             @Protocol int protocol, @Nullable int[] dstPortRange, @Direction int direction,
245             @IpVersion int ipVersion, int dstPort, @Nullable byte[] flowLabel,
246             @Nullable QosCharacteristics qosCharacteristics) {
247         this.mPolicyId = policyId;
248         this.mDscp = dscp;
249         this.mUserPriority = userPriority;
250         this.mSrcIp = srcIp;
251         this.mDstIp = dstIp;
252         this.mSrcPort = srcPort;
253         this.mProtocol = protocol;
254         this.mDstPort = dstPort;
255         this.mDstPortRange = dstPortRange;
256         this.mDirection = direction;
257         this.mIpVersion = ipVersion;
258         this.mFlowLabel = flowLabel;
259         this.mQosCharacteristics = qosCharacteristics;
260     }
261 
262     /**
263      * Validate the parameters in this instance.
264      *
265      * @return true if all parameters are valid, false otherwise
266      * @hide
267      */
validate()268     public boolean validate() {
269         if (mPolicyId < 1 || mPolicyId > 255) {
270             Log.e(TAG, "Policy ID not in valid range: " + mPolicyId);
271             return false;
272         }
273         if (mDscp < DSCP_ANY || mDscp > 63) {
274             Log.e(TAG, "DSCP value not in valid range: " + mDscp);
275             return false;
276         }
277         if (mUserPriority < USER_PRIORITY_ANY || mUserPriority > USER_PRIORITY_VOICE_HIGH) {
278             Log.e(TAG, "User priority not in valid range: " + mUserPriority);
279             return false;
280         }
281         if (mSrcPort < DscpPolicy.SOURCE_PORT_ANY || mSrcPort > 65535) {
282             Log.e(TAG, "Source port not in valid range: " + mSrcPort);
283             return false;
284         }
285         if (mDstPort < DESTINATION_PORT_ANY || mDstPort > 65535) {
286             Log.e(TAG, "Destination port not in valid range: " + mDstPort);
287             return false;
288         }
289         if (mDstPortRange != null && (mDstPortRange[0] < 0 || mDstPortRange[0] > 65535
290                 || mDstPortRange[1] < 0 || mDstPortRange[1] > 65535)) {
291             Log.e(TAG, "Dst port range value not valid. start="
292                     + mDstPortRange[0] + ", end=" + mDstPortRange[1]);
293             return false;
294         }
295         if (!(mDirection == DIRECTION_UPLINK || mDirection == DIRECTION_DOWNLINK)) {
296             Log.e(TAG, "Invalid direction enum: " + mDirection);
297             return false;
298         }
299         if (!(mIpVersion == IP_VERSION_ANY || mIpVersion == IP_VERSION_4
300                 || mIpVersion == IP_VERSION_6)) {
301             Log.e(TAG, "Invalid ipVersion enum: " + mIpVersion);
302             return false;
303         }
304         if (mIpVersion == IP_VERSION_4) {
305             if (mSrcIp != null && !(mSrcIp instanceof Inet4Address)) {
306                 Log.e(TAG, "Src address does not match IP version " + mIpVersion);
307                 return false;
308             }
309             if (mDstIp != null && !(mDstIp instanceof Inet4Address)) {
310                 Log.e(TAG, "Dst address does not match IP version " + mIpVersion);
311                 return false;
312             }
313         }
314         if (mIpVersion == IP_VERSION_6) {
315             if (mSrcIp != null && !(mSrcIp instanceof Inet6Address)) {
316                 Log.e(TAG, "Src address does not match IP version " + mIpVersion);
317                 return false;
318             }
319             if (mDstIp != null && !(mDstIp instanceof Inet6Address)) {
320                 Log.e(TAG, "Dst address does not match IP version " + mIpVersion);
321                 return false;
322             }
323         }
324         if (mQosCharacteristics != null && !mQosCharacteristics.validate()) {
325             Log.e(TAG, "Invalid QoS characteristics provided");
326             return false;
327         }
328 
329         // Check required parameters based on direction.
330         if (mDirection == DIRECTION_UPLINK) {
331             if (mQosCharacteristics == null) {
332                 Log.e(TAG, "QoS characteristics must be provided for uplink requests");
333                 return false;
334             }
335             if (mIpVersion != IP_VERSION_ANY) {
336                 Log.e(TAG, "IP Version should not be set for uplink requests");
337                 return false;
338             }
339             if (mDstPort != DESTINATION_PORT_ANY) {
340                 Log.e(TAG, "Single destination port should not be set for uplink requests");
341                 return false;
342             }
343             if (mFlowLabel != null) {
344                 Log.e(TAG, "Flow label should not be set for uplink requests");
345                 return false;
346             }
347         } else {
348             if (mUserPriority == USER_PRIORITY_ANY) {
349                 Log.e(TAG, "User priority must be provided for downlink requests");
350                 return false;
351             }
352             if (mIpVersion == IP_VERSION_ANY) {
353                 Log.e(TAG, "IP version must be provided for downlink requests");
354                 return false;
355             }
356             if (mDstPortRange != null) {
357                 Log.e(TAG, "Destination port range should not be set for downlink requests");
358                 return false;
359             }
360             if (mFlowLabel != null) {
361                 if (mIpVersion != IP_VERSION_6) {
362                     Log.e(TAG, "Flow label can only be used with IP version 6");
363                     return false;
364                 }
365                 if (mFlowLabel.length != 3) {
366                     Log.e(TAG, "Flow label must be of size 3, provided size is "
367                             + mFlowLabel.length);
368                     return false;
369                 }
370             }
371         }
372         return true;
373     }
374 
375     /**
376      * Set the translated policy ID for this policy.
377      *
378      * Note: Translated policy IDs should only be set by the Wi-Fi service.
379      * @hide
380      */
setTranslatedPolicyId(int translatedPolicyId)381     public void setTranslatedPolicyId(int translatedPolicyId) {
382         mTranslatedPolicyId = translatedPolicyId;
383     }
384 
385     /**
386      * Get the ID for this policy.
387      *
388      * See {@link Builder#Builder(int, int)} for more information.
389      */
390     @IntRange(from = 1, to = 255)
getPolicyId()391     public int getPolicyId() {
392         return mPolicyId;
393     }
394 
395     /**
396      * Get the translated ID for this policy.
397      *
398      * See {@link #setTranslatedPolicyId} for more information.
399      * @hide
400      */
getTranslatedPolicyId()401     public int getTranslatedPolicyId() {
402         return mTranslatedPolicyId;
403     }
404 
405 
406     /**
407      * Get the DSCP value for this policy.
408      *
409      * See {@link Builder#setDscp(int)} for more information.
410      *
411      * @return DSCP value, or {@link #DSCP_ANY} if not assigned.
412      */
413     @IntRange(from = DSCP_ANY, to = 63)
getDscp()414     public int getDscp() {
415         return mDscp;
416     }
417 
418     /**
419      * Get the User Priority (UP) for this policy.
420      *
421      * See {@link Builder#setUserPriority(int)} for more information.
422      *
423      * @return User Priority value, or {@link #USER_PRIORITY_ANY} if not assigned.
424      */
getUserPriority()425     public @UserPriority int getUserPriority() {
426         return mUserPriority;
427     }
428 
429     /**
430      * Get the source IP address for this policy.
431      *
432      * See {@link Builder#setSourceAddress(InetAddress)} for more information.
433      *
434      * @return source IP address, or null if not assigned.
435      */
getSourceAddress()436     public @Nullable InetAddress getSourceAddress() {
437         return mSrcIp;
438     }
439 
440     /**
441      * Get the destination IP address for this policy.
442      *
443      * See {@link Builder#setDestinationAddress(InetAddress)} for more information.
444      *
445      * @return destination IP address, or null if not assigned.
446      */
getDestinationAddress()447     public @Nullable InetAddress getDestinationAddress() {
448         return mDstIp;
449     }
450 
451     /**
452      * Get the source port for this policy.
453      *
454      * See {@link Builder#setSourcePort(int)} for more information.
455      *
456      * @return source port, or {@link DscpPolicy#SOURCE_PORT_ANY} if not assigned.
457      */
458     @IntRange(from = DscpPolicy.SOURCE_PORT_ANY, to = 65535)
getSourcePort()459     public int getSourcePort() {
460         return mSrcPort;
461     }
462 
463     /**
464      * Get the protocol for this policy.
465      *
466      * See {@link Builder#setProtocol(int)} for more information.
467      *
468      * @return protocol, or {@link #PROTOCOL_ANY} if not assigned.
469      */
getProtocol()470     public @Protocol int getProtocol() {
471         return mProtocol;
472     }
473 
474     /**
475      * Get the destination port for this policy.
476      *
477      * See {@link Builder#setDestinationPort(int)} for more information.
478      *
479      * @return destination port, or {@link #DESTINATION_PORT_ANY} if not assigned.
480      */
481     @IntRange(from = DESTINATION_PORT_ANY, to = 65535)
getDestinationPort()482     public int getDestinationPort() {
483         return mDstPort;
484     }
485 
486     /**
487      * Get the destination port range for this policy.
488      *
489      * See {@link Builder#setDestinationPortRange(int, int)} for more information.
490      *
491      * @return destination port range, or null if not assigned.
492      */
getDestinationPortRange()493     public @Nullable int[] getDestinationPortRange() {
494         return mDstPortRange;
495     }
496 
497     /**
498      * Get the direction for this policy.
499      *
500      * See {@link Builder#Builder(int, int)} for more information.
501      */
getDirection()502     public @Direction int getDirection() {
503         return mDirection;
504     }
505 
506     /**
507      * Get the IP version for this policy.
508      *
509      * See {@link Builder#setIpVersion(int)} for more information.
510      *
511      * @return IP version, or {@link #IP_VERSION_ANY} if not assigned.
512      */
getIpVersion()513     public @IpVersion int getIpVersion() {
514         return mIpVersion;
515     }
516 
517     /**
518      * Get the flow label for this policy.
519      *
520      * See {@link Builder#setFlowLabel(byte[])} for more information.
521      *
522      * @return flow label, or null if not assigned.
523      */
getFlowLabel()524     public @Nullable byte[] getFlowLabel() {
525         return mFlowLabel;
526     }
527 
528     /**
529      * Get the QoS characteristics for this policy.
530      *
531      * See {@link Builder#setQosCharacteristics(QosCharacteristics)} for more information.
532      *
533      * @return QoS characteristics object, or null if not assigned.
534      */
535     @RequiresApi(Build.VERSION_CODES.VANILLA_ICE_CREAM)
536     @FlaggedApi(Flags.FLAG_ANDROID_V_WIFI_API)
getQosCharacteristics()537     public @Nullable QosCharacteristics getQosCharacteristics() {
538         if (!SdkLevel.isAtLeastV()) {
539             throw new UnsupportedOperationException();
540         }
541         return mQosCharacteristics;
542     }
543 
544     @Override
equals(@ullable Object o)545     public boolean equals(@Nullable Object o) {
546         if (this == o) return true;
547         if (o == null || getClass() != o.getClass()) return false;
548         QosPolicyParams that = (QosPolicyParams) o;
549         return mPolicyId == that.mPolicyId
550                 && mDscp == that.mDscp
551                 && mUserPriority == that.mUserPriority
552                 && mSrcIp.equals(that.mSrcIp)
553                 && mDstIp.equals(that.mDstIp)
554                 && mSrcPort == that.mSrcPort
555                 && mProtocol == that.mProtocol
556                 && mDstPort == that.mDstPort
557                 && Arrays.equals(mDstPortRange, that.mDstPortRange)
558                 && mDirection == that.mDirection
559                 && mIpVersion == that.mIpVersion
560                 && mFlowLabel == that.mFlowLabel
561                 && Objects.equals(mQosCharacteristics, that.mQosCharacteristics);
562     }
563 
564     @Override
hashCode()565     public int hashCode() {
566         return Objects.hash(mPolicyId, mDscp, mUserPriority, mSrcIp, mDstIp, mSrcPort,
567                 mProtocol, Arrays.hashCode(mDstPortRange), mDirection, mIpVersion, mDstPort,
568                 Arrays.hashCode(mFlowLabel), mQosCharacteristics);
569     }
570 
571     @Override
toString()572     public String toString() {
573         return "{policyId=" + mPolicyId + ", "
574                 + "dscp=" + mDscp + ", "
575                 + "userPriority=" + mUserPriority + ", "
576                 + "srcIp=" + mSrcIp + ", "
577                 + "dstIp=" + mDstIp + ", "
578                 + "srcPort=" + mSrcPort + ", "
579                 + "protocol=" + mProtocol + ", "
580                 + "dstPort=" + mDstPort + ", "
581                 + "dstPortRange=" + Arrays.toString(mDstPortRange) + ", "
582                 + "direction=" + mDirection + ", "
583                 + "ipVersion=" + mIpVersion + ", "
584                 + "flowLabel=" + Arrays.toString(mFlowLabel) + ", "
585                 + "qosCharacteristics=" + mQosCharacteristics + "}";
586     }
587 
588     /** @hide */
589     @Override
describeContents()590     public int describeContents() {
591         return 0;
592     }
593 
getInetAddrOrNull(byte[] byteAddr)594     private InetAddress getInetAddrOrNull(byte[] byteAddr) {
595         if (byteAddr == null) return null;
596         try {
597             return InetAddress.getByAddress(byteAddr);
598         } catch (Exception e) {
599             return null;
600         }
601     }
602 
603     /** @hide */
604     @Override
writeToParcel(@onNull Parcel dest, int flags)605     public void writeToParcel(@NonNull Parcel dest, int flags) {
606         dest.writeInt(mPolicyId);
607         dest.writeInt(mDscp);
608         dest.writeInt(mUserPriority);
609         dest.writeByteArray(mSrcIp != null ? mSrcIp.getAddress() : null);
610         dest.writeByteArray(mDstIp != null ? mDstIp.getAddress() : null);
611         dest.writeInt(mSrcPort);
612         dest.writeInt(mProtocol);
613         dest.writeInt(mDstPort);
614         dest.writeIntArray(mDstPortRange);
615         dest.writeInt(mDirection);
616         dest.writeInt(mIpVersion);
617         dest.writeByteArray(mFlowLabel);
618         if (SdkLevel.isAtLeastV()) {
619             dest.writeParcelable(mQosCharacteristics, 0);
620         }
621     }
622 
623     /** @hide */
QosPolicyParams(@onNull Parcel in)624     QosPolicyParams(@NonNull Parcel in) {
625         this.mPolicyId = in.readInt();
626         this.mDscp = in.readInt();
627         this.mUserPriority = in.readInt();
628         this.mSrcIp = getInetAddrOrNull(in.createByteArray());
629         this.mDstIp = getInetAddrOrNull(in.createByteArray());
630         this.mSrcPort = in.readInt();
631         this.mProtocol = in.readInt();
632         this.mDstPort = in.readInt();
633         this.mDstPortRange = in.createIntArray();
634         this.mDirection = in.readInt();
635         this.mIpVersion = in.readInt();
636         this.mFlowLabel = in.createByteArray();
637         if (SdkLevel.isAtLeastV()) {
638             this.mQosCharacteristics = in.readParcelable(
639                     QosCharacteristics.class.getClassLoader(), QosCharacteristics.class);
640         } else {
641             this.mQosCharacteristics = null;
642         }
643     }
644 
645     public static final @NonNull Parcelable.Creator<QosPolicyParams> CREATOR =
646             new Parcelable.Creator<QosPolicyParams>() {
647                 @Override
648                 public QosPolicyParams createFromParcel(Parcel in) {
649                     return new QosPolicyParams(in);
650                 }
651 
652                 @Override
653                 public QosPolicyParams[] newArray(int size) {
654                     return new QosPolicyParams[size];
655                 }
656             };
657 
658     /**
659      * Builder for {@link QosPolicyParams}.
660      */
661     public static final class Builder {
662         private final int mPolicyId;
663         private final @Direction int mDirection;
664         private @Nullable InetAddress mSrcIp;
665         private @Nullable InetAddress mDstIp;
666         private int mDscp = DSCP_ANY;
667         private @UserPriority int mUserPriority = USER_PRIORITY_ANY;
668         private int mSrcPort = DscpPolicy.SOURCE_PORT_ANY;
669         private int mProtocol = PROTOCOL_ANY;
670         private int mDstPort = DESTINATION_PORT_ANY;
671         private @Nullable int[] mDstPortRange;
672         private @IpVersion int mIpVersion = IP_VERSION_ANY;
673         private byte[] mFlowLabel;
674         private @Nullable QosCharacteristics mQosCharacteristics;
675 
676         /**
677          * Constructor for {@link Builder}.
678          *
679          * @param policyId Unique ID to identify this policy. Each requesting application is
680          *                 responsible for maintaining policy IDs unique for that app. IDs must be
681          *                 in the range 1 <= policyId <= 255.
682          *
683          *                 In the case where a policy with an existing ID is created, the new policy
684          *                 will be rejected. To update an existing policy, remove the existing one
685          *                 before sending the new one.
686          * @param direction Whether this policy applies to the uplink or downlink direction.
687          */
Builder(@ntRangefrom = 1, to = 255) int policyId, @Direction int direction)688         public Builder(@IntRange(from = 1, to = 255) int policyId, @Direction int direction) {
689             mPolicyId = policyId;
690             mDirection = direction;
691         }
692 
693         /**
694          * Specifies that this policy matches packets with the provided source IP address.
695          */
setSourceAddress(@ullable InetAddress value)696         public @NonNull Builder setSourceAddress(@Nullable InetAddress value) {
697             mSrcIp = value;
698             return this;
699         }
700 
701         /**
702          * Specifies that this policy matches packets with the provided destination IP address.
703          */
setDestinationAddress(@ullable InetAddress value)704         public @NonNull Builder setDestinationAddress(@Nullable InetAddress value) {
705             mDstIp = value;
706             return this;
707         }
708 
709         /**
710          * Specifies the DSCP value. For uplink requests, this value will be applied to packets
711          * that match the classifier. For downlink requests, this will be part of the classifier.
712          */
setDscp(@ntRangefrom = DSCP_ANY, to = 63) int value)713         public @NonNull Builder setDscp(@IntRange(from = DSCP_ANY, to = 63) int value) {
714             mDscp = value;
715             return this;
716         }
717 
718         /**
719          * Specifies that the provided User Priority should be applied to packets that
720          * match this classifier. Only applicable to downlink requests.
721          */
setUserPriority(@serPriority int value)722         public @NonNull Builder setUserPriority(@UserPriority int value) {
723             mUserPriority = value;
724             return this;
725         }
726 
727         /**
728          * Specifies that this policy matches packets with the provided source port.
729          */
setSourcePort( @ntRangefrom = DscpPolicy.SOURCE_PORT_ANY, to = 65535) int value)730         public @NonNull Builder setSourcePort(
731                 @IntRange(from = DscpPolicy.SOURCE_PORT_ANY, to = 65535) int value) {
732             mSrcPort = value;
733             return this;
734         }
735 
736         /**
737          * Specifies that this policy matches packets with the provided protocol.
738          */
setProtocol(@rotocol int value)739         public @NonNull Builder setProtocol(@Protocol int value) {
740             mProtocol = value;
741             return this;
742         }
743 
744         /**
745          * Specifies that this policy matches packets with the provided destination port.
746          * Only applicable to downlink requests.
747          */
setDestinationPort( @ntRangefrom = DESTINATION_PORT_ANY, to = 65535) int value)748         public @NonNull Builder setDestinationPort(
749                 @IntRange(from = DESTINATION_PORT_ANY, to = 65535) int value) {
750             mDstPort = value;
751             return this;
752         }
753 
754         /**
755          * Specifies that this policy matches packets with the provided destination port range.
756          * Only applicable to uplink requests.
757          */
setDestinationPortRange( @ntRangefrom = 0, to = 65535) int start, @IntRange(from = 0, to = 65535) int end)758         public @NonNull Builder setDestinationPortRange(
759                 @IntRange(from = 0, to = 65535) int start,
760                 @IntRange(from = 0, to = 65535) int end) {
761             mDstPortRange = new int[]{start, end};
762             return this;
763         }
764 
765         /**
766          * Specifies that this policy matches packets with the provided IP version.
767          * This argument is mandatory for downlink requests, and is ignored for uplink requests.
768          */
setIpVersion(@pVersion int value)769         public @NonNull Builder setIpVersion(@IpVersion int value) {
770             mIpVersion = value;
771             return this;
772         }
773 
774         /**
775          * Specifies that this policy matches packets with the provided flow label.
776          * Only applicable to downlink requests using IPv6.
777          */
setFlowLabel(@ullable byte[] value)778         public @NonNull Builder setFlowLabel(@Nullable byte[] value) {
779             mFlowLabel = value;
780             return this;
781         }
782 
783         /**
784          * Specifies traffic flow parameters to use for this policy request.
785          * This argument is mandatory for uplink requests, but optional for downlink requests.
786          */
787         @FlaggedApi(Flags.FLAG_ANDROID_V_WIFI_API)
788         @RequiresApi(Build.VERSION_CODES.VANILLA_ICE_CREAM)
setQosCharacteristics( @ullable QosCharacteristics qosCharacteristics)789         public @NonNull Builder setQosCharacteristics(
790                 @Nullable QosCharacteristics qosCharacteristics) {
791             if (!SdkLevel.isAtLeastV()) {
792                 throw new UnsupportedOperationException();
793             }
794             mQosCharacteristics = qosCharacteristics;
795             return this;
796         }
797 
798         /**
799          * Construct a QosPolicyParams object with the specified parameters.
800          */
build()801         public @NonNull QosPolicyParams build() {
802             QosPolicyParams params = new QosPolicyParams(mPolicyId, mDscp, mUserPriority, mSrcIp,
803                     mDstIp, mSrcPort, mProtocol, mDstPortRange, mDirection, mIpVersion, mDstPort,
804                     mFlowLabel, mQosCharacteristics);
805             if (!params.validate()) {
806                 throw new IllegalArgumentException("Provided parameters are invalid");
807             }
808             return params;
809         }
810     }
811 }
812