/* * Copyright (C) 2021 The Android Open Source Project * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package android.net; import android.annotation.NonNull; import android.annotation.Nullable; import android.annotation.SystemApi; import android.os.Parcel; import android.os.Parcelable; import android.util.Range; import com.android.net.module.util.InetAddressUtils; import java.net.Inet6Address; import java.net.InetAddress; import java.util.Objects; /** * DSCP policy to be set on the requesting NetworkAgent. * @hide */ @SystemApi public final class DscpPolicy implements Parcelable { /** * Indicates that the policy does not specify a protocol. */ public static final int PROTOCOL_ANY = -1; /** * Indicates that the policy does not specify a port. */ public static final int SOURCE_PORT_ANY = -1; /** The unique policy ID. Each requesting network is responsible for maintaining policy IDs * unique within that network. In the case where a policy with an existing ID is created, the * new policy will update the existing policy with the same ID. */ private final int mPolicyId; /** The QoS DSCP marking to be added to packets matching the policy. */ private final int mDscp; /** The source IP address. */ private final @Nullable InetAddress mSrcAddr; /** The destination IP address. */ private final @Nullable InetAddress mDstAddr; /** The source port. */ private final int mSrcPort; /** The IP protocol that the policy requires. */ private final int mProtocol; /** Destination port range. Inclusive range. */ private final @Nullable Range mDstPortRange; /** * Implement the Parcelable interface * * @hide */ public int describeContents() { return 0; } /* package */ DscpPolicy( int policyId, int dscp, @Nullable InetAddress srcAddr, @Nullable InetAddress dstAddr, int srcPort, int protocol, Range dstPortRange) { this.mPolicyId = policyId; this.mDscp = dscp; this.mSrcAddr = srcAddr; this.mDstAddr = dstAddr; this.mSrcPort = srcPort; this.mProtocol = protocol; this.mDstPortRange = dstPortRange; if (mPolicyId < 1 || mPolicyId > 255) { throw new IllegalArgumentException("Policy ID not in valid range: " + mPolicyId); } if (mDscp < 0 || mDscp > 63) { throw new IllegalArgumentException("DSCP value not in valid range: " + mDscp); } // Since SOURCE_PORT_ANY is the default source port value need to allow it as well. // TODO: Move the default value into this constructor or throw an error from the // instead. if (mSrcPort < -1 || mSrcPort > 65535) { throw new IllegalArgumentException("Source port not in valid range: " + mSrcPort); } if (mDstPortRange != null && (dstPortRange.getLower() < 0 || mDstPortRange.getLower() > 65535) && (mDstPortRange.getUpper() < 0 || mDstPortRange.getUpper() > 65535)) { throw new IllegalArgumentException("Destination port not in valid range"); } if (mSrcAddr != null && mDstAddr != null && (mSrcAddr instanceof Inet6Address) != (mDstAddr instanceof Inet6Address)) { throw new IllegalArgumentException("Source/destination address of different family"); } } /** * The unique policy ID. * * Each requesting network is responsible for maintaining unique * policy IDs. In the case where a policy with an existing ID is created, the new * policy will update the existing policy with the same ID * * @return Policy ID set in Builder. */ public int getPolicyId() { return mPolicyId; } /** * The QoS DSCP marking to be added to packets matching the policy. * * @return DSCP value set in Builder. */ public int getDscpValue() { return mDscp; } /** * The source IP address. * * @return Source IP address set in Builder or {@code null} if none was set. */ public @Nullable InetAddress getSourceAddress() { return mSrcAddr; } /** * The destination IP address. * * @return Destination IP address set in Builder or {@code null} if none was set. */ public @Nullable InetAddress getDestinationAddress() { return mDstAddr; } /** * The source port. * * @return Source port set in Builder or {@link #SOURCE_PORT_ANY} if no port was set. */ public int getSourcePort() { return mSrcPort; } /** * The IP protocol that the policy requires. * * @return Protocol set in Builder or {@link #PROTOCOL_ANY} if no protocol was set. * {@link #PROTOCOL_ANY} indicates that any protocol will be matched. */ public int getProtocol() { return mProtocol; } /** * Destination port range. Inclusive range. * * @return Range set in Builder or {@code null} if none was set. */ public @Nullable Range getDestinationPortRange() { return mDstPortRange; } @Override public String toString() { return "DscpPolicy { " + "policyId = " + mPolicyId + ", " + "dscp = " + mDscp + ", " + "srcAddr = " + mSrcAddr + ", " + "dstAddr = " + mDstAddr + ", " + "srcPort = " + mSrcPort + ", " + "protocol = " + mProtocol + ", " + "dstPortRange = " + (mDstPortRange == null ? "none" : mDstPortRange.toString()) + " }"; } @Override public boolean equals(@Nullable Object o) { if (this == o) return true; if (!(o instanceof DscpPolicy)) return false; DscpPolicy that = (DscpPolicy) o; return true && mPolicyId == that.mPolicyId && mDscp == that.mDscp && Objects.equals(mSrcAddr, that.mSrcAddr) && Objects.equals(mDstAddr, that.mDstAddr) && mSrcPort == that.mSrcPort && mProtocol == that.mProtocol && Objects.equals(mDstPortRange, that.mDstPortRange); } @Override public int hashCode() { return Objects.hash(mPolicyId, mDscp, mSrcAddr.hashCode(), mDstAddr.hashCode(), mSrcPort, mProtocol, mDstPortRange.hashCode()); } /** @hide */ @Override public void writeToParcel(@NonNull Parcel dest, int flags) { dest.writeInt(mPolicyId); dest.writeInt(mDscp); InetAddressUtils.parcelInetAddress(dest, mSrcAddr, flags); InetAddressUtils.parcelInetAddress(dest, mDstAddr, flags); dest.writeInt(mSrcPort); dest.writeInt(mProtocol); dest.writeBoolean(mDstPortRange != null ? true : false); if (mDstPortRange != null) { dest.writeInt(mDstPortRange.getLower()); dest.writeInt(mDstPortRange.getUpper()); } } /** @hide */ DscpPolicy(@NonNull Parcel in) { this.mPolicyId = in.readInt(); this.mDscp = in.readInt(); this.mSrcAddr = InetAddressUtils.unparcelInetAddress(in); this.mDstAddr = InetAddressUtils.unparcelInetAddress(in); this.mSrcPort = in.readInt(); this.mProtocol = in.readInt(); if (in.readBoolean()) { this.mDstPortRange = new Range(in.readInt(), in.readInt()); } else { this.mDstPortRange = null; } } /** @hide */ public @SystemApi static final @NonNull Parcelable.Creator CREATOR = new Parcelable.Creator() { @Override public DscpPolicy[] newArray(int size) { return new DscpPolicy[size]; } @Override public DscpPolicy createFromParcel(@NonNull android.os.Parcel in) { return new DscpPolicy(in); } }; /** * A builder for {@link DscpPolicy} * */ public static final class Builder { private final int mPolicyId; private final int mDscp; private @Nullable InetAddress mSrcAddr; private @Nullable InetAddress mDstAddr; private int mSrcPort = SOURCE_PORT_ANY; private int mProtocol = PROTOCOL_ANY; private @Nullable Range mDstPortRange; private long mBuilderFieldsSet = 0L; /** * Creates a new Builder. * * @param policyId The unique policy ID. Each requesting network is responsible for * maintaining unique policy IDs. In the case where a policy with an * existing ID is created, the new policy will update the existing * policy with the same ID * @param dscpValue The DSCP value to set. */ public Builder(int policyId, int dscpValue) { mPolicyId = policyId; mDscp = dscpValue; } /** * Specifies that this policy matches packets with the specified source IP address. */ public @NonNull Builder setSourceAddress(@NonNull InetAddress value) { mSrcAddr = value; return this; } /** * Specifies that this policy matches packets with the specified destination IP address. */ public @NonNull Builder setDestinationAddress(@NonNull InetAddress value) { mDstAddr = value; return this; } /** * Specifies that this policy matches packets with the specified source port. */ public @NonNull Builder setSourcePort(int value) { mSrcPort = value; return this; } /** * Specifies that this policy matches packets with the specified protocol. */ public @NonNull Builder setProtocol(int value) { mProtocol = value; return this; } /** * Specifies that this policy matches packets with the specified destination port range. */ public @NonNull Builder setDestinationPortRange(@NonNull Range range) { mDstPortRange = range; return this; } /** * Constructs a DscpPolicy with the specified parameters. */ public @NonNull DscpPolicy build() { return new DscpPolicy( mPolicyId, mDscp, mSrcAddr, mDstAddr, mSrcPort, mProtocol, mDstPortRange); } } }