HomeSP.java revision 71a988c8e9859244b83cd55bb6b6ee913fcaf95c
1package com.android.server.wifi.hotspot2.pps; 2 3import com.android.server.wifi.anqp.ANQPElement; 4import com.android.server.wifi.anqp.CellularNetwork; 5import com.android.server.wifi.anqp.DomainNameElement; 6import com.android.server.wifi.anqp.HSConnectionCapabilityElement; 7import com.android.server.wifi.anqp.HSWanMetricsElement; 8import com.android.server.wifi.anqp.IPAddressTypeAvailabilityElement; 9import com.android.server.wifi.anqp.NAIRealmData; 10import com.android.server.wifi.anqp.NAIRealmElement; 11import com.android.server.wifi.anqp.RoamingConsortiumElement; 12import com.android.server.wifi.anqp.ThreeGPPNetworkElement; 13import com.android.server.wifi.hotspot2.AuthMatch; 14import com.android.server.wifi.hotspot2.NetworkInfo; 15import com.android.server.wifi.hotspot2.PasspointMatch; 16import com.android.server.wifi.hotspot2.Utils; 17 18import java.util.ArrayList; 19import java.util.EnumMap; 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, String> 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, String> 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(NetworkInfo networkInfo, List<ANQPElement> anqpElements) { 66 67 if (mSSIDs.containsKey(networkInfo.getSSID())) { 68 String hessid = mSSIDs.get(networkInfo.getSSID()); 69 if (hessid == null || networkInfo.getHESSID().equals(hessid)) { 70 System.out.println("-- SSID"); 71 return PasspointMatch.HomeProvider; 72 } 73 } 74 75 List<Long> allOIs = null; 76 77 if (networkInfo.getRoamingConsortiums() != null) { 78 allOIs = new ArrayList<Long>(); 79 for (long oi : networkInfo.getRoamingConsortiums()) { 80 allOIs.add(oi); 81 } 82 } 83 84 Map<ANQPElementType, ANQPElement> anqpElementMap = null; 85 86 if (anqpElements != null) { 87 anqpElementMap = new EnumMap<ANQPElementType, ANQPElement>(ANQPElementType.class); 88 for (ANQPElement element : anqpElements) { 89 anqpElementMap.put(element.getID(), element); 90 if (element.getID() == ANQPElementType.ANQPRoamingConsortium) { 91 RoamingConsortiumElement rcElement = (RoamingConsortiumElement) element; 92 if (!rcElement.getOIs().isEmpty()) { 93 if (allOIs == null) { 94 allOIs = new ArrayList<Long>(rcElement.getOIs()); 95 } else { 96 allOIs.addAll(rcElement.getOIs()); 97 } 98 } 99 } 100 } 101 } 102 103 // !!! wlan.mnc<MNC>.mcc<MCC>.3gppnetwork.org 104 105 if (allOIs != null) { 106 if (!mRoamingConsortiums.isEmpty()) { 107 for (long oi : allOIs) { 108 if (mRoamingConsortiums.contains(oi)) { 109 System.out.println("-- RC"); 110 return PasspointMatch.HomeProvider; 111 } 112 } 113 } 114 if (!mMatchAnyOIs.isEmpty() || !mMatchAllOIs.isEmpty()) { 115 for (long anOI : allOIs) { 116 117 boolean oneMatchesAll = !mMatchAllOIs.isEmpty(); 118 119 for (long spOI : mMatchAllOIs) { 120 if (spOI != anOI) { 121 oneMatchesAll = false; 122 break; 123 } 124 } 125 126 if (oneMatchesAll) { 127 System.out.println("-- 1inAll"); 128 return PasspointMatch.HomeProvider; 129 } 130 131 if (mMatchAnyOIs.contains(anOI)) { 132 System.out.println("-- 1ofAll"); 133 return PasspointMatch.HomeProvider; 134 } 135 } 136 } 137 } 138 139 if (anqpElementMap == null) { 140 return PasspointMatch.Incomplete; 141 } 142 143 DomainNameElement domainNameElement = 144 (DomainNameElement) anqpElementMap.get(ANQPElementType.ANQPDomName); 145 NAIRealmElement naiRealmElement = 146 (NAIRealmElement) anqpElementMap.get(ANQPElementType.ANQPNAIRealm); 147 ThreeGPPNetworkElement threeGPPNetworkElement = 148 (ThreeGPPNetworkElement) anqpElementMap.get(ANQPElementType.ANQP3GPPNetwork); 149 150 // For future policy decisions: 151 IPAddressTypeAvailabilityElement ipAddressAvailabilityElement = 152 (IPAddressTypeAvailabilityElement) anqpElementMap.get( 153 ANQPElementType.ANQPIPAddrAvailability); 154 HSConnectionCapabilityElement hsConnCapElement = 155 (HSConnectionCapabilityElement) anqpElementMap.get( 156 ANQPElementType.HSConnCapability); 157 HSWanMetricsElement hsWanMetricsElement = 158 (HSWanMetricsElement) anqpElementMap.get(ANQPElementType.HSWANMetrics); 159 160 if (domainNameElement != null) { 161 for (String domain : domainNameElement.getDomains()) { 162 DomainMatcher.Match match = mDomainMatcher.isSubDomain(Utils.splitDomain(domain)); 163 if (match != DomainMatcher.Match.None) { 164 return PasspointMatch.HomeProvider; 165 } 166 } 167 } 168 169 if (naiRealmElement != null) { 170 AuthMatch authMatch = matchRealms(naiRealmElement, threeGPPNetworkElement); 171 if (authMatch != AuthMatch.None) { 172 return PasspointMatch.RoamingProvider; 173 } 174 } 175 return PasspointMatch.None; 176 } 177 178 private AuthMatch matchRealms(NAIRealmElement naiRealmElement, 179 ThreeGPPNetworkElement threeGPPNetworkElement) { 180 List<String> credRealm = Utils.splitDomain(mCredential.getRealm()); 181 182 for (NAIRealmData naiRealmData : naiRealmElement.getRealmData()) { 183 184 DomainMatcher.Match match = DomainMatcher.Match.None; 185 for (String anRealm : naiRealmData.getRealms()) { 186 List<String> anRealmLabels = Utils.splitDomain(anRealm); 187 match = mDomainMatcher.isSubDomain(anRealmLabels); 188 if (match != DomainMatcher.Match.None) { 189 break; 190 } 191 if (anRealmLabels.equals(credRealm)) { 192 match = DomainMatcher.Match.Secondary; 193 break; 194 } 195 } 196 197 if (match != DomainMatcher.Match.None) { 198 if (mCredential.getImsi() != null) { 199 // All the device has is one of EAP-SIM, AKA or AKA', 200 // so a 3GPP element must appear and contain a matching MNC/MCC 201 if (threeGPPNetworkElement == null) { 202 return AuthMatch.None; 203 } 204 for (CellularNetwork network : threeGPPNetworkElement.getPlmns()) { 205 if (network.matchIMSI(mCredential.getImsi())) { 206 AuthMatch authMatch = 207 naiRealmData.matchEAPMethods(mCredential.getEAPMethod()); 208 if (authMatch != AuthMatch.None) { 209 return authMatch; 210 } 211 } 212 } 213 } else { 214 AuthMatch authMatch = naiRealmData.matchEAPMethods(mCredential.getEAPMethod()); 215 if (authMatch != AuthMatch.None) { 216 // Note: Something more intelligent could be done here based on the 217 // authMatch value. It may be useful to have a secondary score to 218 // distinguish more predictable EAP method/parameter matching. 219 return authMatch; 220 } 221 } 222 } 223 } 224 return AuthMatch.None; 225 } 226 227 public String getFQDN() { 228 return mFQDN; 229 } 230 231 @Override 232 public boolean equals(Object thatObject) { 233 if (this == thatObject) { 234 return true; 235 } else if (thatObject == null || getClass() != thatObject.getClass()) { 236 return false; 237 } 238 239 HomeSP that = (HomeSP) thatObject; 240 return mFQDN.equals(that.mFQDN); 241 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