diff options
author | Hai Shalom <haishalom@google.com> | 2020-03-17 23:48:54 +0000 |
---|---|---|
committer | Android (Google) Code Review <android-gerrit@google.com> | 2020-03-17 23:48:54 +0000 |
commit | 95d7544a87272802f591dd44640a18ab1c6d6edd (patch) | |
tree | 4123f2693db7c1c73ad7ae5fcab5c1d63d60554d | |
parent | 47622333f37484d6cf2ebae422e245e0d002d832 (diff) | |
parent | 4354285b8de3345d5146f68ce2d17be83b4f34a4 (diff) |
Merge "[Passpoint] Fix Passpoint matching algorithm for Home networks" into qt-qpr1-dev
5 files changed, 421 insertions, 138 deletions
diff --git a/service/java/com/android/server/wifi/hotspot2/ANQPMatcher.java b/service/java/com/android/server/wifi/hotspot2/ANQPMatcher.java index d95ab3831..69f98b0ef 100644 --- a/service/java/com/android/server/wifi/hotspot2/ANQPMatcher.java +++ b/service/java/com/android/server/wifi/hotspot2/ANQPMatcher.java @@ -75,10 +75,11 @@ public class ANQPMatcher { * * @param element The Roaming Consortium ANQP element * @param providerOIs The roaming consortium OIs of the provider + * @param matchAll Indicates if a match with all OIs must be done * @return true if a match is found */ public static boolean matchRoamingConsortium(RoamingConsortiumElement element, - long[] providerOIs) { + long[] providerOIs, boolean matchAll) { if (element == null) { return false; } @@ -88,10 +89,14 @@ public class ANQPMatcher { List<Long> rcOIs = element.getOIs(); for (long oi : providerOIs) { if (rcOIs.contains(oi)) { - return true; + if (!matchAll) { + return true; + } + } else if (matchAll) { + return false; } } - return false; + return matchAll; } /** @@ -100,27 +105,19 @@ public class ANQPMatcher { * * @param element The NAI Realm ANQP element * @param realm The realm of the provider's credential - * @param eapMethodID The EAP Method ID of the provider's credential - * @param authParam The authentication parameter of the provider's credential * @return an integer indicating the match status */ - public static int matchNAIRealm(NAIRealmElement element, String realm, int eapMethodID, - AuthParam authParam) { + public static boolean matchNAIRealm(NAIRealmElement element, String realm) { if (element == null || element.getRealmDataList().isEmpty()) { - return AuthMatch.INDETERMINATE; + return false; } - int bestMatch = AuthMatch.NONE; for (NAIRealmData realmData : element.getRealmDataList()) { - int match = matchNAIRealmData(realmData, realm, eapMethodID, authParam); - if (match > bestMatch) { - bestMatch = match; - if (bestMatch == AuthMatch.EXACT) { - break; - } + if (matchNAIRealmData(realmData, realm)) { + return true; } } - return bestMatch; + return false; } /** @@ -172,42 +169,16 @@ public class ANQPMatcher { * * @param realmData The NAI Realm data * @param realm The realm of the provider's credential - * @param eapMethodID The EAP Method ID of the provider's credential - * @param authParam The authentication parameter of the provider's credential - * @return an integer indicating the match status + * @return true if a match is found */ - private static int matchNAIRealmData(NAIRealmData realmData, String realm, int eapMethodID, - AuthParam authParam) { + private static boolean matchNAIRealmData(NAIRealmData realmData, String realm) { // Check for realm domain name match. - int realmMatch = AuthMatch.NONE; for (String realmStr : realmData.getRealms()) { if (DomainMatcher.arg2SubdomainOfArg1(realm, realmStr)) { - realmMatch = AuthMatch.REALM; - break; - } - } - - if (realmData.getEAPMethods().isEmpty()) { - return realmMatch; - } - - // Check for EAP method match. - int eapMethodMatch = AuthMatch.NONE; - for (EAPMethod eapMethod : realmData.getEAPMethods()) { - eapMethodMatch = matchEAPMethod(eapMethod, eapMethodID, authParam); - if (eapMethodMatch != AuthMatch.NONE) { - break; + return true; } } - - if (eapMethodMatch == AuthMatch.NONE) { - return AuthMatch.NONE; - } - - if (realmMatch == AuthMatch.NONE) { - return eapMethodMatch; - } - return realmMatch | eapMethodMatch; + return false; } private static int getEapMethodForNAIRealmWithCarrier(String realm, diff --git a/service/java/com/android/server/wifi/hotspot2/PasspointManager.java b/service/java/com/android/server/wifi/hotspot2/PasspointManager.java index c46873761..172d1a13d 100644 --- a/service/java/com/android/server/wifi/hotspot2/PasspointManager.java +++ b/service/java/com/android/server/wifi/hotspot2/PasspointManager.java @@ -217,6 +217,7 @@ public class PasspointManager { public void setProviders(List<PasspointProvider> providers) { mProviders.clear(); for (PasspointProvider provider : providers) { + provider.enableVerboseLogging(mVerboseLoggingEnabled ? 1 : 0); mProviders.put(provider.getConfig().getHomeSp().getFqdn(), provider); if (provider.getPackageName() != null) { startTrackingAppOpsChange(provider.getPackageName(), @@ -377,6 +378,9 @@ public class PasspointManager { public void enableVerboseLogging(int verbose) { mVerboseLoggingEnabled = (verbose > 0) ? true : false; mPasspointProvisioner.enableVerboseLogging(verbose); + for (PasspointProvider provider : mProviders.values()) { + provider.enableVerboseLogging(verbose); + } } /** @@ -433,6 +437,7 @@ public class PasspointManager { mProviders.get(config.getHomeSp().getFqdn()).uninstallCertsAndKeys(); mProviders.remove(config.getHomeSp().getFqdn()); } + newProvider.enableVerboseLogging(mVerboseLoggingEnabled ? 1 : 0); mProviders.put(config.getHomeSp().getFqdn(), newProvider); mWifiConfigManager.saveToStore(true /* forceWrite */); if (newProvider.getPackageName() != null) { @@ -1165,6 +1170,7 @@ public class PasspointManager { Arrays.asList(enterpriseConfig.getCaCertificateAlias()), enterpriseConfig.getClientCertificateAlias(), enterpriseConfig.getClientCertificateAlias(), null, false, false); + provider.enableVerboseLogging(mVerboseLoggingEnabled ? 1 : 0); mProviders.put(passpointConfig.getHomeSp().getFqdn(), provider); return true; } diff --git a/service/java/com/android/server/wifi/hotspot2/PasspointProvider.java b/service/java/com/android/server/wifi/hotspot2/PasspointProvider.java index ca9814aa6..8db71d3e6 100644 --- a/service/java/com/android/server/wifi/hotspot2/PasspointProvider.java +++ b/service/java/com/android/server/wifi/hotspot2/PasspointProvider.java @@ -95,6 +95,7 @@ public class PasspointProvider { private boolean mHasEverConnected; private boolean mIsShared; + private boolean mVerboseLoggingEnabled; /** * This is a flag to indicate if the Provider is created temporarily. @@ -327,39 +328,53 @@ public class PasspointProvider { * Return the matching status with the given AP, based on the ANQP elements from the AP. * * @param anqpElements ANQP elements from the AP - * @param roamingConsortium Roaming Consortium information element from the AP + * @param roamingConsortiumFromAp Roaming Consortium information element from the AP * @return {@link PasspointMatch} */ public PasspointMatch match(Map<ANQPElementType, ANQPElement> anqpElements, - RoamingConsortium roamingConsortium) { - PasspointMatch providerMatch = matchProviderExceptFor3GPP(anqpElements, roamingConsortium); + RoamingConsortium roamingConsortiumFromAp) { + // Match FQDN for Home provider or RCOI(s) for Roaming provider + // For SIM credential, the FQDN is in the format of wlan.mnc*.mcc*.3gppnetwork.org + PasspointMatch providerMatch = matchFqdnAndRcoi(anqpElements, roamingConsortiumFromAp); // 3GPP Network matching. if (providerMatch == PasspointMatch.None && ANQPMatcher.matchThreeGPPNetwork( (ThreeGPPNetworkElement) anqpElements.get(ANQPElementType.ANQP3GPPNetwork), mImsiParameter, mMatchingSIMImsiList)) { + if (mVerboseLoggingEnabled) { + Log.d(TAG, "Final RoamingProvider match with " + + anqpElements.get(ANQPElementType.ANQP3GPPNetwork)); + } return PasspointMatch.RoamingProvider; } - // Perform authentication match against the NAI Realm. - int authMatch = ANQPMatcher.matchNAIRealm( + // Perform NAI Realm matching + boolean realmMatch = ANQPMatcher.matchNAIRealm( (NAIRealmElement) anqpElements.get(ANQPElementType.ANQPNAIRealm), - mConfig.getCredential().getRealm(), mEAPMethodID, mAuthParam); - - // In case of Auth mismatch, demote provider match. - if (authMatch == AuthMatch.NONE) { - return PasspointMatch.None; - } + mConfig.getCredential().getRealm()); // In case of no realm match, return provider match as is. - if ((authMatch & AuthMatch.REALM) == 0) { + if (!realmMatch) { + if (mVerboseLoggingEnabled) { + Log.d(TAG, "No NAI realm match, final match: " + providerMatch); + } return providerMatch; } - // Promote the provider match to roaming provider if provider match is not found, but NAI + if (mVerboseLoggingEnabled) { + Log.d(TAG, "NAI realm match with " + mConfig.getCredential().getRealm()); + } + + // Promote the provider match to RoamingProvider if provider match is not found, but NAI // realm is matched. - return providerMatch == PasspointMatch.None ? PasspointMatch.RoamingProvider - : providerMatch; + if (providerMatch == PasspointMatch.None) { + providerMatch = PasspointMatch.RoamingProvider; + } + + if (mVerboseLoggingEnabled) { + Log.d(TAG, "Final match: " + providerMatch); + } + return providerMatch; } /** @@ -570,42 +585,129 @@ public class PasspointProvider { } /** + * Match given OIs to the Roaming Consortium OIs + * + * @param providerOis Provider OIs to match against + * @param roamingConsortiumElement RCOIs in the ANQP element + * @param roamingConsortiumFromAp RCOIs in the AP scan results + * @param matchAll Indicates if all providerOis must match the RCOIs elements + * @return {@code true} if there is a match, {@code false} otherwise. + */ + private boolean matchOis(long[] providerOis, + RoamingConsortiumElement roamingConsortiumElement, + RoamingConsortium roamingConsortiumFromAp, + boolean matchAll) { + + + // ANQP Roaming Consortium OI matching. + if (ANQPMatcher.matchRoamingConsortium(roamingConsortiumElement, providerOis, matchAll)) { + if (mVerboseLoggingEnabled) { + Log.e(TAG, "ANQP RCOI match " + roamingConsortiumElement); + } + return true; + } + + // AP Roaming Consortium OI matching. + long[] apRoamingConsortiums = roamingConsortiumFromAp.getRoamingConsortiums(); + if (apRoamingConsortiums == null || providerOis == null) { + return false; + } + // Roaming Consortium OI information element matching. + for (long apOi: apRoamingConsortiums) { + boolean matched = false; + for (long providerOi: providerOis) { + if (apOi == providerOi) { + if (mVerboseLoggingEnabled) { + Log.e(TAG, "AP RCOI match: " + apOi); + } + if (!matchAll) { + return true; + } else { + matched = true; + break; + } + } + } + if (matchAll && !matched) { + return false; + } + } + return matchAll; + } + + /** * Perform a provider match based on the given ANQP elements except for matching 3GPP Network. * * @param anqpElements List of ANQP elements - * @param roamingConsortium Roaming Consortium information element from the AP + * @param roamingConsortiumFromAp Roaming Consortium information element from the AP * @return {@link PasspointMatch} */ - private PasspointMatch matchProviderExceptFor3GPP( + private PasspointMatch matchFqdnAndRcoi( Map<ANQPElementType, ANQPElement> anqpElements, - RoamingConsortium roamingConsortium) { + RoamingConsortium roamingConsortiumFromAp) { // Domain name matching. if (ANQPMatcher.matchDomainName( (DomainNameElement) anqpElements.get(ANQPElementType.ANQPDomName), mConfig.getHomeSp().getFqdn(), mImsiParameter, mMatchingSIMImsiList)) { + if (mVerboseLoggingEnabled) { + Log.d(TAG, "Domain name " + mConfig.getHomeSp().getFqdn() + + " match: HomeProvider"); + } return PasspointMatch.HomeProvider; } - // ANQP Roaming Consortium OI matching. - long[] providerOIs = mConfig.getHomeSp().getRoamingConsortiumOis(); - if (ANQPMatcher.matchRoamingConsortium( - (RoamingConsortiumElement) anqpElements.get(ANQPElementType.ANQPRoamingConsortium), - providerOIs)) { - return PasspointMatch.RoamingProvider; + // Other Home Partners matching. + if (mConfig.getHomeSp().getOtherHomePartners() != null) { + for (String otherHomePartner : mConfig.getHomeSp().getOtherHomePartners()) { + if (ANQPMatcher.matchDomainName( + (DomainNameElement) anqpElements.get(ANQPElementType.ANQPDomName), + otherHomePartner, null, null)) { + if (mVerboseLoggingEnabled) { + Log.d(TAG, "Other Home Partner " + otherHomePartner + + " match: HomeProvider"); + } + return PasspointMatch.HomeProvider; + } + } } - long[] roamingConsortiums = roamingConsortium.getRoamingConsortiums(); - // Roaming Consortium OI information element matching. - if (roamingConsortiums != null && providerOIs != null) { - for (long sta_oi: roamingConsortiums) { - for (long ap_oi: providerOIs) { - if (sta_oi == ap_oi) { - return PasspointMatch.RoamingProvider; - } + // HomeOI matching + if (mConfig.getHomeSp().getMatchAllOis() != null) { + // Ensure that every HomeOI whose corresponding HomeOIRequired value is true shall match + // an OI in the Roaming Consortium advertised by the hotspot operator. + if (matchOis(mConfig.getHomeSp().getMatchAllOis(), (RoamingConsortiumElement) + anqpElements.get(ANQPElementType.ANQPRoamingConsortium), + roamingConsortiumFromAp, true)) { + if (mVerboseLoggingEnabled) { + Log.e(TAG, "All HomeOI RCOI match: HomeProvider"); + } + return PasspointMatch.HomeProvider; + } + } else if (mConfig.getHomeSp().getMatchAnyOis() != null) { + // Ensure that any HomeOI whose corresponding HomeOIRequired value is false shall match + // an OI in the Roaming Consortium advertised by the hotspot operator. + if (matchOis(mConfig.getHomeSp().getMatchAnyOis(), (RoamingConsortiumElement) + anqpElements.get(ANQPElementType.ANQPRoamingConsortium), + roamingConsortiumFromAp, false)) { + if (mVerboseLoggingEnabled) { + Log.e(TAG, "Any HomeOI RCOI match: HomeProvider"); } + return PasspointMatch.HomeProvider; } } + // Roaming Consortium OI matching. + if (matchOis(mConfig.getHomeSp().getRoamingConsortiumOis(), (RoamingConsortiumElement) + anqpElements.get(ANQPElementType.ANQPRoamingConsortium), + roamingConsortiumFromAp, false)) { + if (mVerboseLoggingEnabled) { + Log.e(TAG, "ANQP RCOI match: RoamingProvider"); + } + return PasspointMatch.RoamingProvider; + } + if (mVerboseLoggingEnabled) { + Log.e(TAG, "No domain name or RCOI match"); + } return PasspointMatch.None; } @@ -768,4 +870,12 @@ public class PasspointProvider { simCredential.setEapType(eapType); return simCredential; } + + /** + * Enable verbose logging + * @param verbose more than 0 enables verbose logging + */ + public void enableVerboseLogging(int verbose) { + mVerboseLoggingEnabled = (verbose > 0) ? true : false; + } } diff --git a/tests/wifitests/src/com/android/server/wifi/hotspot2/ANQPMatcherTest.java b/tests/wifitests/src/com/android/server/wifi/hotspot2/ANQPMatcherTest.java index 4d4ea4487..df9c332a3 100644 --- a/tests/wifitests/src/com/android/server/wifi/hotspot2/ANQPMatcherTest.java +++ b/tests/wifitests/src/com/android/server/wifi/hotspot2/ANQPMatcherTest.java @@ -33,7 +33,6 @@ import com.android.server.wifi.hotspot2.anqp.RoamingConsortiumElement; import com.android.server.wifi.hotspot2.anqp.ThreeGPPNetworkElement; import com.android.server.wifi.hotspot2.anqp.eap.AuthParam; import com.android.server.wifi.hotspot2.anqp.eap.EAPMethod; -import com.android.server.wifi.hotspot2.anqp.eap.InnerAuthEAP; import com.android.server.wifi.hotspot2.anqp.eap.NonEAPInnerAuth; import org.junit.Test; @@ -102,7 +101,7 @@ public class ANQPMatcherTest { */ @Test public void matchRoamingConsortiumWithNullElement() throws Exception { - assertFalse(ANQPMatcher.matchRoamingConsortium(null, new long[0])); + assertFalse(ANQPMatcher.matchRoamingConsortium(null, new long[0], false)); } /** @@ -116,23 +115,22 @@ public class ANQPMatcherTest { long oi = 0x1234L; RoamingConsortiumElement element = new RoamingConsortiumElement(Arrays.asList(new Long[] {oi})); - assertTrue(ANQPMatcher.matchRoamingConsortium(element, new long[] {oi})); + assertTrue(ANQPMatcher.matchRoamingConsortium(element, new long[] {oi}, false)); } /** - * Verify that an indeterminate match will be returned when matching a null NAI Realm + * Verify that no match will be returned when matching a null NAI Realm * ANQP element. * * @throws Exception */ @Test public void matchNAIRealmWithNullElement() throws Exception { - assertEquals(AuthMatch.INDETERMINATE, ANQPMatcher.matchNAIRealm(null, "test.com", - EAPConstants.EAP_TLS, new InnerAuthEAP(EAPConstants.EAP_TTLS))); + assertFalse(ANQPMatcher.matchNAIRealm(null, "test.com")); } /** - * Verify that an indeterminate match will be returned when matching a NAI Realm + * Verify that no match will be returned when matching a NAI Realm * ANQP element contained no NAI realm data. * * @throws Exception @@ -140,8 +138,7 @@ public class ANQPMatcherTest { @Test public void matchNAIRealmWithEmtpyRealmData() throws Exception { NAIRealmElement element = new NAIRealmElement(new ArrayList<NAIRealmData>()); - assertEquals(AuthMatch.INDETERMINATE, ANQPMatcher.matchNAIRealm(element, "test.com", - EAPConstants.EAP_TLS, null)); + assertFalse(ANQPMatcher.matchNAIRealm(element, "test.com")); } /** @@ -157,38 +154,11 @@ public class ANQPMatcherTest { Arrays.asList(new String[] {realm}), new ArrayList<EAPMethod>()); NAIRealmElement element = new NAIRealmElement( Arrays.asList(new NAIRealmData[] {realmData})); - assertEquals(AuthMatch.REALM, ANQPMatcher.matchNAIRealm(element, realm, - EAPConstants.EAP_TLS, null)); + assertTrue(ANQPMatcher.matchNAIRealm(element, realm)); } /** - * Verify that method match will be returned when the specified EAP - * method only matches a eap method in the NAI Realm ANQP element if the element does not have - * auth params. - * - * @throws Exception - */ - @Test - public void matchNAIRealmWithMethodMatch() throws Exception { - // Test data. - String providerRealm = "test.com"; - String anqpRealm = "test2.com"; - NonEAPInnerAuth authParam = new NonEAPInnerAuth(NonEAPInnerAuth.AUTH_TYPE_MSCHAP); - int eapMethodID = EAPConstants.EAP_TLS; - - // Setup NAI Realm element that has EAP method and no auth params. - EAPMethod method = new EAPMethod(eapMethodID, new HashMap<Integer, Set<AuthParam>>()); - NAIRealmData realmData = new NAIRealmData( - Arrays.asList(new String[]{anqpRealm}), Arrays.asList(new EAPMethod[]{method})); - NAIRealmElement element = new NAIRealmElement( - Arrays.asList(new NAIRealmData[]{realmData})); - - assertEquals(AuthMatch.METHOD, - ANQPMatcher.matchNAIRealm(element, providerRealm, eapMethodID, authParam)); - } - - /** - * Verify that a realm and method match will be returned when the specified realm and EAP + * Verify that a realm match will be returned when the specified realm and EAP * method matches a realm in the NAI Realm ANQP element. * * @throws Exception @@ -206,12 +176,11 @@ public class ANQPMatcherTest { NAIRealmElement element = new NAIRealmElement( Arrays.asList(new NAIRealmData[] {realmData})); - assertEquals(AuthMatch.REALM | AuthMatch.METHOD, - ANQPMatcher.matchNAIRealm(element, realm, eapMethodID, null)); + assertTrue(ANQPMatcher.matchNAIRealm(element, realm)); } /** - * Verify that an exact match will be returned when the specified realm, EAP + * Verify that a realm match will be returned when the specified realm, EAP * method, and the authentication parameter matches a realm with the associated EAP method and * authentication parameter in the NAI Realm ANQP element. * @@ -235,12 +204,11 @@ public class ANQPMatcherTest { NAIRealmElement element = new NAIRealmElement( Arrays.asList(new NAIRealmData[] {realmData})); - assertEquals(AuthMatch.EXACT, - ANQPMatcher.matchNAIRealm(element, realm, eapMethodID, authParam)); + assertTrue(ANQPMatcher.matchNAIRealm(element, realm)); } /** - * Verify that a mismatch (AuthMatch.NONE) will be returned when the specified EAP method + * Verify that a realm match will be returned when the specified EAP method * doesn't match with the corresponding EAP method in the NAI Realm ANQP element. * * @throws Exception @@ -263,12 +231,11 @@ public class ANQPMatcherTest { NAIRealmElement element = new NAIRealmElement( Arrays.asList(new NAIRealmData[] {realmData})); - assertEquals(AuthMatch.NONE, - ANQPMatcher.matchNAIRealm(element, realm, EAPConstants.EAP_TLS, null)); + assertTrue(ANQPMatcher.matchNAIRealm(element, realm)); } /** - * Verify that a mismatch (AuthMatch.NONE) will be returned when the specified authentication + * Verify that a realm match will be returned when the specified authentication * parameter doesn't match with the corresponding authentication parameter in the NAI Realm * ANQP element. * @@ -292,10 +259,8 @@ public class ANQPMatcherTest { NAIRealmElement element = new NAIRealmElement( Arrays.asList(new NAIRealmData[] {realmData})); - // Mismatch in authentication type. - assertEquals(AuthMatch.NONE, - ANQPMatcher.matchNAIRealm(element, realm, EAPConstants.EAP_TTLS, - new NonEAPInnerAuth(NonEAPInnerAuth.AUTH_TYPE_PAP))); + // Mismatch in authentication type which we ignore. + assertTrue(ANQPMatcher.matchNAIRealm(element, realm)); } /** @@ -458,4 +423,64 @@ public class ANQPMatcherTest { assertEquals(-1, ANQPMatcher.getCarrierEapMethodFromMatchingNAIRealm(TEST_3GPP_FQDN, element)); } + + /** + * Verify that match is found when HomeOI contains some of the RCOIs advertised by an AP marked + * as not required. + * + * @throws Exception + */ + @Test + public void matchAnyHomeOi() throws Exception { + long[] providerOis = new long[] {0x1234L, 0x5678L, 0xabcdL}; + Long[] anqpOis = new Long[] {0x1234L, 0x5678L, 0xdeadL, 0xf0cdL}; + RoamingConsortiumElement element = + new RoamingConsortiumElement(Arrays.asList(anqpOis)); + assertTrue(ANQPMatcher.matchRoamingConsortium(element, providerOis, false)); + } + + /** + * Verify that no match is found when HomeOI does not contain any of the RCOIs advertised by an + * AP marked as not required. + * + * @throws Exception + */ + @Test + public void matchAnyHomeOiNegative() throws Exception { + long[] providerOis = new long[] {0x1234L, 0x5678L, 0xabcdL}; + Long[] anqpOis = new Long[] {0xabc2L, 0x1232L}; + RoamingConsortiumElement element = + new RoamingConsortiumElement(Arrays.asList(anqpOis)); + assertFalse(ANQPMatcher.matchRoamingConsortium(element, providerOis, false)); + } + + /** + * Verify that match is found when HomeOI contains all of the RCOIs advertised by an AP marked + * as required. + * + * @throws Exception + */ + @Test + public void matchAllHomeOi() throws Exception { + long[] providerOis = new long[] {0x1234L, 0x5678L, 0xabcdL}; + Long[] anqpOis = new Long[] {0x1234L, 0x5678L, 0xabcdL, 0xdeadL, 0xf0cdL}; + RoamingConsortiumElement element = + new RoamingConsortiumElement(Arrays.asList(anqpOis)); + assertTrue(ANQPMatcher.matchRoamingConsortium(element, providerOis, true)); + } + + /** + * Verify that match is not found when HomeOI does not contain all of the RCOIs advertised by an + * AP marked as required. + * + * @throws Exception + */ + @Test + public void matchAllHomeOiNegative() throws Exception { + long[] providerOis = new long[] {0x1234L, 0x5678L, 0xabcdL}; + Long[] anqpOis = new Long[] {0x1234L, 0x5678L, 0xdeadL, 0xf0cdL}; + RoamingConsortiumElement element = + new RoamingConsortiumElement(Arrays.asList(anqpOis)); + assertFalse(ANQPMatcher.matchRoamingConsortium(element, providerOis, true)); + } } diff --git a/tests/wifitests/src/com/android/server/wifi/hotspot2/PasspointProviderTest.java b/tests/wifitests/src/com/android/server/wifi/hotspot2/PasspointProviderTest.java index 31229c562..c35d67301 100644 --- a/tests/wifitests/src/com/android/server/wifi/hotspot2/PasspointProviderTest.java +++ b/tests/wifitests/src/com/android/server/wifi/hotspot2/PasspointProviderTest.java @@ -478,9 +478,10 @@ public class PasspointProviderTest { } /** - * Verify that there is no match when the provider's FQDN matches a domain name in the - * Domain Name ANQP element but the provider's credential doesn't match the authentication - * method provided in the NAI realm. + * Verify that Home provider is matched even when the provider's FQDN matches a domain name in + * the Domain Name ANQP element but the provider's credential doesn't match the authentication + * method provided in the NAI realm. This can happen when the infrastructure provider is not + * the identity provider, and authentication method matching is not required in the spec. * * @throws Exception */ @@ -509,7 +510,8 @@ public class PasspointProviderTest { anqpElementMap.put(ANQPElementType.ANQPNAIRealm, createNAIRealmElement(testRealm, EAPConstants.EAP_TLS, null)); - assertEquals(PasspointMatch.None, mProvider.match(anqpElementMap, mRoamingConsortium)); + assertEquals(PasspointMatch.HomeProvider, + mProvider.match(anqpElementMap, mRoamingConsortium)); } /** @@ -657,8 +659,8 @@ public class PasspointProviderTest { } /** - * Verify that there is no match when a roaming consortium OI matches an OI - * in the roaming consortium ANQP element and but NAI realm is not matched. + * Verify that there is Roaming provider match when a roaming consortium OI matches an OI + * in the roaming consortium ANQP element and regardless of NAI realm mismatch. * * @throws Exception */ @@ -689,7 +691,7 @@ public class PasspointProviderTest { anqpElementMap.put(ANQPElementType.ANQPNAIRealm, createNAIRealmElement(testRealm, EAPConstants.EAP_TLS, null)); - assertEquals(PasspointMatch.None, + assertEquals(PasspointMatch.RoamingProvider, mProvider.match(anqpElementMap, mRoamingConsortium)); } @@ -766,8 +768,14 @@ public class PasspointProviderTest { } /** - * Verify that there is no match when a roaming consortium OI matches an OI + * Verify that there is Roaming provider match when a roaming consortium OI matches an OI * in the roaming consortium information element, but NAI realm is not matched. + * This can happen in roaming federation where the infrastructure provider is not the + * identity provider. + * Page 133 in the Hotspot2.0 specification states: + * Per subclause 11.25.8 of [2], if the value of HomeOI matches an OI in the Roaming + * Consortium advertised by a hotspot operator, successful authentication with that hotspot + * is possible. * * @throws Exception */ @@ -799,7 +807,7 @@ public class PasspointProviderTest { anqpElementMap.put(ANQPElementType.ANQPNAIRealm, createNAIRealmElement(testRealm, EAPConstants.EAP_TLS, null)); - assertEquals(PasspointMatch.None, + assertEquals(PasspointMatch.RoamingProvider, mProvider.match(anqpElementMap, mRoamingConsortium)); } @@ -1354,4 +1362,167 @@ public class PasspointProviderTest { mProvider.setHasEverConnected(true); assertTrue(mProvider.getHasEverConnected()); } + + /** + * Verify that an expected WifiConfiguration will be returned for a Passpoint provider + * with a user credential. + * + * @throws Exception + */ + @Test + public void matchOtherPartnersDomainName() throws Exception { + // Setup test provider. + PasspointConfiguration config = new PasspointConfiguration(); + HomeSp homeSp = new HomeSp(); + homeSp.setFqdn("test1.com"); + homeSp.setOtherHomePartners(new String [] {"test3.com"}); + config.setHomeSp(homeSp); + Credential credential = new Credential(); + credential.setUserCredential(new Credential.UserCredential()); + config.setCredential(credential); + mProvider = createProvider(config); + verifyInstalledConfig(config, true); + + // Setup Domain Name ANQP element to test2.com and test3.com + Map<ANQPElementType, ANQPElement> anqpElementMap = new HashMap<>(); + anqpElementMap.put(ANQPElementType.ANQPDomName, + createDomainNameElement(new String[] {"test2.com", "test3.com"})); + + assertEquals(PasspointMatch.HomeProvider, + mProvider.match(anqpElementMap, mRoamingConsortium)); + } + + /** + * Verify that matching Any HomeOI results in a Home Provider match + * + * @throws Exception + */ + @Test + public void matchAnyHomeOi() throws Exception { + // Setup test provider. + PasspointConfiguration config = new PasspointConfiguration(); + HomeSp homeSp = new HomeSp(); + homeSp.setFqdn("test1.com"); + homeSp.setMatchAnyOis(new long[] {0x1234L, 0x2345L}); + homeSp.setRoamingConsortiumOis(null); + config.setHomeSp(homeSp); + Credential credential = new Credential(); + credential.setUserCredential(new Credential.UserCredential()); + config.setCredential(credential); + mProvider = createProvider(config); + verifyInstalledConfig(config, true); + Long[] anqpOis = new Long[] {0x1234L, 0xdeadL, 0xf0cdL}; + + // Setup Domain Name ANQP element to test2.com and test3.com + Map<ANQPElementType, ANQPElement> anqpElementMap = new HashMap<>(); + anqpElementMap.put(ANQPElementType.ANQPDomName, + createDomainNameElement(new String[] {"test2.com", "test3.com"})); + // Setup RCOIs advertised by the AP + anqpElementMap.put(ANQPElementType.ANQPRoamingConsortium, + createRoamingConsortiumElement(anqpOis)); + + assertEquals(PasspointMatch.HomeProvider, + mProvider.match(anqpElementMap, mRoamingConsortium)); + } + + /** + * Verify that non-matching Any HomeOI results in a None Provider match + * + * @throws Exception + */ + @Test + public void matchAnyHomeOiNegative() throws Exception { + // Setup test provider. + PasspointConfiguration config = new PasspointConfiguration(); + HomeSp homeSp = new HomeSp(); + homeSp.setFqdn("test1.com"); + homeSp.setMatchAnyOis(new long[] {0x1234L, 0x2345L}); + homeSp.setRoamingConsortiumOis(null); + config.setHomeSp(homeSp); + Credential credential = new Credential(); + credential.setUserCredential(new Credential.UserCredential()); + config.setCredential(credential); + mProvider = createProvider(config); + verifyInstalledConfig(config, true); + Long[] anqpOis = new Long[] {0x12a4L, 0xceadL, 0xf0cdL}; + + // Setup Domain Name ANQP element to test2.com and test3.com + Map<ANQPElementType, ANQPElement> anqpElementMap = new HashMap<>(); + anqpElementMap.put(ANQPElementType.ANQPDomName, + createDomainNameElement(new String[] {"test2.com", "test3.com"})); + // Setup RCOIs advertised by the AP + anqpElementMap.put(ANQPElementType.ANQPRoamingConsortium, + createRoamingConsortiumElement(anqpOis)); + + assertEquals(PasspointMatch.None, + mProvider.match(anqpElementMap, mRoamingConsortium)); + } + + /** + * Verify that matching All HomeOI results in a Home Provider match + * + * @throws Exception + */ + @Test + public void matchAllHomeOi() throws Exception { + // Setup test provider. + PasspointConfiguration config = new PasspointConfiguration(); + HomeSp homeSp = new HomeSp(); + homeSp.setFqdn("test1.com"); + homeSp.setMatchAllOis(new long[] {0x1234L, 0x2345L}); + homeSp.setRoamingConsortiumOis(null); + config.setHomeSp(homeSp); + Credential credential = new Credential(); + credential.setUserCredential(new Credential.UserCredential()); + config.setCredential(credential); + mProvider = createProvider(config); + verifyInstalledConfig(config, true); + Long[] anqpOis = new Long[] {0x1234L, 0x2345L, 0xabcdL, 0xdeadL, 0xf0cdL}; + + // Setup Domain Name ANQP element to test2.com and test3.com + Map<ANQPElementType, ANQPElement> anqpElementMap = new HashMap<>(); + anqpElementMap.put(ANQPElementType.ANQPDomName, + createDomainNameElement(new String[] {"test2.com", "test3.com"})); + // Setup RCOIs advertised by the AP + anqpElementMap.put(ANQPElementType.ANQPRoamingConsortium, + createRoamingConsortiumElement(anqpOis)); + + assertEquals(PasspointMatch.HomeProvider, + mProvider.match(anqpElementMap, mRoamingConsortium)); + } + + /** + * Verify that non-matching All HomeOI results in a None Provider match + * + * @throws Exception + */ + @Test + public void matchAllHomeOiNegative() throws Exception { + // Setup test provider. + PasspointConfiguration config = new PasspointConfiguration(); + HomeSp homeSp = new HomeSp(); + homeSp.setFqdn("test1.com"); + homeSp.setMatchAllOis(new long[] {0x1234L, 0x2345L}); + homeSp.setRoamingConsortiumOis(null); + config.setHomeSp(homeSp); + Credential credential = new Credential(); + credential.setUserCredential(new Credential.UserCredential()); + config.setCredential(credential); + mProvider = createProvider(config); + verifyInstalledConfig(config, true); + + // 0x1234 matches, but 0x2345 does not + Long[] anqpOis = new Long[] {0x1234L, 0x5678L, 0xdeadL, 0xf0cdL}; + + // Setup Domain Name ANQP element to test2.com and test3.com + Map<ANQPElementType, ANQPElement> anqpElementMap = new HashMap<>(); + anqpElementMap.put(ANQPElementType.ANQPDomName, + createDomainNameElement(new String[] {"test2.com", "test3.com"})); + // Setup RCOIs advertised by the AP + anqpElementMap.put(ANQPElementType.ANQPRoamingConsortium, + createRoamingConsortiumElement(anqpOis)); + + assertEquals(PasspointMatch.None, + mProvider.match(anqpElementMap, mRoamingConsortium)); + } } |