HomeSP.java revision 3baa1769b394a44351228f1b6950706d56fe61fa
1package com.android.server.wifi.hotspot2.pps; 2 3import android.util.Log; 4 5import com.android.server.wifi.SIMAccessor; 6import com.android.server.wifi.anqp.ANQPElement; 7import com.android.server.wifi.anqp.DomainNameElement; 8import com.android.server.wifi.anqp.NAIRealmElement; 9import com.android.server.wifi.anqp.RoamingConsortiumElement; 10import com.android.server.wifi.anqp.ThreeGPPNetworkElement; 11import com.android.server.wifi.hotspot2.AuthMatch; 12import com.android.server.wifi.hotspot2.NetworkDetail; 13import com.android.server.wifi.hotspot2.PasspointMatch; 14import com.android.server.wifi.hotspot2.Utils; 15 16import java.util.ArrayList; 17import java.util.Collection; 18import java.util.Collections; 19import java.util.HashSet; 20import java.util.List; 21import java.util.Map; 22import java.util.Set; 23 24import static com.android.server.wifi.anqp.Constants.ANQPElementType; 25 26public class HomeSP { 27 private final Map<String, Long> mSSIDs; // SSID, HESSID, [0,N] 28 private final String mFQDN; 29 private final DomainMatcher mDomainMatcher; 30 private final Set<String> mOtherHomePartners; 31 private final HashSet<Long> mRoamingConsortiums; // [0,N] 32 private final Set<Long> mMatchAnyOIs; // [0,N] 33 private final List<Long> mMatchAllOIs; // [0,N] 34 35 private final Credential mCredential; 36 37 // Informational: 38 private final String mFriendlyName; // [1] 39 private final String mIconURL; // [0,1] 40 41 public HomeSP(Map<String, Long> ssidMap, 42 /*@NotNull*/ String fqdn, 43 /*@NotNull*/ HashSet<Long> roamingConsortiums, 44 /*@NotNull*/ Set<String> otherHomePartners, 45 /*@NotNull*/ Set<Long> matchAnyOIs, 46 /*@NotNull*/ List<Long> matchAllOIs, 47 String friendlyName, 48 String iconURL, 49 Credential credential) { 50 51 mSSIDs = ssidMap; 52 List<List<String>> otherPartners = new ArrayList<List<String>>(otherHomePartners.size()); 53 for (String otherPartner : otherHomePartners) { 54 otherPartners.add(Utils.splitDomain(otherPartner)); 55 } 56 mOtherHomePartners = otherHomePartners; 57 mFQDN = fqdn; 58 mDomainMatcher = new DomainMatcher(Utils.splitDomain(fqdn), otherPartners); 59 mRoamingConsortiums = roamingConsortiums; 60 mMatchAnyOIs = matchAnyOIs; 61 mMatchAllOIs = matchAllOIs; 62 mFriendlyName = friendlyName; 63 mIconURL = iconURL; 64 mCredential = credential; 65 } 66 67 public HomeSP getClone(String password) { 68 if (getCredential().hasDisregardPassword()) { 69 return new HomeSP(mSSIDs, 70 mFQDN, 71 mRoamingConsortiums, 72 mOtherHomePartners, 73 mMatchAnyOIs, 74 mMatchAllOIs, 75 mFriendlyName, 76 mIconURL, 77 new Credential(mCredential, password)); 78 } 79 else { 80 return this; 81 } 82 } 83 84 public PasspointMatch match(NetworkDetail networkDetail, 85 Map<ANQPElementType, ANQPElement> anqpElementMap, 86 SIMAccessor simAccessor) { 87 88 PasspointMatch spMatch = matchSP(networkDetail, anqpElementMap, simAccessor); 89 90 if (spMatch == PasspointMatch.HomeProvider || spMatch == PasspointMatch.RoamingProvider) { 91 NAIRealmElement naiRealmElement = 92 (NAIRealmElement) anqpElementMap.get(ANQPElementType.ANQPNAIRealm); 93 ThreeGPPNetworkElement threeGPPNetworkElement = 94 (ThreeGPPNetworkElement) anqpElementMap.get(ANQPElementType.ANQP3GPPNetwork); 95 96 AuthMatch authMatch = naiRealmElement.match(mCredential, threeGPPNetworkElement); 97 Log.d(Utils.hs2LogTag(getClass()), networkDetail.toKeyString() + " match on " + mFQDN + 98 ": " + spMatch + ", auth " + authMatch); 99 return authMatch == AuthMatch.None ? PasspointMatch.None : spMatch; 100 } 101 else { 102 return spMatch; 103 } 104 } 105 106 public PasspointMatch matchSP(NetworkDetail networkDetail, 107 Map<ANQPElementType, ANQPElement> anqpElementMap, 108 SIMAccessor simAccessor) { 109 110 if (mSSIDs.containsKey(networkDetail.getSSID())) { 111 Long hessid = mSSIDs.get(networkDetail.getSSID()); 112 if (hessid == null || networkDetail.getHESSID() == hessid) { 113 Log.d(Utils.hs2LogTag(getClass()), "match SSID"); 114 return PasspointMatch.HomeProvider; 115 } 116 } 117 118 Set<Long> anOIs = new HashSet<>(); 119 120 if (networkDetail.getRoamingConsortiums() != null) { 121 for (long oi : networkDetail.getRoamingConsortiums()) { 122 anOIs.add(oi); 123 } 124 } 125 RoamingConsortiumElement rcElement = anqpElementMap != null ? 126 (RoamingConsortiumElement) anqpElementMap.get(ANQPElementType.ANQPRoamingConsortium) 127 : null; 128 if (rcElement != null) { 129 anOIs.addAll(rcElement.getOIs()); 130 } 131 132 // It may seem reasonable to check for home provider match prior to checking for roaming 133 // relationship, but it is possible to avoid an ANQP query if it turns out that the 134 // "match all" rule fails based only on beacon info only. 135 boolean roamingMatch = false; 136 137 if (!mMatchAllOIs.isEmpty()) { 138 boolean matchesAll = true; 139 140 for (long spOI : mMatchAllOIs) { 141 if (!anOIs.contains(spOI)) { 142 matchesAll = false; 143 break; 144 } 145 } 146 if (matchesAll) { 147 roamingMatch = true; 148 } 149 else { 150 if (anqpElementMap != null || networkDetail.getAnqpOICount() == 0) { 151 return PasspointMatch.Declined; 152 } 153 else { 154 return PasspointMatch.Incomplete; 155 } 156 } 157 } 158 159 if (!roamingMatch && 160 (!Collections.disjoint(mMatchAnyOIs, anOIs) || 161 !Collections.disjoint(mRoamingConsortiums, anOIs))) { 162 roamingMatch = true; 163 } 164 165 if (anqpElementMap == null) { 166 return PasspointMatch.Incomplete; 167 } 168 169 DomainNameElement domainNameElement = 170 (DomainNameElement) anqpElementMap.get(ANQPElementType.ANQPDomName); 171 172 if (domainNameElement != null) { 173 for (String domain : domainNameElement.getDomains()) { 174 List<String> anLabels = Utils.splitDomain(domain); 175 DomainMatcher.Match match = mDomainMatcher.isSubDomain(anLabels); 176 if (match != DomainMatcher.Match.None) { 177 return PasspointMatch.HomeProvider; 178 } 179 180 /* This is fundamentally wrong: We can't match the ANQP data to something unrelated 181 * to this Home SP. Commented out until this has been clarified by the WFA. 182 String imsi = simAccessor.getMatchingImsi(Utils.getMccMnc(anLabels)); 183 if (imsi != null) { 184 Log.d(Utils.hs2LogTag(getClass()), "Domain " + domain + 185 " matches IMSI " + imsi); 186 return PasspointMatch.HomeProvider; 187 } 188 */ 189 } 190 } 191 192 return roamingMatch ? PasspointMatch.RoamingProvider : PasspointMatch.None; 193 } 194 195 public String getFQDN() { return mFQDN; } 196 public String getFriendlyName() { return mFriendlyName; } 197 public HashSet<Long> getRoamingConsortiums() { return mRoamingConsortiums; } 198 public Credential getCredential() { return mCredential; } 199 200 public Map<String, Long> getSSIDs() { 201 return mSSIDs; 202 } 203 204 public Collection<String> getOtherHomePartners() { 205 return mOtherHomePartners; 206 } 207 208 public Set<Long> getMatchAnyOIs() { 209 return mMatchAnyOIs; 210 } 211 212 public List<Long> getMatchAllOIs() { 213 return mMatchAllOIs; 214 } 215 216 public String getIconURL() { 217 return mIconURL; 218 } 219 220 public boolean deepEquals(HomeSP other) { 221 return mFQDN.equals(other.mFQDN) && 222 mSSIDs.equals(other.mSSIDs) && 223 mOtherHomePartners.equals(other.mOtherHomePartners) && 224 mRoamingConsortiums.equals(other.mRoamingConsortiums) && 225 mMatchAnyOIs.equals(other.mMatchAnyOIs) && 226 mMatchAllOIs.equals(other.mMatchAllOIs) && 227 mFriendlyName.equals(other.mFriendlyName) && 228 Utils.compare(mIconURL, other.mIconURL) == 0 && 229 mCredential.equals(other.mCredential); 230 } 231 232 @Override 233 public boolean equals(Object thatObject) { 234 if (this == thatObject) { 235 return true; 236 } else if (thatObject == null || getClass() != thatObject.getClass()) { 237 return false; 238 } 239 240 HomeSP that = (HomeSP) thatObject; 241 return mFQDN.equals(that.mFQDN); 242 } 243 244 @Override 245 public int hashCode() { 246 return mFQDN.hashCode(); 247 } 248 249 @Override 250 public String toString() { 251 return "HomeSP{" + 252 "mSSIDs=" + mSSIDs + 253 ", mFQDN='" + mFQDN + '\'' + 254 ", mDomainMatcher=" + mDomainMatcher + 255 ", mRoamingConsortiums={" + Utils.roamingConsortiumsToString(mRoamingConsortiums) + 256 '}' + 257 ", mMatchAnyOIs={" + Utils.roamingConsortiumsToString(mMatchAnyOIs) + '}' + 258 ", mMatchAllOIs={" + Utils.roamingConsortiumsToString(mMatchAllOIs) + '}' + 259 ", mCredential=" + mCredential + 260 ", mFriendlyName='" + mFriendlyName + '\'' + 261 ", mIconURL='" + mIconURL + '\'' + 262 '}'; 263 } 264} 265