1 /** 2 * Copyright (c) 2016, 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.hotspot2.pps; 18 19 import android.os.Parcelable; 20 import android.os.Parcel; 21 import android.text.TextUtils; 22 import android.util.Log; 23 24 import java.nio.charset.StandardCharsets; 25 import java.util.Arrays; 26 import java.util.Collections; 27 import java.util.HashMap; 28 import java.util.Map; 29 import java.util.Objects; 30 31 /** 32 * Class representing HomeSP subtree in PerProviderSubscription (PPS) 33 * Management Object (MO) tree. 34 * 35 * For more info, refer to Hotspot 2.0 PPS MO defined in section 9.1 of the Hotspot 2.0 36 * Release 2 Technical Specification. 37 */ 38 public final class HomeSp implements Parcelable { 39 private static final String TAG = "HomeSp"; 40 41 /** 42 * Maximum number of bytes allowed for a SSID. 43 */ 44 private static final int MAX_SSID_BYTES = 32; 45 46 /** 47 * Integer value used for indicating null value in the Parcel. 48 */ 49 private static final int NULL_VALUE = -1; 50 51 /** 52 * FQDN (Fully Qualified Domain Name) of this home service provider. 53 */ 54 private String mFqdn = null; 55 /** 56 * Set the FQDN (Fully Qualified Domain Name) associated with this home service provider. 57 * 58 * @param fqdn The FQDN to set to 59 */ setFqdn(String fqdn)60 public void setFqdn(String fqdn) { 61 mFqdn = fqdn; 62 } 63 /** 64 * Get the FQDN (Fully Qualified Domain Name) associated with this home service provider. 65 * 66 * @return the FQDN associated with this home service provider 67 */ getFqdn()68 public String getFqdn() { 69 return mFqdn; 70 } 71 72 /** 73 * Friendly name of this home service provider. 74 */ 75 private String mFriendlyName = null; 76 /** 77 * Set the friendly name associated with this home service provider. 78 * 79 * @param friendlyName The friendly name to set to 80 */ setFriendlyName(String friendlyName)81 public void setFriendlyName(String friendlyName) { 82 mFriendlyName = friendlyName; 83 } 84 /** 85 * Get the friendly name associated with this home service provider. 86 * 87 * @return the friendly name associated with this home service provider 88 */ getFriendlyName()89 public String getFriendlyName() { 90 return mFriendlyName; 91 } 92 93 /** 94 * Icon URL of this home service provider. 95 */ 96 private String mIconUrl = null; 97 /** 98 * @hide 99 */ setIconUrl(String iconUrl)100 public void setIconUrl(String iconUrl) { 101 mIconUrl = iconUrl; 102 } 103 /** 104 * @hide 105 */ getIconUrl()106 public String getIconUrl() { 107 return mIconUrl; 108 } 109 110 /** 111 * <SSID, HESSID> duple of the networks that are consider home networks. 112 * 113 * According to the Section 9.1.2 of the Hotspot 2.0 Release 2 Technical Specification, 114 * all nodes in the PSS MO are encoded using UTF-8 unless stated otherwise. Thus, the SSID 115 * string is assumed to be encoded using UTF-8. 116 */ 117 private Map<String, Long> mHomeNetworkIds = null; 118 /** 119 * @hide 120 */ setHomeNetworkIds(Map<String, Long> homeNetworkIds)121 public void setHomeNetworkIds(Map<String, Long> homeNetworkIds) { 122 mHomeNetworkIds = homeNetworkIds; 123 } 124 /** 125 * @hide 126 */ getHomeNetworkIds()127 public Map<String, Long> getHomeNetworkIds() { 128 return mHomeNetworkIds; 129 } 130 131 /** 132 * Used for determining if this provider is a member of a given Hotspot provider. 133 * Every Organization Identifiers (OIs) in this list are required to match an OI in the 134 * the Roaming Consortium advertised by a Hotspot, in order to consider this provider 135 * as a member of that Hotspot provider (e.g. successful authentication with such Hotspot 136 * is possible). 137 * 138 * Refer to HomeSP/HomeOIList subtree in PerProviderSubscription (PPS) Management Object 139 * (MO) tree for more detail. 140 */ 141 private long[] mMatchAllOis = null; 142 /** 143 * @hide 144 */ setMatchAllOis(long[] matchAllOis)145 public void setMatchAllOis(long[] matchAllOis) { 146 mMatchAllOis = matchAllOis; 147 } 148 /** 149 * @hide 150 */ getMatchAllOis()151 public long[] getMatchAllOis() { 152 return mMatchAllOis; 153 } 154 155 /** 156 * Used for determining if this provider is a member of a given Hotspot provider. 157 * Matching of any Organization Identifiers (OIs) in this list with an OI in the 158 * Roaming Consortium advertised by a Hotspot, will consider this provider as a member 159 * of that Hotspot provider (e.g. successful authentication with such Hotspot 160 * is possible). 161 * 162 * {@link #mMatchAllOIs} will have precedence over this one, meaning this list will 163 * only be used for matching if {@link #mMatchAllOIs} is null or empty. 164 * 165 * Refer to HomeSP/HomeOIList subtree in PerProviderSubscription (PPS) Management Object 166 * (MO) tree for more detail. 167 */ 168 private long[] mMatchAnyOis = null; 169 /** 170 * @hide 171 */ setMatchAnyOis(long[] matchAnyOis)172 public void setMatchAnyOis(long[] matchAnyOis) { 173 mMatchAnyOis = matchAnyOis; 174 } 175 /** 176 * @hide 177 */ getMatchAnyOis()178 public long[] getMatchAnyOis() { 179 return mMatchAnyOis; 180 } 181 182 /** 183 * List of FQDN (Fully Qualified Domain Name) of partner providers. 184 * These providers should also be regarded as home Hotspot operators. 185 * This relationship is most likely achieved via a commercial agreement or 186 * operator merges between the providers. 187 */ 188 private String[] mOtherHomePartners = null; 189 /** 190 * @hide 191 */ setOtherHomePartners(String[] otherHomePartners)192 public void setOtherHomePartners(String[] otherHomePartners) { 193 mOtherHomePartners = otherHomePartners; 194 } 195 /** 196 * @hide 197 */ getOtherHomePartners()198 public String[] getOtherHomePartners() { 199 return mOtherHomePartners; 200 } 201 202 /** 203 * List of Organization Identifiers (OIs) identifying a roaming consortium of 204 * which this provider is a member. 205 */ 206 private long[] mRoamingConsortiumOis = null; 207 /** 208 * Set the Organization Identifiers (OIs) identifying a roaming consortium of which this 209 * provider is a member. 210 * 211 * @param roamingConsortiumOis Array of roaming consortium OIs 212 */ setRoamingConsortiumOis(long[] roamingConsortiumOis)213 public void setRoamingConsortiumOis(long[] roamingConsortiumOis) { 214 mRoamingConsortiumOis = roamingConsortiumOis; 215 } 216 /** 217 * Get the Organization Identifiers (OIs) identifying a roaming consortium of which this 218 * provider is a member. 219 * 220 * @return array of roaming consortium OIs 221 */ getRoamingConsortiumOis()222 public long[] getRoamingConsortiumOis() { 223 return mRoamingConsortiumOis; 224 } 225 226 /** 227 * Constructor for creating HomeSp with default values. 228 */ HomeSp()229 public HomeSp() {} 230 231 /** 232 * Copy constructor. 233 * 234 * @param source The source to copy from 235 */ HomeSp(HomeSp source)236 public HomeSp(HomeSp source) { 237 if (source == null) { 238 return; 239 } 240 mFqdn = source.mFqdn; 241 mFriendlyName = source.mFriendlyName; 242 mIconUrl = source.mIconUrl; 243 if (source.mHomeNetworkIds != null) { 244 mHomeNetworkIds = Collections.unmodifiableMap(source.mHomeNetworkIds); 245 } 246 if (source.mMatchAllOis != null) { 247 mMatchAllOis = Arrays.copyOf(source.mMatchAllOis, source.mMatchAllOis.length); 248 } 249 if (source.mMatchAnyOis != null) { 250 mMatchAnyOis = Arrays.copyOf(source.mMatchAnyOis, source.mMatchAnyOis.length); 251 } 252 if (source.mOtherHomePartners != null) { 253 mOtherHomePartners = Arrays.copyOf(source.mOtherHomePartners, 254 source.mOtherHomePartners.length); 255 } 256 if (source.mRoamingConsortiumOis != null) { 257 mRoamingConsortiumOis = Arrays.copyOf(source.mRoamingConsortiumOis, 258 source.mRoamingConsortiumOis.length); 259 } 260 } 261 262 @Override describeContents()263 public int describeContents() { 264 return 0; 265 } 266 267 @Override writeToParcel(Parcel dest, int flags)268 public void writeToParcel(Parcel dest, int flags) { 269 dest.writeString(mFqdn); 270 dest.writeString(mFriendlyName); 271 dest.writeString(mIconUrl); 272 writeHomeNetworkIds(dest, mHomeNetworkIds); 273 dest.writeLongArray(mMatchAllOis); 274 dest.writeLongArray(mMatchAnyOis); 275 dest.writeStringArray(mOtherHomePartners); 276 dest.writeLongArray(mRoamingConsortiumOis); 277 } 278 279 @Override equals(Object thatObject)280 public boolean equals(Object thatObject) { 281 if (this == thatObject) { 282 return true; 283 } 284 if (!(thatObject instanceof HomeSp)) { 285 return false; 286 } 287 HomeSp that = (HomeSp) thatObject; 288 289 return TextUtils.equals(mFqdn, that.mFqdn) 290 && TextUtils.equals(mFriendlyName, that.mFriendlyName) 291 && TextUtils.equals(mIconUrl, that.mIconUrl) 292 && (mHomeNetworkIds == null ? that.mHomeNetworkIds == null 293 : mHomeNetworkIds.equals(that.mHomeNetworkIds)) 294 && Arrays.equals(mMatchAllOis, that.mMatchAllOis) 295 && Arrays.equals(mMatchAnyOis, that.mMatchAnyOis) 296 && Arrays.equals(mOtherHomePartners, that.mOtherHomePartners) 297 && Arrays.equals(mRoamingConsortiumOis, that.mRoamingConsortiumOis); 298 } 299 300 @Override hashCode()301 public int hashCode() { 302 return Objects.hash(mFqdn, mFriendlyName, mIconUrl, mHomeNetworkIds, mMatchAllOis, 303 mMatchAnyOis, mOtherHomePartners, mRoamingConsortiumOis); 304 } 305 306 @Override toString()307 public String toString() { 308 StringBuilder builder = new StringBuilder(); 309 builder.append("FQDN: ").append(mFqdn).append("\n"); 310 builder.append("FriendlyName: ").append(mFriendlyName).append("\n"); 311 builder.append("IconURL: ").append(mIconUrl).append("\n"); 312 builder.append("HomeNetworkIDs: ").append(mHomeNetworkIds).append("\n"); 313 builder.append("MatchAllOIs: ").append(mMatchAllOis).append("\n"); 314 builder.append("MatchAnyOIs: ").append(mMatchAnyOis).append("\n"); 315 builder.append("OtherHomePartners: ").append(mOtherHomePartners).append("\n"); 316 builder.append("RoamingConsortiumOIs: ").append(mRoamingConsortiumOis).append("\n"); 317 return builder.toString(); 318 } 319 320 /** 321 * Validate HomeSp data. 322 * 323 * @return true on success or false on failure 324 * @hide 325 */ validate()326 public boolean validate() { 327 if (TextUtils.isEmpty(mFqdn)) { 328 Log.d(TAG, "Missing FQDN"); 329 return false; 330 } 331 if (TextUtils.isEmpty(mFriendlyName)) { 332 Log.d(TAG, "Missing friendly name"); 333 return false; 334 } 335 // Verify SSIDs specified in the NetworkID 336 if (mHomeNetworkIds != null) { 337 for (Map.Entry<String, Long> entry : mHomeNetworkIds.entrySet()) { 338 if (entry.getKey() == null || 339 entry.getKey().getBytes(StandardCharsets.UTF_8).length > MAX_SSID_BYTES) { 340 Log.d(TAG, "Invalid SSID in HomeNetworkIDs"); 341 return false; 342 } 343 } 344 } 345 return true; 346 } 347 348 public static final @android.annotation.NonNull Creator<HomeSp> CREATOR = 349 new Creator<HomeSp>() { 350 @Override 351 public HomeSp createFromParcel(Parcel in) { 352 HomeSp homeSp = new HomeSp(); 353 homeSp.setFqdn(in.readString()); 354 homeSp.setFriendlyName(in.readString()); 355 homeSp.setIconUrl(in.readString()); 356 homeSp.setHomeNetworkIds(readHomeNetworkIds(in)); 357 homeSp.setMatchAllOis(in.createLongArray()); 358 homeSp.setMatchAnyOis(in.createLongArray()); 359 homeSp.setOtherHomePartners(in.createStringArray()); 360 homeSp.setRoamingConsortiumOis(in.createLongArray()); 361 return homeSp; 362 } 363 364 @Override 365 public HomeSp[] newArray(int size) { 366 return new HomeSp[size]; 367 } 368 369 /** 370 * Helper function for reading a Home Network IDs map from a Parcel. 371 * 372 * @param in The Parcel to read from 373 * @return Map of home network IDs 374 */ 375 private Map<String, Long> readHomeNetworkIds(Parcel in) { 376 int size = in.readInt(); 377 if (size == NULL_VALUE) { 378 return null; 379 } 380 Map<String, Long> networkIds = new HashMap<>(size); 381 for (int i = 0; i < size; i++) { 382 String key = in.readString(); 383 Long value = null; 384 long readValue = in.readLong(); 385 if (readValue != NULL_VALUE) { 386 value = Long.valueOf(readValue); 387 } 388 networkIds.put(key, value); 389 } 390 return networkIds; 391 } 392 }; 393 394 /** 395 * Helper function for writing Home Network IDs map to a Parcel. 396 * 397 * @param dest The Parcel to write to 398 * @param networkIds The map of home network IDs 399 */ writeHomeNetworkIds(Parcel dest, Map<String, Long> networkIds)400 private static void writeHomeNetworkIds(Parcel dest, Map<String, Long> networkIds) { 401 if (networkIds == null) { 402 dest.writeInt(NULL_VALUE); 403 return; 404 } 405 dest.writeInt(networkIds.size()); 406 for (Map.Entry<String, Long> entry : networkIds.entrySet()) { 407 dest.writeString(entry.getKey()); 408 if (entry.getValue() == null) { 409 dest.writeLong(NULL_VALUE); 410 } else { 411 dest.writeLong(entry.getValue()); 412 } 413 } 414 } 415 } 416