HomeSP.java revision 05d2f4e6f26834a94b53187e6121379a16749088
1package com.android.server.wifi.hotspot2.pps; 2 3import android.util.Log; 4 5import com.android.server.wifi.anqp.ANQPElement; 6import com.android.server.wifi.anqp.CellularNetwork; 7import com.android.server.wifi.anqp.DomainNameElement; 8import com.android.server.wifi.anqp.NAIRealmData; 9import com.android.server.wifi.anqp.NAIRealmElement; 10import com.android.server.wifi.anqp.RoamingConsortiumElement; 11import com.android.server.wifi.anqp.ThreeGPPNetworkElement; 12import com.android.server.wifi.hotspot2.AuthMatch; 13import com.android.server.wifi.hotspot2.NetworkDetail; 14import com.android.server.wifi.hotspot2.PasspointMatch; 15import com.android.server.wifi.hotspot2.Utils; 16 17import java.util.ArrayList; 18import java.util.Collection; 19import java.util.Collections; 20import java.util.HashSet; 21import java.util.List; 22import java.util.Map; 23import java.util.Set; 24 25import static com.android.server.wifi.anqp.Constants.ANQPElementType; 26 27public class HomeSP { 28 private final Map<String, Long> mSSIDs; // SSID, HESSID, [0,N] 29 private final String mFQDN; 30 private final DomainMatcher mDomainMatcher; 31 private final Set<String> mOtherHomePartners; 32 private final HashSet<Long> mRoamingConsortiums; // [0,N] 33 private final Set<Long> mMatchAnyOIs; // [0,N] 34 private final List<Long> mMatchAllOIs; // [0,N] 35 36 private final Credential mCredential; 37 38 // Informational: 39 private final String mFriendlyName; // [1] 40 private final String mIconURL; // [0,1] 41 42 public HomeSP(Map<String, Long> ssidMap, 43 /*@NotNull*/ String fqdn, 44 /*@NotNull*/ HashSet<Long> roamingConsortiums, 45 /*@NotNull*/ Set<String> otherHomePartners, 46 /*@NotNull*/ Set<Long> matchAnyOIs, 47 /*@NotNull*/ List<Long> matchAllOIs, 48 String friendlyName, 49 String iconURL, 50 Credential credential) { 51 52 mSSIDs = ssidMap; 53 List<List<String>> otherPartners = new ArrayList<List<String>>(otherHomePartners.size()); 54 for (String otherPartner : otherHomePartners) { 55 otherPartners.add(Utils.splitDomain(otherPartner)); 56 } 57 mOtherHomePartners = otherHomePartners; 58 mFQDN = fqdn; 59 mDomainMatcher = new DomainMatcher(Utils.splitDomain(fqdn), otherPartners); 60 mRoamingConsortiums = roamingConsortiums; 61 mMatchAnyOIs = matchAnyOIs; 62 mMatchAllOIs = matchAllOIs; 63 mFriendlyName = friendlyName; 64 mIconURL = iconURL; 65 mCredential = credential; 66 } 67 68 public PasspointMatch match(NetworkDetail networkDetail, 69 Map<ANQPElementType, ANQPElement> anqpElementMap, 70 List<String> imsis) { 71 72 if (mSSIDs.containsKey(networkDetail.getSSID())) { 73 Long hessid = mSSIDs.get(networkDetail.getSSID()); 74 if (hessid == null || networkDetail.getHESSID() == hessid) { 75 Log.d("HS2J", "match SSID"); 76 return PasspointMatch.HomeProvider; 77 } 78 } 79 80 Set<Long> anOIs = new HashSet<Long>(); 81 82 if (networkDetail.getRoamingConsortiums() != null) { 83 for (long oi : networkDetail.getRoamingConsortiums()) { 84 anOIs.add(oi); 85 } 86 } 87 RoamingConsortiumElement rcElement = anqpElementMap != null ? 88 (RoamingConsortiumElement) anqpElementMap.get(ANQPElementType.ANQPRoamingConsortium) 89 : null; 90 if (rcElement != null) { 91 anOIs.addAll(rcElement.getOIs()); 92 } 93 94 boolean authPossible = false; 95 96 if (!mMatchAllOIs.isEmpty()) { 97 boolean matchesAll = true; 98 99 for (long spOI : mMatchAllOIs) { 100 if (!anOIs.contains(spOI)) { 101 matchesAll = false; 102 break; 103 } 104 } 105 if (matchesAll) { 106 authPossible = true; 107 } 108 else { 109 if (anqpElementMap != null || networkDetail.getAnqpOICount() == 0) { 110 return PasspointMatch.Declined; 111 } 112 else { 113 return PasspointMatch.Incomplete; 114 } 115 } 116 } 117 118 if (!authPossible && 119 (!Collections.disjoint(mMatchAnyOIs, anOIs) || 120 !Collections.disjoint(mRoamingConsortiums, anOIs))) { 121 authPossible = true; 122 } 123 124 if (anqpElementMap == null) { 125 return PasspointMatch.Incomplete; 126 } 127 128 DomainNameElement domainNameElement = 129 (DomainNameElement) anqpElementMap.get(ANQPElementType.ANQPDomName); 130 NAIRealmElement naiRealmElement = 131 (NAIRealmElement) anqpElementMap.get(ANQPElementType.ANQPNAIRealm); 132 ThreeGPPNetworkElement threeGPPNetworkElement = 133 (ThreeGPPNetworkElement) anqpElementMap.get(ANQPElementType.ANQP3GPPNetwork); 134 135 if (domainNameElement != null) { 136 for (String domain : domainNameElement.getDomains()) { 137 List<String> anLabels = Utils.splitDomain(domain); 138 DomainMatcher.Match match = mDomainMatcher.isSubDomain(anLabels); 139 if (match != DomainMatcher.Match.None) { 140 return PasspointMatch.HomeProvider; 141 } 142 143 String mccMnc = Utils.getMccMnc(anLabels); 144 if (mccMnc != null) { 145 for (String imsi : imsis) { 146 if (imsi.startsWith(mccMnc)) { 147 return PasspointMatch.HomeProvider; 148 } 149 } 150 } 151 } 152 } 153 154 if (!authPossible && naiRealmElement != null) { 155 AuthMatch authMatch = matchRealms(naiRealmElement, threeGPPNetworkElement); 156 if (authMatch != AuthMatch.None) { 157 return PasspointMatch.RoamingProvider; 158 } 159 } 160 161 return PasspointMatch.None; 162 } 163 164 private AuthMatch matchRealms(NAIRealmElement naiRealmElement, 165 ThreeGPPNetworkElement threeGPPNetworkElement) { 166 List<String> credRealm = Utils.splitDomain(mCredential.getRealm()); 167 168 for (NAIRealmData naiRealmData : naiRealmElement.getRealmData()) { 169 170 DomainMatcher.Match match = DomainMatcher.Match.None; 171 for (String anRealm : naiRealmData.getRealms()) { 172 List<String> anRealmLabels = Utils.splitDomain(anRealm); 173 match = mDomainMatcher.isSubDomain(anRealmLabels); 174 if (match != DomainMatcher.Match.None) { 175 break; 176 } 177 if (DomainMatcher.arg2SubdomainOfArg1(credRealm, anRealmLabels)) { 178 match = DomainMatcher.Match.Secondary; 179 break; 180 } 181 } 182 183 if (match != DomainMatcher.Match.None) { 184 if (mCredential.getImsi() != null) { 185 // All the device has is one of EAP-SIM, AKA or AKA', 186 // so a 3GPP element must appear and contain a matching MNC/MCC 187 if (threeGPPNetworkElement == null) { 188 return AuthMatch.None; 189 } 190 for (CellularNetwork network : threeGPPNetworkElement.getPlmns()) { 191 if (network.matchIMSI(mCredential.getImsi())) { 192 AuthMatch authMatch = 193 naiRealmData.matchEAPMethods(mCredential.getEAPMethod()); 194 if (authMatch != AuthMatch.None) { 195 return authMatch; 196 } 197 } 198 } 199 } else { 200 AuthMatch authMatch = naiRealmData.matchEAPMethods(mCredential.getEAPMethod()); 201 if (authMatch != AuthMatch.None) { 202 // Note: Something more intelligent could be done here based on the 203 // authMatch value. It may be useful to have a secondary score to 204 // distinguish more predictable EAP method/parameter matching. 205 return authMatch; 206 } 207 } 208 } 209 } 210 return AuthMatch.None; 211 } 212 213 public String getFQDN() { return mFQDN; } 214 public String getFriendlyName() { return mFriendlyName; } 215 public HashSet<Long> getRoamingConsortiums() { return mRoamingConsortiums; } 216 public Credential getCredential() { return mCredential; } 217 218 public Map<String, Long> getSSIDs() { 219 return mSSIDs; 220 } 221 222 public Collection<String> getOtherHomePartners() { 223 return mOtherHomePartners; 224 } 225 226 public Set<Long> getMatchAnyOIs() { 227 return mMatchAnyOIs; 228 } 229 230 public List<Long> getMatchAllOIs() { 231 return mMatchAllOIs; 232 } 233 234 public String getIconURL() { 235 return mIconURL; 236 } 237 238 public boolean deepEquals(HomeSP other) { 239 return mFQDN.equals(other.mFQDN) && 240 mSSIDs.equals(other.mSSIDs) && 241 mOtherHomePartners.equals(other.mOtherHomePartners) && 242 mRoamingConsortiums.equals(other.mRoamingConsortiums) && 243 mMatchAnyOIs.equals(other.mMatchAnyOIs) && 244 mMatchAllOIs.equals(other.mMatchAllOIs) && 245 mFriendlyName.equals(other.mFriendlyName) && 246 Utils.compare(mIconURL, other.mIconURL) == 0 && 247 mCredential.equals(other.mCredential); 248 } 249 250 @Override 251 public boolean equals(Object thatObject) { 252 if (this == thatObject) { 253 return true; 254 } else if (thatObject == null || getClass() != thatObject.getClass()) { 255 return false; 256 } 257 258 HomeSP that = (HomeSP) thatObject; 259 return mFQDN.equals(that.mFQDN); 260 } 261 262 @Override 263 public int hashCode() { 264 return mFQDN.hashCode(); 265 } 266 267 @Override 268 public String toString() { 269 return "HomeSP{" + 270 "mSSIDs=" + mSSIDs + 271 ", mFQDN='" + mFQDN + '\'' + 272 ", mDomainMatcher=" + mDomainMatcher + 273 ", mRoamingConsortiums={" + Utils.roamingConsortiumsToString(mRoamingConsortiums) + 274 '}' + 275 ", mMatchAnyOIs={" + Utils.roamingConsortiumsToString(mMatchAnyOIs) + '}' + 276 ", mMatchAllOIs={" + Utils.roamingConsortiumsToString(mMatchAllOIs) + '}' + 277 ", mCredential=" + mCredential + 278 ", mFriendlyName='" + mFriendlyName + '\'' + 279 ", mIconURL='" + mIconURL + '\'' + 280 '}'; 281 } 282} 283