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