1 /*
2  * Copyright (C) 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.net;
18 
19 import android.annotation.NonNull;
20 import android.annotation.Nullable;
21 import android.annotation.SystemApi;
22 import android.annotation.TestApi;
23 import android.os.Parcel;
24 import android.os.Parcelable;
25 
26 import java.util.ArrayList;
27 import java.util.Collection;
28 import java.util.LinkedHashSet;
29 import java.util.List;
30 import java.util.Objects;
31 
32 /**
33  * Information on a tethered downstream client.
34  * @hide
35  */
36 @SystemApi
37 @TestApi
38 public final class TetheredClient implements Parcelable {
39     @NonNull
40     private final MacAddress mMacAddress;
41     @NonNull
42     private final List<AddressInfo> mAddresses;
43     // TODO: use an @IntDef here
44     private final int mTetheringType;
45 
TetheredClient(@onNull MacAddress macAddress, @NonNull Collection<AddressInfo> addresses, int tetheringType)46     public TetheredClient(@NonNull MacAddress macAddress,
47             @NonNull Collection<AddressInfo> addresses, int tetheringType) {
48         mMacAddress = macAddress;
49         mAddresses = new ArrayList<>(addresses);
50         mTetheringType = tetheringType;
51     }
52 
TetheredClient(@onNull Parcel in)53     private TetheredClient(@NonNull Parcel in) {
54         this(in.readParcelable(null), in.createTypedArrayList(AddressInfo.CREATOR), in.readInt());
55     }
56 
57     @Override
writeToParcel(@onNull Parcel dest, int flags)58     public void writeToParcel(@NonNull Parcel dest, int flags) {
59         dest.writeParcelable(mMacAddress, flags);
60         dest.writeTypedList(mAddresses);
61         dest.writeInt(mTetheringType);
62     }
63 
64     /**
65      * Get the MAC address used to identify the client.
66      */
67     @NonNull
getMacAddress()68     public MacAddress getMacAddress() {
69         return mMacAddress;
70     }
71 
72     /**
73      * Get information on the list of addresses that are associated with the client.
74      */
75     @NonNull
getAddresses()76     public List<AddressInfo> getAddresses() {
77         return new ArrayList<>(mAddresses);
78     }
79 
80     /**
81      * Get the type of tethering used by the client.
82      * @return one of the {@code TetheringManager#TETHERING_*} constants.
83      */
getTetheringType()84     public int getTetheringType() {
85         return mTetheringType;
86     }
87 
88     /**
89      * Return a new {@link TetheredClient} that has all the attributes of this instance, plus the
90      * {@link AddressInfo} of the provided {@link TetheredClient}.
91      *
92      * <p>Duplicate addresses are removed.
93      * @hide
94      */
addAddresses(@onNull TetheredClient other)95     public TetheredClient addAddresses(@NonNull TetheredClient other) {
96         final LinkedHashSet<AddressInfo> newAddresses = new LinkedHashSet<>(
97                 mAddresses.size() + other.mAddresses.size());
98         newAddresses.addAll(mAddresses);
99         newAddresses.addAll(other.mAddresses);
100         return new TetheredClient(mMacAddress, newAddresses, mTetheringType);
101     }
102 
103     @Override
hashCode()104     public int hashCode() {
105         return Objects.hash(mMacAddress, mAddresses, mTetheringType);
106     }
107 
108     @Override
equals(@ullable Object obj)109     public boolean equals(@Nullable Object obj) {
110         if (!(obj instanceof TetheredClient)) return false;
111         final TetheredClient other = (TetheredClient) obj;
112         return mMacAddress.equals(other.mMacAddress)
113                 && mAddresses.equals(other.mAddresses)
114                 && mTetheringType == other.mTetheringType;
115     }
116 
117     /**
118      * Information on an lease assigned to a tethered client.
119      */
120     public static final class AddressInfo implements Parcelable {
121         @NonNull
122         private final LinkAddress mAddress;
123         @Nullable
124         private final String mHostname;
125 
126         /** @hide */
AddressInfo(@onNull LinkAddress address, @Nullable String hostname)127         public AddressInfo(@NonNull LinkAddress address, @Nullable String hostname) {
128             this.mAddress = address;
129             this.mHostname = hostname;
130         }
131 
AddressInfo(Parcel in)132         private AddressInfo(Parcel in) {
133             this(in.readParcelable(null),  in.readString());
134         }
135 
136         @Override
writeToParcel(@onNull Parcel dest, int flags)137         public void writeToParcel(@NonNull Parcel dest, int flags) {
138             dest.writeParcelable(mAddress, flags);
139             dest.writeString(mHostname);
140         }
141 
142         /**
143          * Get the link address (including prefix length and lifetime) used by the client.
144          *
145          * This may be an IPv4 or IPv6 address.
146          */
147         @NonNull
getAddress()148         public LinkAddress getAddress() {
149             return mAddress;
150         }
151 
152         /**
153          * Get the hostname that was advertised by the client when obtaining its address, if any.
154          */
155         @Nullable
getHostname()156         public String getHostname() {
157             return mHostname;
158         }
159 
160         /**
161          * Get the expiration time of the address assigned to the client.
162          * @hide
163          */
getExpirationTime()164         public long getExpirationTime() {
165             return mAddress.getExpirationTime();
166         }
167 
168         @Override
describeContents()169         public int describeContents() {
170             return 0;
171         }
172 
173         @Override
hashCode()174         public int hashCode() {
175             return Objects.hash(mAddress, mHostname);
176         }
177 
178         @Override
equals(@ullable Object obj)179         public boolean equals(@Nullable Object obj) {
180             if (!(obj instanceof AddressInfo)) return false;
181             final AddressInfo other = (AddressInfo) obj;
182             // Use .equals() for addresses as all changes, including address expiry changes,
183             // should be included.
184             return other.mAddress.equals(mAddress)
185                     && Objects.equals(mHostname, other.mHostname);
186         }
187 
188         @NonNull
189         public static final Creator<AddressInfo> CREATOR = new Creator<AddressInfo>() {
190             @NonNull
191             @Override
192             public AddressInfo createFromParcel(@NonNull Parcel in) {
193                 return new AddressInfo(in);
194             }
195 
196             @NonNull
197             @Override
198             public AddressInfo[] newArray(int size) {
199                 return new AddressInfo[size];
200             }
201         };
202 
203         @NonNull
204         @Override
toString()205         public String toString() {
206             return "AddressInfo {"
207                     + mAddress
208                     + (mHostname != null ? ", hostname " + mHostname : "")
209                     + "}";
210         }
211     }
212 
213     @Override
describeContents()214     public int describeContents() {
215         return 0;
216     }
217 
218     @NonNull
219     public static final Creator<TetheredClient> CREATOR = new Creator<TetheredClient>() {
220         @NonNull
221         @Override
222         public TetheredClient createFromParcel(@NonNull Parcel in) {
223             return new TetheredClient(in);
224         }
225 
226         @NonNull
227         @Override
228         public TetheredClient[] newArray(int size) {
229             return new TetheredClient[size];
230         }
231     };
232 
233     @NonNull
234     @Override
toString()235     public String toString() {
236         return "TetheredClient {hwAddr " + mMacAddress
237                 + ", addresses " + mAddresses
238                 + ", tetheringType " + mTetheringType
239                 + "}";
240     }
241 }
242